Skip to content
Snippets Groups Projects
mapSearch.js.map 3.17 MiB
Newer Older
  • Learn to ignore specific revisions
  • {"version":3,"sources":["jquery.min.js","bootstrap.min.js","ol.js","map.js","mapSearch.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;ACJA;AACA;AACA;AACA;AACA;AACA;AACA;ACNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC940FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC3eA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"mapSearch.js","sourcesContent":["/*! jQuery v1.11.2 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */\n!function(a,b){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error(\"jQuery requires a window with a document\");return b(a)}:b(a)}(\"undefined\"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=\"1.11.2\",m=function(a,b){return new m.fn.init(a,b)},n=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,o=/^-ms-/,p=/-([\\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:\"\",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for(\"boolean\"==typeof g&&(j=g,g=arguments[h]||{},h++),\"object\"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:\"jQuery\"+(l+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return\"function\"===m.type(a)},isArray:Array.isArray||function(a){return\"array\"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||\"object\"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,\"constructor\")&&!j.call(a.constructor.prototype,\"isPrototypeOf\"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+\"\":\"object\"==typeof a||\"function\"==typeof a?h[i.call(a)]||\"object\":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,\"ms-\").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?\"\":(a+\"\").replace(n,\"\")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,\"string\"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return\"string\"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"),function(a,b){h[\"[object \"+b+\"]\"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return\"function\"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:\"array\"===c||0===b||\"number\"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u=\"sizzle\"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",L=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",M=\"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",N=M.replace(\"w\",\"w#\"),O=\"\\\\[\"+L+\"*(\"+M+\")(?:\"+L+\"*([*^$|!~]?=)\"+L+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+N+\"))|)\"+L+\"*\\\\]\",P=\":(\"+M+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+O+\")*)|.*)\\\\)|)\",Q=new RegExp(L+\"+\",\"g\"),R=new RegExp(\"^\"+L+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+L+\"+$\",\"g\"),S=new RegExp(\"^\"+L+\"*,\"+L+\"*\"),T=new RegExp(\"^\"+L+\"*([>+~]|\"+L+\")\"+L+\"*\"),U=new RegExp(\"=\"+L+\"*([^\\\\]'\\\"]*?)\"+L+\"*\\\\]\",\"g\"),V=new RegExp(P),W=new RegExp(\"^\"+N+\"$\"),X={ID:new RegExp(\"^#(\"+M+\")\"),CLASS:new RegExp(\"^\\\\.(\"+M+\")\"),TAG:new RegExp(\"^(\"+M.replace(\"w\",\"w*\")+\")\"),ATTR:new RegExp(\"^\"+O),PSEUDO:new RegExp(\"^\"+P),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+L+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+L+\"*(?:([+-]|)\"+L+\"*(\\\\d+)|))\"+L+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+K+\")$\",\"i\"),needsContext:new RegExp(\"^\"+L+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+L+\"*((?:-\\\\d)?\\\\d*)\"+L+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\\d$/i,$=/^[^{]+\\{\\s*\\[native \\w/,_=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ab=/[+~]/,bb=/'|\\\\/g,cb=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+L+\"?|(\"+L+\")|.)\",\"ig\"),db=function(a,b,c){var d=\"0x\"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,\"string\"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&\"object\"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute(\"id\"))?s=r.replace(bb,\"\\\\$&\"):b.setAttribute(\"id\",s),s=\"[id='\"+s+\"'] \",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(\",\")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute(\"id\")}}}return i(a.replace(R,\"$1\"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+\" \")>d.cacheLength&&delete b[a.shift()],b[c+\" \"]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement(\"div\");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split(\"|\"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return\"input\"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return(\"input\"===c||\"button\"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&\"undefined\"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?\"HTML\"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener(\"unload\",eb,!1):e.attachEvent&&e.attachEvent(\"onunload\",eb)),p=!f(g),c.attributes=jb(function(a){return a.className=\"i\",!a.getAttribute(\"className\")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment(\"\")),!a.getElementsByTagName(\"*\").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(\"undefined\"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute(\"id\")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=\"undefined\"!=typeof a.getAttributeNode&&a.getAttributeNode(\"id\");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return\"undefined\"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if(\"*\"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML=\"<a id='\"+u+\"'></a><select id='\"+u+\"-\\f]' msallowcapture=''><option selected=''></option></select>\",a.querySelectorAll(\"[msallowcapture^='']\").length&&q.push(\"[*^$]=\"+L+\"*(?:''|\\\"\\\")\"),a.querySelectorAll(\"[selected]\").length||q.push(\"\\\\[\"+L+\"*(?:value|\"+K+\")\"),a.querySelectorAll(\"[id~=\"+u+\"-]\").length||q.push(\"~=\"),a.querySelectorAll(\":checked\").length||q.push(\":checked\"),a.querySelectorAll(\"a#\"+u+\"+*\").length||q.push(\".#.+[+~]\")}),jb(function(a){var b=g.createElement(\"input\");b.setAttribute(\"type\",\"hidden\"),a.appendChild(b).setAttribute(\"name\",\"D\"),a.querySelectorAll(\"[name=d]\").length&&q.push(\"name\"+L+\"*[*^$|!~]?=\"),a.querySelectorAll(\":enabled\").length||q.push(\":enabled\",\":disabled\"),a.querySelectorAll(\"*,:x\"),q.push(\",.*:\")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,\"div\"),s.call(a,\"[s!='']:x\"),r.push(\"!=\",P)}),q=q.length&&new RegExp(q.join(\"|\")),r=r.length&&new RegExp(r.join(\"|\")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,\"='$1']\"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error(\"Syntax error, unrecognized expression: \"+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c=\"\",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if(\"string\"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||\"\").replace(cb,db),\"~=\"===a[2]&&(a[3]=\" \"+a[3]+\" \"),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),\"nth\"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*(\"even\"===a[3]||\"odd\"===a[3])),a[5]=+(a[7]+a[8]||\"odd\"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||\"\":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(\")\",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return\"*\"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+\" \"];return b||(b=new RegExp(\"(^|\"+L+\")\"+a+\"(\"+L+\"|$)\"))&&y(a,function(a){return b.test(\"string\"==typeof a.className&&a.className||\"undefined\"!=typeof a.getAttribute&&a.getAttribute(\"class\")||\"\")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?\"!=\"===b:b?(e+=\"\",\"=\"===b?e===c:\"!=\"===b?e!==c:\"^=\"===b?c&&0===e.indexOf(c):\"*=\"===b?c&&e.indexOf(c)>-1:\"$=\"===b?c&&e.slice(-c.length)===c:\"~=\"===b?(\" \"+e.replace(Q,\" \")+\" \").indexOf(c)>-1:\"|=\"===b?e===c||e.slice(0,c.length+1)===c+\"-\":!1):!0}},CHILD:function(a,b,c,d,e){var f=\"nth\"!==a.slice(0,3),g=\"last\"!==a.slice(-4),h=\"of-type\"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?\"nextSibling\":\"previousSibling\",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p=\"only\"===a&&!o&&\"nextSibling\"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error(\"unsupported pseudo: \"+a);return e[u]?e(b):e.length>1?(c=[a,a,\"\",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,\"$1\"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||\"\")||gb.error(\"unsupported lang: \"+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute(\"xml:lang\")||b.getAttribute(\"lang\"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+\"-\");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&!!a.checked||\"option\"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&\"button\"===a.type||\"button\"===b},text:function(a){var b;return\"input\"===a.nodeName.toLowerCase()&&\"text\"===a.type&&(null==(b=a.getAttribute(\"type\"))||\"text\"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=mb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=nb(b);function qb(){}qb.prototype=d.filters=d.pseudos,d.setFilters=new qb,g=gb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+\" \"];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R,\" \")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?gb.error(a):z(a,i).slice(0)};function rb(a){for(var b=0,c=a.length,d=\"\";c>b;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&\"parentNode\"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||\"*\",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[\" \"],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:\" \"===a[i-2].type?\"*\":\"\"})).replace(R,\"$1\"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q=\"0\",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG(\"*\",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+\" \"];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n=\"function\"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&\"ID\"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split(\"\").sort(B).join(\"\")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement(\"div\"))}),jb(function(a){return a.innerHTML=\"<a href='#'></a>\",\"#\"===a.firstChild.getAttribute(\"href\")})||kb(\"type|href|height|width\",function(a,b,c){return c?void 0:a.getAttribute(b,\"type\"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML=\"<input/>\",a.firstChild.setAttribute(\"value\",\"\"),\"\"===a.firstChild.getAttribute(\"value\")})||kb(\"value\",function(a,b,c){return c||\"input\"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute(\"disabled\")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);m.find=s,m.expr=s.selectors,m.expr[\":\"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,v=/^.[^:#\\[\\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if(\"string\"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=\":not(\"+a+\")\"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if(\"string\"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+\" \"+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,\"string\"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if(\"string\"==typeof a){if(c=\"<\"===a.charAt(0)&&\">\"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?\"undefined\"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||\"string\"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?\"string\"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,\"parentNode\")},parentsUntil:function(a,b,c){return m.dir(a,\"parentNode\",c)},next:function(a){return D(a,\"nextSibling\")},prev:function(a){return D(a,\"previousSibling\")},nextAll:function(a){return m.dir(a,\"nextSibling\")},prevAll:function(a){return m.dir(a,\"previousSibling\")},nextUntil:function(a,b,c){return m.dir(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return m.dir(a,\"previousSibling\",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return\"Until\"!==a.slice(-5)&&(d=c),d&&\"string\"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a=\"string\"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);\"function\"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&\"string\"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[[\"resolve\",\"done\",m.Callbacks(\"once memory\"),\"resolved\"],[\"reject\",\"fail\",m.Callbacks(\"once memory\"),\"rejected\"],[\"notify\",\"progress\",m.Callbacks(\"memory\")]],c=\"pending\",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+\"With\"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+\"With\"](this===e?d:this,arguments),this},e[f[0]+\"With\"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler(\"ready\"),m(y).off(\"ready\")))}}});function I(){y.addEventListener?(y.removeEventListener(\"DOMContentLoaded\",J,!1),a.removeEventListener(\"load\",J,!1)):(y.detachEvent(\"onreadystatechange\",J),a.detachEvent(\"onload\",J))}function J(){(y.addEventListener||\"load\"===event.type||\"complete\"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),\"complete\"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener(\"DOMContentLoaded\",J,!1),a.addEventListener(\"load\",J,!1);else{y.attachEvent(\"onreadystatechange\",J),a.attachEvent(\"onload\",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll(\"left\")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K=\"undefined\",L;for(L in m(k))break;k.ownLast=\"0\"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName(\"body\")[0],c&&c.style&&(b=y.createElement(\"div\"),d=y.createElement(\"div\"),d.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText=\"display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1\",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement(\"div\");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+\" \").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute(\"classid\")===b};var M=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d=\"data-\"+b.replace(N,\"-$1\").toLowerCase();if(c=a.getAttribute(d),\"string\"==typeof c){try{c=\"true\"===c?!0:\"false\"===c?!1:\"null\"===c?null:+c+\"\"===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if((\"data\"!==b||!m.isEmptyObject(a[b]))&&\"toJSON\"!==b)return!1;\nreturn!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||\"string\"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),(\"object\"==typeof b||\"function\"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),\"string\"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(\" \")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{\"applet \":!0,\"embed \":!0,\"object \":\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,\"parsedAttrs\"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf(\"data-\")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,\"parsedAttrs\",!0)}return e}return\"object\"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||\"fx\")+\"queue\",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||\"fx\";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};\"inprogress\"===e&&(e=c.shift(),d--),e&&(\"fx\"===b&&c.unshift(\"inprogress\"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+\"queueHooks\";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks(\"once memory\").add(function(){m._removeData(a,b+\"queue\"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return\"string\"!=typeof a&&(b=a,a=\"fx\",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),\"fx\"===a&&\"inprogress\"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};\"string\"!=typeof a&&(b=a,a=void 0),a=a||\"fx\";while(g--)c=m._data(f[g],a+\"queueHooks\"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,T=[\"Top\",\"Right\",\"Bottom\",\"Left\"],U=function(a,b){return a=b||a,\"none\"===m.css(a,\"display\")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if(\"object\"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement(\"input\"),b=y.createElement(\"div\"),c=y.createDocumentFragment();if(b.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName(\"tbody\").length,k.htmlSerialize=!!b.getElementsByTagName(\"link\").length,k.html5Clone=\"<:nav></:nav>\"!==y.createElement(\"nav\").cloneNode(!0).outerHTML,a.type=\"checkbox\",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML=\"<textarea>x</textarea>\",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML=\"<input type='radio' checked='checked' name='t'/>\",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent(\"onclick\",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement(\"div\");for(b in{submit:!0,change:!0,focusin:!0})c=\"on\"+b,(k[b+\"Bubbles\"]=c in a)||(d.setAttribute(c,\"t\"),k[b+\"Bubbles\"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||\"\").match(E)||[\"\"],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||\"\").split(\".\").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(\".\")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent(\"on\"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||\"\").match(E)||[\"\"],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||\"\").split(\".\").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp(\"(^|\\\\.)\"+p.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&(\"**\"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,\"events\"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,\"type\")?b.type:b,q=j.call(b,\"namespace\")?b.namespace.split(\".\"):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(\".\")>=0&&(q=p.split(\".\"),p=q.shift(),q.sort()),g=p.indexOf(\":\")<0&&\"on\"+p,b=b[m.expando]?b:new m.Event(p,\"object\"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join(\".\"),b.namespace_re=b.namespace?new RegExp(\"(^|\\\\.)\"+q.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,\"events\")||{})[b.type]&&m._data(h,\"handle\"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,\"events\")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||\"click\"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||\"click\"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+\" \",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:\"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:\"focusin\"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:\"focusout\"},click:{trigger:function(){return m.nodeName(this,\"input\")&&\"checkbox\"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,\"a\")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d=\"on\"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,\"form\")?!1:void m.event.add(this,\"click._submit keypress._submit\",function(a){var b=a.target,c=m.nodeName(b,\"input\")||m.nodeName(b,\"button\")?b.form:void 0;c&&!m._data(c,\"submitBubbles\")&&(m.event.add(c,\"submit._submit\",function(a){a._submit_bubble=!0}),m._data(c,\"submitBubbles\",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate(\"submit\",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,\"form\")?!1:void m.event.remove(this,\"._submit\")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?((\"checkbox\"===this.type||\"radio\"===this.type)&&(m.event.add(this,\"propertychange._change\",function(a){\"checked\"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,\"click._change\",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate(\"change\",this,a,!0)})),!1):void m.event.add(this,\"beforeactivate._change\",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,\"changeBubbles\")&&(m.event.add(b,\"change._change\",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate(\"change\",this.parentNode,a,!0)}),m._data(b,\"changeBubbles\",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||\"radio\"!==b.type&&\"checkbox\"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,\"._change\"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if(\"object\"==typeof a){\"string\"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&(\"string\"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+\".\"+d.namespace:d.origType,d.selector,d.handler),this;if(\"object\"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||\"function\"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split(\"|\"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb=\"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",fb=/ jQuery\\d+=\"(?:null|\\d+)\"/g,gb=new RegExp(\"<(?:\"+eb+\")[\\\\s/>]\",\"i\"),hb=/^\\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,jb=/<([\\w:]+)/,kb=/<tbody/i,lb=/<|&#?\\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\\s*(?:[^=]|=\\s*.checked.)/i,ob=/^$|\\/(?:java|ecma)script/i,pb=/^true\\/(.*)/,qb=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,rb={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],area:[1,\"<map>\",\"</map>\"],param:[1,\"<object>\",\"</object>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:k.htmlSerialize?[0,\"\",\"\"]:[1,\"X<div>\",\"</div>\"]},sb=db(y),tb=sb.appendChild(y.createElement(\"div\"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||\"*\"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||\"*\"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,\"table\")&&m.nodeName(11!==b.nodeType?b:b.firstChild,\"tr\")?a.getElementsByTagName(\"tbody\")[0]||a.appendChild(a.ownerDocument.createElement(\"tbody\")):a}function xb(a){return a.type=(null!==m.find.attr(a,\"type\"))+\"/\"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute(\"type\"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,\"globalEval\",!b||m._data(b[d],\"globalEval\"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}\"script\"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):\"object\"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):\"input\"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):\"option\"===c?b.defaultSelected=b.selected=a.defaultSelected:(\"input\"===c||\"textarea\"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test(\"<\"+a.nodeName+\">\")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,\"script\"),d.length>0&&zb(d,!i&&ub(a,\"script\")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if(\"object\"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement(\"div\")),i=(jb.exec(f)||[\"\",\"\"])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,\"<$1></$2>\")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f=\"table\"!==i||kb.test(f)?\"<table>\"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],\"tbody\")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent=\"\";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,\"input\"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),\"script\"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||\"\")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,\"script\")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,\"select\")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,\"\"):void 0;if(!(\"string\"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||[\"\",\"\"])[1].toLowerCase()])){a=a.replace(ib,\"<$1></$2>\");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&\"string\"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,\"script\"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,\"script\"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||\"\")&&!m._data(d,\"globalEval\")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||\"\").replace(qb,\"\")));i=c=null}return this}}),m.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],\"display\");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),\"none\"!==c&&c||(Cb=(Cb||m(\"<iframe frameborder='0' width='0' height='0'/>\")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName(\"body\")[0],c&&c.style?(b=y.createElement(\"div\"),d=y.createElement(\"div\"),d.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1\",b.appendChild(y.createElement(\"div\")).style.width=\"5px\",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp(\"^(\"+S+\")(?!px)[a-z%]+$\",\"i\"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(\"\"!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+\"\"}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left=\"fontSize\"===b?\"1em\":g,g=h.pixelLeft+\"px\",h.left=d,f&&(e.left=f)),void 0===g?g:g+\"\"||\"auto\"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement(\"div\"),b.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",d=b.getElementsByTagName(\"a\")[0],c=d&&d.style){c.cssText=\"float:left;opacity:.5\",k.opacity=\"0.5\"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip=\"content-box\",b.cloneNode(!0).style.backgroundClip=\"\",k.clearCloneStyle=\"content-box\"===b.style.backgroundClip,k.boxSizing=\"\"===c.boxSizing||\"\"===c.MozBoxSizing||\"\"===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName(\"body\")[0],c&&c.style&&(b=y.createElement(\"div\"),d=y.createElement(\"div\"),d.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",c.appendChild(d).appendChild(b),b.style.cssText=\"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute\",e=f=!1,h=!0,a.getComputedStyle&&(e=\"1%\"!==(a.getComputedStyle(b,null)||{}).top,f=\"4px\"===(a.getComputedStyle(b,null)||{width:\"4px\"}).width,i=b.appendChild(y.createElement(\"div\")),i.style.cssText=b.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0\",i.style.marginRight=i.style.width=\"0\",b.style.width=\"1px\",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight),b.removeChild(i)),b.innerHTML=\"<table><tr><td></td><td>t</td></tr></table>\",i=b.getElementsByTagName(\"td\"),i[0].style.cssText=\"margin:0;border:0;padding:0;display:none\",g=0===i[0].offsetHeight,g&&(i[0].style.display=\"\",i[1].style.display=\"none\",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\\([^)]*\\)/i,Nb=/opacity\\s*=\\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp(\"^(\"+S+\")(.*)$\",\"i\"),Qb=new RegExp(\"^([+-])=(\"+S+\")\",\"i\"),Rb={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Sb={letterSpacing:\"0\",fontWeight:\"400\"},Tb=[\"Webkit\",\"O\",\"Moz\",\"ms\"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,\"olddisplay\"),c=d.style.display,b?(f[g]||\"none\"!==c||(d.style.display=\"\"),\"\"===d.style.display&&U(d)&&(f[g]=m._data(d,\"olddisplay\",Fb(d.nodeName)))):(e=U(d),(c&&\"none\"!==c||!e)&&m._data(d,\"olddisplay\",e?c:m.css(d,\"display\"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&\"none\"!==d.style.display&&\"\"!==d.style.display||(d.style.display=b?f[g]||\"\":\"none\"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||\"px\"):b}function Xb(a,b,c,d,e){for(var f=c===(d?\"border\":\"content\")?4:\"width\"===b?1:0,g=0;4>f;f+=2)\"margin\"===c&&(g+=m.css(a,c+T[f],!0,e)),d?(\"content\"===c&&(g-=m.css(a,\"padding\"+T[f],!0,e)),\"margin\"!==c&&(g-=m.css(a,\"border\"+T[f]+\"Width\",!0,e))):(g+=m.css(a,\"padding\"+T[f],!0,e),\"padding\"!==c&&(g+=m.css(a,\"border\"+T[f]+\"Width\",!0,e)));return g}function Yb(a,b,c){var d=!0,e=\"width\"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&\"border-box\"===m.css(a,\"boxSizing\",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?\"border\":\"content\"),d,f)+\"px\"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,\"opacity\");return\"\"===c?\"1\":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":k.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&\"get\"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,\"string\"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f=\"number\"),null!=c&&c===c&&(\"number\"!==f||m.cssNumber[h]||(c+=\"px\"),k.clearCloneStyle||\"\"!==c||0!==b.indexOf(\"background\")||(i[b]=\"inherit\"),!(g&&\"set\"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&\"get\"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),\"normal\"===f&&b in Sb&&(f=Sb[b]),\"\"===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each([\"height\",\"width\"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,\"display\"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&\"border-box\"===m.css(a,\"boxSizing\",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?.01*parseFloat(RegExp.$1)+\"\":b?\"1\":\"\"},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?\"alpha(opacity=\"+100*b+\")\":\"\",f=d&&d.filter||c.filter||\"\";c.zoom=1,(b>=1||\"\"===b)&&\"\"===m.trim(f.replace(Mb,\"\"))&&c.removeAttribute&&(c.removeAttribute(\"filter\"),\"\"===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+\" \"+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:\"inline-block\"},Jb,[a,\"marginRight\"]):void 0}),m.each({margin:\"\",padding:\"\",border:\"Width\"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f=\"string\"==typeof c?c.split(\" \"):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return\"boolean\"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)\n}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||\"swing\",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?\"\":\"px\")},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,\"\"),b&&\"auto\"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp(\"^(?:([+-])=|)(\"+S+\")([a-z%]*)$\",\"i\"),cc=/queueHooks$/,dc=[ic],ec={\"*\":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?\"\":\"px\"),g=(m.cssNumber[a]||\"px\"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||\".5\",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d[\"margin\"+c]=d[\"padding\"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec[\"*\"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,\"fxshow\");c.queue||(h=m._queueHooks(a,\"fx\"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,\"fx\").length||h.empty.fire()})})),1===a.nodeType&&(\"height\"in b||\"width\"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,\"display\"),l=\"none\"===j?m._data(a,\"olddisplay\")||Fb(a.nodeName):j,\"inline\"===l&&\"none\"===m.css(a,\"float\")&&(k.inlineBlockNeedsLayout&&\"inline\"!==Fb(a.nodeName)?p.zoom=1:p.display=\"inline-block\")),c.overflow&&(p.overflow=\"hidden\",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||\"toggle\"===e,e===(q?\"hide\":\"show\")){if(\"show\"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))\"inline\"===(\"none\"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?\"hidden\"in r&&(q=r.hidden):r=m._data(a,\"fxshow\",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,\"fxshow\");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start=\"width\"===d||\"height\"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&\"expand\"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=[\"*\"]):a=a.split(\" \");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&\"object\"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:\"number\"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue=\"fx\"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,\"finish\"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return\"string\"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||\"fx\",[]),this.each(function(){var b=!0,e=null!=a&&a+\"queueHooks\",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||\"fx\"),this.each(function(){var b,c=m._data(this),d=c[a+\"queue\"],e=c[a+\"queueHooks\"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each([\"toggle\",\"show\",\"hide\"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||\"boolean\"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc(\"show\"),slideUp:gc(\"hide\"),slideToggle:gc(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||\"fx\",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement(\"div\"),b.setAttribute(\"className\",\"t\"),b.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",d=b.getElementsByTagName(\"a\")[0],c=y.createElement(\"select\"),e=c.appendChild(y.createElement(\"option\")),a=b.getElementsByTagName(\"input\")[0],d.style.cssText=\"top:1px\",k.getSetAttribute=\"t\"!==b.className,k.style=/top/.test(d.getAttribute(\"style\")),k.hrefNormalized=\"/a\"===d.getAttribute(\"href\"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement(\"form\").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement(\"input\"),a.setAttribute(\"value\",\"\"),k.input=\"\"===a.getAttribute(\"value\"),a.value=\"t\",a.setAttribute(\"type\",\"radio\"),k.radioValue=\"t\"===a.value}();var lc=/\\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e=\"\":\"number\"==typeof e?e+=\"\":m.isArray(e)&&(e=m.map(e,function(a){return null==a?\"\":a+\"\"})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&\"set\"in b&&void 0!==b.set(this,e,\"value\")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&\"get\"in b&&void 0!==(c=b.get(e,\"value\"))?c:(c=e.value,\"string\"==typeof c?c.replace(lc,\"\"):null==c?\"\":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,\"value\");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f=\"select-one\"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute(\"disabled\"))||c.parentNode.disabled&&m.nodeName(c.parentNode,\"optgroup\"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each([\"radio\",\"checkbox\"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute(\"value\")?\"on\":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&\"get\"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&\"set\"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+\"\"),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase(\"default-\"+c)]=a[d]=!1:m.attr(a,c,\"\"),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&\"radio\"===b&&m.nodeName(a,\"input\")){var c=a.value;return a.setAttribute(\"type\",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase(\"default-\"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase(\"default-\"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,\"input\")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+=\"\",\"value\"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&\"\"!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,\"\"===b?!1:b,c)}},m.each([\"width\",\"height\"],function(a,b){m.attrHooks[b]={set:function(a,c){return\"\"===c?(a.setAttribute(b,\"auto\"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+\"\"}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{\"for\":\"htmlFor\",\"class\":\"className\"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&\"set\"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&\"get\"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,\"tabindex\");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each([\"href\",\"src\"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype=\"encoding\");var uc=/[\\t\\r\\n\\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=\"string\"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||\"\").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(\" \"+c.className+\" \").replace(uc,\" \"):\" \")){f=0;while(e=b[f++])d.indexOf(\" \"+e+\" \")<0&&(d+=e+\" \");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||\"string\"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||\"\").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(\" \"+c.className+\" \").replace(uc,\" \"):\"\")){f=0;while(e=b[f++])while(d.indexOf(\" \"+e+\" \")>=0)d=d.replace(\" \"+e+\" \",\" \");g=a?m.trim(d):\"\",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return\"boolean\"==typeof b&&\"string\"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if(\"string\"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||\"boolean\"===c)&&(this.className&&m._data(this,\"__className__\",this.className),this.className=this.className||a===!1?\"\":m._data(this,\"__className__\")||\"\")})},hasClass:function(a){for(var b=\" \"+a+\" \",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(\" \"+this[c].className+\" \").replace(uc,\" \").indexOf(b)>=0)return!0;return!1}}),m.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu\".split(\" \"),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,\"**\"):this.off(b,a||\"**\",c)}});var vc=m.now(),wc=/\\?/,xc=/(,)|(\\[|{)|(}|])|\"(?:[^\"\\\\\\r\\n]|\\\\[\"\\\\\\/bfnrt]|\\\\u[\\da-fA-F]{4})*\"\\s*:?|true|false|null|-?(?!0\\d)\\d+(?:\\.\\d+|)(?:[eE][+-]?\\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+\"\");var c,d=null,e=m.trim(b+\"\");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,\"\")}))?Function(\"return \"+e)():m.error(\"Invalid JSON: \"+b)},m.parseXML=function(b){var c,d;if(!b||\"string\"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,\"text/xml\")):(c=new ActiveXObject(\"Microsoft.XMLDOM\"),c.async=\"false\",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName(\"parsererror\").length||m.error(\"Invalid XML: \"+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\\/\\//,Gc=/^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,Hc={},Ic={},Jc=\"*/\".concat(\"*\");try{zc=location.href}catch(Kc){zc=y.createElement(\"a\"),zc.href=\"\",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){\"string\"!=typeof b&&(c=b,b=\"*\");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])\"+\"===d.charAt(0)?(d=d.slice(1)||\"*\",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return\"string\"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e[\"*\"]&&g(\"*\")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while(\"*\"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader(\"Content-Type\"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+\" \"+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if(\"*\"===f)f=i;else if(\"*\"!==i&&i!==f){if(g=j[i+\" \"+f]||j[\"* \"+f],!g)for(e in j)if(h=e.split(\" \"),h[1]===f&&(g=j[i+\" \"+h[0]]||j[\"* \"+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a[\"throws\"])b=g(b);else try{b=g(b)}catch(l){return{state:\"parsererror\",error:g?l:\"No conversion from \"+i+\" to \"+f}}}return{state:\"success\",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:\"GET\",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Jc,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":m.parseJSON,\"text xml\":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){\"object\"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks(\"once memory\"),q=k.statusCode||{},r={},s={},t=0,u=\"canceled\",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+\"\").replace(Ac,\"\").replace(Fc,yc[1]+\"//\"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||\"*\").toLowerCase().match(E)||[\"\"],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||(\"http:\"===c[1]?\"80\":\"443\"))===(yc[3]||(\"http:\"===yc[1]?\"80\":\"443\")))),k.data&&k.processData&&\"string\"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=m.event&&k.global,h&&0===m.active++&&m.event.trigger(\"ajaxStart\"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?\"&\":\"?\")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,\"$1_=\"+vc++):e+(wc.test(e)?\"&\":\"?\")+\"_=\"+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader(\"If-Modified-Since\",m.lastModified[e]),m.etag[e]&&v.setRequestHeader(\"If-None-Match\",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader(\"Content-Type\",k.contentType),v.setRequestHeader(\"Accept\",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+(\"*\"!==k.dataTypes[0]?\", \"+Jc+\"; q=0.01\":\"\"):k.accepts[\"*\"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u=\"abort\";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger(\"ajaxSend\",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort(\"timeout\")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,\"No Transport\");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||\"\",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader(\"Last-Modified\"),w&&(m.lastModified[e]=w),w=v.getResponseHeader(\"etag\"),w&&(m.etag[e]=w)),204===a||\"HEAD\"===k.type?x=\"nocontent\":304===a?x=\"notmodified\":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x=\"error\",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+\"\",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?\"ajaxSuccess\":\"ajaxError\",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger(\"ajaxComplete\",[v,k]),--m.active||m.event.trigger(\"ajaxStop\")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,\"json\")},getScript:function(a,b){return m.get(a,void 0,b,\"script\")}}),m.each([\"get\",\"post\"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m._evalUrl=function(a){return m.ajax({url:a,type:\"GET\",dataType:\"script\",async:!1,global:!1,\"throws\":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,\"body\")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&\"none\"===(a.style&&a.style.display||m.css(a,\"display\"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\\[\\]$/,Sc=/\\r?\\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+\"[\"+(\"object\"==typeof e?b:\"\")+\"]\",e,c,d)});else if(c||\"object\"!==m.type(b))d(a,b);else for(e in b)Vc(a+\"[\"+e+\"]\",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?\"\":b,d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join(\"&\").replace(Qc,\"+\")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,\"elements\");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(\":disabled\")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,\"\\r\\n\")}}):{name:b.name,value:c.replace(Sc,\"\\r\\n\")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.attachEvent&&a.attachEvent(\"onunload\",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&\"withCredentials\"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c[\"X-Requested-With\"]||(c[\"X-Requested-With\"]=\"XMLHttpRequest\");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+\"\");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,\"string\"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=\"\"}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}}m.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/(?:java|ecma)script/},converters:{\"text script\":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter(\"script\",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\",a.global=!1)}),m.ajaxTransport(\"script\",function(a){if(a.crossDomain){var b,c=y.head||m(\"head\")[0]||y.documentElement;return{send:function(d,e){b=y.createElement(\"script\"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,\"success\"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\\?(?=&|$)|\\?\\?/;m.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var a=_c.pop()||m.expando+\"_\"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?\"url\":\"string\"==typeof b.data&&!(b.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&ad.test(b.data)&&\"data\");return h||\"jsonp\"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,\"$1\"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?\"&\":\"?\")+b.jsonp+\"=\"+e),b.converters[\"script json\"]=function(){return g||m.error(e+\" was not called\"),g[0]},b.dataTypes[0]=\"json\",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),\"script\"):void 0}),m.parseHTML=function(a,b,c){if(!a||\"string\"!=typeof a)return null;\"boolean\"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if(\"string\"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(\" \");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&\"object\"==typeof b&&(f=\"POST\"),g.length>0&&m.ajax({url:a,type:f,dataType:\"html\",data:b}).done(function(a){e=arguments,g.html(d?m(\"<div>\").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,\"position\"),l=m(a),n={};\"static\"===k&&(a.style.position=\"relative\"),h=l.offset(),f=m.css(a,\"top\"),i=m.css(a,\"left\"),j=(\"absolute\"===k||\"fixed\"===k)&&m.inArray(\"auto\",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),\"using\"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return\"fixed\"===m.css(d,\"position\")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],\"html\")||(c=a.offset()),c.top+=m.css(a[0],\"borderTopWidth\",!0),c.left+=m.css(a[0],\"borderLeftWidth\",!0)),{top:b.top-c.top-m.css(d,\"marginTop\",!0),left:b.left-c.left-m.css(d,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,\"html\")&&\"static\"===m.css(a,\"position\"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each([\"top\",\"left\"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+\"px\":c):void 0})}),m.each({Height:\"height\",Width:\"width\"},function(a,b){m.each({padding:\"inner\"+a,content:b,\"\":\"outer\"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||\"boolean\"!=typeof d),g=c||(d===!0||e===!0?\"margin\":\"border\");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement[\"client\"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body[\"scroll\"+a],e[\"scroll\"+a],b.body[\"offset\"+a],e[\"offset\"+a],e[\"client\"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});\n","/*!\n * Bootstrap v3.3.4 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\nif(\"undefined\"==typeof jQuery)throw new Error(\"Bootstrap's JavaScript requires jQuery\");+function(a){\"use strict\";var b=a.fn.jquery.split(\" \")[0].split(\".\");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error(\"Bootstrap's JavaScript requires jQuery version 1.9.1 or higher\")}(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]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(\"bsTransitionEnd\",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(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){\"use strict\";function b(b){return this.each(function(){var c=a(this),e=c.data(\"bs.alert\");e||c.data(\"bs.alert\",e=new d(this)),\"string\"==typeof b&&e[b].call(c)})}var c='[data-dismiss=\"alert\"]',d=function(b){a(b).on(\"click\",c,this.close)};d.VERSION=\"3.3.4\",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger(\"closed.bs.alert\").remove()}var e=a(this),f=e.attr(\"data-target\");f||(f=e.attr(\"href\"),f=f&&f.replace(/.*(?=#[^\\s]*$)/,\"\"));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(\".alert\")),g.trigger(b=a.Event(\"close.bs.alert\")),b.isDefaultPrevented()||(g.removeClass(\"in\"),a.support.transition&&g.hasClass(\"fade\")?g.one(\"bsTransitionEnd\",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on(\"click.bs.alert.data-api\",c,d.prototype.close)}(jQuery),+function(a){\"use strict\";function b(b){return this.each(function(){var d=a(this),e=d.data(\"bs.button\"),f=\"object\"==typeof b&&b;e||d.data(\"bs.button\",e=new c(this,f)),\"toggle\"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION=\"3.3.4\",c.DEFAULTS={loadingText:\"loading...\"},c.prototype.setState=function(b){var c=\"disabled\",d=this.$element,e=d.is(\"input\")?\"val\":\"html\",f=d.data();b+=\"Text\",null==f.resetText&&d.data(\"resetText\",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),\"loadingText\"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle=\"buttons\"]');if(b.length){var c=this.$element.find(\"input\");\"radio\"==c.prop(\"type\")&&(c.prop(\"checked\")&&this.$element.hasClass(\"active\")?a=!1:b.find(\".active\").removeClass(\"active\")),a&&c.prop(\"checked\",!this.$element.hasClass(\"active\")).trigger(\"change\")}else this.$element.attr(\"aria-pressed\",!this.$element.hasClass(\"active\"));a&&this.$element.toggleClass(\"active\")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on(\"click.bs.button.data-api\",'[data-toggle^=\"button\"]',function(c){var d=a(c.target);d.hasClass(\"btn\")||(d=d.closest(\".btn\")),b.call(d,\"toggle\"),c.preventDefault()}).on(\"focus.bs.button.data-api blur.bs.button.data-api\",'[data-toggle^=\"button\"]',function(b){a(b.target).closest(\".btn\").toggleClass(\"focus\",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){\"use strict\";function b(b){return this.each(function(){var d=a(this),e=d.data(\"bs.carousel\"),f=a.extend({},c.DEFAULTS,d.data(),\"object\"==typeof b&&b),g=\"string\"==typeof b?b:f.slide;e||d.data(\"bs.carousel\",e=new c(this,f)),\"number\"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(\".carousel-indicators\"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on(\"keydown.bs.carousel\",a.proxy(this.keydown,this)),\"hover\"==this.options.pause&&!(\"ontouchstart\"in document.documentElement)&&this.$element.on(\"mouseenter.bs.carousel\",a.proxy(this.pause,this)).on(\"mouseleave.bs.carousel\",a.proxy(this.cycle,this))};c.VERSION=\"3.3.4\",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:\"hover\",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.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},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(\".item\"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d=\"prev\"==a&&0===c||\"next\"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e=\"prev\"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(\".item.active\"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one(\"slid.bs.carousel\",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?\"next\":\"prev\",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(\".next, .prev\").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide(\"next\")},c.prototype.prev=function(){return this.sliding?void 0:this.slide(\"prev\")},c.prototype.slide=function(b,d){var e=this.$element.find(\".item.active\"),f=d||this.getItemForDirection(b,e),g=this.interval,h=\"next\"==b?\"left\":\"right\",i=this;if(f.hasClass(\"active\"))return this.sliding=!1;var j=f[0],k=a.Event(\"slide.bs.carousel\",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(\".active\").removeClass(\"active\");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass(\"active\")}var m=a.Event(\"slid.bs.carousel\",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass(\"slide\")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one(\"bsTransitionEnd\",function(){f.removeClass([b,h].join(\" \")).addClass(\"active\"),e.removeClass([\"active\",h].join(\" \")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass(\"active\"),f.addClass(\"active\"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr(\"data-target\")||(d=e.attr(\"href\"))&&d.replace(/.*(?=#[^\\s]+$)/,\"\"));if(f.hasClass(\"carousel\")){var g=a.extend({},f.data(),e.data()),h=e.attr(\"data-slide-to\");h&&(g.interval=!1),b.call(f,g),h&&f.data(\"bs.carousel\").to(h),c.preventDefault()}};a(document).on(\"click.bs.carousel.data-api\",\"[data-slide]\",e).on(\"click.bs.carousel.data-api\",\"[data-slide-to]\",e),a(window).on(\"load\",function(){a('[data-ride=\"carousel\"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){\"use strict\";function b(b){var c,d=b.attr(\"data-target\")||(c=b.attr(\"href\"))&&c.replace(/.*(?=#[^\\s]+$)/,\"\");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data(\"bs.collapse\"),f=a.extend({},d.DEFAULTS,c.data(),\"object\"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data(\"bs.collapse\",e=new d(this,f)),\"string\"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle=\"collapse\"][href=\"#'+b.id+'\"],[data-toggle=\"collapse\"][data-target=\"#'+b.id+'\"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION=\"3.3.4\",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass(\"width\");return a?\"width\":\"height\"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass(\"in\")){var b,e=this.$parent&&this.$parent.children(\".panel\").children(\".in, .collapsing\");if(!(e&&e.length&&(b=e.data(\"bs.collapse\"),b&&b.transitioning))){var f=a.Event(\"show.bs.collapse\");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,\"hide\"),b||e.data(\"bs.collapse\",null));var g=this.dimension();this.$element.removeClass(\"collapse\").addClass(\"collapsing\")[g](0).attr(\"aria-expanded\",!0),this.$trigger.removeClass(\"collapsed\").attr(\"aria-expanded\",!0),this.transitioning=1;var h=function(){this.$element.removeClass(\"collapsing\").addClass(\"collapse in\")[g](\"\"),this.transitioning=0,this.$element.trigger(\"shown.bs.collapse\")};if(!a.support.transition)return h.call(this);var i=a.camelCase([\"scroll\",g].join(\"-\"));this.$element.one(\"bsTransitionEnd\",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.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 in\").attr(\"aria-expanded\",!1),this.$trigger.addClass(\"collapsed\").attr(\"aria-expanded\",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass(\"collapsing\").addClass(\"collapse\").trigger(\"hidden.bs.collapse\")};return a.support.transition?void this.$element[c](0).one(\"bsTransitionEnd\",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass(\"in\")?\"hide\":\"show\"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle=\"collapse\"][data-parent=\"'+this.options.parent+'\"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass(\"in\");a.attr(\"aria-expanded\",c),b.toggleClass(\"collapsed\",!c).attr(\"aria-expanded\",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on(\"click.bs.collapse.data-api\",'[data-toggle=\"collapse\"]',function(d){var e=a(this);e.attr(\"data-target\")||d.preventDefault();var f=b(e),g=f.data(\"bs.collapse\"),h=g?\"toggle\":e.data();c.call(f,h)})}(jQuery),+function(a){\"use strict\";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass(\"open\")&&(e.trigger(b=a.Event(\"hide.bs.dropdown\",f)),b.isDefaultPrevented()||(d.attr(\"aria-expanded\",\"false\"),e.removeClass(\"open\").trigger(\"hidden.bs.dropdown\",f)))}))}function c(b){var c=b.attr(\"data-target\");c||(c=b.attr(\"href\"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\\s]*$)/,\"\"));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data(\"bs.dropdown\");d||c.data(\"bs.dropdown\",d=new g(this)),\"string\"==typeof b&&d[b].call(c)})}var e=\".dropdown-backdrop\",f='[data-toggle=\"dropdown\"]',g=function(b){a(b).on(\"click.bs.dropdown\",this.toggle)};g.VERSION=\"3.3.4\",g.prototype.toggle=function(d){var e=a(this);if(!e.is(\".disabled, :disabled\")){var f=c(e),g=f.hasClass(\"open\");if(b(),!g){\"ontouchstart\"in document.documentElement&&!f.closest(\".navbar-nav\").length&&a('<div class=\"dropdown-backdrop\"/>').insertAfter(a(this)).on(\"click\",b);var h={relatedTarget:this};if(f.trigger(d=a.Event(\"show.bs.dropdown\",h)),d.isDefaultPrevented())return;e.trigger(\"focus\").attr(\"aria-expanded\",\"true\"),f.toggleClass(\"open\").trigger(\"shown.bs.dropdown\",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(\".disabled, :disabled\")){var e=c(d),g=e.hasClass(\"open\");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger(\"focus\"),d.trigger(\"click\");var h=\" li:not(.disabled):visible a\",i=e.find('[role=\"menu\"]'+h+', [role=\"listbox\"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger(\"focus\")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,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\",f,g.prototype.toggle).on(\"keydown.bs.dropdown.data-api\",f,g.prototype.keydown).on(\"keydown.bs.dropdown.data-api\",'[role=\"menu\"]',g.prototype.keydown).on(\"keydown.bs.dropdown.data-api\",'[role=\"listbox\"]',g.prototype.keydown)}(jQuery),+function(a){\"use strict\";function b(b,d){return this.each(function(){var e=a(this),f=e.data(\"bs.modal\"),g=a.extend({},c.DEFAULTS,e.data(),\"object\"==typeof b&&b);f||e.data(\"bs.modal\",f=new c(this,g)),\"string\"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(\".modal-dialog\"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(\".modal-content\").load(this.options.remote,a.proxy(function(){this.$element.trigger(\"loaded.bs.modal\")},this))};c.VERSION=\"3.3.4\",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event(\"show.bs.modal\",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass(\"modal-open\"),this.escape(),this.resize(),this.$element.on(\"click.dismiss.bs.modal\",'[data-dismiss=\"modal\"]',a.proxy(this.hide,this)),this.$dialog.on(\"mousedown.dismiss.bs.modal\",function(){d.$element.one(\"mouseup.dismiss.bs.modal\",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass(\"fade\");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass(\"in\").attr(\"aria-hidden\",!1),d.enforceFocus();var f=a.Event(\"shown.bs.modal\",{relatedTarget:b});e?d.$dialog.one(\"bsTransitionEnd\",function(){d.$element.trigger(\"focus\").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger(\"focus\").trigger(f)}))},c.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(),this.resize(),a(document).off(\"focusin.bs.modal\"),this.$element.removeClass(\"in\").attr(\"aria-hidden\",!0).off(\"click.dismiss.bs.modal\").off(\"mouseup.dismiss.bs.modal\"),this.$dialog.off(\"mousedown.dismiss.bs.modal\"),a.support.transition&&this.$element.hasClass(\"fade\")?this.$element.one(\"bsTransitionEnd\",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.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.trigger(\"focus\")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on(\"keydown.dismiss.bs.modal\",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off(\"keydown.dismiss.bs.modal\")},c.prototype.resize=function(){this.isShown?a(window).on(\"resize.bs.modal\",a.proxy(this.handleUpdate,this)):a(window).off(\"resize.bs.modal\")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass(\"modal-open\"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger(\"hidden.bs.modal\")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass(\"fade\")?\"fade\":\"\";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class=\"modal-backdrop '+e+'\" />').appendTo(this.$body),this.$element.on(\"click.dismiss.bs.modal\",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&(\"static\"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass(\"in\"),!b)return;f?this.$backdrop.one(\"bsTransitionEnd\",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass(\"in\");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass(\"fade\")?this.$backdrop.one(\"bsTransitionEnd\",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:\"\",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:\"\"})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:\"\",paddingRight:\"\"})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css(\"padding-right\")||0,10);this.originalBodyPad=document.body.style.paddingRight||\"\",this.bodyIsOverflowing&&this.$body.css(\"padding-right\",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css(\"padding-right\",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement(\"div\");a.className=\"modal-scrollbar-measure\",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on(\"click.bs.modal.data-api\",'[data-toggle=\"modal\"]',function(c){var d=a(this),e=d.attr(\"href\"),f=a(d.attr(\"data-target\")||e&&e.replace(/.*(?=#[^\\s]+$)/,\"\")),g=f.data(\"bs.modal\")?\"toggle\":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is(\"a\")&&c.preventDefault(),f.one(\"show.bs.modal\",function(a){a.isDefaultPrevented()||f.one(\"hidden.bs.modal\",function(){d.is(\":visible\")&&d.trigger(\"focus\")})}),b.call(f,g,this)})}(jQuery),+function(a){\"use strict\";function b(b){return this.each(function(){var d=a(this),e=d.data(\"bs.tooltip\"),f=\"object\"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data(\"bs.tooltip\",e=new c(this,f)),\"string\"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.init(\"tooltip\",a,b)};c.VERSION=\"3.3.4\",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:\"top\",selector:!1,template:'<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',trigger:\"hover focus\",title:\"\",delay:0,html:!1,container:!1,viewport:{selector:\"body\",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error(\"`selector` option must be specified when initializing \"+this.type+\" on the window.document object!\");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\":\"focusin\",i=\"hover\"==g?\"mouseleave\":\"focusout\";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()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.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},c.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},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data(\"bs.\"+this.type);return c&&c.$tip&&c.$tip.is(\":visible\")?void(c.hoverState=\"in\"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data(\"bs.\"+this.type,c)),clearTimeout(c.timeout),c.hoverState=\"in\",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){\"in\"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data(\"bs.\"+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data(\"bs.\"+this.type,c)),clearTimeout(c.timeout),c.hoverState=\"out\",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){\"out\"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event(\"show.bs.\"+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr(\"id\",g),this.$element.attr(\"aria-describedby\",g),this.options.animation&&f.addClass(\"fade\");var h=\"function\"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\\s?auto?\\s?/i,j=i.test(h);j&&(h=h.replace(i,\"\")||\"top\"),f.detach().css({top:0,left:0,display:\"block\"}).addClass(h).data(\"bs.\"+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h=\"bottom\"==h&&k.bottom+m>p.bottom?\"top\":\"top\"==h&&k.top-m<p.top?\"bottom\":\"right\"==h&&k.right+l>p.width?\"left\":\"left\"==h&&k.left-l<p.left?\"right\":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger(\"shown.bs.\"+e.type),e.hoverState=null,\"out\"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass(\"fade\")?f.one(\"bsTransitionEnd\",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var 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),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass(\"in\");var i=d[0].offsetWidth,j=d[0].offsetHeight;\"top\"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?\"offsetWidth\":\"offsetHeight\";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?\"left\":\"top\",50*(1-a/b)+\"%\").css(c?\"top\":\"left\",\"\")},c.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\")},c.prototype.hide=function(b){function d(){\"in\"!=e.hoverState&&f.detach(),e.$element.removeAttr(\"aria-describedby\").trigger(\"hidden.bs.\"+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event(\"hide.bs.\"+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass(\"in\"),a.support.transition&&f.hasClass(\"fade\")?f.one(\"bsTransitionEnd\",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.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\",\"\")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d=\"BODY\"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.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}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.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)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(\".tooltip-arrow\")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data(\"bs.\"+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data(\"bs.\"+this.type,c))),c.tip().hasClass(\"in\")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off(\".\"+a.type).removeData(\"bs.\"+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){\"use strict\";function b(b){return this.each(function(){var d=a(this),e=d.data(\"bs.popover\"),f=\"object\"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data(\"bs.popover\",e=new c(this,f)),\"string\"==typeof b&&e[b]())})}var c=function(a,b){this.init(\"popover\",a,b)};if(!a.fn.tooltip)throw new Error(\"Popover requires tooltip.js\");c.VERSION=\"3.3.4\",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:\"right\",trigger:\"click\",content:\"\",template:'<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.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\").children().detach().end()[this.options.html?\"string\"==typeof c?\"html\":\"append\":\"text\"](c),a.removeClass(\"fade top bottom left right in\"),a.find(\".popover-title\").html()||a.find(\".popover-title\").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.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)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(\".arrow\")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){\"use strict\";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||\"\")+\" .nav li > a\",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on(\"scroll.bs.scrollspy\",a.proxy(this.process,this)),this.refresh(),this.process()}function c(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]()})}b.VERSION=\"3.3.4\",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c=\"offset\",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c=\"position\",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data(\"target\")||b.attr(\"href\"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(\":visible\")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();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.bs.scrollspy\")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,\".active\").removeClass(\"active\")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on(\"load.bs.scrollspy.data-api\",function(){a('[data-spy=\"scroll\"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){\"use strict\";function b(b){return this.each(function(){var d=a(this),e=d.data(\"bs.tab\");e||d.data(\"bs.tab\",e=new c(this)),\"string\"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION=\"3.3.4\",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest(\"ul:not(.dropdown-menu)\"),d=b.data(\"target\");if(d||(d=b.attr(\"href\"),d=d&&d.replace(/.*(?=#[^\\s]*$)/,\"\")),!b.parent(\"li\").hasClass(\"active\")){\nvar e=c.find(\".active:last a\"),f=a.Event(\"hide.bs.tab\",{relatedTarget:b[0]}),g=a.Event(\"show.bs.tab\",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest(\"li\"),c),this.activate(h,h.parent(),function(){e.trigger({type:\"hidden.bs.tab\",relatedTarget:b[0]}),b.trigger({type:\"shown.bs.tab\",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass(\"active\").find(\"> .dropdown-menu > .active\").removeClass(\"active\").end().find('[data-toggle=\"tab\"]').attr(\"aria-expanded\",!1),b.addClass(\"active\").find('[data-toggle=\"tab\"]').attr(\"aria-expanded\",!0),h?(b[0].offsetWidth,b.addClass(\"in\")):b.removeClass(\"fade\"),b.parent(\".dropdown-menu\").length&&b.closest(\"li.dropdown\").addClass(\"active\").end().find('[data-toggle=\"tab\"]').attr(\"aria-expanded\",!0),e&&e()}var g=d.find(\"> .active\"),h=e&&a.support.transition&&(g.length&&g.hasClass(\"fade\")||!!d.find(\"> .fade\").length);g.length&&h?g.one(\"bsTransitionEnd\",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass(\"in\")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),\"show\")};a(document).on(\"click.bs.tab.data-api\",'[data-toggle=\"tab\"]',e).on(\"click.bs.tab.data-api\",'[data-toggle=\"pill\"]',e)}(jQuery),+function(a){\"use strict\";function b(b){return this.each(function(){var d=a(this),e=d.data(\"bs.affix\"),f=\"object\"==typeof b&&b;e||d.data(\"bs.affix\",e=new c(this,f)),\"string\"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).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(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION=\"3.3.4\",c.RESET=\"affix affix-top affix-bottom\",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&\"top\"==this.affixed)return c>e?\"top\":!1;if(\"bottom\"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:\"bottom\":a-d>=e+g?!1:\"bottom\";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?\"top\":null!=d&&i+j>=a-d?\"bottom\":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass(\"affix\");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(\":visible\")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();\"object\"!=typeof d&&(f=e=d),\"function\"==typeof e&&(e=d.top(this.$element)),\"function\"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css(\"top\",\"\");var i=\"affix\"+(h?\"-\"+h:\"\"),j=a.Event(i+\".bs.affix\");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin=\"bottom\"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace(\"affix\",\"affixed\")+\".bs.affix\")}\"bottom\"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on(\"load\",function(){a('[data-spy=\"affix\"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);","// OpenLayers 3. See https://openlayers.org/\n// License: https://raw.githubusercontent.com/openlayers/ol3/master/LICENSE.md\n// Version: v3.20.1\n;(function (root, factory) {\n  if (typeof exports === \"object\") {\n    module.exports = factory();\n  } else if (typeof define === \"function\" && define.amd) {\n    define([], factory);\n  } else {\n    root.ol = factory();\n  }\n}(this, function () {\n  var OPENLAYERS = {};\n  var goog = this.goog = {};\nthis.CLOSURE_NO_DEPS = true;\n// Copyright 2006 The Closure Library Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Bootstrap for the Google JS Library (Closure).\n *\n * In uncompiled mode base.js will write out Closure's deps file, unless the\n * global <code>CLOSURE_NO_DEPS</code> is set to true.  This allows projects to\n * include their own deps file(s) from different locations.\n *\n * @author arv@google.com (Erik Arvidsson)\n *\n * @provideGoog\n */\n\n\n/**\n * @define {boolean} Overridden to true by the compiler when\n *     --process_closure_primitives is specified.\n */\nvar COMPILED = false;\n\n\n/**\n * Base namespace for the Closure library.  Checks to see goog is already\n * defined in the current scope before assigning to prevent clobbering if\n * base.js is loaded more than once.\n *\n * @const\n */\nvar goog = goog || {};\n\n\n/**\n * Reference to the global context.  In most cases this will be 'window'.\n */\ngoog.global = this;\n\n\n/**\n * A hook for overriding the define values in uncompiled mode.\n *\n * In uncompiled mode, {@code CLOSURE_UNCOMPILED_DEFINES} may be defined before\n * loading base.js.  If a key is defined in {@code CLOSURE_UNCOMPILED_DEFINES},\n * {@code goog.define} will use the value instead of the default value.  This\n * allows flags to be overwritten without compilation (this is normally\n * accomplished with the compiler's \"define\" flag).\n *\n * Example:\n * <pre>\n *   var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false};\n * </pre>\n *\n * @type {Object<string, (string|number|boolean)>|undefined}\n */\ngoog.global.CLOSURE_UNCOMPILED_DEFINES;\n\n\n/**\n * A hook for overriding the define values in uncompiled or compiled mode,\n * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code.  In\n * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence.\n *\n * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or\n * string literals or the compiler will emit an error.\n *\n * While any @define value may be set, only those set with goog.define will be\n * effective for uncompiled code.\n *\n * Example:\n * <pre>\n *   var CLOSURE_DEFINES = {'goog.DEBUG': false} ;\n * </pre>\n *\n * @type {Object<string, (string|number|boolean)>|undefined}\n */\ngoog.global.CLOSURE_DEFINES;\n\n\n/**\n * Returns true if the specified value is not undefined.\n * WARNING: Do not use this to test if an object has a property. Use the in\n * operator instead.\n *\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is defined.\n */\ngoog.isDef = function(val) {\n  // void 0 always evaluates to undefined and hence we do not need to depend on\n  // the definition of the global variable named 'undefined'.\n  return val !== void 0;\n};\n\n\n/**\n * Builds an object structure for the provided namespace path, ensuring that\n * names that already exist are not overwritten. For example:\n * \"a.b.c\" -> a = {};a.b={};a.b.c={};\n * Used by goog.provide and goog.exportSymbol.\n * @param {string} name name of the object that this file defines.\n * @param {*=} opt_object the object to expose at the end of the path.\n * @param {Object=} opt_objectToExportTo The object to add the path to; default\n *     is |goog.global|.\n * @private\n */\ngoog.exportPath_ = function(name, opt_object, opt_objectToExportTo) {\n  var parts = name.split('.');\n  var cur = opt_objectToExportTo || goog.global;\n\n  // Internet Explorer exhibits strange behavior when throwing errors from\n  // methods externed in this manner.  See the testExportSymbolExceptions in\n  // base_test.html for an example.\n  if (!(parts[0] in cur) && cur.execScript) {\n    cur.execScript('var ' + parts[0]);\n  }\n\n  // Certain browsers cannot parse code in the form for((a in b); c;);\n  // This pattern is produced by the JSCompiler when it collapses the\n  // statement above into the conditional loop below. To prevent this from\n  // happening, use a for-loop and reserve the init logic as below.\n\n  // Parentheses added to eliminate strict JS warning in Firefox.\n  for (var part; parts.length && (part = parts.shift());) {\n    if (!parts.length && goog.isDef(opt_object)) {\n      // last part and we have an object; use it\n      cur[part] = opt_object;\n    } else if (cur[part]) {\n      cur = cur[part];\n    } else {\n      cur = cur[part] = {};\n    }\n  }\n};\n\n\n/**\n * Defines a named value. In uncompiled mode, the value is retrieved from\n * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and\n * has the property specified, and otherwise used the defined defaultValue.\n * When compiled the default can be overridden using the compiler\n * options or the value set in the CLOSURE_DEFINES object.\n *\n * @param {string} name The distinguished name to provide.\n * @param {string|number|boolean} defaultValue\n */\ngoog.define = function(name, defaultValue) {\n  var value = defaultValue;\n  if (!COMPILED) {\n    if (goog.global.CLOSURE_UNCOMPILED_DEFINES &&\n        Object.prototype.hasOwnProperty.call(\n            goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) {\n      value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name];\n    } else if (\n        goog.global.CLOSURE_DEFINES &&\n        Object.prototype.hasOwnProperty.call(\n            goog.global.CLOSURE_DEFINES, name)) {\n      value = goog.global.CLOSURE_DEFINES[name];\n    }\n  }\n  goog.exportPath_(name, value);\n};\n\n\n/**\n * @define {boolean} DEBUG is provided as a convenience so that debugging code\n * that should not be included in a production js_binary can be easily stripped\n * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most\n * toString() methods should be declared inside an \"if (goog.DEBUG)\" conditional\n * because they are generally used for debugging purposes and it is difficult\n * for the JSCompiler to statically determine whether they are used.\n */\ngoog.define('goog.DEBUG', true);\n\n\n/**\n * @define {string} LOCALE defines the locale being used for compilation. It is\n * used to select locale specific data to be compiled in js binary. BUILD rule\n * can specify this value by \"--define goog.LOCALE=<locale_name>\" as JSCompiler\n * option.\n *\n * Take into account that the locale code format is important. You should use\n * the canonical Unicode format with hyphen as a delimiter. Language must be\n * lowercase, Language Script - Capitalized, Region - UPPERCASE.\n * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN.\n *\n * See more info about locale codes here:\n * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers\n *\n * For language codes you should use values defined by ISO 693-1. See it here\n * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from\n * this rule: the Hebrew language. For legacy reasons the old code (iw) should\n * be used instead of the new code (he), see http://wiki/Main/IIISynonyms.\n */\ngoog.define('goog.LOCALE', 'en');  // default to en\n\n\n/**\n * @define {boolean} Whether this code is running on trusted sites.\n *\n * On untrusted sites, several native functions can be defined or overridden by\n * external libraries like Prototype, Datejs, and JQuery and setting this flag\n * to false forces closure to use its own implementations when possible.\n *\n * If your JavaScript can be loaded by a third party site and you are wary about\n * relying on non-standard implementations, specify\n * \"--define goog.TRUSTED_SITE=false\" to the JSCompiler.\n */\ngoog.define('goog.TRUSTED_SITE', true);\n\n\n/**\n * @define {boolean} Whether a project is expected to be running in strict mode.\n *\n * This define can be used to trigger alternate implementations compatible with\n * running in EcmaScript Strict mode or warn about unavailable functionality.\n * @see https://goo.gl/PudQ4y\n *\n */\ngoog.define('goog.STRICT_MODE_COMPATIBLE', false);\n\n\n/**\n * @define {boolean} Whether code that calls {@link goog.setTestOnly} should\n *     be disallowed in the compilation unit.\n */\ngoog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG);\n\n\n/**\n * @define {boolean} Whether to use a Chrome app CSP-compliant method for\n *     loading scripts via goog.require. @see appendScriptSrcNode_.\n */\ngoog.define('goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', false);\n\n\n/**\n * Defines a namespace in Closure.\n *\n * A namespace may only be defined once in a codebase. It may be defined using\n * goog.provide() or goog.module().\n *\n * The presence of one or more goog.provide() calls in a file indicates\n * that the file defines the given objects/namespaces.\n * Provided symbols must not be null or undefined.\n *\n * In addition, goog.provide() creates the object stubs for a namespace\n * (for example, goog.provide(\"goog.foo.bar\") will create the object\n * goog.foo.bar if it does not already exist).\n *\n * Build tools also scan for provide/require/module statements\n * to discern dependencies, build dependency files (see deps.js), etc.\n *\n * @see goog.require\n * @see goog.module\n * @param {string} name Namespace provided by this file in the form\n *     \"goog.package.part\".\n */\ngoog.provide = function(name) {\n  if (goog.isInModuleLoader_()) {\n    throw Error('goog.provide can not be used within a goog.module.');\n  }\n  if (!COMPILED) {\n    // Ensure that the same namespace isn't provided twice.\n    // A goog.module/goog.provide maps a goog.require to a specific file\n    if (goog.isProvided_(name)) {\n      throw Error('Namespace \"' + name + '\" already declared.');\n    }\n  }\n\n  goog.constructNamespace_(name);\n};\n\n\n/**\n * @param {string} name Namespace provided by this file in the form\n *     \"goog.package.part\".\n * @param {Object=} opt_obj The object to embed in the namespace.\n * @private\n */\ngoog.constructNamespace_ = function(name, opt_obj) {\n  if (!COMPILED) {\n    delete goog.implicitNamespaces_[name];\n\n    var namespace = name;\n    while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) {\n      if (goog.getObjectByName(namespace)) {\n        break;\n      }\n      goog.implicitNamespaces_[namespace] = true;\n    }\n  }\n\n  goog.exportPath_(name, opt_obj);\n};\n\n\n/**\n * Module identifier validation regexp.\n * Note: This is a conservative check, it is very possible to be more lenient,\n *   the primary exclusion here is \"/\" and \"\\\" and a leading \".\", these\n *   restrictions are intended to leave the door open for using goog.require\n *   with relative file paths rather than module identifiers.\n * @private\n */\ngoog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/;\n\n\n/**\n * Defines a module in Closure.\n *\n * Marks that this file must be loaded as a module and claims the namespace.\n *\n * A namespace may only be defined once in a codebase. It may be defined using\n * goog.provide() or goog.module().\n *\n * goog.module() has three requirements:\n * - goog.module may not be used in the same file as goog.provide.\n * - goog.module must be the first statement in the file.\n * - only one goog.module is allowed per file.\n *\n * When a goog.module annotated file is loaded, it is enclosed in\n * a strict function closure. This means that:\n * - any variables declared in a goog.module file are private to the file\n * (not global), though the compiler is expected to inline the module.\n * - The code must obey all the rules of \"strict\" JavaScript.\n * - the file will be marked as \"use strict\"\n *\n * NOTE: unlike goog.provide, goog.module does not declare any symbols by\n * itself. If declared symbols are desired, use\n * goog.module.declareLegacyNamespace().\n *\n *\n * See the public goog.module proposal: http://goo.gl/Va1hin\n *\n * @param {string} name Namespace provided by this file in the form\n *     \"goog.package.part\", is expected but not required.\n */\ngoog.module = function(name) {\n  if (!goog.isString(name) || !name ||\n      name.search(goog.VALID_MODULE_RE_) == -1) {\n    throw Error('Invalid module identifier');\n  }\n  if (!goog.isInModuleLoader_()) {\n    throw Error('Module ' + name + ' has been loaded incorrectly.');\n  }\n  if (goog.moduleLoaderState_.moduleName) {\n    throw Error('goog.module may only be called once per module.');\n  }\n\n  // Store the module name for the loader.\n  goog.moduleLoaderState_.moduleName = name;\n  if (!COMPILED) {\n    // Ensure that the same namespace isn't provided twice.\n    // A goog.module/goog.provide maps a goog.require to a specific file\n    if (goog.isProvided_(name)) {\n      throw Error('Namespace \"' + name + '\" already declared.');\n    }\n    delete goog.implicitNamespaces_[name];\n  }\n};\n\n\n/**\n * @param {string} name The module identifier.\n * @return {?} The module exports for an already loaded module or null.\n *\n * Note: This is not an alternative to goog.require, it does not\n * indicate a hard dependency, instead it is used to indicate\n * an optional dependency or to access the exports of a module\n * that has already been loaded.\n * @suppress {missingProvide}\n */\ngoog.module.get = function(name) {\n  return goog.module.getInternal_(name);\n};\n\n\n/**\n * @param {string} name The module identifier.\n * @return {?} The module exports for an already loaded module or null.\n * @private\n */\ngoog.module.getInternal_ = function(name) {\n  if (!COMPILED) {\n    if (goog.isProvided_(name)) {\n      // goog.require only return a value with-in goog.module files.\n      return name in goog.loadedModules_ ? goog.loadedModules_[name] :\n                                           goog.getObjectByName(name);\n    } else {\n      return null;\n    }\n  }\n};\n\n\n/**\n * @private {?{moduleName: (string|undefined), declareLegacyNamespace:boolean}}\n */\ngoog.moduleLoaderState_ = null;\n\n\n/**\n * @private\n * @return {boolean} Whether a goog.module is currently being initialized.\n */\ngoog.isInModuleLoader_ = function() {\n  return goog.moduleLoaderState_ != null;\n};\n\n\n/**\n * Provide the module's exports as a globally accessible object under the\n * module's declared name.  This is intended to ease migration to goog.module\n * for files that have existing usages.\n * @suppress {missingProvide}\n */\ngoog.module.declareLegacyNamespace = function() {\n  if (!COMPILED && !goog.isInModuleLoader_()) {\n    throw new Error(\n        'goog.module.declareLegacyNamespace must be called from ' +\n        'within a goog.module');\n  }\n  if (!COMPILED && !goog.moduleLoaderState_.moduleName) {\n    throw Error(\n        'goog.module must be called prior to ' +\n        'goog.module.declareLegacyNamespace.');\n  }\n  goog.moduleLoaderState_.declareLegacyNamespace = true;\n};\n\n\n/**\n * Marks that the current file should only be used for testing, and never for\n * live code in production.\n *\n * In the case of unit tests, the message may optionally be an exact namespace\n * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra\n * provide (if not explicitly defined in the code).\n *\n * @param {string=} opt_message Optional message to add to the error that's\n *     raised when used in production code.\n */\ngoog.setTestOnly = function(opt_message) {\n  if (goog.DISALLOW_TEST_ONLY_CODE) {\n    opt_message = opt_message || '';\n    throw Error(\n        'Importing test-only code into non-debug environment' +\n        (opt_message ? ': ' + opt_message : '.'));\n  }\n};\n\n\n/**\n * Forward declares a symbol. This is an indication to the compiler that the\n * symbol may be used in the source yet is not required and may not be provided\n * in compilation.\n *\n * The most common usage of forward declaration is code that takes a type as a\n * function parameter but does not need to require it. By forward declaring\n * instead of requiring, no hard dependency is made, and (if not required\n * elsewhere) the namespace may never be required and thus, not be pulled\n * into the JavaScript binary. If it is required elsewhere, it will be type\n * checked as normal.\n *\n *\n * @param {string} name The namespace to forward declare in the form of\n *     \"goog.package.part\".\n */\ngoog.forwardDeclare = function(name) {};\n\n\n/**\n * Forward declare type information. Used to assign types to goog.global\n * referenced object that would otherwise result in unknown type references\n * and thus block property disambiguation.\n */\ngoog.forwardDeclare('Document');\ngoog.forwardDeclare('HTMLScriptElement');\ngoog.forwardDeclare('XMLHttpRequest');\n\n\nif (!COMPILED) {\n  /**\n   * Check if the given name has been goog.provided. This will return false for\n   * names that are available only as implicit namespaces.\n   * @param {string} name name of the object to look for.\n   * @return {boolean} Whether the name has been provided.\n   * @private\n   */\n  goog.isProvided_ = function(name) {\n    return (name in goog.loadedModules_) ||\n        (!goog.implicitNamespaces_[name] &&\n         goog.isDefAndNotNull(goog.getObjectByName(name)));\n  };\n\n  /**\n   * Namespaces implicitly defined by goog.provide. For example,\n   * goog.provide('goog.events.Event') implicitly declares that 'goog' and\n   * 'goog.events' must be namespaces.\n   *\n   * @type {!Object<string, (boolean|undefined)>}\n   * @private\n   */\n  goog.implicitNamespaces_ = {'goog.module': true};\n\n  // NOTE: We add goog.module as an implicit namespace as goog.module is defined\n  // here and because the existing module package has not been moved yet out of\n  // the goog.module namespace. This satisifies both the debug loader and\n  // ahead-of-time dependency management.\n}\n\n\n/**\n * Returns an object based on its fully qualified external name.  The object\n * is not found if null or undefined.  If you are using a compilation pass that\n * renames property names beware that using this function will not find renamed\n * properties.\n *\n * @param {string} name The fully qualified name.\n * @param {Object=} opt_obj The object within which to look; default is\n *     |goog.global|.\n * @return {?} The value (object or primitive) or, if not found, null.\n */\ngoog.getObjectByName = function(name, opt_obj) {\n  var parts = name.split('.');\n  var cur = opt_obj || goog.global;\n  for (var part; part = parts.shift();) {\n    if (goog.isDefAndNotNull(cur[part])) {\n      cur = cur[part];\n    } else {\n      return null;\n    }\n  }\n  return cur;\n};\n\n\n/**\n * Globalizes a whole namespace, such as goog or goog.lang.\n *\n * @param {!Object} obj The namespace to globalize.\n * @param {Object=} opt_global The object to add the properties to.\n * @deprecated Properties may be explicitly exported to the global scope, but\n *     this should no longer be done in bulk.\n */\ngoog.globalize = function(obj, opt_global) {\n  var global = opt_global || goog.global;\n  for (var x in obj) {\n    global[x] = obj[x];\n  }\n};\n\n\n/**\n * Adds a dependency from a file to the files it requires.\n * @param {string} relPath The path to the js file.\n * @param {!Array<string>} provides An array of strings with\n *     the names of the objects this file provides.\n * @param {!Array<string>} requires An array of strings with\n *     the names of the objects this file requires.\n * @param {boolean|!Object<string>=} opt_loadFlags Parameters indicating\n *     how the file must be loaded.  The boolean 'true' is equivalent\n *     to {'module': 'goog'} for backwards-compatibility.  Valid properties\n *     and values include {'module': 'goog'} and {'lang': 'es6'}.\n */\ngoog.addDependency = function(relPath, provides, requires, opt_loadFlags) {\n  if (goog.DEPENDENCIES_ENABLED) {\n    var provide, require;\n    var path = relPath.replace(/\\\\/g, '/');\n    var deps = goog.dependencies_;\n    if (!opt_loadFlags || typeof opt_loadFlags === 'boolean') {\n      opt_loadFlags = opt_loadFlags ? {'module': 'goog'} : {};\n    }\n    for (var i = 0; provide = provides[i]; i++) {\n      deps.nameToPath[provide] = path;\n      deps.loadFlags[path] = opt_loadFlags;\n    }\n    for (var j = 0; require = requires[j]; j++) {\n      if (!(path in deps.requires)) {\n        deps.requires[path] = {};\n      }\n      deps.requires[path][require] = true;\n    }\n  }\n};\n\n\n\n\n// NOTE(nnaze): The debug DOM loader was included in base.js as an original way\n// to do \"debug-mode\" development.  The dependency system can sometimes be\n// confusing, as can the debug DOM loader's asynchronous nature.\n//\n// With the DOM loader, a call to goog.require() is not blocking -- the script\n// will not load until some point after the current script.  If a namespace is\n// needed at runtime, it needs to be defined in a previous script, or loaded via\n// require() with its registered dependencies.\n//\n// User-defined namespaces may need their own deps file. For a reference on\n// creating a deps file, see:\n// Externally: https://developers.google.com/closure/library/docs/depswriter\n//\n// Because of legacy clients, the DOM loader can't be easily removed from\n// base.js.  Work is being done to make it disableable or replaceable for\n// different environments (DOM-less JavaScript interpreters like Rhino or V8,\n// for example). See bootstrap/ for more information.\n\n\n/**\n * @define {boolean} Whether to enable the debug loader.\n *\n * If enabled, a call to goog.require() will attempt to load the namespace by\n * appending a script tag to the DOM (if the namespace has been registered).\n *\n * If disabled, goog.require() will simply assert that the namespace has been\n * provided (and depend on the fact that some outside tool correctly ordered\n * the script).\n */\ngoog.define('goog.ENABLE_DEBUG_LOADER', true);\n\n\n/**\n * @param {string} msg\n * @private\n */\ngoog.logToConsole_ = function(msg) {\n  if (goog.global.console) {\n    goog.global.console['error'](msg);\n  }\n};\n\n\n/**\n * Implements a system for the dynamic resolution of dependencies that works in\n * parallel with the BUILD system. Note that all calls to goog.require will be\n * stripped by the JSCompiler when the --process_closure_primitives option is\n * used.\n * @see goog.provide\n * @param {string} name Namespace to include (as was given in goog.provide()) in\n *     the form \"goog.package.part\".\n * @return {?} If called within a goog.module file, the associated namespace or\n *     module otherwise null.\n */\ngoog.require = function(name) {\n  // If the object already exists we do not need do do anything.\n  if (!COMPILED) {\n    if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) {\n      goog.maybeProcessDeferredDep_(name);\n    }\n\n    if (goog.isProvided_(name)) {\n      if (goog.isInModuleLoader_()) {\n        return goog.module.getInternal_(name);\n      } else {\n        return null;\n      }\n    }\n\n    if (goog.ENABLE_DEBUG_LOADER) {\n      var path = goog.getPathFromDeps_(name);\n      if (path) {\n        goog.writeScripts_(path);\n        return null;\n      }\n    }\n\n    var errorMessage = 'goog.require could not find: ' + name;\n    goog.logToConsole_(errorMessage);\n\n    throw Error(errorMessage);\n  }\n};\n\n\n/**\n * Path for included scripts.\n * @type {string}\n */\ngoog.basePath = '';\n\n\n/**\n * A hook for overriding the base path.\n * @type {string|undefined}\n */\ngoog.global.CLOSURE_BASE_PATH;\n\n\n/**\n * Whether to write out Closure's deps file. By default, the deps are written.\n * @type {boolean|undefined}\n */\ngoog.global.CLOSURE_NO_DEPS;\n\n\n/**\n * A function to import a single script. This is meant to be overridden when\n * Closure is being run in non-HTML contexts, such as web workers. It's defined\n * in the global scope so that it can be set before base.js is loaded, which\n * allows deps.js to be imported properly.\n *\n * The function is passed the script source, which is a relative URI. It should\n * return true if the script was imported, false otherwise.\n * @type {(function(string): boolean)|undefined}\n */\ngoog.global.CLOSURE_IMPORT_SCRIPT;\n\n\n/**\n * Null function used for default values of callbacks, etc.\n * @return {void} Nothing.\n */\ngoog.nullFunction = function() {};\n\n\n/**\n * When defining a class Foo with an abstract method bar(), you can do:\n * Foo.prototype.bar = goog.abstractMethod\n *\n * Now if a subclass of Foo fails to override bar(), an error will be thrown\n * when bar() is invoked.\n *\n * Note: This does not take the name of the function to override as an argument\n * because that would make it more difficult to obfuscate our JavaScript code.\n *\n * @type {!Function}\n * @throws {Error} when invoked to indicate the method should be overridden.\n */\ngoog.abstractMethod = function() {\n  throw Error('unimplemented abstract method');\n};\n\n\n/**\n * Adds a {@code getInstance} static method that always returns the same\n * instance object.\n * @param {!Function} ctor The constructor for the class to add the static\n *     method to.\n */\ngoog.addSingletonGetter = function(ctor) {\n  ctor.getInstance = function() {\n    if (ctor.instance_) {\n      return ctor.instance_;\n    }\n    if (goog.DEBUG) {\n      // NOTE: JSCompiler can't optimize away Array#push.\n      goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor;\n    }\n    return ctor.instance_ = new ctor;\n  };\n};\n\n\n/**\n * All singleton classes that have been instantiated, for testing. Don't read\n * it directly, use the {@code goog.testing.singleton} module. The compiler\n * removes this variable if unused.\n * @type {!Array<!Function>}\n * @private\n */\ngoog.instantiatedSingletons_ = [];\n\n\n/**\n * @define {boolean} Whether to load goog.modules using {@code eval} when using\n * the debug loader.  This provides a better debugging experience as the\n * source is unmodified and can be edited using Chrome Workspaces or similar.\n * However in some environments the use of {@code eval} is banned\n * so we provide an alternative.\n */\ngoog.define('goog.LOAD_MODULE_USING_EVAL', true);\n\n\n/**\n * @define {boolean} Whether the exports of goog.modules should be sealed when\n * possible.\n */\ngoog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG);\n\n\n/**\n * The registry of initialized modules:\n * the module identifier to module exports map.\n * @private @const {!Object<string, ?>}\n */\ngoog.loadedModules_ = {};\n\n\n/**\n * True if goog.dependencies_ is available.\n * @const {boolean}\n */\ngoog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER;\n\n\n/**\n * @define {string} How to decide whether to transpile.  Valid values\n * are 'always', 'never', and 'detect'.  The default ('detect') is to\n * use feature detection to determine which language levels need\n * transpilation.\n */\n// NOTE(user): we could expand this to accept a language level to bypass\n// detection: e.g. goog.TRANSPILE == 'es5' would transpile ES6 files but\n// would leave ES3 and ES5 files alone.\ngoog.define('goog.TRANSPILE', 'detect');\n\n\n/**\n * @define {string} Path to the transpiler.  Executing the script at this\n * path (relative to base.js) should define a function $jscomp.transpile.\n */\ngoog.define('goog.TRANSPILER', 'transpile.js');\n\n\nif (goog.DEPENDENCIES_ENABLED) {\n  /**\n   * This object is used to keep track of dependencies and other data that is\n   * used for loading scripts.\n   * @private\n   * @type {{\n   *   loadFlags: !Object<string, !Object<string, string>>,\n   *   nameToPath: !Object<string, string>,\n   *   requires: !Object<string, !Object<string, boolean>>,\n   *   visited: !Object<string, boolean>,\n   *   written: !Object<string, boolean>,\n   *   deferred: !Object<string, string>\n   * }}\n   */\n  goog.dependencies_ = {\n    loadFlags: {},  // 1 to 1\n\n    nameToPath: {},  // 1 to 1\n\n    requires: {},  // 1 to many\n\n    // Used when resolving dependencies to prevent us from visiting file twice.\n    visited: {},\n\n    written: {},  // Used to keep track of script files we have written.\n\n    deferred: {}  // Used to track deferred module evaluations in old IEs\n  };\n\n\n  /**\n   * Tries to detect whether is in the context of an HTML document.\n   * @return {boolean} True if it looks like HTML document.\n   * @private\n   */\n  goog.inHtmlDocument_ = function() {\n    /** @type {Document} */\n    var doc = goog.global.document;\n    return doc != null && 'write' in doc;  // XULDocument misses write.\n  };\n\n\n  /**\n   * Tries to detect the base path of base.js script that bootstraps Closure.\n   * @private\n   */\n  goog.findBasePath_ = function() {\n    if (goog.isDef(goog.global.CLOSURE_BASE_PATH)) {\n      goog.basePath = goog.global.CLOSURE_BASE_PATH;\n      return;\n    } else if (!goog.inHtmlDocument_()) {\n      return;\n    }\n    /** @type {Document} */\n    var doc = goog.global.document;\n    var scripts = doc.getElementsByTagName('SCRIPT');\n    // Search backwards since the current script is in almost all cases the one\n    // that has base.js.\n    for (var i = scripts.length - 1; i >= 0; --i) {\n      var script = /** @type {!HTMLScriptElement} */ (scripts[i]);\n      var src = script.src;\n      var qmark = src.lastIndexOf('?');\n      var l = qmark == -1 ? src.length : qmark;\n      if (src.substr(l - 7, 7) == 'base.js') {\n        goog.basePath = src.substr(0, l - 7);\n        return;\n      }\n    }\n  };\n\n\n  /**\n   * Imports a script if, and only if, that script hasn't already been imported.\n   * (Must be called at execution time)\n   * @param {string} src Script source.\n   * @param {string=} opt_sourceText The optionally source text to evaluate\n   * @private\n   */\n  goog.importScript_ = function(src, opt_sourceText) {\n    var importScript =\n        goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_;\n    if (importScript(src, opt_sourceText)) {\n      goog.dependencies_.written[src] = true;\n    }\n  };\n\n\n  /**\n   * Whether the browser is IE9 or earlier, which needs special handling\n   * for deferred modules.\n   * @const @private {boolean}\n   */\n  goog.IS_OLD_IE_ =\n      !!(!goog.global.atob && goog.global.document && goog.global.document.all);\n\n\n  /**\n   * Given a URL initiate retrieval and execution of a script that needs\n   * pre-processing.\n   * @param {string} src Script source URL.\n   * @param {boolean} isModule Whether this is a goog.module.\n   * @param {boolean} needsTranspile Whether this source needs transpilation.\n   * @private\n   */\n  goog.importProcessedScript_ = function(src, isModule, needsTranspile) {\n    // In an attempt to keep browsers from timing out loading scripts using\n    // synchronous XHRs, put each load in its own script block.\n    var bootstrap = 'goog.retrieveAndExec_(\"' + src + '\", ' + isModule + ', ' +\n        needsTranspile + ');';\n\n    goog.importScript_('', bootstrap);\n  };\n\n\n  /** @private {!Array<string>} */\n  goog.queuedModules_ = [];\n\n\n  /**\n   * Return an appropriate module text. Suitable to insert into\n   * a script tag (that is unescaped).\n   * @param {string} srcUrl\n   * @param {string} scriptText\n   * @return {string}\n   * @private\n   */\n  goog.wrapModule_ = function(srcUrl, scriptText) {\n    if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) {\n      return '' +\n          'goog.loadModule(function(exports) {' +\n          '\"use strict\";' + scriptText +\n          '\\n' +  // terminate any trailing single line comment.\n          ';return exports' +\n          '});' +\n          '\\n//# sourceURL=' + srcUrl + '\\n';\n    } else {\n      return '' +\n          'goog.loadModule(' +\n          goog.global.JSON.stringify(\n              scriptText + '\\n//# sourceURL=' + srcUrl + '\\n') +\n          ');';\n    }\n  };\n\n  // On IE9 and earlier, it is necessary to handle\n  // deferred module loads. In later browsers, the\n  // code to be evaluated is simply inserted as a script\n  // block in the correct order. To eval deferred\n  // code at the right time, we piggy back on goog.require to call\n  // goog.maybeProcessDeferredDep_.\n  //\n  // The goog.requires are used both to bootstrap\n  // the loading process (when no deps are available) and\n  // declare that they should be available.\n  //\n  // Here we eval the sources, if all the deps are available\n  // either already eval'd or goog.require'd.  This will\n  // be the case when all the dependencies have already\n  // been loaded, and the dependent module is loaded.\n  //\n  // But this alone isn't sufficient because it is also\n  // necessary to handle the case where there is no root\n  // that is not deferred.  For that there we register for an event\n  // and trigger goog.loadQueuedModules_ handle any remaining deferred\n  // evaluations.\n\n  /**\n   * Handle any remaining deferred goog.module evals.\n   * @private\n   */\n  goog.loadQueuedModules_ = function() {\n    var count = goog.queuedModules_.length;\n    if (count > 0) {\n      var queue = goog.queuedModules_;\n      goog.queuedModules_ = [];\n      for (var i = 0; i < count; i++) {\n        var path = queue[i];\n        goog.maybeProcessDeferredPath_(path);\n      }\n    }\n  };\n\n\n  /**\n   * Eval the named module if its dependencies are\n   * available.\n   * @param {string} name The module to load.\n   * @private\n   */\n  goog.maybeProcessDeferredDep_ = function(name) {\n    if (goog.isDeferredModule_(name) && goog.allDepsAreAvailable_(name)) {\n      var path = goog.getPathFromDeps_(name);\n      goog.maybeProcessDeferredPath_(goog.basePath + path);\n    }\n  };\n\n  /**\n   * @param {string} name The module to check.\n   * @return {boolean} Whether the name represents a\n   *     module whose evaluation has been deferred.\n   * @private\n   */\n  goog.isDeferredModule_ = function(name) {\n    var path = goog.getPathFromDeps_(name);\n    var loadFlags = path && goog.dependencies_.loadFlags[path] || {};\n    if (path && (loadFlags['module'] == 'goog' ||\n                 goog.needsTranspile_(loadFlags['lang']))) {\n      var abspath = goog.basePath + path;\n      return (abspath) in goog.dependencies_.deferred;\n    }\n    return false;\n  };\n\n  /**\n   * @param {string} name The module to check.\n   * @return {boolean} Whether the name represents a\n   *     module whose declared dependencies have all been loaded\n   *     (eval'd or a deferred module load)\n   * @private\n   */\n  goog.allDepsAreAvailable_ = function(name) {\n    var path = goog.getPathFromDeps_(name);\n    if (path && (path in goog.dependencies_.requires)) {\n      for (var requireName in goog.dependencies_.requires[path]) {\n        if (!goog.isProvided_(requireName) &&\n            !goog.isDeferredModule_(requireName)) {\n          return false;\n        }\n      }\n    }\n    return true;\n  };\n\n\n  /**\n   * @param {string} abspath\n   * @private\n   */\n  goog.maybeProcessDeferredPath_ = function(abspath) {\n    if (abspath in goog.dependencies_.deferred) {\n      var src = goog.dependencies_.deferred[abspath];\n      delete goog.dependencies_.deferred[abspath];\n      goog.globalEval(src);\n    }\n  };\n\n\n  /**\n   * Load a goog.module from the provided URL.  This is not a general purpose\n   * code loader and does not support late loading code, that is it should only\n   * be used during page load. This method exists to support unit tests and\n   * \"debug\" loaders that would otherwise have inserted script tags. Under the\n   * hood this needs to use a synchronous XHR and is not recommeneded for\n   * production code.\n   *\n   * The module's goog.requires must have already been satisified; an exception\n   * will be thrown if this is not the case. This assumption is that no\n   * \"deps.js\" file exists, so there is no way to discover and locate the\n   * module-to-be-loaded's dependencies and no attempt is made to do so.\n   *\n   * There should only be one attempt to load a module.  If\n   * \"goog.loadModuleFromUrl\" is called for an already loaded module, an\n   * exception will be throw.\n   *\n   * @param {string} url The URL from which to attempt to load the goog.module.\n   */\n  goog.loadModuleFromUrl = function(url) {\n    // Because this executes synchronously, we don't need to do any additional\n    // bookkeeping. When \"goog.loadModule\" the namespace will be marked as\n    // having been provided which is sufficient.\n    goog.retrieveAndExec_(url, true, false);\n  };\n\n\n  /**\n   * Writes a new script pointing to {@code src} directly into the DOM.\n   *\n   * NOTE: This method is not CSP-compliant. @see goog.appendScriptSrcNode_ for\n   * the fallback mechanism.\n   *\n   * @param {string} src The script URL.\n   * @private\n   */\n  goog.writeScriptSrcNode_ = function(src) {\n    goog.global.document.write(\n        '<script type=\"text/javascript\" src=\"' + src + '\"></' +\n        'script>');\n  };\n\n\n  /**\n   * Appends a new script node to the DOM using a CSP-compliant mechanism. This\n   * method exists as a fallback for document.write (which is not allowed in a\n   * strict CSP context, e.g., Chrome apps).\n   *\n   * NOTE: This method is not analogous to using document.write to insert a\n   * <script> tag; specifically, the user agent will execute a script added by\n   * document.write immediately after the current script block finishes\n   * executing, whereas the DOM-appended script node will not be executed until\n   * the entire document is parsed and executed. That is to say, this script is\n   * added to the end of the script execution queue.\n   *\n   * The page must not attempt to call goog.required entities until after the\n   * document has loaded, e.g., in or after the window.onload callback.\n   *\n   * @param {string} src The script URL.\n   * @private\n   */\n  goog.appendScriptSrcNode_ = function(src) {\n    /** @type {Document} */\n    var doc = goog.global.document;\n    var scriptEl =\n        /** @type {HTMLScriptElement} */ (doc.createElement('script'));\n    scriptEl.type = 'text/javascript';\n    scriptEl.src = src;\n    scriptEl.defer = false;\n    scriptEl.async = false;\n    doc.head.appendChild(scriptEl);\n  };\n\n\n  /**\n   * The default implementation of the import function. Writes a script tag to\n   * import the script.\n   *\n   * @param {string} src The script url.\n   * @param {string=} opt_sourceText The optionally source text to evaluate\n   * @return {boolean} True if the script was imported, false otherwise.\n   * @private\n   */\n  goog.writeScriptTag_ = function(src, opt_sourceText) {\n    if (goog.inHtmlDocument_()) {\n      /** @type {!HTMLDocument} */\n      var doc = goog.global.document;\n\n      // If the user tries to require a new symbol after document load,\n      // something has gone terribly wrong. Doing a document.write would\n      // wipe out the page. This does not apply to the CSP-compliant method\n      // of writing script tags.\n      if (!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING &&\n          doc.readyState == 'complete') {\n        // Certain test frameworks load base.js multiple times, which tries\n        // to write deps.js each time. If that happens, just fail silently.\n        // These frameworks wipe the page between each load of base.js, so this\n        // is OK.\n        var isDeps = /\\bdeps.js$/.test(src);\n        if (isDeps) {\n          return false;\n        } else {\n          throw Error('Cannot write \"' + src + '\" after document load');\n        }\n      }\n\n      if (opt_sourceText === undefined) {\n        if (!goog.IS_OLD_IE_) {\n          if (goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING) {\n            goog.appendScriptSrcNode_(src);\n          } else {\n            goog.writeScriptSrcNode_(src);\n          }\n        } else {\n          var state = \" onreadystatechange='goog.onScriptLoad_(this, \" +\n              ++goog.lastNonModuleScriptIndex_ + \")' \";\n          doc.write(\n              '<script type=\"text/javascript\" src=\"' + src + '\"' + state +\n              '></' +\n              'script>');\n        }\n      } else {\n        doc.write(\n            '<script type=\"text/javascript\">' + opt_sourceText + '</' +\n            'script>');\n      }\n      return true;\n    } else {\n      return false;\n    }\n  };\n\n\n  /**\n   * Determines whether the given language needs to be transpiled.\n   * @param {string} lang\n   * @return {boolean}\n   * @private\n   */\n  goog.needsTranspile_ = function(lang) {\n    if (goog.TRANSPILE == 'always') {\n      return true;\n    } else if (goog.TRANSPILE == 'never') {\n      return false;\n    } else if (!goog.transpiledLanguages_) {\n      goog.transpiledLanguages_ = {'es5': true, 'es6': true, 'es6-impl': true};\n      /** @preserveTry */\n      try {\n        // Perform some quick conformance checks, to distinguish\n        // between browsers that support es5, es6-impl, or es6.\n\n        // Identify ES3-only browsers by their incorrect treatment of commas.\n        goog.transpiledLanguages_['es5'] = eval('[1,].length!=1');\n\n        // As browsers mature, features will be moved from the full test\n        // into the impl test.  This must happen before the corresponding\n        // features are changed in the Closure Compiler's FeatureSet object.\n\n        // Test 1: es6-impl [FF49, Edge 13, Chrome 49]\n        //   (a) let/const keyword, (b) class expressions, (c) Map object,\n        //   (d) iterable arguments, (e) spread operator\n        var es6implTest =\n            'let a={};const X=class{constructor(){}x(z){return new Map([' +\n            '...arguments]).get(z[0])==3}};return new X().x([a,3])';\n\n        // Test 2: es6 [FF50 (?), Edge 14 (?), Chrome 50]\n        //   (a) default params (specifically shadowing locals),\n        //   (b) destructuring, (c) block-scoped functions,\n        //   (d) for-of (const), (e) new.target/Reflect.construct\n        var es6fullTest =\n            'class X{constructor(){if(new.target!=String)throw 1;this.x=42}}' +\n            'let q=Reflect.construct(X,[],String);if(q.x!=42||!(q instanceof ' +\n            'String))throw 1;for(const a of[2,3]){if(a==2)continue;function ' +\n            'f(z={a}){let a=0;return z.a}{function f(){return 0;}}return f()' +\n            '==3}';\n\n        if (eval('(()=>{\"use strict\";' + es6implTest + '})()')) {\n          goog.transpiledLanguages_['es6-impl'] = false;\n        }\n        if (eval('(()=>{\"use strict\";' + es6fullTest + '})()')) {\n          goog.transpiledLanguages_['es6'] = false;\n        }\n      } catch (err) {\n      }\n    }\n    return !!goog.transpiledLanguages_[lang];\n  };\n\n\n  /** @private {?Object<string, boolean>} */\n  goog.transpiledLanguages_ = null;\n\n\n  /** @private {number} */\n  goog.lastNonModuleScriptIndex_ = 0;\n\n\n  /**\n   * A readystatechange handler for legacy IE\n   * @param {!HTMLScriptElement} script\n   * @param {number} scriptIndex\n   * @return {boolean}\n   * @private\n   */\n  goog.onScriptLoad_ = function(script, scriptIndex) {\n    // for now load the modules when we reach the last script,\n    // later allow more inter-mingling.\n    if (script.readyState == 'complete' &&\n        goog.lastNonModuleScriptIndex_ == scriptIndex) {\n      goog.loadQueuedModules_();\n    }\n    return true;\n  };\n\n  /**\n   * Resolves dependencies based on the dependencies added using addDependency\n   * and calls importScript_ in the correct order.\n   * @param {string} pathToLoad The path from which to start discovering\n   *     dependencies.\n   * @private\n   */\n  goog.writeScripts_ = function(pathToLoad) {\n    /** @type {!Array<string>} The scripts we need to write this time. */\n    var scripts = [];\n    var seenScript = {};\n    var deps = goog.dependencies_;\n\n    /** @param {string} path */\n    function visitNode(path) {\n      if (path in deps.written) {\n        return;\n      }\n\n      // We have already visited this one. We can get here if we have cyclic\n      // dependencies.\n      if (path in deps.visited) {\n        return;\n      }\n\n      deps.visited[path] = true;\n\n      if (path in deps.requires) {\n        for (var requireName in deps.requires[path]) {\n          // If the required name is defined, we assume that it was already\n          // bootstrapped by other means.\n          if (!goog.isProvided_(requireName)) {\n            if (requireName in deps.nameToPath) {\n              visitNode(deps.nameToPath[requireName]);\n            } else {\n              throw Error('Undefined nameToPath for ' + requireName);\n            }\n          }\n        }\n      }\n\n      if (!(path in seenScript)) {\n        seenScript[path] = true;\n        scripts.push(path);\n      }\n    }\n\n    visitNode(pathToLoad);\n\n    // record that we are going to load all these scripts.\n    for (var i = 0; i < scripts.length; i++) {\n      var path = scripts[i];\n      goog.dependencies_.written[path] = true;\n    }\n\n    // If a module is loaded synchronously then we need to\n    // clear the current inModuleLoader value, and restore it when we are\n    // done loading the current \"requires\".\n    var moduleState = goog.moduleLoaderState_;\n    goog.moduleLoaderState_ = null;\n\n    for (var i = 0; i < scripts.length; i++) {\n      var path = scripts[i];\n      if (path) {\n        var loadFlags = deps.loadFlags[path] || {};\n        var needsTranspile = goog.needsTranspile_(loadFlags['lang']);\n        if (loadFlags['module'] == 'goog' || needsTranspile) {\n          goog.importProcessedScript_(\n              goog.basePath + path, loadFlags['module'] == 'goog',\n              needsTranspile);\n        } else {\n          goog.importScript_(goog.basePath + path);\n        }\n      } else {\n        goog.moduleLoaderState_ = moduleState;\n        throw Error('Undefined script input');\n      }\n    }\n\n    // restore the current \"module loading state\"\n    goog.moduleLoaderState_ = moduleState;\n  };\n\n\n  /**\n   * Looks at the dependency rules and tries to determine the script file that\n   * fulfills a particular rule.\n   * @param {string} rule In the form goog.namespace.Class or project.script.\n   * @return {?string} Url corresponding to the rule, or null.\n   * @private\n   */\n  goog.getPathFromDeps_ = function(rule) {\n    if (rule in goog.dependencies_.nameToPath) {\n      return goog.dependencies_.nameToPath[rule];\n    } else {\n      return null;\n    }\n  };\n\n  goog.findBasePath_();\n\n  // Allow projects to manage the deps files themselves.\n  if (!goog.global.CLOSURE_NO_DEPS) {\n    goog.importScript_(goog.basePath + 'deps.js');\n  }\n}\n\n\n/**\n * @param {function(?):?|string} moduleDef The module definition.\n */\ngoog.loadModule = function(moduleDef) {\n  // NOTE: we allow function definitions to be either in the from\n  // of a string to eval (which keeps the original source intact) or\n  // in a eval forbidden environment (CSP) we allow a function definition\n  // which in its body must call {@code goog.module}, and return the exports\n  // of the module.\n  var previousState = goog.moduleLoaderState_;\n  try {\n    goog.moduleLoaderState_ = {\n      moduleName: undefined,\n      declareLegacyNamespace: false\n    };\n    var exports;\n    if (goog.isFunction(moduleDef)) {\n      exports = moduleDef.call(undefined, {});\n    } else if (goog.isString(moduleDef)) {\n      exports = goog.loadModuleFromSource_.call(undefined, moduleDef);\n    } else {\n      throw Error('Invalid module definition');\n    }\n\n    var moduleName = goog.moduleLoaderState_.moduleName;\n    if (!goog.isString(moduleName) || !moduleName) {\n      throw Error('Invalid module name \\\"' + moduleName + '\\\"');\n    }\n\n    // Don't seal legacy namespaces as they may be uses as a parent of\n    // another namespace\n    if (goog.moduleLoaderState_.declareLegacyNamespace) {\n      goog.constructNamespace_(moduleName, exports);\n    } else if (goog.SEAL_MODULE_EXPORTS && Object.seal) {\n      Object.seal(exports);\n    }\n\n    goog.loadedModules_[moduleName] = exports;\n  } finally {\n    goog.moduleLoaderState_ = previousState;\n  }\n};\n\n\n/**\n * @private @const {function(string):?}\n *\n * The new type inference warns because this function has no formal\n * parameters, but its jsdoc says that it takes one argument.\n * (The argument is used via arguments[0], but NTI does not detect this.)\n * @suppress {newCheckTypes}\n */\ngoog.loadModuleFromSource_ = function() {\n  // NOTE: we avoid declaring parameters or local variables here to avoid\n  // masking globals or leaking values into the module definition.\n  'use strict';\n  var exports = {};\n  eval(arguments[0]);\n  return exports;\n};\n\n\n/**\n * Normalize a file path by removing redundant \"..\" and extraneous \".\" file\n * path components.\n * @param {string} path\n * @return {string}\n * @private\n */\ngoog.normalizePath_ = function(path) {\n  var components = path.split('/');\n  var i = 0;\n  while (i < components.length) {\n    if (components[i] == '.') {\n      components.splice(i, 1);\n    } else if (\n        i && components[i] == '..' && components[i - 1] &&\n        components[i - 1] != '..') {\n      components.splice(--i, 2);\n    } else {\n      i++;\n    }\n  }\n  return components.join('/');\n};\n\n\n/**\n * Loads file by synchronous XHR. Should not be used in production environments.\n * @param {string} src Source URL.\n * @return {?string} File contents, or null if load failed.\n * @private\n */\ngoog.loadFileSync_ = function(src) {\n  if (goog.global.CLOSURE_LOAD_FILE_SYNC) {\n    return goog.global.CLOSURE_LOAD_FILE_SYNC(src);\n  } else {\n    try {\n      /** @type {XMLHttpRequest} */\n      var xhr = new goog.global['XMLHttpRequest']();\n      xhr.open('get', src, false);\n      xhr.send();\n      // NOTE: Successful http: requests have a status of 200, but successful\n      // file: requests may have a status of zero.  Any other status, or a\n      // thrown exception (particularly in case of file: requests) indicates\n      // some sort of error, which we treat as a missing or unavailable file.\n      return xhr.status == 0 || xhr.status == 200 ? xhr.responseText : null;\n    } catch (err) {\n      // No need to rethrow or log, since errors should show up on their own.\n      return null;\n    }\n  }\n};\n\n\n/**\n * Retrieve and execute a script that needs some sort of wrapping.\n * @param {string} src Script source URL.\n * @param {boolean} isModule Whether to load as a module.\n * @param {boolean} needsTranspile Whether to transpile down to ES3.\n * @private\n */\ngoog.retrieveAndExec_ = function(src, isModule, needsTranspile) {\n  if (!COMPILED) {\n    // The full but non-canonicalized URL for later use.\n    var originalPath = src;\n    // Canonicalize the path, removing any /./ or /../ since Chrome's debugging\n    // console doesn't auto-canonicalize XHR loads as it does <script> srcs.\n    src = goog.normalizePath_(src);\n\n    var importScript =\n        goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_;\n\n    var scriptText = goog.loadFileSync_(src);\n    if (scriptText == null) {\n      throw new Error('Load of \"' + src + '\" failed');\n    }\n\n    if (needsTranspile) {\n      scriptText = goog.transpile_.call(goog.global, scriptText, src);\n    }\n\n    if (isModule) {\n      scriptText = goog.wrapModule_(src, scriptText);\n    } else {\n      scriptText += '\\n//# sourceURL=' + src;\n    }\n    var isOldIE = goog.IS_OLD_IE_;\n    if (isOldIE) {\n      goog.dependencies_.deferred[originalPath] = scriptText;\n      goog.queuedModules_.push(originalPath);\n    } else {\n      importScript(src, scriptText);\n    }\n  }\n};\n\n\n/**\n * Lazily retrieves the transpiler and applies it to the source.\n * @param {string} code JS code.\n * @param {string} path Path to the code.\n * @return {string} The transpiled code.\n * @private\n */\ngoog.transpile_ = function(code, path) {\n  var jscomp = goog.global['$jscomp'];\n  if (!jscomp) {\n    goog.global['$jscomp'] = jscomp = {};\n  }\n  var transpile = jscomp.transpile;\n  if (!transpile) {\n    var transpilerPath = goog.basePath + goog.TRANSPILER;\n    var transpilerCode = goog.loadFileSync_(transpilerPath);\n    if (transpilerCode) {\n      // This must be executed synchronously, since by the time we know we\n      // need it, we're about to load and write the ES6 code synchronously,\n      // so a normal script-tag load will be too slow.\n      eval(transpilerCode + '\\n//# sourceURL=' + transpilerPath);\n      // Note: transpile.js reassigns goog.global['$jscomp'] so pull it again.\n      jscomp = goog.global['$jscomp'];\n      transpile = jscomp.transpile;\n    }\n  }\n  if (!transpile) {\n    // The transpiler is an optional component.  If it's not available then\n    // replace it with a pass-through function that simply logs.\n    var suffix = ' requires transpilation but no transpiler was found.';\n    transpile = jscomp.transpile = function(code, path) {\n      // TODO(user): figure out some way to get this error to show up\n      // in test results, noting that the failure may occur in many\n      // different ways, including in loadModule() before the test\n      // runner even comes up.\n      goog.logToConsole_(path + suffix);\n      return code;\n    };\n  }\n  // Note: any transpilation errors/warnings will be logged to the console.\n  return transpile(code, path);\n};\n\n\n//==============================================================================\n// Language Enhancements\n//==============================================================================\n\n\n/**\n * This is a \"fixed\" version of the typeof operator.  It differs from the typeof\n * operator in such a way that null returns 'null' and arrays return 'array'.\n * @param {?} value The value to get the type of.\n * @return {string} The name of the type.\n */\ngoog.typeOf = function(value) {\n  var s = typeof value;\n  if (s == 'object') {\n    if (value) {\n      // Check these first, so we can avoid calling Object.prototype.toString if\n      // possible.\n      //\n      // IE improperly marshals typeof across execution contexts, but a\n      // cross-context object will still return false for \"instanceof Object\".\n      if (value instanceof Array) {\n        return 'array';\n      } else if (value instanceof Object) {\n        return s;\n      }\n\n      // HACK: In order to use an Object prototype method on the arbitrary\n      //   value, the compiler requires the value be cast to type Object,\n      //   even though the ECMA spec explicitly allows it.\n      var className = Object.prototype.toString.call(\n          /** @type {!Object} */ (value));\n      // In Firefox 3.6, attempting to access iframe window objects' length\n      // property throws an NS_ERROR_FAILURE, so we need to special-case it\n      // here.\n      if (className == '[object Window]') {\n        return 'object';\n      }\n\n      // We cannot always use constructor == Array or instanceof Array because\n      // different frames have different Array objects. In IE6, if the iframe\n      // where the array was created is destroyed, the array loses its\n      // prototype. Then dereferencing val.splice here throws an exception, so\n      // we can't use goog.isFunction. Calling typeof directly returns 'unknown'\n      // so that will work. In this case, this function will return false and\n      // most array functions will still work because the array is still\n      // array-like (supports length and []) even though it has lost its\n      // prototype.\n      // Mark Miller noticed that Object.prototype.toString\n      // allows access to the unforgeable [[Class]] property.\n      //  15.2.4.2 Object.prototype.toString ( )\n      //  When the toString method is called, the following steps are taken:\n      //      1. Get the [[Class]] property of this object.\n      //      2. Compute a string value by concatenating the three strings\n      //         \"[object \", Result(1), and \"]\".\n      //      3. Return Result(2).\n      // and this behavior survives the destruction of the execution context.\n      if ((className == '[object Array]' ||\n           // In IE all non value types are wrapped as objects across window\n           // boundaries (not iframe though) so we have to do object detection\n           // for this edge case.\n           typeof value.length == 'number' &&\n               typeof value.splice != 'undefined' &&\n               typeof value.propertyIsEnumerable != 'undefined' &&\n               !value.propertyIsEnumerable('splice')\n\n               )) {\n        return 'array';\n      }\n      // HACK: There is still an array case that fails.\n      //     function ArrayImpostor() {}\n      //     ArrayImpostor.prototype = [];\n      //     var impostor = new ArrayImpostor;\n      // this can be fixed by getting rid of the fast path\n      // (value instanceof Array) and solely relying on\n      // (value && Object.prototype.toString.vall(value) === '[object Array]')\n      // but that would require many more function calls and is not warranted\n      // unless closure code is receiving objects from untrusted sources.\n\n      // IE in cross-window calls does not correctly marshal the function type\n      // (it appears just as an object) so we cannot use just typeof val ==\n      // 'function'. However, if the object has a call property, it is a\n      // function.\n      if ((className == '[object Function]' ||\n           typeof value.call != 'undefined' &&\n               typeof value.propertyIsEnumerable != 'undefined' &&\n               !value.propertyIsEnumerable('call'))) {\n        return 'function';\n      }\n\n    } else {\n      return 'null';\n    }\n\n  } else if (s == 'function' && typeof value.call == 'undefined') {\n    // In Safari typeof nodeList returns 'function', and on Firefox typeof\n    // behaves similarly for HTML{Applet,Embed,Object}, Elements and RegExps. We\n    // would like to return object for those and we can detect an invalid\n    // function by making sure that the function object has a call method.\n    return 'object';\n  }\n  return s;\n};\n\n\n/**\n * Returns true if the specified value is null.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is null.\n */\ngoog.isNull = function(val) {\n  return val === null;\n};\n\n\n/**\n * Returns true if the specified value is defined and not null.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is defined and not null.\n */\ngoog.isDefAndNotNull = function(val) {\n  // Note that undefined == null.\n  return val != null;\n};\n\n\n/**\n * Returns true if the specified value is an array.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is an array.\n */\ngoog.isArray = function(val) {\n  return goog.typeOf(val) == 'array';\n};\n\n\n/**\n * Returns true if the object looks like an array. To qualify as array like\n * the value needs to be either a NodeList or an object with a Number length\n * property. As a special case, a function value is not array like, because its\n * length property is fixed to correspond to the number of expected arguments.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is an array.\n */\ngoog.isArrayLike = function(val) {\n  var type = goog.typeOf(val);\n  // We do not use goog.isObject here in order to exclude function values.\n  return type == 'array' || type == 'object' && typeof val.length == 'number';\n};\n\n\n/**\n * Returns true if the object looks like a Date. To qualify as Date-like the\n * value needs to be an object and have a getFullYear() function.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is a like a Date.\n */\ngoog.isDateLike = function(val) {\n  return goog.isObject(val) && typeof val.getFullYear == 'function';\n};\n\n\n/**\n * Returns true if the specified value is a string.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is a string.\n */\ngoog.isString = function(val) {\n  return typeof val == 'string';\n};\n\n\n/**\n * Returns true if the specified value is a boolean.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is boolean.\n */\ngoog.isBoolean = function(val) {\n  return typeof val == 'boolean';\n};\n\n\n/**\n * Returns true if the specified value is a number.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is a number.\n */\ngoog.isNumber = function(val) {\n  return typeof val == 'number';\n};\n\n\n/**\n * Returns true if the specified value is a function.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is a function.\n */\ngoog.isFunction = function(val) {\n  return goog.typeOf(val) == 'function';\n};\n\n\n/**\n * Returns true if the specified value is an object.  This includes arrays and\n * functions.\n * @param {?} val Variable to test.\n * @return {boolean} Whether variable is an object.\n */\ngoog.isObject = function(val) {\n  var type = typeof val;\n  return type == 'object' && val != null || type == 'function';\n  // return Object(val) === val also works, but is slower, especially if val is\n  // not an object.\n};\n\n\n/**\n * Gets a unique ID for an object. This mutates the object so that further calls\n * with the same object as a parameter returns the same value. The unique ID is\n * guaranteed to be unique across the current session amongst objects that are\n * passed into {@code getUid}. There is no guarantee that the ID is unique or\n * consistent across sessions. It is unsafe to generate unique ID for function\n * prototypes.\n *\n * @param {Object} obj The object to get the unique ID for.\n * @return {number} The unique ID for the object.\n */\ngoog.getUid = function(obj) {\n  // TODO(arv): Make the type stricter, do not accept null.\n\n  // In Opera window.hasOwnProperty exists but always returns false so we avoid\n  // using it. As a consequence the unique ID generated for BaseClass.prototype\n  // and SubClass.prototype will be the same.\n  return obj[goog.UID_PROPERTY_] ||\n      (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_);\n};\n\n\n/**\n * Whether the given object is already assigned a unique ID.\n *\n * This does not modify the object.\n *\n * @param {!Object} obj The object to check.\n * @return {boolean} Whether there is an assigned unique id for the object.\n */\ngoog.hasUid = function(obj) {\n  return !!obj[goog.UID_PROPERTY_];\n};\n\n\n/**\n * Removes the unique ID from an object. This is useful if the object was\n * previously mutated using {@code goog.getUid} in which case the mutation is\n * undone.\n * @param {Object} obj The object to remove the unique ID field from.\n */\ngoog.removeUid = function(obj) {\n  // TODO(arv): Make the type stricter, do not accept null.\n\n  // In IE, DOM nodes are not instances of Object and throw an exception if we\n  // try to delete.  Instead we try to use removeAttribute.\n  if (obj !== null && 'removeAttribute' in obj) {\n    obj.removeAttribute(goog.UID_PROPERTY_);\n  }\n  /** @preserveTry */\n  try {\n    delete obj[goog.UID_PROPERTY_];\n  } catch (ex) {\n  }\n};\n\n\n/**\n * Name for unique ID property. Initialized in a way to help avoid collisions\n * with other closure JavaScript on the same page.\n * @type {string}\n * @private\n */\ngoog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0);\n\n\n/**\n * Counter for UID.\n * @type {number}\n * @private\n */\ngoog.uidCounter_ = 0;\n\n\n/**\n * Adds a hash code field to an object. The hash code is unique for the\n * given object.\n * @param {Object} obj The object to get the hash code for.\n * @return {number} The hash code for the object.\n * @deprecated Use goog.getUid instead.\n */\ngoog.getHashCode = goog.getUid;\n\n\n/**\n * Removes the hash code field from an object.\n * @param {Object} obj The object to remove the field from.\n * @deprecated Use goog.removeUid instead.\n */\ngoog.removeHashCode = goog.removeUid;\n\n\n/**\n * Clones a value. The input may be an Object, Array, or basic type. Objects and\n * arrays will be cloned recursively.\n *\n * WARNINGS:\n * <code>goog.cloneObject</code> does not detect reference loops. Objects that\n * refer to themselves will cause infinite recursion.\n *\n * <code>goog.cloneObject</code> is unaware of unique identifiers, and copies\n * UIDs created by <code>getUid</code> into cloned results.\n *\n * @param {*} obj The value to clone.\n * @return {*} A clone of the input value.\n * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods.\n */\ngoog.cloneObject = function(obj) {\n  var type = goog.typeOf(obj);\n  if (type == 'object' || type == 'array') {\n    if (obj.clone) {\n      return obj.clone();\n    }\n    var clone = type == 'array' ? [] : {};\n    for (var key in obj) {\n      clone[key] = goog.cloneObject(obj[key]);\n    }\n    return clone;\n  }\n\n  return obj;\n};\n\n\n/**\n * A native implementation of goog.bind.\n * @param {Function} fn A function to partially apply.\n * @param {Object|undefined} selfObj Specifies the object which this should\n *     point to when the function is run.\n * @param {...*} var_args Additional arguments that are partially applied to the\n *     function.\n * @return {!Function} A partially-applied form of the function bind() was\n *     invoked as a method of.\n * @private\n * @suppress {deprecated} The compiler thinks that Function.prototype.bind is\n *     deprecated because some people have declared a pure-JS version.\n *     Only the pure-JS version is truly deprecated.\n */\ngoog.bindNative_ = function(fn, selfObj, var_args) {\n  return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments));\n};\n\n\n/**\n * A pure-JS implementation of goog.bind.\n * @param {Function} fn A function to partially apply.\n * @param {Object|undefined} selfObj Specifies the object which this should\n *     point to when the function is run.\n * @param {...*} var_args Additional arguments that are partially applied to the\n *     function.\n * @return {!Function} A partially-applied form of the function bind() was\n *     invoked as a method of.\n * @private\n */\ngoog.bindJs_ = function(fn, selfObj, var_args) {\n  if (!fn) {\n    throw new Error();\n  }\n\n  if (arguments.length > 2) {\n    var boundArgs = Array.prototype.slice.call(arguments, 2);\n    return function() {\n      // Prepend the bound arguments to the current arguments.\n      var newArgs = Array.prototype.slice.call(arguments);\n      Array.prototype.unshift.apply(newArgs, boundArgs);\n      return fn.apply(selfObj, newArgs);\n    };\n\n  } else {\n    return function() { return fn.apply(selfObj, arguments); };\n  }\n};\n\n\n/**\n * Partially applies this function to a particular 'this object' and zero or\n * more arguments. The result is a new function with some arguments of the first\n * function pre-filled and the value of this 'pre-specified'.\n *\n * Remaining arguments specified at call-time are appended to the pre-specified\n * ones.\n *\n * Also see: {@link #partial}.\n *\n * Usage:\n * <pre>var barMethBound = goog.bind(myFunction, myObj, 'arg1', 'arg2');\n * barMethBound('arg3', 'arg4');</pre>\n *\n * @param {?function(this:T, ...)} fn A function to partially apply.\n * @param {T} selfObj Specifies the object which this should point to when the\n *     function is run.\n * @param {...*} var_args Additional arguments that are partially applied to the\n *     function.\n * @return {!Function} A partially-applied form of the function goog.bind() was\n *     invoked as a method of.\n * @template T\n * @suppress {deprecated} See above.\n */\ngoog.bind = function(fn, selfObj, var_args) {\n  // TODO(nicksantos): narrow the type signature.\n  if (Function.prototype.bind &&\n      // NOTE(nicksantos): Somebody pulled base.js into the default Chrome\n      // extension environment. This means that for Chrome extensions, they get\n      // the implementation of Function.prototype.bind that calls goog.bind\n      // instead of the native one. Even worse, we don't want to introduce a\n      // circular dependency between goog.bind and Function.prototype.bind, so\n      // we have to hack this to make sure it works correctly.\n      Function.prototype.bind.toString().indexOf('native code') != -1) {\n    goog.bind = goog.bindNative_;\n  } else {\n    goog.bind = goog.bindJs_;\n  }\n  return goog.bind.apply(null, arguments);\n};\n\n\n/**\n * Like goog.bind(), except that a 'this object' is not required. Useful when\n * the target function is already bound.\n *\n * Usage:\n * var g = goog.partial(f, arg1, arg2);\n * g(arg3, arg4);\n *\n * @param {Function} fn A function to partially apply.\n * @param {...*} var_args Additional arguments that are partially applied to fn.\n * @return {!Function} A partially-applied form of the function goog.partial()\n *     was invoked as a method of.\n */\ngoog.partial = function(fn, var_args) {\n  var args = Array.prototype.slice.call(arguments, 1);\n  return function() {\n    // Clone the array (with slice()) and append additional arguments\n    // to the existing arguments.\n    var newArgs = args.slice();\n    newArgs.push.apply(newArgs, arguments);\n    return fn.apply(this, newArgs);\n  };\n};\n\n\n/**\n * Copies all the members of a source object to a target object. This method\n * does not work on all browsers for all objects that contain keys such as\n * toString or hasOwnProperty. Use goog.object.extend for this purpose.\n * @param {Object} target Target.\n * @param {Object} source Source.\n */\ngoog.mixin = function(target, source) {\n  for (var x in source) {\n    target[x] = source[x];\n  }\n\n  // For IE7 or lower, the for-in-loop does not contain any properties that are\n  // not enumerable on the prototype object (for example, isPrototypeOf from\n  // Object.prototype) but also it will not include 'replace' on objects that\n  // extend String and change 'replace' (not that it is common for anyone to\n  // extend anything except Object).\n};\n\n\n/**\n * @return {number} An integer value representing the number of milliseconds\n *     between midnight, January 1, 1970 and the current time.\n */\ngoog.now = (goog.TRUSTED_SITE && Date.now) || (function() {\n             // Unary plus operator converts its operand to a number which in\n             // the case of\n             // a date is done by calling getTime().\n             return +new Date();\n           });\n\n\n/**\n * Evals JavaScript in the global scope.  In IE this uses execScript, other\n * browsers use goog.global.eval. If goog.global.eval does not evaluate in the\n * global scope (for example, in Safari), appends a script tag instead.\n * Throws an exception if neither execScript or eval is defined.\n * @param {string} script JavaScript string.\n */\ngoog.globalEval = function(script) {\n  if (goog.global.execScript) {\n    goog.global.execScript(script, 'JavaScript');\n  } else if (goog.global.eval) {\n    // Test to see if eval works\n    if (goog.evalWorksForGlobals_ == null) {\n      goog.global.eval('var _evalTest_ = 1;');\n      if (typeof goog.global['_evalTest_'] != 'undefined') {\n        try {\n          delete goog.global['_evalTest_'];\n        } catch (ignore) {\n          // Microsoft edge fails the deletion above in strict mode.\n        }\n        goog.evalWorksForGlobals_ = true;\n      } else {\n        goog.evalWorksForGlobals_ = false;\n      }\n    }\n\n    if (goog.evalWorksForGlobals_) {\n      goog.global.eval(script);\n    } else {\n      /** @type {Document} */\n      var doc = goog.global.document;\n      var scriptElt =\n          /** @type {!HTMLScriptElement} */ (doc.createElement('SCRIPT'));\n      scriptElt.type = 'text/javascript';\n      scriptElt.defer = false;\n      // Note(user): can't use .innerHTML since \"t('<test>')\" will fail and\n      // .text doesn't work in Safari 2.  Therefore we append a text node.\n      scriptElt.appendChild(doc.createTextNode(script));\n      doc.body.appendChild(scriptElt);\n      doc.body.removeChild(scriptElt);\n    }\n  } else {\n    throw Error('goog.globalEval not available');\n  }\n};\n\n\n/**\n * Indicates whether or not we can call 'eval' directly to eval code in the\n * global scope. Set to a Boolean by the first call to goog.globalEval (which\n * empirically tests whether eval works for globals). @see goog.globalEval\n * @type {?boolean}\n * @private\n */\ngoog.evalWorksForGlobals_ = null;\n\n\n/**\n * Optional map of CSS class names to obfuscated names used with\n * goog.getCssName().\n * @private {!Object<string, string>|undefined}\n * @see goog.setCssNameMapping\n */\ngoog.cssNameMapping_;\n\n\n/**\n * Optional obfuscation style for CSS class names. Should be set to either\n * 'BY_WHOLE' or 'BY_PART' if defined.\n * @type {string|undefined}\n * @private\n * @see goog.setCssNameMapping\n */\ngoog.cssNameMappingStyle_;\n\n\n/**\n * Handles strings that are intended to be used as CSS class names.\n *\n * This function works in tandem with @see goog.setCssNameMapping.\n *\n * Without any mapping set, the arguments are simple joined with a hyphen and\n * passed through unaltered.\n *\n * When there is a mapping, there are two possible styles in which these\n * mappings are used. In the BY_PART style, each part (i.e. in between hyphens)\n * of the passed in css name is rewritten according to the map. In the BY_WHOLE\n * style, the full css name is looked up in the map directly. If a rewrite is\n * not specified by the map, the compiler will output a warning.\n *\n * When the mapping is passed to the compiler, it will replace calls to\n * goog.getCssName with the strings from the mapping, e.g.\n *     var x = goog.getCssName('foo');\n *     var y = goog.getCssName(this.baseClass, 'active');\n *  becomes:\n *     var x = 'foo';\n *     var y = this.baseClass + '-active';\n *\n * If one argument is passed it will be processed, if two are passed only the\n * modifier will be processed, as it is assumed the first argument was generated\n * as a result of calling goog.getCssName.\n *\n * @param {string} className The class name.\n * @param {string=} opt_modifier A modifier to be appended to the class name.\n * @return {string} The class name or the concatenation of the class name and\n *     the modifier.\n */\ngoog.getCssName = function(className, opt_modifier) {\n  var getMapping = function(cssName) {\n    return goog.cssNameMapping_[cssName] || cssName;\n  };\n\n  var renameByParts = function(cssName) {\n    // Remap all the parts individually.\n    var parts = cssName.split('-');\n    var mapped = [];\n    for (var i = 0; i < parts.length; i++) {\n      mapped.push(getMapping(parts[i]));\n    }\n    return mapped.join('-');\n  };\n\n  var rename;\n  if (goog.cssNameMapping_) {\n    rename =\n        goog.cssNameMappingStyle_ == 'BY_WHOLE' ? getMapping : renameByParts;\n  } else {\n    rename = function(a) { return a; };\n  }\n\n  if (opt_modifier) {\n    return className + '-' + rename(opt_modifier);\n  } else {\n    return rename(className);\n  }\n};\n\n\n/**\n * Sets the map to check when returning a value from goog.getCssName(). Example:\n * <pre>\n * goog.setCssNameMapping({\n *   \"goog\": \"a\",\n *   \"disabled\": \"b\",\n * });\n *\n * var x = goog.getCssName('goog');\n * // The following evaluates to: \"a a-b\".\n * goog.getCssName('goog') + ' ' + goog.getCssName(x, 'disabled')\n * </pre>\n * When declared as a map of string literals to string literals, the JSCompiler\n * will replace all calls to goog.getCssName() using the supplied map if the\n * --process_closure_primitives flag is set.\n *\n * @param {!Object} mapping A map of strings to strings where keys are possible\n *     arguments to goog.getCssName() and values are the corresponding values\n *     that should be returned.\n * @param {string=} opt_style The style of css name mapping. There are two valid\n *     options: 'BY_PART', and 'BY_WHOLE'.\n * @see goog.getCssName for a description.\n */\ngoog.setCssNameMapping = function(mapping, opt_style) {\n  goog.cssNameMapping_ = mapping;\n  goog.cssNameMappingStyle_ = opt_style;\n};\n\n\n/**\n * To use CSS renaming in compiled mode, one of the input files should have a\n * call to goog.setCssNameMapping() with an object literal that the JSCompiler\n * can extract and use to replace all calls to goog.getCssName(). In uncompiled\n * mode, JavaScript code should be loaded before this base.js file that declares\n * a global variable, CLOSURE_CSS_NAME_MAPPING, which is used below. This is\n * to ensure that the mapping is loaded before any calls to goog.getCssName()\n * are made in uncompiled mode.\n *\n * A hook for overriding the CSS name mapping.\n * @type {!Object<string, string>|undefined}\n */\ngoog.global.CLOSURE_CSS_NAME_MAPPING;\n\n\nif (!COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING) {\n  // This does not call goog.setCssNameMapping() because the JSCompiler\n  // requires that goog.setCssNameMapping() be called with an object literal.\n  goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING;\n}\n\n\n/**\n * Gets a localized message.\n *\n * This function is a compiler primitive. If you give the compiler a localized\n * message bundle, it will replace the string at compile-time with a localized\n * version, and expand goog.getMsg call to a concatenated string.\n *\n * Messages must be initialized in the form:\n * <code>\n * var MSG_NAME = goog.getMsg('Hello {$placeholder}', {'placeholder': 'world'});\n * </code>\n *\n * This function produces a string which should be treated as plain text. Use\n * {@link goog.html.SafeHtmlFormatter} in conjunction with goog.getMsg to\n * produce SafeHtml.\n *\n * @param {string} str Translatable string, places holders in the form {$foo}.\n * @param {Object<string, string>=} opt_values Maps place holder name to value.\n * @return {string} message with placeholders filled.\n */\ngoog.getMsg = function(str, opt_values) {\n  if (opt_values) {\n    str = str.replace(/\\{\\$([^}]+)}/g, function(match, key) {\n      return (opt_values != null && key in opt_values) ? opt_values[key] :\n                                                         match;\n    });\n  }\n  return str;\n};\n\n\n/**\n * Gets a localized message. If the message does not have a translation, gives a\n * fallback message.\n *\n * This is useful when introducing a new message that has not yet been\n * translated into all languages.\n *\n * This function is a compiler primitive. Must be used in the form:\n * <code>var x = goog.getMsgWithFallback(MSG_A, MSG_B);</code>\n * where MSG_A and MSG_B were initialized with goog.getMsg.\n *\n * @param {string} a The preferred message.\n * @param {string} b The fallback message.\n * @return {string} The best translated message.\n */\ngoog.getMsgWithFallback = function(a, b) {\n  return a;\n};\n\n\n/**\n * Exposes an unobfuscated global namespace path for the given object.\n * Note that fields of the exported object *will* be obfuscated, unless they are\n * exported in turn via this function or goog.exportProperty.\n *\n * Also handy for making public items that are defined in anonymous closures.\n *\n * ex. goog.exportSymbol('public.path.Foo', Foo);\n *\n * ex. goog.exportSymbol('public.path.Foo.staticFunction', Foo.staticFunction);\n *     public.path.Foo.staticFunction();\n *\n * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod',\n *                       Foo.prototype.myMethod);\n *     new public.path.Foo().myMethod();\n *\n * @param {string} publicPath Unobfuscated name to export.\n * @param {*} object Object the name should point to.\n * @param {Object=} opt_objectToExportTo The object to add the path to; default\n *     is goog.global.\n */\ngoog.exportSymbol = function(publicPath, object, opt_objectToExportTo) {\n  goog.exportPath_(publicPath, object, opt_objectToExportTo);\n};\n\n\n/**\n * Exports a property unobfuscated into the object's namespace.\n * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction);\n * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod);\n * @param {Object} object Object whose static property is being exported.\n * @param {string} publicName Unobfuscated name to export.\n * @param {*} symbol Object the name should point to.\n */\ngoog.exportProperty = function(object, publicName, symbol) {\n  object[publicName] = symbol;\n};\n\n\n/**\n * Inherit the prototype methods from one constructor into another.\n *\n * Usage:\n * <pre>\n * function ParentClass(a, b) { }\n * ParentClass.prototype.foo = function(a) { };\n *\n * function ChildClass(a, b, c) {\n *   ChildClass.base(this, 'constructor', a, b);\n * }\n * goog.inherits(ChildClass, ParentClass);\n *\n * var child = new ChildClass('a', 'b', 'see');\n * child.foo(); // This works.\n * </pre>\n *\n * @param {!Function} childCtor Child class.\n * @param {!Function} parentCtor Parent class.\n */\ngoog.inherits = function(childCtor, parentCtor) {\n  /** @constructor */\n  function tempCtor() {}\n  tempCtor.prototype = parentCtor.prototype;\n  childCtor.superClass_ = parentCtor.prototype;\n  childCtor.prototype = new tempCtor();\n  /** @override */\n  childCtor.prototype.constructor = childCtor;\n\n  /**\n   * Calls superclass constructor/method.\n   *\n   * This function is only available if you use goog.inherits to\n   * express inheritance relationships between classes.\n   *\n   * NOTE: This is a replacement for goog.base and for superClass_\n   * property defined in childCtor.\n   *\n   * @param {!Object} me Should always be \"this\".\n   * @param {string} methodName The method name to call. Calling\n   *     superclass constructor can be done with the special string\n   *     'constructor'.\n   * @param {...*} var_args The arguments to pass to superclass\n   *     method/constructor.\n   * @return {*} The return value of the superclass method/constructor.\n   */\n  childCtor.base = function(me, methodName, var_args) {\n    // Copying using loop to avoid deop due to passing arguments object to\n    // function. This is faster in many JS engines as of late 2014.\n    var args = new Array(arguments.length - 2);\n    for (var i = 2; i < arguments.length; i++) {\n      args[i - 2] = arguments[i];\n    }\n    return parentCtor.prototype[methodName].apply(me, args);\n  };\n};\n\n\n/**\n * Call up to the superclass.\n *\n * If this is called from a constructor, then this calls the superclass\n * constructor with arguments 1-N.\n *\n * If this is called from a prototype method, then you must pass the name of the\n * method as the second argument to this function. If you do not, you will get a\n * runtime error. This calls the superclass' method with arguments 2-N.\n *\n * This function only works if you use goog.inherits to express inheritance\n * relationships between your classes.\n *\n * This function is a compiler primitive. At compile-time, the compiler will do\n * macro expansion to remove a lot of the extra overhead that this function\n * introduces. The compiler will also enforce a lot of the assumptions that this\n * function makes, and treat it as a compiler error if you break them.\n *\n * @param {!Object} me Should always be \"this\".\n * @param {*=} opt_methodName The method name if calling a super method.\n * @param {...*} var_args The rest of the arguments.\n * @return {*} The return value of the superclass method.\n * @suppress {es5Strict} This method can not be used in strict mode, but\n *     all Closure Library consumers must depend on this file.\n */\ngoog.base = function(me, opt_methodName, var_args) {\n  var caller = arguments.callee.caller;\n\n  if (goog.STRICT_MODE_COMPATIBLE || (goog.DEBUG && !caller)) {\n    throw Error(\n        'arguments.caller not defined.  goog.base() cannot be used ' +\n        'with strict mode code. See ' +\n        'http://www.ecma-international.org/ecma-262/5.1/#sec-C');\n  }\n\n  if (caller.superClass_) {\n    // Copying using loop to avoid deop due to passing arguments object to\n    // function. This is faster in many JS engines as of late 2014.\n    var ctorArgs = new Array(arguments.length - 1);\n    for (var i = 1; i < arguments.length; i++) {\n      ctorArgs[i - 1] = arguments[i];\n    }\n    // This is a constructor. Call the superclass constructor.\n    return caller.superClass_.constructor.apply(me, ctorArgs);\n  }\n\n  // Copying using loop to avoid deop due to passing arguments object to\n  // function. This is faster in many JS engines as of late 2014.\n  var args = new Array(arguments.length - 2);\n  for (var i = 2; i < arguments.length; i++) {\n    args[i - 2] = arguments[i];\n  }\n  var foundCaller = false;\n  for (var ctor = me.constructor; ctor;\n       ctor = ctor.superClass_ && ctor.superClass_.constructor) {\n    if (ctor.prototype[opt_methodName] === caller) {\n      foundCaller = true;\n    } else if (foundCaller) {\n      return ctor.prototype[opt_methodName].apply(me, args);\n    }\n  }\n\n  // If we did not find the caller in the prototype chain, then one of two\n  // things happened:\n  // 1) The caller is an instance method.\n  // 2) This method was not called by the right caller.\n  if (me[opt_methodName] === caller) {\n    return me.constructor.prototype[opt_methodName].apply(me, args);\n  } else {\n    throw Error(\n        'goog.base called from a method of one name ' +\n        'to a method of a different name');\n  }\n};\n\n\n/**\n * Allow for aliasing within scope functions.  This function exists for\n * uncompiled code - in compiled code the calls will be inlined and the aliases\n * applied.  In uncompiled code the function is simply run since the aliases as\n * written are valid JavaScript.\n *\n *\n * @param {function()} fn Function to call.  This function can contain aliases\n *     to namespaces (e.g. \"var dom = goog.dom\") or classes\n *     (e.g. \"var Timer = goog.Timer\").\n */\ngoog.scope = function(fn) {\n  if (goog.isInModuleLoader_()) {\n    throw Error('goog.scope is not supported within a goog.module.');\n  }\n  fn.call(goog.global);\n};\n\n\n/*\n * To support uncompiled, strict mode bundles that use eval to divide source\n * like so:\n *    eval('someSource;//# sourceUrl sourcefile.js');\n * We need to export the globally defined symbols \"goog\" and \"COMPILED\".\n * Exporting \"goog\" breaks the compiler optimizations, so we required that\n * be defined externally.\n * NOTE: We don't use goog.exportSymbol here because we don't want to trigger\n * extern generation when that compiler option is enabled.\n */\nif (!COMPILED) {\n  goog.global['COMPILED'] = COMPILED;\n}\n\n\n//==============================================================================\n// goog.defineClass implementation\n//==============================================================================\n\n\n/**\n * Creates a restricted form of a Closure \"class\":\n *   - from the compiler's perspective, the instance returned from the\n *     constructor is sealed (no new properties may be added).  This enables\n *     better checks.\n *   - the compiler will rewrite this definition to a form that is optimal\n *     for type checking and optimization (initially this will be a more\n *     traditional form).\n *\n * @param {Function} superClass The superclass, Object or null.\n * @param {goog.defineClass.ClassDescriptor} def\n *     An object literal describing\n *     the class.  It may have the following properties:\n *     \"constructor\": the constructor function\n *     \"statics\": an object literal containing methods to add to the constructor\n *        as \"static\" methods or a function that will receive the constructor\n *        function as its only parameter to which static properties can\n *        be added.\n *     all other properties are added to the prototype.\n * @return {!Function} The class constructor.\n */\ngoog.defineClass = function(superClass, def) {\n  // TODO(johnlenz): consider making the superClass an optional parameter.\n  var constructor = def.constructor;\n  var statics = def.statics;\n  // Wrap the constructor prior to setting up the prototype and static methods.\n  if (!constructor || constructor == Object.prototype.constructor) {\n    constructor = function() {\n      throw Error('cannot instantiate an interface (no constructor defined).');\n    };\n  }\n\n  var cls = goog.defineClass.createSealingConstructor_(constructor, superClass);\n  if (superClass) {\n    goog.inherits(cls, superClass);\n  }\n\n  // Remove all the properties that should not be copied to the prototype.\n  delete def.constructor;\n  delete def.statics;\n\n  goog.defineClass.applyProperties_(cls.prototype, def);\n  if (statics != null) {\n    if (statics instanceof Function) {\n      statics(cls);\n    } else {\n      goog.defineClass.applyProperties_(cls, statics);\n    }\n  }\n\n  return cls;\n};\n\n\n/**\n * @typedef {{\n *   constructor: (!Function|undefined),\n *   statics: (Object|undefined|function(Function):void)\n * }}\n * @suppress {missingProvide}\n */\ngoog.defineClass.ClassDescriptor;\n\n\n/**\n * @define {boolean} Whether the instances returned by goog.defineClass should\n *     be sealed when possible.\n *\n * When sealing is disabled the constructor function will not be wrapped by\n * goog.defineClass, making it incompatible with ES6 class methods.\n */\ngoog.define('goog.defineClass.SEAL_CLASS_INSTANCES', goog.DEBUG);\n\n\n/**\n * If goog.defineClass.SEAL_CLASS_INSTANCES is enabled and Object.seal is\n * defined, this function will wrap the constructor in a function that seals the\n * results of the provided constructor function.\n *\n * @param {!Function} ctr The constructor whose results maybe be sealed.\n * @param {Function} superClass The superclass constructor.\n * @return {!Function} The replacement constructor.\n * @private\n */\ngoog.defineClass.createSealingConstructor_ = function(ctr, superClass) {\n  if (!goog.defineClass.SEAL_CLASS_INSTANCES) {\n    // Do now wrap the constructor when sealing is disabled. Angular code\n    // depends on this for injection to work properly.\n    return ctr;\n  }\n\n  // Compute whether the constructor is sealable at definition time, rather\n  // than when the instance is being constructed.\n  var superclassSealable = !goog.defineClass.isUnsealable_(superClass);\n\n  /**\n   * @this {Object}\n   * @return {?}\n   */\n  var wrappedCtr = function() {\n    // Don't seal an instance of a subclass when it calls the constructor of\n    // its super class as there is most likely still setup to do.\n    var instance = ctr.apply(this, arguments) || this;\n    instance[goog.UID_PROPERTY_] = instance[goog.UID_PROPERTY_];\n\n    if (this.constructor === wrappedCtr && superclassSealable &&\n        Object.seal instanceof Function) {\n      Object.seal(instance);\n    }\n    return instance;\n  };\n\n  return wrappedCtr;\n};\n\n\n/**\n * @param {Function} ctr The constructor to test.\n * @returns {boolean} Whether the constructor has been tagged as unsealable\n *     using goog.tagUnsealableClass.\n * @private\n */\ngoog.defineClass.isUnsealable_ = function(ctr) {\n  return ctr && ctr.prototype &&\n      ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_];\n};\n\n\n// TODO(johnlenz): share these values with the goog.object\n/**\n * The names of the fields that are defined on Object.prototype.\n * @type {!Array<string>}\n * @private\n * @const\n */\ngoog.defineClass.OBJECT_PROTOTYPE_FIELDS_ = [\n  'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',\n  'toLocaleString', 'toString', 'valueOf'\n];\n\n\n// TODO(johnlenz): share this function with the goog.object\n/**\n * @param {!Object} target The object to add properties to.\n * @param {!Object} source The object to copy properties from.\n * @private\n */\ngoog.defineClass.applyProperties_ = function(target, source) {\n  // TODO(johnlenz): update this to support ES5 getters/setters\n\n  var key;\n  for (key in source) {\n    if (Object.prototype.hasOwnProperty.call(source, key)) {\n      target[key] = source[key];\n    }\n  }\n\n  // For IE the for-in-loop does not contain any properties that are not\n  // enumerable on the prototype object (for example isPrototypeOf from\n  // Object.prototype) and it will also not include 'replace' on objects that\n  // extend String and change 'replace' (not that it is common for anyone to\n  // extend anything except Object).\n  for (var i = 0; i < goog.defineClass.OBJECT_PROTOTYPE_FIELDS_.length; i++) {\n    key = goog.defineClass.OBJECT_PROTOTYPE_FIELDS_[i];\n    if (Object.prototype.hasOwnProperty.call(source, key)) {\n      target[key] = source[key];\n    }\n  }\n};\n\n\n/**\n * Sealing classes breaks the older idiom of assigning properties on the\n * prototype rather than in the constructor. As such, goog.defineClass\n * must not seal subclasses of these old-style classes until they are fixed.\n * Until then, this marks a class as \"broken\", instructing defineClass\n * not to seal subclasses.\n * @param {!Function} ctr The legacy constructor to tag as unsealable.\n */\ngoog.tagUnsealableClass = function(ctr) {\n  if (!COMPILED && goog.defineClass.SEAL_CLASS_INSTANCES) {\n    ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_] = true;\n  }\n};\n\n\n/**\n * Name for unsealable tag property.\n * @const @private {string}\n */\ngoog.UNSEALABLE_CONSTRUCTOR_PROPERTY_ = 'goog_defineClass_legacy_unsealable';\n\ngoog.provide('ol');\n\n\n/**\n * Constants defined with the define tag cannot be changed in application\n * code, but can be set at compile time.\n * Some reduce the size of the build in advanced compile mode.\n */\n\n\n/**\n * @define {boolean} Enable debug mode. Default is `true`.\n */\nol.DEBUG = true;\n\n\n/**\n * @define {boolean} Assume touch.  Default is `false`.\n */\nol.ASSUME_TOUCH = false;\n\n\n/**\n * TODO: rename this to something having to do with tile grids\n * see https://github.com/openlayers/ol3/issues/2076\n * @define {number} Default maximum zoom for default tile grids.\n */\nol.DEFAULT_MAX_ZOOM = 42;\n\n\n/**\n * @define {number} Default min zoom level for the map view.  Default is `0`.\n */\nol.DEFAULT_MIN_ZOOM = 0;\n\n\n/**\n * @define {number} Default maximum allowed threshold  (in pixels) for\n *     reprojection triangulation. Default is `0.5`.\n */\nol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD = 0.5;\n\n\n/**\n * @define {number} Default tile size.\n */\nol.DEFAULT_TILE_SIZE = 256;\n\n\n/**\n * @define {string} Default WMS version.\n */\nol.DEFAULT_WMS_VERSION = '1.3.0';\n\n\n/**\n * @define {number} Hysteresis pixels.\n */\nol.DRAG_BOX_HYSTERESIS_PIXELS = 8;\n\n\n/**\n * @define {boolean} Enable the Canvas renderer.  Default is `true`. Setting\n *     this to false at compile time in advanced mode removes all code\n *     supporting the Canvas renderer from the build.\n */\nol.ENABLE_CANVAS = true;\n\n\n/**\n * @define {boolean} Enable rendering of ol.layer.Image based layers.  Default\n *     is `true`. Setting this to false at compile time in advanced mode removes\n *     all code supporting Image layers from the build.\n */\nol.ENABLE_IMAGE = true;\n\n\n/**\n * @define {boolean} Enable integration with the Proj4js library.  Default is\n *     `true`.\n */\nol.ENABLE_PROJ4JS = true;\n\n\n/**\n * @define {boolean} Enable automatic reprojection of raster sources. Default is\n *     `true`.\n */\nol.ENABLE_RASTER_REPROJECTION = true;\n\n\n/**\n * @define {boolean} Enable rendering of ol.layer.Tile based layers.  Default is\n *     `true`. Setting this to false at compile time in advanced mode removes\n *     all code supporting Tile layers from the build.\n */\nol.ENABLE_TILE = true;\n\n\n/**\n * @define {boolean} Enable rendering of ol.layer.Vector based layers.  Default\n *     is `true`. Setting this to false at compile time in advanced mode removes\n *     all code supporting Vector layers from the build.\n */\nol.ENABLE_VECTOR = true;\n\n\n/**\n * @define {boolean} Enable rendering of ol.layer.VectorTile based layers.\n *     Default is `true`. Setting this to false at compile time in advanced mode\n *     removes all code supporting VectorTile layers from the build.\n */\nol.ENABLE_VECTOR_TILE = true;\n\n\n/**\n * @define {boolean} Enable the WebGL renderer.  Default is `true`. Setting\n *     this to false at compile time in advanced mode removes all code\n *     supporting the WebGL renderer from the build.\n */\nol.ENABLE_WEBGL = true;\n\n\n/**\n * @define {number} The size in pixels of the first atlas image. Default is\n * `256`.\n */\nol.INITIAL_ATLAS_SIZE = 256;\n\n\n/**\n * @define {number} The maximum size in pixels of atlas images. Default is\n * `-1`, meaning it is not used (and `ol.WEBGL_MAX_TEXTURE_SIZE` is\n * used instead).\n */\nol.MAX_ATLAS_SIZE = -1;\n\n\n/**\n * @define {number} Maximum mouse wheel delta.\n */\nol.MOUSEWHEELZOOM_MAXDELTA = 1;\n\n\n/**\n * @define {number} Maximum width and/or height extent ratio that determines\n * when the overview map should be zoomed out.\n */\nol.OVERVIEWMAP_MAX_RATIO = 0.75;\n\n\n/**\n * @define {number} Minimum width and/or height extent ratio that determines\n * when the overview map should be zoomed in.\n */\nol.OVERVIEWMAP_MIN_RATIO = 0.1;\n\n\n/**\n * @define {number} Maximum number of source tiles for raster reprojection of\n *     a single tile.\n *     If too many source tiles are determined to be loaded to create a single\n *     reprojected tile the browser can become unresponsive or even crash.\n *     This can happen if the developer defines projections improperly and/or\n *     with unlimited extents.\n *     If too many tiles are required, no tiles are loaded and\n *     `ol.Tile.State.ERROR` state is set. Default is `100`.\n */\nol.RASTER_REPROJECTION_MAX_SOURCE_TILES = 100;\n\n\n/**\n * @define {number} Maximum number of subdivision steps during raster\n *     reprojection triangulation. Prevents high memory usage and large\n *     number of proj4 calls (for certain transformations and areas).\n *     At most `2*(2^this)` triangles are created for each triangulated\n *     extent (tile/image). Default is `10`.\n */\nol.RASTER_REPROJECTION_MAX_SUBDIVISION = 10;\n\n\n/**\n * @define {number} Maximum allowed size of triangle relative to world width.\n *     When transforming corners of world extent between certain projections,\n *     the resulting triangulation seems to have zero error and no subdivision\n *     is performed.\n *     If the triangle width is more than this (relative to world width; 0-1),\n *     subdivison is forced (up to `ol.RASTER_REPROJECTION_MAX_SUBDIVISION`).\n *     Default is `0.25`.\n */\nol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH = 0.25;\n\n\n/**\n * @define {number} Tolerance for geometry simplification in device pixels.\n */\nol.SIMPLIFY_TOLERANCE = 0.5;\n\n\n/**\n * @define {number} Texture cache high water mark.\n */\nol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024;\n\n\n/**\n * @define {string} OpenLayers version.\n */\nol.VERSION = '';\n\n\n/**\n * The maximum supported WebGL texture size in pixels. If WebGL is not\n * supported, the value is set to `undefined`.\n * @const\n * @type {number|undefined}\n */\nol.WEBGL_MAX_TEXTURE_SIZE; // value is set in `ol.has`\n\n\n/**\n * List of supported WebGL extensions.\n * @const\n * @type {Array.<string>}\n */\nol.WEBGL_EXTENSIONS; // value is set in `ol.has`\n\n\n/**\n * Inherit the prototype methods from one constructor into another.\n *\n * Usage:\n *\n *     function ParentClass(a, b) { }\n *     ParentClass.prototype.foo = function(a) { }\n *\n *     function ChildClass(a, b, c) {\n *       // Call parent constructor\n *       ParentClass.call(this, a, b);\n *     }\n *     ol.inherits(ChildClass, ParentClass);\n *\n *     var child = new ChildClass('a', 'b', 'see');\n *     child.foo(); // This works.\n *\n * @param {!Function} childCtor Child constructor.\n * @param {!Function} parentCtor Parent constructor.\n * @function\n * @api\n */\nol.inherits = function(childCtor, parentCtor) {\n  childCtor.prototype = Object.create(parentCtor.prototype);\n  childCtor.prototype.constructor = childCtor;\n};\n\n\n/**\n * A reusable function, used e.g. as a default for callbacks.\n *\n * @return {undefined} Nothing.\n */\nol.nullFunction = function() {};\n\n\n/**\n * Gets a unique ID for an object. This mutates the object so that further calls\n * with the same object as a parameter returns the same value. Unique IDs are generated\n * as a strictly increasing sequence. Adapted from goog.getUid.\n *\n * @param {Object} obj The object to get the unique ID for.\n * @return {number} The unique ID for the object.\n */\nol.getUid = function(obj) {\n  return obj.ol_uid ||\n      (obj.ol_uid = ++ol.uidCounter_);\n};\n\n\n/**\n * Counter for getUid.\n * @type {number}\n * @private\n */\nol.uidCounter_ = 0;\n\ngoog.provide('ol.AssertionError');\n\ngoog.require('ol');\n\n/**\n * Error object thrown when an assertion failed. This is an ECMA-262 Error,\n * extended with a `code` property.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error}\n * @constructor\n * @extends {Error}\n * @implements {oli.AssertionError}\n * @param {number} code Error code.\n */\nol.AssertionError = function(code) {\n\n  /**\n   * @type {string}\n   */\n  this.message = 'Assertion failed. See ' +\n      (ol.VERSION ? 'https://openlayers.org/en/' + ol.VERSION.split('-')[0] : '') +\n      '/doc/errors/#' + code + ' for details.';\n\n  /**\n   * Error code. The meaning of the code can be found on\n   * {@link https://openlayers.org/en/latest/doc/errors/} (replace `latest` with\n   * the version found in the OpenLayers script's header comment if a version\n   * other than the latest is used).\n   * @type {number}\n   * @api\n   */\n  this.code = code;\n\n  this.name = 'AssertionError';\n\n};\nol.inherits(ol.AssertionError, Error);\n\ngoog.provide('ol.asserts');\n\ngoog.require('ol.AssertionError');\n\n\n/**\n * @param {*} assertion Assertion we expected to be truthy.\n * @param {number} errorCode Error code.\n */\nol.asserts.assert = function(assertion, errorCode) {\n  if (!assertion) {\n    throw new ol.AssertionError(errorCode);\n  }\n};\n\ngoog.provide('ol.math');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\n\n\n/**\n * Takes a number and clamps it to within the provided bounds.\n * @param {number} value The input number.\n * @param {number} min The minimum value to return.\n * @param {number} max The maximum value to return.\n * @return {number} The input number if it is within bounds, or the nearest\n *     number within the bounds.\n */\nol.math.clamp = function(value, min, max) {\n  return Math.min(Math.max(value, min), max);\n};\n\n\n/**\n * Return the hyperbolic cosine of a given number. The method will use the\n * native `Math.cosh` function if it is available, otherwise the hyperbolic\n * cosine will be calculated via the reference implementation of the Mozilla\n * developer network.\n *\n * @param {number} x X.\n * @return {number} Hyperbolic cosine of x.\n */\nol.math.cosh = (function() {\n  // Wrapped in a iife, to save the overhead of checking for the native\n  // implementation on every invocation.\n  var cosh;\n  if ('cosh' in Math) {\n    // The environment supports the native Math.cosh function, use it…\n    cosh = Math.cosh;\n  } else {\n    // … else, use the reference implementation of MDN:\n    cosh = function(x) {\n      var y = Math.exp(x);\n      return (y + 1 / y) / 2;\n    };\n  }\n  return cosh;\n}());\n\n\n/**\n * @param {number} x X.\n * @return {number} The smallest power of two greater than or equal to x.\n */\nol.math.roundUpToPowerOfTwo = function(x) {\n  ol.asserts.assert(0 < x, 29); // `x` must be greater than `0`\n  return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));\n};\n\n\n/**\n * Returns the square of the closest distance between the point (x, y) and the\n * line segment (x1, y1) to (x2, y2).\n * @param {number} x X.\n * @param {number} y Y.\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nol.math.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) {\n  var dx = x2 - x1;\n  var dy = y2 - y1;\n  if (dx !== 0 || dy !== 0) {\n    var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n    if (t > 1) {\n      x1 = x2;\n      y1 = y2;\n    } else if (t > 0) {\n      x1 += dx * t;\n      y1 += dy * t;\n    }\n  }\n  return ol.math.squaredDistance(x, y, x1, y1);\n};\n\n\n/**\n * Returns the square of the distance between the points (x1, y1) and (x2, y2).\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nol.math.squaredDistance = function(x1, y1, x2, y2) {\n  var dx = x2 - x1;\n  var dy = y2 - y1;\n  return dx * dx + dy * dy;\n};\n\n\n/**\n * Solves system of linear equations using Gaussian elimination method.\n *\n * @param {Array.<Array.<number>>} mat Augmented matrix (n x n + 1 column)\n *                                     in row-major order.\n * @return {Array.<number>} The resulting vector.\n */\nol.math.solveLinearSystem = function(mat) {\n  var n = mat.length;\n\n  if (ol.DEBUG) {\n    for (var row = 0; row < n; row++) {\n      console.assert(mat[row].length == n + 1,\n                          'every row should have correct number of columns');\n    }\n  }\n\n  for (var i = 0; i < n; i++) {\n    // Find max in the i-th column (ignoring i - 1 first rows)\n    var maxRow = i;\n    var maxEl = Math.abs(mat[i][i]);\n    for (var r = i + 1; r < n; r++) {\n      var absValue = Math.abs(mat[r][i]);\n      if (absValue > maxEl) {\n        maxEl = absValue;\n        maxRow = r;\n      }\n    }\n\n    if (maxEl === 0) {\n      return null; // matrix is singular\n    }\n\n    // Swap max row with i-th (current) row\n    var tmp = mat[maxRow];\n    mat[maxRow] = mat[i];\n    mat[i] = tmp;\n\n    // Subtract the i-th row to make all the remaining rows 0 in the i-th column\n    for (var j = i + 1; j < n; j++) {\n      var coef = -mat[j][i] / mat[i][i];\n      for (var k = i; k < n + 1; k++) {\n        if (i == k) {\n          mat[j][k] = 0;\n        } else {\n          mat[j][k] += coef * mat[i][k];\n        }\n      }\n    }\n  }\n\n  // Solve Ax=b for upper triangular matrix A (mat)\n  var x = new Array(n);\n  for (var l = n - 1; l >= 0; l--) {\n    x[l] = mat[l][n] / mat[l][l];\n    for (var m = l - 1; m >= 0; m--) {\n      mat[m][n] -= mat[m][l] * x[l];\n    }\n  }\n  return x;\n};\n\n\n/**\n * Converts radians to to degrees.\n *\n * @param {number} angleInRadians Angle in radians.\n * @return {number} Angle in degrees.\n */\nol.math.toDegrees = function(angleInRadians) {\n  return angleInRadians * 180 / Math.PI;\n};\n\n\n/**\n * Converts degrees to radians.\n *\n * @param {number} angleInDegrees Angle in degrees.\n * @return {number} Angle in radians.\n */\nol.math.toRadians = function(angleInDegrees) {\n  return angleInDegrees * Math.PI / 180;\n};\n\n/**\n * Returns the modulo of a / b, depending on the sign of b.\n *\n * @param {number} a Dividend.\n * @param {number} b Divisor.\n * @return {number} Modulo.\n */\nol.math.modulo = function(a, b) {\n  var r = a % b;\n  return r * b < 0 ? r + b : r;\n};\n\n/**\n * Calculates the linearly interpolated value of x between a and b.\n *\n * @param {number} a Number\n * @param {number} b Number\n * @param {number} x Value to be interpolated.\n * @return {number} Interpolated value.\n */\nol.math.lerp = function(a, b, x) {\n  return a + x * (b - a);\n};\n\ngoog.provide('ol.CenterConstraint');\n\ngoog.require('ol.math');\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @return {ol.CenterConstraintType} The constraint.\n */\nol.CenterConstraint.createExtent = function(extent) {\n  return (\n      /**\n       * @param {ol.Coordinate|undefined} center Center.\n       * @return {ol.Coordinate|undefined} Center.\n       */\n      function(center) {\n        if (center) {\n          return [\n            ol.math.clamp(center[0], extent[0], extent[2]),\n            ol.math.clamp(center[1], extent[1], extent[3])\n          ];\n        } else {\n          return undefined;\n        }\n      });\n};\n\n\n/**\n * @param {ol.Coordinate|undefined} center Center.\n * @return {ol.Coordinate|undefined} Center.\n */\nol.CenterConstraint.none = function(center) {\n  return center;\n};\n\ngoog.provide('ol.Constraints');\n\n\n/**\n * @constructor\n * @param {ol.CenterConstraintType} centerConstraint Center constraint.\n * @param {ol.ResolutionConstraintType} resolutionConstraint\n *     Resolution constraint.\n * @param {ol.RotationConstraintType} rotationConstraint\n *     Rotation constraint.\n */\nol.Constraints = function(centerConstraint, resolutionConstraint, rotationConstraint) {\n\n  /**\n   * @type {ol.CenterConstraintType}\n   */\n  this.center = centerConstraint;\n\n  /**\n   * @type {ol.ResolutionConstraintType}\n   */\n  this.resolution = resolutionConstraint;\n\n  /**\n   * @type {ol.RotationConstraintType}\n   */\n  this.rotation = rotationConstraint;\n\n};\n\ngoog.provide('ol.obj');\n\n\n/**\n * Polyfill for Object.assign().  Assigns enumerable and own properties from\n * one or more source objects to a target object.\n *\n * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n * @param {!Object} target The target object.\n * @param {...Object} var_sources The source object(s).\n * @return {!Object} The modified target object.\n */\nol.obj.assign = (typeof Object.assign === 'function') ? Object.assign : function(target, var_sources) {\n  if (target === undefined || target === null) {\n    throw new TypeError('Cannot convert undefined or null to object');\n  }\n\n  var output = Object(target);\n  for (var i = 1, ii = arguments.length; i < ii; ++i) {\n    var source = arguments[i];\n    if (source !== undefined && source !== null) {\n      for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n          output[key] = source[key];\n        }\n      }\n    }\n  }\n  return output;\n};\n\n\n/**\n * Removes all properties from an object.\n * @param {Object} object The object to clear.\n */\nol.obj.clear = function(object) {\n  for (var property in object) {\n    delete object[property];\n  }\n};\n\n\n/**\n * Get an array of property values from an object.\n * @param {Object<K,V>} object The object from which to get the values.\n * @return {!Array<V>} The property values.\n * @template K,V\n */\nol.obj.getValues = function(object) {\n  var values = [];\n  for (var property in object) {\n    values.push(object[property]);\n  }\n  return values;\n};\n\n\n/**\n * Determine if an object has any properties.\n * @param {Object} object The object to check.\n * @return {boolean} The object is empty.\n */\nol.obj.isEmpty = function(object) {\n  var property;\n  for (property in object) {\n    return false;\n  }\n  return !property;\n};\n\ngoog.provide('ol.events');\n\ngoog.require('ol.obj');\n\n\n/**\n * @param {ol.EventsKey} listenerObj Listener object.\n * @return {ol.EventsListenerFunctionType} Bound listener.\n */\nol.events.bindListener_ = function(listenerObj) {\n  var boundListener = function(evt) {\n    var listener = listenerObj.listener;\n    var bindTo = listenerObj.bindTo || listenerObj.target;\n    if (listenerObj.callOnce) {\n      ol.events.unlistenByKey(listenerObj);\n    }\n    return listener.call(bindTo, evt);\n  };\n  listenerObj.boundListener = boundListener;\n  return boundListener;\n};\n\n\n/**\n * Finds the matching {@link ol.EventsKey} in the given listener\n * array.\n *\n * @param {!Array<!ol.EventsKey>} listeners Array of listeners.\n * @param {!Function} listener The listener function.\n * @param {Object=} opt_this The `this` value inside the listener.\n * @param {boolean=} opt_setDeleteIndex Set the deleteIndex on the matching\n *     listener, for {@link ol.events.unlistenByKey}.\n * @return {ol.EventsKey|undefined} The matching listener object.\n * @private\n */\nol.events.findListener_ = function(listeners, listener, opt_this,\n    opt_setDeleteIndex) {\n  var listenerObj;\n  for (var i = 0, ii = listeners.length; i < ii; ++i) {\n    listenerObj = listeners[i];\n    if (listenerObj.listener === listener &&\n        listenerObj.bindTo === opt_this) {\n      if (opt_setDeleteIndex) {\n        listenerObj.deleteIndex = i;\n      }\n      return listenerObj;\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @param {ol.EventTargetLike} target Target.\n * @param {string} type Type.\n * @return {Array.<ol.EventsKey>|undefined} Listeners.\n */\nol.events.getListeners = function(target, type) {\n  var listenerMap = target.ol_lm;\n  return listenerMap ? listenerMap[type] : undefined;\n};\n\n\n/**\n * Get the lookup of listeners.  If one does not exist on the target, it is\n * created.\n * @param {ol.EventTargetLike} target Target.\n * @return {!Object.<string, Array.<ol.EventsKey>>} Map of\n *     listeners by event type.\n * @private\n */\nol.events.getListenerMap_ = function(target) {\n  var listenerMap = target.ol_lm;\n  if (!listenerMap) {\n    listenerMap = target.ol_lm = {};\n  }\n  return listenerMap;\n};\n\n\n/**\n * Clean up all listener objects of the given type.  All properties on the\n * listener objects will be removed, and if no listeners remain in the listener\n * map, it will be removed from the target.\n * @param {ol.EventTargetLike} target Target.\n * @param {string} type Type.\n * @private\n */\nol.events.removeListeners_ = function(target, type) {\n  var listeners = ol.events.getListeners(target, type);\n  if (listeners) {\n    for (var i = 0, ii = listeners.length; i < ii; ++i) {\n      target.removeEventListener(type, listeners[i].boundListener);\n      ol.obj.clear(listeners[i]);\n    }\n    listeners.length = 0;\n    var listenerMap = target.ol_lm;\n    if (listenerMap) {\n      delete listenerMap[type];\n      if (Object.keys(listenerMap).length === 0) {\n        delete target.ol_lm;\n      }\n    }\n  }\n};\n\n\n/**\n * Registers an event listener on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * This function efficiently binds a `listener` to a `this` object, and returns\n * a key for use with {@link ol.events.unlistenByKey}.\n *\n * @param {ol.EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ol.EventsListenerFunctionType} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n *     listener. Default is the `target`.\n * @param {boolean=} opt_once If true, add the listener as one-off listener.\n * @return {ol.EventsKey} Unique key for the listener.\n */\nol.events.listen = function(target, type, listener, opt_this, opt_once) {\n  var listenerMap = ol.events.getListenerMap_(target);\n  var listeners = listenerMap[type];\n  if (!listeners) {\n    listeners = listenerMap[type] = [];\n  }\n  var listenerObj = ol.events.findListener_(listeners, listener, opt_this,\n      false);\n  if (listenerObj) {\n    if (!opt_once) {\n      // Turn one-off listener into a permanent one.\n      listenerObj.callOnce = false;\n    }\n  } else {\n    listenerObj = /** @type {ol.EventsKey} */ ({\n      bindTo: opt_this,\n      callOnce: !!opt_once,\n      listener: listener,\n      target: target,\n      type: type\n    });\n    target.addEventListener(type, ol.events.bindListener_(listenerObj));\n    listeners.push(listenerObj);\n  }\n\n  return listenerObj;\n};\n\n\n/**\n * Registers a one-off event listener on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * This function efficiently binds a `listener` as self-unregistering listener\n * to a `this` object, and returns a key for use with\n * {@link ol.events.unlistenByKey} in case the listener needs to be unregistered\n * before it is called.\n *\n * When {@link ol.events.listen} is called with the same arguments after this\n * function, the self-unregistering listener will be turned into a permanent\n * listener.\n *\n * @param {ol.EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ol.EventsListenerFunctionType} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n *     listener. Default is the `target`.\n * @return {ol.EventsKey} Key for unlistenByKey.\n */\nol.events.listenOnce = function(target, type, listener, opt_this) {\n  return ol.events.listen(target, type, listener, opt_this, true);\n};\n\n\n/**\n * Unregisters an event listener on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * To return a listener, this function needs to be called with the exact same\n * arguments that were used for a previous {@link ol.events.listen} call.\n *\n * @param {ol.EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ol.EventsListenerFunctionType} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n *     listener. Default is the `target`.\n */\nol.events.unlisten = function(target, type, listener, opt_this) {\n  var listeners = ol.events.getListeners(target, type);\n  if (listeners) {\n    var listenerObj = ol.events.findListener_(listeners, listener, opt_this,\n        true);\n    if (listenerObj) {\n      ol.events.unlistenByKey(listenerObj);\n    }\n  }\n};\n\n\n/**\n * Unregisters event listeners on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * The argument passed to this function is the key returned from\n * {@link ol.events.listen} or {@link ol.events.listenOnce}.\n *\n * @param {ol.EventsKey} key The key.\n */\nol.events.unlistenByKey = function(key) {\n  if (key && key.target) {\n    key.target.removeEventListener(key.type, key.boundListener);\n    var listeners = ol.events.getListeners(key.target, key.type);\n    if (listeners) {\n      var i = 'deleteIndex' in key ? key.deleteIndex : listeners.indexOf(key);\n      if (i !== -1) {\n        listeners.splice(i, 1);\n      }\n      if (listeners.length === 0) {\n        ol.events.removeListeners_(key.target, key.type);\n      }\n    }\n    ol.obj.clear(key);\n  }\n};\n\n\n/**\n * Unregisters all event listeners on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * @param {ol.EventTargetLike} target Target.\n */\nol.events.unlistenAll = function(target) {\n  var listenerMap = ol.events.getListenerMap_(target);\n  for (var type in listenerMap) {\n    ol.events.removeListeners_(target, type);\n  }\n};\n\ngoog.provide('ol.Disposable');\n\ngoog.require('ol');\n\n/**\n * Objects that need to clean up after themselves.\n * @constructor\n */\nol.Disposable = function() {};\n\n/**\n * The object has already been disposed.\n * @type {boolean}\n * @private\n */\nol.Disposable.prototype.disposed_ = false;\n\n/**\n * Clean up.\n */\nol.Disposable.prototype.dispose = function() {\n  if (!this.disposed_) {\n    this.disposed_ = true;\n    this.disposeInternal();\n  }\n};\n\n/**\n * Extension point for disposable objects.\n * @protected\n */\nol.Disposable.prototype.disposeInternal = ol.nullFunction;\n\ngoog.provide('ol.events.Event');\n\n\n/**\n * @classdesc\n * Stripped down implementation of the W3C DOM Level 2 Event interface.\n * @see {@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface}\n *\n * This implementation only provides `type` and `target` properties, and\n * `stopPropagation` and `preventDefault` methods. It is meant as base class\n * for higher level events defined in the library, and works with\n * {@link ol.events.EventTarget}.\n *\n * @constructor\n * @implements {oli.events.Event}\n * @param {string} type Type.\n */\nol.events.Event = function(type) {\n\n  /**\n   * @type {boolean}\n   */\n  this.propagationStopped;\n\n  /**\n   * The event type.\n   * @type {string}\n   * @api stable\n   */\n  this.type = type;\n\n  /**\n   * The event target.\n   * @type {Object}\n   * @api stable\n   */\n  this.target = null;\n\n};\n\n\n/**\n * Stop event propagation.\n * @function\n * @api stable\n */\nol.events.Event.prototype.preventDefault =\n\n/**\n * Stop event propagation.\n * @function\n * @api stable\n */\nol.events.Event.prototype.stopPropagation = function() {\n  this.propagationStopped = true;\n};\n\n\n/**\n * @param {Event|ol.events.Event} evt Event\n */\nol.events.Event.stopPropagation = function(evt) {\n  evt.stopPropagation();\n};\n\n\n/**\n * @param {Event|ol.events.Event} evt Event\n */\nol.events.Event.preventDefault = function(evt) {\n  evt.preventDefault();\n};\n\ngoog.provide('ol.events.EventTarget');\n\ngoog.require('ol');\ngoog.require('ol.Disposable');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\n\n\n/**\n * @classdesc\n * A simplified implementation of the W3C DOM Level 2 EventTarget interface.\n * @see {@link https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget}\n *\n * There are two important simplifications compared to the specification:\n *\n * 1. The handling of `useCapture` in `addEventListener` and\n *    `removeEventListener`. There is no real capture model.\n * 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`.\n *    There is no event target hierarchy. When a listener calls\n *    `stopPropagation` or `preventDefault` on an event object, it means that no\n *    more listeners after this one will be called. Same as when the listener\n *    returns false.\n *\n * @constructor\n * @extends {ol.Disposable}\n */\nol.events.EventTarget = function() {\n\n  ol.Disposable.call(this);\n\n  /**\n   * @private\n   * @type {!Object.<string, number>}\n   */\n  this.pendingRemovals_ = {};\n\n  /**\n   * @private\n   * @type {!Object.<string, number>}\n   */\n  this.dispatching_ = {};\n\n  /**\n   * @private\n   * @type {!Object.<string, Array.<ol.EventsListenerFunctionType>>}\n   */\n  this.listeners_ = {};\n\n};\nol.inherits(ol.events.EventTarget, ol.Disposable);\n\n\n/**\n * @param {string} type Type.\n * @param {ol.EventsListenerFunctionType} listener Listener.\n */\nol.events.EventTarget.prototype.addEventListener = function(type, listener) {\n  var listeners = this.listeners_[type];\n  if (!listeners) {\n    listeners = this.listeners_[type] = [];\n  }\n  if (listeners.indexOf(listener) === -1) {\n    listeners.push(listener);\n  }\n};\n\n\n/**\n * @param {{type: string,\n *     target: (EventTarget|ol.events.EventTarget|undefined)}|ol.events.Event|\n *     string} event Event or event type.\n * @return {boolean|undefined} `false` if anyone called preventDefault on the\n *     event object or if any of the listeners returned false.\n */\nol.events.EventTarget.prototype.dispatchEvent = function(event) {\n  var evt = typeof event === 'string' ? new ol.events.Event(event) : event;\n  var type = evt.type;\n  evt.target = this;\n  var listeners = this.listeners_[type];\n  var propagate;\n  if (listeners) {\n    if (!(type in this.dispatching_)) {\n      this.dispatching_[type] = 0;\n      this.pendingRemovals_[type] = 0;\n    }\n    ++this.dispatching_[type];\n    for (var i = 0, ii = listeners.length; i < ii; ++i) {\n      if (listeners[i].call(this, evt) === false || evt.propagationStopped) {\n        propagate = false;\n        break;\n      }\n    }\n    --this.dispatching_[type];\n    if (this.dispatching_[type] === 0) {\n      var pendingRemovals = this.pendingRemovals_[type];\n      delete this.pendingRemovals_[type];\n      while (pendingRemovals--) {\n        this.removeEventListener(type, ol.nullFunction);\n      }\n      delete this.dispatching_[type];\n    }\n    return propagate;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.events.EventTarget.prototype.disposeInternal = function() {\n  ol.events.unlistenAll(this);\n};\n\n\n/**\n * Get the listeners for a specified event type. Listeners are returned in the\n * order that they will be called in.\n *\n * @param {string} type Type.\n * @return {Array.<ol.EventsListenerFunctionType>} Listeners.\n */\nol.events.EventTarget.prototype.getListeners = function(type) {\n  return this.listeners_[type];\n};\n\n\n/**\n * @param {string=} opt_type Type. If not provided,\n *     `true` will be returned if this EventTarget has any listeners.\n * @return {boolean} Has listeners.\n */\nol.events.EventTarget.prototype.hasListener = function(opt_type) {\n  return opt_type ?\n      opt_type in this.listeners_ :\n      Object.keys(this.listeners_).length > 0;\n};\n\n\n/**\n * @param {string} type Type.\n * @param {ol.EventsListenerFunctionType} listener Listener.\n */\nol.events.EventTarget.prototype.removeEventListener = function(type, listener) {\n  var listeners = this.listeners_[type];\n  if (listeners) {\n    var index = listeners.indexOf(listener);\n    ol.DEBUG && console.assert(index != -1, 'listener not found');\n    if (type in this.pendingRemovals_) {\n      // make listener a no-op, and remove later in #dispatchEvent()\n      listeners[index] = ol.nullFunction;\n      ++this.pendingRemovals_[type];\n    } else {\n      listeners.splice(index, 1);\n      if (listeners.length === 0) {\n        delete this.listeners_[type];\n      }\n    }\n  }\n};\n\ngoog.provide('ol.events.EventType');\n\n/**\n * @enum {string}\n * @const\n */\nol.events.EventType = {\n  /**\n   * Generic change event. Triggered when the revision counter is increased.\n   * @event ol.events.Event#change\n   * @api\n   */\n  CHANGE: 'change',\n\n  CLICK: 'click',\n  DBLCLICK: 'dblclick',\n  DRAGENTER: 'dragenter',\n  DRAGOVER: 'dragover',\n  DROP: 'drop',\n  ERROR: 'error',\n  KEYDOWN: 'keydown',\n  KEYPRESS: 'keypress',\n  LOAD: 'load',\n  MOUSEDOWN: 'mousedown',\n  MOUSEMOVE: 'mousemove',\n  MOUSEOUT: 'mouseout',\n  MOUSEUP: 'mouseup',\n  MOUSEWHEEL: 'mousewheel',\n  MSPOINTERDOWN: 'mspointerdown',\n  RESIZE: 'resize',\n  TOUCHSTART: 'touchstart',\n  TOUCHMOVE: 'touchmove',\n  TOUCHEND: 'touchend',\n  WHEEL: 'wheel'\n};\n\ngoog.provide('ol.Observable');\n\ngoog.require('ol');\ngoog.require('ol.events');\ngoog.require('ol.events.EventTarget');\ngoog.require('ol.events.EventType');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * An event target providing convenient methods for listener registration\n * and unregistration. A generic `change` event is always available through\n * {@link ol.Observable#changed}.\n *\n * @constructor\n * @extends {ol.events.EventTarget}\n * @fires ol.events.Event\n * @struct\n * @api stable\n */\nol.Observable = function() {\n\n  ol.events.EventTarget.call(this);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.revision_ = 0;\n\n};\nol.inherits(ol.Observable, ol.events.EventTarget);\n\n\n/**\n * Removes an event listener using the key returned by `on()` or `once()`.\n * @param {ol.EventsKey|Array.<ol.EventsKey>} key The key returned by `on()`\n *     or `once()` (or an array of keys).\n * @api stable\n */\nol.Observable.unByKey = function(key) {\n  if (Array.isArray(key)) {\n    for (var i = 0, ii = key.length; i < ii; ++i) {\n      ol.events.unlistenByKey(key[i]);\n    }\n  } else {\n    ol.events.unlistenByKey(/** @type {ol.EventsKey} */ (key));\n  }\n};\n\n\n/**\n * Increases the revision counter and dispatches a 'change' event.\n * @api\n */\nol.Observable.prototype.changed = function() {\n  ++this.revision_;\n  this.dispatchEvent(ol.events.EventType.CHANGE);\n};\n\n\n/**\n * Dispatches an event and calls all listeners listening for events\n * of this type. The event parameter can either be a string or an\n * Object with a `type` property.\n *\n * @param {{type: string,\n *     target: (EventTarget|ol.events.EventTarget|undefined)}|ol.events.Event|\n *     string} event Event object.\n * @function\n * @api\n */\nol.Observable.prototype.dispatchEvent;\n\n\n/**\n * Get the version number for this object.  Each time the object is modified,\n * its version number will be incremented.\n * @return {number} Revision.\n * @api\n */\nol.Observable.prototype.getRevision = function() {\n  return this.revision_;\n};\n\n\n/**\n * Listen for a certain type of event.\n * @param {string|Array.<string>} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @param {Object=} opt_this The object to use as `this` in `listener`.\n * @return {ol.EventsKey|Array.<ol.EventsKey>} Unique key for the listener. If\n *     called with an array of event types as the first argument, the return\n *     will be an array of keys.\n * @api stable\n */\nol.Observable.prototype.on = function(type, listener, opt_this) {\n  if (Array.isArray(type)) {\n    var len = type.length;\n    var keys = new Array(len);\n    for (var i = 0; i < len; ++i) {\n      keys[i] = ol.events.listen(this, type[i], listener, opt_this);\n    }\n    return keys;\n  } else {\n    return ol.events.listen(\n        this, /** @type {string} */ (type), listener, opt_this);\n  }\n};\n\n\n/**\n * Listen once for a certain type of event.\n * @param {string|Array.<string>} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @param {Object=} opt_this The object to use as `this` in `listener`.\n * @return {ol.EventsKey|Array.<ol.EventsKey>} Unique key for the listener. If\n *     called with an array of event types as the first argument, the return\n *     will be an array of keys.\n * @api stable\n */\nol.Observable.prototype.once = function(type, listener, opt_this) {\n  if (Array.isArray(type)) {\n    var len = type.length;\n    var keys = new Array(len);\n    for (var i = 0; i < len; ++i) {\n      keys[i] = ol.events.listenOnce(this, type[i], listener, opt_this);\n    }\n    return keys;\n  } else {\n    return ol.events.listenOnce(\n        this, /** @type {string} */ (type), listener, opt_this);\n  }\n};\n\n\n/**\n * Unlisten for a certain type of event.\n * @param {string|Array.<string>} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @param {Object=} opt_this The object which was used as `this` by the\n * `listener`.\n * @api stable\n */\nol.Observable.prototype.un = function(type, listener, opt_this) {\n  if (Array.isArray(type)) {\n    for (var i = 0, ii = type.length; i < ii; ++i) {\n      ol.events.unlisten(this, type[i], listener, opt_this);\n    }\n    return;\n  } else {\n    ol.events.unlisten(this, /** @type {string} */ (type), listener, opt_this);\n  }\n};\n\n\n/**\n * Removes an event listener using the key returned by `on()` or `once()`.\n * Note that using the {@link ol.Observable.unByKey} static function is to\n * be preferred.\n * @param {ol.EventsKey|Array.<ol.EventsKey>} key The key returned by `on()`\n *     or `once()` (or an array of keys).\n * @function\n * @api stable\n */\nol.Observable.prototype.unByKey = ol.Observable.unByKey;\n\ngoog.provide('ol.Object');\n\ngoog.require('ol');\ngoog.require('ol.Observable');\ngoog.require('ol.events.Event');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Most non-trivial classes inherit from this.\n *\n * This extends {@link ol.Observable} with observable properties, where each\n * property is observable as well as the object as a whole.\n *\n * Classes that inherit from this have pre-defined properties, to which you can\n * add your owns. The pre-defined properties are listed in this documentation as\n * 'Observable Properties', and have their own accessors; for example,\n * {@link ol.Map} has a `target` property, accessed with `getTarget()`  and\n * changed with `setTarget()`. Not all properties are however settable. There\n * are also general-purpose accessors `get()` and `set()`. For example,\n * `get('target')` is equivalent to `getTarget()`.\n *\n * The `set` accessors trigger a change event, and you can monitor this by\n * registering a listener. For example, {@link ol.View} has a `center`\n * property, so `view.on('change:center', function(evt) {...});` would call the\n * function whenever the value of the center property changes. Within the\n * function, `evt.target` would be the view, so `evt.target.getCenter()` would\n * return the new center.\n *\n * You can add your own observable properties with\n * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`.\n * You can listen for changes on that property value with\n * `object.on('change:prop', listener)`. You can get a list of all\n * properties with {@link ol.Object#getProperties object.getProperties()}.\n *\n * Note that the observable properties are separate from standard JS properties.\n * You can, for example, give your map object a title with\n * `map.title='New title'` and with `map.set('title', 'Another title')`. The\n * first will be a `hasOwnProperty`; the second will appear in\n * `getProperties()`. Only the second is observable.\n *\n * Properties can be deleted by using the unset method. E.g.\n * object.unset('foo').\n *\n * @constructor\n * @extends {ol.Observable}\n * @param {Object.<string, *>=} opt_values An object with key-value pairs.\n * @fires ol.Object.Event\n * @api\n */\nol.Object = function(opt_values) {\n  ol.Observable.call(this);\n\n  // Call ol.getUid to ensure that the order of objects' ids is the same as\n  // the order in which they were created.  This also helps to ensure that\n  // object properties are always added in the same order, which helps many\n  // JavaScript engines generate faster code.\n  ol.getUid(this);\n\n  /**\n   * @private\n   * @type {!Object.<string, *>}\n   */\n  this.values_ = {};\n\n  if (opt_values !== undefined) {\n    this.setProperties(opt_values);\n  }\n};\nol.inherits(ol.Object, ol.Observable);\n\n\n/**\n * @private\n * @type {Object.<string, string>}\n */\nol.Object.changeEventTypeCache_ = {};\n\n\n/**\n * @param {string} key Key name.\n * @return {string} Change name.\n */\nol.Object.getChangeEventType = function(key) {\n  return ol.Object.changeEventTypeCache_.hasOwnProperty(key) ?\n      ol.Object.changeEventTypeCache_[key] :\n      (ol.Object.changeEventTypeCache_[key] = 'change:' + key);\n};\n\n\n/**\n * Gets a value.\n * @param {string} key Key name.\n * @return {*} Value.\n * @api stable\n */\nol.Object.prototype.get = function(key) {\n  var value;\n  if (this.values_.hasOwnProperty(key)) {\n    value = this.values_[key];\n  }\n  return value;\n};\n\n\n/**\n * Get a list of object property names.\n * @return {Array.<string>} List of property names.\n * @api stable\n */\nol.Object.prototype.getKeys = function() {\n  return Object.keys(this.values_);\n};\n\n\n/**\n * Get an object of all property names and values.\n * @return {Object.<string, *>} Object.\n * @api stable\n */\nol.Object.prototype.getProperties = function() {\n  return ol.obj.assign({}, this.values_);\n};\n\n\n/**\n * @param {string} key Key name.\n * @param {*} oldValue Old value.\n */\nol.Object.prototype.notify = function(key, oldValue) {\n  var eventType;\n  eventType = ol.Object.getChangeEventType(key);\n  this.dispatchEvent(new ol.Object.Event(eventType, key, oldValue));\n  eventType = ol.Object.EventType.PROPERTYCHANGE;\n  this.dispatchEvent(new ol.Object.Event(eventType, key, oldValue));\n};\n\n\n/**\n * Sets a value.\n * @param {string} key Key name.\n * @param {*} value Value.\n * @param {boolean=} opt_silent Update without triggering an event.\n * @api stable\n */\nol.Object.prototype.set = function(key, value, opt_silent) {\n  if (opt_silent) {\n    this.values_[key] = value;\n  } else {\n    var oldValue = this.values_[key];\n    this.values_[key] = value;\n    if (oldValue !== value) {\n      this.notify(key, oldValue);\n    }\n  }\n};\n\n\n/**\n * Sets a collection of key-value pairs.  Note that this changes any existing\n * properties and adds new ones (it does not remove any existing properties).\n * @param {Object.<string, *>} values Values.\n * @param {boolean=} opt_silent Update without triggering an event.\n * @api stable\n */\nol.Object.prototype.setProperties = function(values, opt_silent) {\n  var key;\n  for (key in values) {\n    this.set(key, values[key], opt_silent);\n  }\n};\n\n\n/**\n * Unsets a property.\n * @param {string} key Key name.\n * @param {boolean=} opt_silent Unset without triggering an event.\n * @api stable\n */\nol.Object.prototype.unset = function(key, opt_silent) {\n  if (key in this.values_) {\n    var oldValue = this.values_[key];\n    delete this.values_[key];\n    if (!opt_silent) {\n      this.notify(key, oldValue);\n    }\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.Object.EventType = {\n  /**\n   * Triggered when a property is changed.\n   * @event ol.Object.Event#propertychange\n   * @api stable\n   */\n  PROPERTYCHANGE: 'propertychange'\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.Object} instances are instances of this type.\n *\n * @param {string} type The event type.\n * @param {string} key The property name.\n * @param {*} oldValue The old value for `key`.\n * @extends {ol.events.Event}\n * @implements {oli.Object.Event}\n * @constructor\n */\nol.Object.Event = function(type, key, oldValue) {\n  ol.events.Event.call(this, type);\n\n  /**\n   * The name of the property whose value is changing.\n   * @type {string}\n   * @api stable\n   */\n  this.key = key;\n\n  /**\n   * The old value. To get the new value use `e.target.get(e.key)` where\n   * `e` is the event object.\n   * @type {*}\n   * @api stable\n   */\n  this.oldValue = oldValue;\n\n};\nol.inherits(ol.Object.Event, ol.events.Event);\n\ngoog.provide('ol.array');\n\ngoog.require('ol');\n\n\n/**\n * 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.\n * https://github.com/darkskyapp/binary-search\n *\n * @param {Array.<*>} haystack Items to search through.\n * @param {*} needle The item to look for.\n * @param {Function=} opt_comparator Comparator function.\n * @return {number} The index of the item if found, -1 if not.\n */\nol.array.binarySearch = function(haystack, needle, opt_comparator) {\n  var mid, cmp;\n  var comparator = opt_comparator || ol.array.numberSafeCompareFunction;\n  var low = 0;\n  var high = haystack.length;\n  var found = false;\n\n  while (low < high) {\n    /* Note that \"(low + high) >>> 1\" may overflow, and results in a typecast\n     * to double (which gives the wrong results). */\n    mid = low + (high - low >> 1);\n    cmp = +comparator(haystack[mid], needle);\n\n    if (cmp < 0.0) { /* Too low. */\n      low  = mid + 1;\n\n    } else { /* Key found or too high */\n      high = mid;\n      found = !cmp;\n    }\n  }\n\n  /* Key not found. */\n  return found ? low : ~low;\n};\n\n\n/**\n * Compare function for array sort that is safe for numbers.\n * @param {*} a The first object to be compared.\n * @param {*} b The second object to be compared.\n * @return {number} A negative number, zero, or a positive number as the first\n *     argument is less than, equal to, or greater than the second.\n */\nol.array.numberSafeCompareFunction = function(a, b) {\n  return a > b ? 1 : a < b ? -1 : 0;\n};\n\n\n/**\n * Whether the array contains the given object.\n * @param {Array.<*>} arr The array to test for the presence of the element.\n * @param {*} obj The object for which to test.\n * @return {boolean} The object is in the array.\n */\nol.array.includes = function(arr, obj) {\n  return arr.indexOf(obj) >= 0;\n};\n\n\n/**\n * @param {Array.<number>} arr Array.\n * @param {number} target Target.\n * @param {number} direction 0 means return the nearest, > 0\n *    means return the largest nearest, < 0 means return the\n *    smallest nearest.\n * @return {number} Index.\n */\nol.array.linearFindNearest = function(arr, target, direction) {\n  var n = arr.length;\n  if (arr[0] <= target) {\n    return 0;\n  } else if (target <= arr[n - 1]) {\n    return n - 1;\n  } else {\n    var i;\n    if (direction > 0) {\n      for (i = 1; i < n; ++i) {\n        if (arr[i] < target) {\n          return i - 1;\n        }\n      }\n    } else if (direction < 0) {\n      for (i = 1; i < n; ++i) {\n        if (arr[i] <= target) {\n          return i;\n        }\n      }\n    } else {\n      for (i = 1; i < n; ++i) {\n        if (arr[i] == target) {\n          return i;\n        } else if (arr[i] < target) {\n          if (arr[i - 1] - target < target - arr[i]) {\n            return i - 1;\n          } else {\n            return i;\n          }\n        }\n      }\n    }\n    return n - 1;\n  }\n};\n\n\n/**\n * @param {Array.<*>} arr Array.\n * @param {number} begin Begin index.\n * @param {number} end End index.\n */\nol.array.reverseSubArray = function(arr, begin, end) {\n  ol.DEBUG && console.assert(begin >= 0,\n      'Array begin index should be equal to or greater than 0');\n  ol.DEBUG && console.assert(end < arr.length,\n      'Array end index should be less than the array length');\n  while (begin < end) {\n    var tmp = arr[begin];\n    arr[begin] = arr[end];\n    arr[end] = tmp;\n    ++begin;\n    --end;\n  }\n};\n\n\n/**\n * @param {Array.<*>} arr Array.\n * @return {!Array.<?>} Flattened Array.\n */\nol.array.flatten = function(arr) {\n  var data = arr.reduce(function(flattened, value) {\n    if (Array.isArray(value)) {\n      return flattened.concat(ol.array.flatten(value));\n    } else {\n      return flattened.concat(value);\n    }\n  }, []);\n  return data;\n};\n\n\n/**\n * @param {Array.<VALUE>} arr The array to modify.\n * @param {Array.<VALUE>|VALUE} data The elements or arrays of elements\n *     to add to arr.\n * @template VALUE\n */\nol.array.extend = function(arr, data) {\n  var i;\n  var extension = Array.isArray(data) ? data : [data];\n  var length = extension.length;\n  for (i = 0; i < length; i++) {\n    arr[arr.length] = extension[i];\n  }\n};\n\n\n/**\n * @param {Array.<VALUE>} arr The array to modify.\n * @param {VALUE} obj The element to remove.\n * @template VALUE\n * @return {boolean} If the element was removed.\n */\nol.array.remove = function(arr, obj) {\n  var i = arr.indexOf(obj);\n  var found = i > -1;\n  if (found) {\n    arr.splice(i, 1);\n  }\n  return found;\n};\n\n\n/**\n * @param {Array.<VALUE>} arr The array to search in.\n * @param {function(VALUE, number, ?) : boolean} func The function to compare.\n * @template VALUE\n * @return {VALUE} The element found.\n */\nol.array.find = function(arr, func) {\n  var length = arr.length >>> 0;\n  var value;\n\n  for (var i = 0; i < length; i++) {\n    value = arr[i];\n    if (func(value, i, arr)) {\n      return value;\n    }\n  }\n  return null;\n};\n\n\n/**\n * @param {Array|Uint8ClampedArray} arr1 The first array to compare.\n * @param {Array|Uint8ClampedArray} arr2 The second array to compare.\n * @return {boolean} Whether the two arrays are equal.\n */\nol.array.equals = function(arr1, arr2) {\n  var len1 = arr1.length;\n  if (len1 !== arr2.length) {\n    return false;\n  }\n  for (var i = 0; i < len1; i++) {\n    if (arr1[i] !== arr2[i]) {\n      return false;\n    }\n  }\n  return true;\n};\n\n\n/**\n * @param {Array.<*>} arr The array to sort (modifies original).\n * @param {Function} compareFnc Comparison function.\n */\nol.array.stableSort = function(arr, compareFnc) {\n  var length = arr.length;\n  var tmp = Array(arr.length);\n  var i;\n  for (i = 0; i < length; i++) {\n    tmp[i] = {index: i, value: arr[i]};\n  }\n  tmp.sort(function(a, b) {\n    return compareFnc(a.value, b.value) || a.index - b.index;\n  });\n  for (i = 0; i < arr.length; i++) {\n    arr[i] = tmp[i].value;\n  }\n};\n\n\n/**\n * @param {Array.<*>} arr The array to search in.\n * @param {Function} func Comparison function.\n * @return {number} Return index.\n */\nol.array.findIndex = function(arr, func) {\n  var index;\n  var found = !arr.every(function(el, idx) {\n    index = idx;\n    return !func(el, idx, arr);\n  });\n  return found ? index : -1;\n};\n\n\n/**\n * @param {Array.<*>} arr The array to test.\n * @param {Function=} opt_func Comparison function.\n * @param {boolean=} opt_strict Strictly sorted (default false).\n * @return {boolean} Return index.\n */\nol.array.isSorted = function(arr, opt_func, opt_strict) {\n  var compare = opt_func || ol.array.numberSafeCompareFunction;\n  return arr.every(function(currentVal, index) {\n    if (index === 0) {\n      return true;\n    }\n    var res = compare(arr[index - 1], currentVal);\n    return !(res > 0 || opt_strict && res === 0);\n  });\n};\n\ngoog.provide('ol.ResolutionConstraint');\n\ngoog.require('ol.array');\ngoog.require('ol.math');\n\n\n/**\n * @param {Array.<number>} resolutions Resolutions.\n * @return {ol.ResolutionConstraintType} Zoom function.\n */\nol.ResolutionConstraint.createSnapToResolutions = function(resolutions) {\n  return (\n      /**\n       * @param {number|undefined} resolution Resolution.\n       * @param {number} delta Delta.\n       * @param {number} direction Direction.\n       * @return {number|undefined} Resolution.\n       */\n      function(resolution, delta, direction) {\n        if (resolution !== undefined) {\n          var z =\n              ol.array.linearFindNearest(resolutions, resolution, direction);\n          z = ol.math.clamp(z + delta, 0, resolutions.length - 1);\n          var index = Math.floor(z);\n          if (z != index && index < resolutions.length - 1) {\n            var power = resolutions[index] / resolutions[index + 1];\n            return resolutions[index] / Math.pow(power, z - index);\n          } else {\n            return resolutions[index];\n          }\n        } else {\n          return undefined;\n        }\n      });\n};\n\n\n/**\n * @param {number} power Power.\n * @param {number} maxResolution Maximum resolution.\n * @param {number=} opt_maxLevel Maximum level.\n * @return {ol.ResolutionConstraintType} Zoom function.\n */\nol.ResolutionConstraint.createSnapToPower = function(power, maxResolution, opt_maxLevel) {\n  return (\n      /**\n       * @param {number|undefined} resolution Resolution.\n       * @param {number} delta Delta.\n       * @param {number} direction Direction.\n       * @return {number|undefined} Resolution.\n       */\n      function(resolution, delta, direction) {\n        if (resolution !== undefined) {\n          var offset = -direction / 2 + 0.5;\n          var oldLevel = Math.floor(\n              Math.log(maxResolution / resolution) / Math.log(power) + offset);\n          var newLevel = Math.max(oldLevel + delta, 0);\n          if (opt_maxLevel !== undefined) {\n            newLevel = Math.min(newLevel, opt_maxLevel);\n          }\n          return maxResolution / Math.pow(power, newLevel);\n        } else {\n          return undefined;\n        }\n      });\n};\n\ngoog.provide('ol.RotationConstraint');\n\ngoog.require('ol.math');\n\n\n/**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\nol.RotationConstraint.disable = function(rotation, delta) {\n  if (rotation !== undefined) {\n    return 0;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\nol.RotationConstraint.none = function(rotation, delta) {\n  if (rotation !== undefined) {\n    return rotation + delta;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {number} n N.\n * @return {ol.RotationConstraintType} Rotation constraint.\n */\nol.RotationConstraint.createSnapToN = function(n) {\n  var theta = 2 * Math.PI / n;\n  return (\n      /**\n       * @param {number|undefined} rotation Rotation.\n       * @param {number} delta Delta.\n       * @return {number|undefined} Rotation.\n       */\n      function(rotation, delta) {\n        if (rotation !== undefined) {\n          rotation = Math.floor((rotation + delta) / theta + 0.5) * theta;\n          return rotation;\n        } else {\n          return undefined;\n        }\n      });\n};\n\n\n/**\n * @param {number=} opt_tolerance Tolerance.\n * @return {ol.RotationConstraintType} Rotation constraint.\n */\nol.RotationConstraint.createSnapToZero = function(opt_tolerance) {\n  var tolerance = opt_tolerance || ol.math.toRadians(5);\n  return (\n      /**\n       * @param {number|undefined} rotation Rotation.\n       * @param {number} delta Delta.\n       * @return {number|undefined} Rotation.\n       */\n      function(rotation, delta) {\n        if (rotation !== undefined) {\n          if (Math.abs(rotation + delta) <= tolerance) {\n            return 0;\n          } else {\n            return rotation + delta;\n          }\n        } else {\n          return undefined;\n        }\n      });\n};\n\ngoog.provide('ol.string');\n\n/**\n * @param {number} number Number to be formatted\n * @param {number} width The desired width\n * @param {number=} opt_precision Precision of the output string (i.e. number of decimal places)\n * @returns {string} Formatted string\n*/\nol.string.padNumber = function(number, width, opt_precision) {\n  var numberString = opt_precision !== undefined ? number.toFixed(opt_precision) : '' + number;\n  var decimal = numberString.indexOf('.');\n  decimal = decimal === -1 ? numberString.length : decimal;\n  return decimal > width ? numberString : new Array(1 + width - decimal).join('0') + numberString;\n};\n\n/**\n * Adapted from https://github.com/omichelsen/compare-versions/blob/master/index.js\n * @param {string|number} v1 First version\n * @param {string|number} v2 Second version\n * @returns {number} Value\n */\nol.string.compareVersions = function(v1, v2) {\n  var s1 = ('' + v1).split('.');\n  var s2 = ('' + v2).split('.');\n\n  for (var i = 0; i < Math.max(s1.length, s2.length); i++) {\n    var n1 = parseInt(s1[i] || '0', 10);\n    var n2 = parseInt(s2[i] || '0', 10);\n\n    if (n1 > n2) {\n      return 1;\n    }\n    if (n2 > n1) {\n      return -1;\n    }\n  }\n\n  return 0;\n};\n\ngoog.provide('ol.coordinate');\n\ngoog.require('ol.math');\ngoog.require('ol.string');\n\n\n/**\n * Add `delta` to `coordinate`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n *     var coord = [7.85, 47.983333];\n *     ol.coordinate.add(coord, [-2, 4]);\n *     // coord is now [5.85, 51.983333]\n *\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {ol.Coordinate} delta Delta.\n * @return {ol.Coordinate} The input coordinate adjusted by the given delta.\n * @api stable\n */\nol.coordinate.add = function(coordinate, delta) {\n  coordinate[0] += delta[0];\n  coordinate[1] += delta[1];\n  return coordinate;\n};\n\n\n/**\n * Calculates the point closest to the passed coordinate on the passed segment.\n * This is the foot of the perpendicular of the coordinate to the segment when\n * the foot is on the segment, or the closest segment coordinate when the foot\n * is outside the segment.\n *\n * @param {ol.Coordinate} coordinate The coordinate.\n * @param {Array.<ol.Coordinate>} segment The two coordinates of the segment.\n * @return {ol.Coordinate} The foot of the perpendicular of the coordinate to\n *     the segment.\n */\nol.coordinate.closestOnSegment = function(coordinate, segment) {\n  var x0 = coordinate[0];\n  var y0 = coordinate[1];\n  var start = segment[0];\n  var end = segment[1];\n  var x1 = start[0];\n  var y1 = start[1];\n  var x2 = end[0];\n  var y2 = end[1];\n  var dx = x2 - x1;\n  var dy = y2 - y1;\n  var along = (dx === 0 && dy === 0) ? 0 :\n      ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0);\n  var x, y;\n  if (along <= 0) {\n    x = x1;\n    y = y1;\n  } else if (along >= 1) {\n    x = x2;\n    y = y2;\n  } else {\n    x = x1 + along * dx;\n    y = y1 + along * dy;\n  }\n  return [x, y];\n};\n\n\n/**\n * Returns a {@link ol.CoordinateFormatType} function that can be used to format\n * a {ol.Coordinate} to a string.\n *\n * Example without specifying the fractional digits:\n *\n *     var coord = [7.85, 47.983333];\n *     var stringifyFunc = ol.coordinate.createStringXY();\n *     var out = stringifyFunc(coord);\n *     // out is now '8, 48'\n *\n * Example with explicitly specifying 2 fractional digits:\n *\n *     var coord = [7.85, 47.983333];\n *     var stringifyFunc = ol.coordinate.createStringXY(2);\n *     var out = stringifyFunc(coord);\n *     // out is now '7.85, 47.98'\n *\n * @param {number=} opt_fractionDigits The number of digits to include\n *    after the decimal point. Default is `0`.\n * @return {ol.CoordinateFormatType} Coordinate format.\n * @api stable\n */\nol.coordinate.createStringXY = function(opt_fractionDigits) {\n  return (\n      /**\n       * @param {ol.Coordinate|undefined} coordinate Coordinate.\n       * @return {string} String XY.\n       */\n      function(coordinate) {\n        return ol.coordinate.toStringXY(coordinate, opt_fractionDigits);\n      });\n};\n\n\n/**\n * @private\n * @param {number} degrees Degrees.\n * @param {string} hemispheres Hemispheres.\n * @param {number=} opt_fractionDigits The number of digits to include\n *    after the decimal point. Default is `0`.\n * @return {string} String.\n */\nol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres, opt_fractionDigits) {\n  var normalizedDegrees = ol.math.modulo(degrees + 180, 360) - 180;\n  var x = Math.abs(3600 * normalizedDegrees);\n  var dflPrecision = opt_fractionDigits || 0;\n  return Math.floor(x / 3600) + '\\u00b0 ' +\n      ol.string.padNumber(Math.floor((x / 60) % 60), 2) + '\\u2032 ' +\n      ol.string.padNumber((x % 60), 2, dflPrecision) + '\\u2033 ' +\n      hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0);\n};\n\n\n/**\n * Transforms the given {@link ol.Coordinate} to a string using the given string\n * template. The strings `{x}` and `{y}` in the template will be replaced with\n * the first and second coordinate values respectively.\n *\n * Example without specifying the fractional digits:\n *\n *     var coord = [7.85, 47.983333];\n *     var template = 'Coordinate is ({x}|{y}).';\n *     var out = ol.coordinate.format(coord, template);\n *     // out is now 'Coordinate is (8|48).'\n *\n * Example explicitly specifying the fractional digits:\n *\n *     var coord = [7.85, 47.983333];\n *     var template = 'Coordinate is ({x}|{y}).';\n *     var out = ol.coordinate.format(coord, template, 2);\n *     // out is now 'Coordinate is (7.85|47.98).'\n *\n * @param {ol.Coordinate|undefined} coordinate Coordinate.\n * @param {string} template A template string with `{x}` and `{y}` placeholders\n *     that will be replaced by first and second coordinate values.\n * @param {number=} opt_fractionDigits The number of digits to include\n *    after the decimal point. Default is `0`.\n * @return {string} Formatted coordinate.\n * @api stable\n */\nol.coordinate.format = function(coordinate, template, opt_fractionDigits) {\n  if (coordinate) {\n    return template\n      .replace('{x}', coordinate[0].toFixed(opt_fractionDigits))\n      .replace('{y}', coordinate[1].toFixed(opt_fractionDigits));\n  } else {\n    return '';\n  }\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate1 First coordinate.\n * @param {ol.Coordinate} coordinate2 Second coordinate.\n * @return {boolean} Whether the passed coordinates are equal.\n */\nol.coordinate.equals = function(coordinate1, coordinate2) {\n  var equals = true;\n  for (var i = coordinate1.length - 1; i >= 0; --i) {\n    if (coordinate1[i] != coordinate2[i]) {\n      equals = false;\n      break;\n    }\n  }\n  return equals;\n};\n\n\n/**\n * Rotate `coordinate` by `angle`. `coordinate` is modified in place and\n * returned by the function.\n *\n * Example:\n *\n *     var coord = [7.85, 47.983333];\n *     var rotateRadians = Math.PI / 2; // 90 degrees\n *     ol.coordinate.rotate(coord, rotateRadians);\n *     // coord is now [-47.983333, 7.85]\n *\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} angle Angle in radian.\n * @return {ol.Coordinate} Coordinate.\n * @api stable\n */\nol.coordinate.rotate = function(coordinate, angle) {\n  var cosAngle = Math.cos(angle);\n  var sinAngle = Math.sin(angle);\n  var x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;\n  var y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;\n  coordinate[0] = x;\n  coordinate[1] = y;\n  return coordinate;\n};\n\n\n/**\n * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n *     var coord = [7.85, 47.983333];\n *     var scale = 1.2;\n *     ol.coordinate.scale(coord, scale);\n *     // coord is now [9.42, 57.5799996]\n *\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} scale Scale factor.\n * @return {ol.Coordinate} Coordinate.\n */\nol.coordinate.scale = function(coordinate, scale) {\n  coordinate[0] *= scale;\n  coordinate[1] *= scale;\n  return coordinate;\n};\n\n\n/**\n * Subtract `delta` to `coordinate`. `coordinate` is modified in place and\n * returned by the function.\n *\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {ol.Coordinate} delta Delta.\n * @return {ol.Coordinate} Coordinate.\n */\nol.coordinate.sub = function(coordinate, delta) {\n  coordinate[0] -= delta[0];\n  coordinate[1] -= delta[1];\n  return coordinate;\n};\n\n\n/**\n * @param {ol.Coordinate} coord1 First coordinate.\n * @param {ol.Coordinate} coord2 Second coordinate.\n * @return {number} Squared distance between coord1 and coord2.\n */\nol.coordinate.squaredDistance = function(coord1, coord2) {\n  var dx = coord1[0] - coord2[0];\n  var dy = coord1[1] - coord2[1];\n  return dx * dx + dy * dy;\n};\n\n\n/**\n * Calculate the squared distance from a coordinate to a line segment.\n *\n * @param {ol.Coordinate} coordinate Coordinate of the point.\n * @param {Array.<ol.Coordinate>} segment Line segment (2 coordinates).\n * @return {number} Squared distance from the point to the line segment.\n */\nol.coordinate.squaredDistanceToSegment = function(coordinate, segment) {\n  return ol.coordinate.squaredDistance(coordinate,\n      ol.coordinate.closestOnSegment(coordinate, segment));\n};\n\n\n/**\n * Format a geographic coordinate with the hemisphere, degrees, minutes, and\n * seconds.\n *\n * Example without specifying fractional digits:\n *\n *     var coord = [7.85, 47.983333];\n *     var out = ol.coordinate.toStringHDMS(coord);\n *     // out is now '47° 58′ 60″ N 7° 50′ 60″ E'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n *     var coord = [7.85, 47.983333];\n *     var out = ol.coordinate.toStringHDMS(coord, 1);\n *     // out is now '47° 58′ 60.0″ N 7° 50′ 60.0″ E'\n *\n * @param {ol.Coordinate|undefined} coordinate Coordinate.\n * @param {number=} opt_fractionDigits The number of digits to include\n *    after the decimal point. Default is `0`.\n * @return {string} Hemisphere, degrees, minutes and seconds.\n * @api stable\n */\nol.coordinate.toStringHDMS = function(coordinate, opt_fractionDigits) {\n  if (coordinate) {\n    return ol.coordinate.degreesToStringHDMS_(coordinate[1], 'NS', opt_fractionDigits) + ' ' +\n        ol.coordinate.degreesToStringHDMS_(coordinate[0], 'EW', opt_fractionDigits);\n  } else {\n    return '';\n  }\n};\n\n\n/**\n * Format a coordinate as a comma delimited string.\n *\n * Example without specifying fractional digits:\n *\n *     var coord = [7.85, 47.983333];\n *     var out = ol.coordinate.toStringXY(coord);\n *     // out is now '8, 48'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n *     var coord = [7.85, 47.983333];\n *     var out = ol.coordinate.toStringXY(coord, 1);\n *     // out is now '7.8, 48.0'\n *\n * @param {ol.Coordinate|undefined} coordinate Coordinate.\n * @param {number=} opt_fractionDigits The number of digits to include\n *    after the decimal point. Default is `0`.\n * @return {string} XY.\n * @api stable\n */\nol.coordinate.toStringXY = function(coordinate, opt_fractionDigits) {\n  return ol.coordinate.format(coordinate, '{x}, {y}', opt_fractionDigits);\n};\n\ngoog.provide('ol.easing');\n\n\n/**\n * Start slow and speed up.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nol.easing.easeIn = function(t) {\n  return Math.pow(t, 3);\n};\n\n\n/**\n * Start fast and slow down.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nol.easing.easeOut = function(t) {\n  return 1 - ol.easing.easeIn(1 - t);\n};\n\n\n/**\n * Start slow, speed up, and then slow down again.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nol.easing.inAndOut = function(t) {\n  return 3 * t * t - 2 * t * t * t;\n};\n\n\n/**\n * Maintain a constant speed over time.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nol.easing.linear = function(t) {\n  return t;\n};\n\n\n/**\n * Start slow, speed up, and at the very end slow down again.  This has the\n * same general behavior as {@link ol.easing.inAndOut}, but the final slowdown\n * is delayed.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nol.easing.upAndDown = function(t) {\n  if (t < 0.5) {\n    return ol.easing.inAndOut(2 * t);\n  } else {\n    return 1 - ol.easing.inAndOut(2 * (t - 0.5));\n  }\n};\n\ngoog.provide('ol.extent.Corner');\n\n/**\n * Extent corner.\n * @enum {string}\n */\nol.extent.Corner = {\n  BOTTOM_LEFT: 'bottom-left',\n  BOTTOM_RIGHT: 'bottom-right',\n  TOP_LEFT: 'top-left',\n  TOP_RIGHT: 'top-right'\n};\n\ngoog.provide('ol.extent.Relationship');\n\n\n/**\n * Relationship to an extent.\n * @enum {number}\n */\nol.extent.Relationship = {\n  UNKNOWN: 0,\n  INTERSECTING: 1,\n  ABOVE: 2,\n  RIGHT: 4,\n  BELOW: 8,\n  LEFT: 16\n};\n\ngoog.provide('ol.extent');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.extent.Corner');\ngoog.require('ol.extent.Relationship');\n\n\n/**\n * Build an extent that includes all given coordinates.\n *\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @return {ol.Extent} Bounding extent.\n * @api stable\n */\nol.extent.boundingExtent = function(coordinates) {\n  var extent = ol.extent.createEmpty();\n  for (var i = 0, ii = coordinates.length; i < ii; ++i) {\n    ol.extent.extendCoordinate(extent, coordinates[i]);\n  }\n  return extent;\n};\n\n\n/**\n * @param {Array.<number>} xs Xs.\n * @param {Array.<number>} ys Ys.\n * @param {ol.Extent=} opt_extent Destination extent.\n * @private\n * @return {ol.Extent} Extent.\n */\nol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) {\n  ol.DEBUG && console.assert(xs.length > 0, 'xs length should be larger than 0');\n  ol.DEBUG && console.assert(ys.length > 0, 'ys length should be larger than 0');\n  var minX = Math.min.apply(null, xs);\n  var minY = Math.min.apply(null, ys);\n  var maxX = Math.max.apply(null, xs);\n  var maxY = Math.max.apply(null, ys);\n  return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);\n};\n\n\n/**\n * Return extent increased by the provided value.\n * @param {ol.Extent} extent Extent.\n * @param {number} value The amount by which the extent should be buffered.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} Extent.\n * @api stable\n */\nol.extent.buffer = function(extent, value, opt_extent) {\n  if (opt_extent) {\n    opt_extent[0] = extent[0] - value;\n    opt_extent[1] = extent[1] - value;\n    opt_extent[2] = extent[2] + value;\n    opt_extent[3] = extent[3] + value;\n    return opt_extent;\n  } else {\n    return [\n      extent[0] - value,\n      extent[1] - value,\n      extent[2] + value,\n      extent[3] + value\n    ];\n  }\n};\n\n\n/**\n * Creates a clone of an extent.\n *\n * @param {ol.Extent} extent Extent to clone.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} The clone.\n */\nol.extent.clone = function(extent, opt_extent) {\n  if (opt_extent) {\n    opt_extent[0] = extent[0];\n    opt_extent[1] = extent[1];\n    opt_extent[2] = extent[2];\n    opt_extent[3] = extent[3];\n    return opt_extent;\n  } else {\n    return extent.slice();\n  }\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {number} Closest squared distance.\n */\nol.extent.closestSquaredDistanceXY = function(extent, x, y) {\n  var dx, dy;\n  if (x < extent[0]) {\n    dx = extent[0] - x;\n  } else if (extent[2] < x) {\n    dx = x - extent[2];\n  } else {\n    dx = 0;\n  }\n  if (y < extent[1]) {\n    dy = extent[1] - y;\n  } else if (extent[3] < y) {\n    dy = y - extent[3];\n  } else {\n    dy = 0;\n  }\n  return dx * dx + dy * dy;\n};\n\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {ol.Extent} extent Extent.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @return {boolean} The coordinate is contained in the extent.\n * @api stable\n */\nol.extent.containsCoordinate = function(extent, coordinate) {\n  return ol.extent.containsXY(extent, coordinate[0], coordinate[1]);\n};\n\n\n/**\n * Check if one extent contains another.\n *\n * An extent is deemed contained if it lies completely within the other extent,\n * including if they share one or more edges.\n *\n * @param {ol.Extent} extent1 Extent 1.\n * @param {ol.Extent} extent2 Extent 2.\n * @return {boolean} The second extent is contained by or on the edge of the\n *     first.\n * @api stable\n */\nol.extent.containsExtent = function(extent1, extent2) {\n  return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] &&\n      extent1[1] <= extent2[1] && extent2[3] <= extent1[3];\n};\n\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {ol.Extent} extent Extent.\n * @param {number} x X coordinate.\n * @param {number} y Y coordinate.\n * @return {boolean} The x, y values are contained in the extent.\n * @api stable\n */\nol.extent.containsXY = function(extent, x, y) {\n  return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];\n};\n\n\n/**\n * Get the relationship between a coordinate and extent.\n * @param {ol.Extent} extent The extent.\n * @param {ol.Coordinate} coordinate The coordinate.\n * @return {number} The relationship (bitwise compare with\n *     ol.extent.Relationship).\n */\nol.extent.coordinateRelationship = function(extent, coordinate) {\n  var minX = extent[0];\n  var minY = extent[1];\n  var maxX = extent[2];\n  var maxY = extent[3];\n  var x = coordinate[0];\n  var y = coordinate[1];\n  var relationship = ol.extent.Relationship.UNKNOWN;\n  if (x < minX) {\n    relationship = relationship | ol.extent.Relationship.LEFT;\n  } else if (x > maxX) {\n    relationship = relationship | ol.extent.Relationship.RIGHT;\n  }\n  if (y < minY) {\n    relationship = relationship | ol.extent.Relationship.BELOW;\n  } else if (y > maxY) {\n    relationship = relationship | ol.extent.Relationship.ABOVE;\n  }\n  if (relationship === ol.extent.Relationship.UNKNOWN) {\n    relationship = ol.extent.Relationship.INTERSECTING;\n  }\n  return relationship;\n};\n\n\n/**\n * Create an empty extent.\n * @return {ol.Extent} Empty extent.\n * @api stable\n */\nol.extent.createEmpty = function() {\n  return [Infinity, Infinity, -Infinity, -Infinity];\n};\n\n\n/**\n * Create a new extent or update the provided extent.\n * @param {number} minX Minimum X.\n * @param {number} minY Minimum Y.\n * @param {number} maxX Maximum X.\n * @param {number} maxY Maximum Y.\n * @param {ol.Extent=} opt_extent Destination extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.createOrUpdate = function(minX, minY, maxX, maxY, opt_extent) {\n  if (opt_extent) {\n    opt_extent[0] = minX;\n    opt_extent[1] = minY;\n    opt_extent[2] = maxX;\n    opt_extent[3] = maxY;\n    return opt_extent;\n  } else {\n    return [minX, minY, maxX, maxY];\n  }\n};\n\n\n/**\n * Create a new empty extent or make the provided one empty.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.createOrUpdateEmpty = function(opt_extent) {\n  return ol.extent.createOrUpdate(\n      Infinity, Infinity, -Infinity, -Infinity, opt_extent);\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.createOrUpdateFromCoordinate = function(coordinate, opt_extent) {\n  var x = coordinate[0];\n  var y = coordinate[1];\n  return ol.extent.createOrUpdate(x, y, x, y, opt_extent);\n};\n\n\n/**\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.createOrUpdateFromCoordinates = function(coordinates, opt_extent) {\n  var extent = ol.extent.createOrUpdateEmpty(opt_extent);\n  return ol.extent.extendCoordinates(extent, coordinates);\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.createOrUpdateFromFlatCoordinates = function(flatCoordinates, offset, end, stride, opt_extent) {\n  var extent = ol.extent.createOrUpdateEmpty(opt_extent);\n  return ol.extent.extendFlatCoordinates(\n      extent, flatCoordinates, offset, end, stride);\n};\n\n\n/**\n * @param {Array.<Array.<ol.Coordinate>>} rings Rings.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.createOrUpdateFromRings = function(rings, opt_extent) {\n  var extent = ol.extent.createOrUpdateEmpty(opt_extent);\n  return ol.extent.extendRings(extent, rings);\n};\n\n\n/**\n * Determine if two extents are equivalent.\n * @param {ol.Extent} extent1 Extent 1.\n * @param {ol.Extent} extent2 Extent 2.\n * @return {boolean} The two extents are equivalent.\n * @api stable\n */\nol.extent.equals = function(extent1, extent2) {\n  return extent1[0] == extent2[0] && extent1[2] == extent2[2] &&\n      extent1[1] == extent2[1] && extent1[3] == extent2[3];\n};\n\n\n/**\n * Modify an extent to include another extent.\n * @param {ol.Extent} extent1 The extent to be modified.\n * @param {ol.Extent} extent2 The extent that will be included in the first.\n * @return {ol.Extent} A reference to the first (extended) extent.\n * @api stable\n */\nol.extent.extend = function(extent1, extent2) {\n  if (extent2[0] < extent1[0]) {\n    extent1[0] = extent2[0];\n  }\n  if (extent2[2] > extent1[2]) {\n    extent1[2] = extent2[2];\n  }\n  if (extent2[1] < extent1[1]) {\n    extent1[1] = extent2[1];\n  }\n  if (extent2[3] > extent1[3]) {\n    extent1[3] = extent2[3];\n  }\n  return extent1;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {ol.Coordinate} coordinate Coordinate.\n */\nol.extent.extendCoordinate = function(extent, coordinate) {\n  if (coordinate[0] < extent[0]) {\n    extent[0] = coordinate[0];\n  }\n  if (coordinate[0] > extent[2]) {\n    extent[2] = coordinate[0];\n  }\n  if (coordinate[1] < extent[1]) {\n    extent[1] = coordinate[1];\n  }\n  if (coordinate[1] > extent[3]) {\n    extent[3] = coordinate[1];\n  }\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @return {ol.Extent} Extent.\n */\nol.extent.extendCoordinates = function(extent, coordinates) {\n  var i, ii;\n  for (i = 0, ii = coordinates.length; i < ii; ++i) {\n    ol.extent.extendCoordinate(extent, coordinates[i]);\n  }\n  return extent;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {ol.Extent} Extent.\n */\nol.extent.extendFlatCoordinates = function(extent, flatCoordinates, offset, end, stride) {\n  for (; offset < end; offset += stride) {\n    ol.extent.extendXY(\n        extent, flatCoordinates[offset], flatCoordinates[offset + 1]);\n  }\n  return extent;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {Array.<Array.<ol.Coordinate>>} rings Rings.\n * @return {ol.Extent} Extent.\n */\nol.extent.extendRings = function(extent, rings) {\n  var i, ii;\n  for (i = 0, ii = rings.length; i < ii; ++i) {\n    ol.extent.extendCoordinates(extent, rings[i]);\n  }\n  return extent;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n */\nol.extent.extendXY = function(extent, x, y) {\n  extent[0] = Math.min(extent[0], x);\n  extent[1] = Math.min(extent[1], y);\n  extent[2] = Math.max(extent[2], x);\n  extent[3] = Math.max(extent[3], y);\n};\n\n\n/**\n * This function calls `callback` for each corner of the extent. If the\n * callback returns a truthy value the function returns that value\n * immediately. Otherwise the function returns `false`.\n * @param {ol.Extent} extent Extent.\n * @param {function(this:T, ol.Coordinate): S} callback Callback.\n * @param {T=} opt_this Value to use as `this` when executing `callback`.\n * @return {S|boolean} Value.\n * @template S, T\n */\nol.extent.forEachCorner = function(extent, callback, opt_this) {\n  var val;\n  val = callback.call(opt_this, ol.extent.getBottomLeft(extent));\n  if (val) {\n    return val;\n  }\n  val = callback.call(opt_this, ol.extent.getBottomRight(extent));\n  if (val) {\n    return val;\n  }\n  val = callback.call(opt_this, ol.extent.getTopRight(extent));\n  if (val) {\n    return val;\n  }\n  val = callback.call(opt_this, ol.extent.getTopLeft(extent));\n  if (val) {\n    return val;\n  }\n  return false;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @return {number} Area.\n */\nol.extent.getArea = function(extent) {\n  var area = 0;\n  if (!ol.extent.isEmpty(extent)) {\n    area = ol.extent.getWidth(extent) * ol.extent.getHeight(extent);\n  }\n  return area;\n};\n\n\n/**\n * Get the bottom left coordinate of an extent.\n * @param {ol.Extent} extent Extent.\n * @return {ol.Coordinate} Bottom left coordinate.\n * @api stable\n */\nol.extent.getBottomLeft = function(extent) {\n  return [extent[0], extent[1]];\n};\n\n\n/**\n * Get the bottom right coordinate of an extent.\n * @param {ol.Extent} extent Extent.\n * @return {ol.Coordinate} Bottom right coordinate.\n * @api stable\n */\nol.extent.getBottomRight = function(extent) {\n  return [extent[2], extent[1]];\n};\n\n\n/**\n * Get the center coordinate of an extent.\n * @param {ol.Extent} extent Extent.\n * @return {ol.Coordinate} Center.\n * @api stable\n */\nol.extent.getCenter = function(extent) {\n  return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];\n};\n\n\n/**\n * Get a corner coordinate of an extent.\n * @param {ol.Extent} extent Extent.\n * @param {ol.extent.Corner} corner Corner.\n * @return {ol.Coordinate} Corner coordinate.\n */\nol.extent.getCorner = function(extent, corner) {\n  var coordinate;\n  if (corner === ol.extent.Corner.BOTTOM_LEFT) {\n    coordinate = ol.extent.getBottomLeft(extent);\n  } else if (corner === ol.extent.Corner.BOTTOM_RIGHT) {\n    coordinate = ol.extent.getBottomRight(extent);\n  } else if (corner === ol.extent.Corner.TOP_LEFT) {\n    coordinate = ol.extent.getTopLeft(extent);\n  } else if (corner === ol.extent.Corner.TOP_RIGHT) {\n    coordinate = ol.extent.getTopRight(extent);\n  } else {\n    ol.asserts.assert(false, 13); // Invalid corner\n  }\n  return /** @type {!ol.Coordinate} */ (coordinate);\n};\n\n\n/**\n * @param {ol.Extent} extent1 Extent 1.\n * @param {ol.Extent} extent2 Extent 2.\n * @return {number} Enlarged area.\n */\nol.extent.getEnlargedArea = function(extent1, extent2) {\n  var minX = Math.min(extent1[0], extent2[0]);\n  var minY = Math.min(extent1[1], extent2[1]);\n  var maxX = Math.max(extent1[2], extent2[2]);\n  var maxY = Math.max(extent1[3], extent2[3]);\n  return (maxX - minX) * (maxY - minY);\n};\n\n\n/**\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {ol.Extent=} opt_extent Destination extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.getForViewAndSize = function(center, resolution, rotation, size, opt_extent) {\n  var dx = resolution * size[0] / 2;\n  var dy = resolution * size[1] / 2;\n  var cosRotation = Math.cos(rotation);\n  var sinRotation = Math.sin(rotation);\n  var xCos = dx * cosRotation;\n  var xSin = dx * sinRotation;\n  var yCos = dy * cosRotation;\n  var ySin = dy * sinRotation;\n  var x = center[0];\n  var y = center[1];\n  var x0 = x - xCos + ySin;\n  var x1 = x - xCos - ySin;\n  var x2 = x + xCos - ySin;\n  var x3 = x + xCos + ySin;\n  var y0 = y - xSin - yCos;\n  var y1 = y - xSin + yCos;\n  var y2 = y + xSin + yCos;\n  var y3 = y + xSin - yCos;\n  return ol.extent.createOrUpdate(\n      Math.min(x0, x1, x2, x3), Math.min(y0, y1, y2, y3),\n      Math.max(x0, x1, x2, x3), Math.max(y0, y1, y2, y3),\n      opt_extent);\n};\n\n\n/**\n * Get the height of an extent.\n * @param {ol.Extent} extent Extent.\n * @return {number} Height.\n * @api stable\n */\nol.extent.getHeight = function(extent) {\n  return extent[3] - extent[1];\n};\n\n\n/**\n * @param {ol.Extent} extent1 Extent 1.\n * @param {ol.Extent} extent2 Extent 2.\n * @return {number} Intersection area.\n */\nol.extent.getIntersectionArea = function(extent1, extent2) {\n  var intersection = ol.extent.getIntersection(extent1, extent2);\n  return ol.extent.getArea(intersection);\n};\n\n\n/**\n * Get the intersection of two extents.\n * @param {ol.Extent} extent1 Extent 1.\n * @param {ol.Extent} extent2 Extent 2.\n * @param {ol.Extent=} opt_extent Optional extent to populate with intersection.\n * @return {ol.Extent} Intersecting extent.\n * @api stable\n */\nol.extent.getIntersection = function(extent1, extent2, opt_extent) {\n  var intersection = opt_extent ? opt_extent : ol.extent.createEmpty();\n  if (ol.extent.intersects(extent1, extent2)) {\n    if (extent1[0] > extent2[0]) {\n      intersection[0] = extent1[0];\n    } else {\n      intersection[0] = extent2[0];\n    }\n    if (extent1[1] > extent2[1]) {\n      intersection[1] = extent1[1];\n    } else {\n      intersection[1] = extent2[1];\n    }\n    if (extent1[2] < extent2[2]) {\n      intersection[2] = extent1[2];\n    } else {\n      intersection[2] = extent2[2];\n    }\n    if (extent1[3] < extent2[3]) {\n      intersection[3] = extent1[3];\n    } else {\n      intersection[3] = extent2[3];\n    }\n  }\n  return intersection;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @return {number} Margin.\n */\nol.extent.getMargin = function(extent) {\n  return ol.extent.getWidth(extent) + ol.extent.getHeight(extent);\n};\n\n\n/**\n * Get the size (width, height) of an extent.\n * @param {ol.Extent} extent The extent.\n * @return {ol.Size} The extent size.\n * @api stable\n */\nol.extent.getSize = function(extent) {\n  return [extent[2] - extent[0], extent[3] - extent[1]];\n};\n\n\n/**\n * Get the top left coordinate of an extent.\n * @param {ol.Extent} extent Extent.\n * @return {ol.Coordinate} Top left coordinate.\n * @api stable\n */\nol.extent.getTopLeft = function(extent) {\n  return [extent[0], extent[3]];\n};\n\n\n/**\n * Get the top right coordinate of an extent.\n * @param {ol.Extent} extent Extent.\n * @return {ol.Coordinate} Top right coordinate.\n * @api stable\n */\nol.extent.getTopRight = function(extent) {\n  return [extent[2], extent[3]];\n};\n\n\n/**\n * Get the width of an extent.\n * @param {ol.Extent} extent Extent.\n * @return {number} Width.\n * @api stable\n */\nol.extent.getWidth = function(extent) {\n  return extent[2] - extent[0];\n};\n\n\n/**\n * Determine if one extent intersects another.\n * @param {ol.Extent} extent1 Extent 1.\n * @param {ol.Extent} extent2 Extent.\n * @return {boolean} The two extents intersect.\n * @api stable\n */\nol.extent.intersects = function(extent1, extent2) {\n  return extent1[0] <= extent2[2] &&\n      extent1[2] >= extent2[0] &&\n      extent1[1] <= extent2[3] &&\n      extent1[3] >= extent2[1];\n};\n\n\n/**\n * Determine if an extent is empty.\n * @param {ol.Extent} extent Extent.\n * @return {boolean} Is empty.\n * @api stable\n */\nol.extent.isEmpty = function(extent) {\n  return extent[2] < extent[0] || extent[3] < extent[1];\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} Extent.\n */\nol.extent.returnOrUpdate = function(extent, opt_extent) {\n  if (opt_extent) {\n    opt_extent[0] = extent[0];\n    opt_extent[1] = extent[1];\n    opt_extent[2] = extent[2];\n    opt_extent[3] = extent[3];\n    return opt_extent;\n  } else {\n    return extent;\n  }\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} value Value.\n */\nol.extent.scaleFromCenter = function(extent, value) {\n  var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1);\n  var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1);\n  extent[0] -= deltaX;\n  extent[2] += deltaX;\n  extent[1] -= deltaY;\n  extent[3] += deltaY;\n};\n\n\n/**\n * Determine if the segment between two coordinates intersects (crosses,\n * touches, or is contained by) the provided extent.\n * @param {ol.Extent} extent The extent.\n * @param {ol.Coordinate} start Segment start coordinate.\n * @param {ol.Coordinate} end Segment end coordinate.\n * @return {boolean} The segment intersects the extent.\n */\nol.extent.intersectsSegment = function(extent, start, end) {\n  var intersects = false;\n  var startRel = ol.extent.coordinateRelationship(extent, start);\n  var endRel = ol.extent.coordinateRelationship(extent, end);\n  if (startRel === ol.extent.Relationship.INTERSECTING ||\n      endRel === ol.extent.Relationship.INTERSECTING) {\n    intersects = true;\n  } else {\n    var minX = extent[0];\n    var minY = extent[1];\n    var maxX = extent[2];\n    var maxY = extent[3];\n    var startX = start[0];\n    var startY = start[1];\n    var endX = end[0];\n    var endY = end[1];\n    var slope = (endY - startY) / (endX - startX);\n    var x, y;\n    if (!!(endRel & ol.extent.Relationship.ABOVE) &&\n        !(startRel & ol.extent.Relationship.ABOVE)) {\n      // potentially intersects top\n      x = endX - ((endY - maxY) / slope);\n      intersects = x >= minX && x <= maxX;\n    }\n    if (!intersects && !!(endRel & ol.extent.Relationship.RIGHT) &&\n        !(startRel & ol.extent.Relationship.RIGHT)) {\n      // potentially intersects right\n      y = endY - ((endX - maxX) * slope);\n      intersects = y >= minY && y <= maxY;\n    }\n    if (!intersects && !!(endRel & ol.extent.Relationship.BELOW) &&\n        !(startRel & ol.extent.Relationship.BELOW)) {\n      // potentially intersects bottom\n      x = endX - ((endY - minY) / slope);\n      intersects = x >= minX && x <= maxX;\n    }\n    if (!intersects && !!(endRel & ol.extent.Relationship.LEFT) &&\n        !(startRel & ol.extent.Relationship.LEFT)) {\n      // potentially intersects left\n      y = endY - ((endX - minX) * slope);\n      intersects = y >= minY && y <= maxY;\n    }\n\n  }\n  return intersects;\n};\n\n\n/**\n * Apply a transform function to the extent.\n * @param {ol.Extent} extent Extent.\n * @param {ol.TransformFunction} transformFn Transform function.  Called with\n * [minX, minY, maxX, maxY] extent coordinates.\n * @param {ol.Extent=} opt_extent Destination extent.\n * @return {ol.Extent} Extent.\n * @api stable\n */\nol.extent.applyTransform = function(extent, transformFn, opt_extent) {\n  var coordinates = [\n    extent[0], extent[1],\n    extent[0], extent[3],\n    extent[2], extent[1],\n    extent[2], extent[3]\n  ];\n  transformFn(coordinates, coordinates, 2);\n  var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];\n  var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];\n  return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);\n};\n\ngoog.provide('ol.geom.GeometryLayout');\n\n\n/**\n * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')\n * or measure ('M') coordinate is available. Supported values are `'XY'`,\n * `'XYZ'`, `'XYM'`, `'XYZM'`.\n * @enum {string}\n */\nol.geom.GeometryLayout = {\n  XY: 'XY',\n  XYZ: 'XYZ',\n  XYM: 'XYM',\n  XYZM: 'XYZM'\n};\n\ngoog.provide('ol.geom.GeometryType');\n\n\n/**\n * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,\n * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,\n * `'GeometryCollection'`, `'Circle'`.\n * @enum {string}\n */\nol.geom.GeometryType = {\n  POINT: 'Point',\n  LINE_STRING: 'LineString',\n  LINEAR_RING: 'LinearRing',\n  POLYGON: 'Polygon',\n  MULTI_POINT: 'MultiPoint',\n  MULTI_LINE_STRING: 'MultiLineString',\n  MULTI_POLYGON: 'MultiPolygon',\n  GEOMETRY_COLLECTION: 'GeometryCollection',\n  CIRCLE: 'Circle'\n};\n\ngoog.provide('ol.functions');\n\n/**\n * Always returns true.\n * @returns {boolean} true.\n */\nol.functions.TRUE = function() {\n  return true;\n};\n\n/**\n * Always returns false.\n * @returns {boolean} false.\n */\nol.functions.FALSE = function() {\n  return false;\n};\n\n/**\n * @license\n * Latitude/longitude spherical geodesy formulae taken from\n * http://www.movable-type.co.uk/scripts/latlong.html\n * Licensed under CC-BY-3.0.\n */\n\ngoog.provide('ol.Sphere');\n\ngoog.require('ol.math');\n\n\n/**\n * @classdesc\n * Class to create objects that can be used with {@link\n * ol.geom.Polygon.circular}.\n *\n * For example to create a sphere whose radius is equal to the semi-major\n * axis of the WGS84 ellipsoid:\n *\n * ```js\n * var wgs84Sphere= new ol.Sphere(6378137);\n * ```\n *\n * @constructor\n * @param {number} radius Radius.\n * @api\n */\nol.Sphere = function(radius) {\n\n  /**\n   * @type {number}\n   */\n  this.radius = radius;\n\n};\n\n\n/**\n * Returns the geodesic area for a list of coordinates.\n *\n * [Reference](http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409)\n * Robert. G. Chamberlain and William H. Duquette, \"Some Algorithms for\n * Polygons on a Sphere\", JPL Publication 07-03, Jet Propulsion\n * Laboratory, Pasadena, CA, June 2007\n *\n * @param {Array.<ol.Coordinate>} coordinates List of coordinates of a linear\n * ring. If the ring is oriented clockwise, the area will be positive,\n * otherwise it will be negative.\n * @return {number} Area.\n * @api\n */\nol.Sphere.prototype.geodesicArea = function(coordinates) {\n  var area = 0, len = coordinates.length;\n  var x1 = coordinates[len - 1][0];\n  var y1 = coordinates[len - 1][1];\n  for (var i = 0; i < len; i++) {\n    var x2 = coordinates[i][0], y2 = coordinates[i][1];\n    area += ol.math.toRadians(x2 - x1) *\n        (2 + Math.sin(ol.math.toRadians(y1)) +\n        Math.sin(ol.math.toRadians(y2)));\n    x1 = x2;\n    y1 = y2;\n  }\n  return area * this.radius * this.radius / 2.0;\n};\n\n\n/**\n * Returns the distance from c1 to c2 using the haversine formula.\n *\n * @param {ol.Coordinate} c1 Coordinate 1.\n * @param {ol.Coordinate} c2 Coordinate 2.\n * @return {number} Haversine distance.\n * @api\n */\nol.Sphere.prototype.haversineDistance = function(c1, c2) {\n  var lat1 = ol.math.toRadians(c1[1]);\n  var lat2 = ol.math.toRadians(c2[1]);\n  var deltaLatBy2 = (lat2 - lat1) / 2;\n  var deltaLonBy2 = ol.math.toRadians(c2[0] - c1[0]) / 2;\n  var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) +\n      Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) *\n      Math.cos(lat1) * Math.cos(lat2);\n  return 2 * this.radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n};\n\n\n/**\n * Returns the coordinate at the given distance and bearing from `c1`.\n *\n * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees).\n * @param {number} distance The great-circle distance between the origin\n *     point and the target point.\n * @param {number} bearing The bearing (in radians).\n * @return {ol.Coordinate} The target point.\n */\nol.Sphere.prototype.offset = function(c1, distance, bearing) {\n  var lat1 = ol.math.toRadians(c1[1]);\n  var lon1 = ol.math.toRadians(c1[0]);\n  var dByR = distance / this.radius;\n  var lat = Math.asin(\n      Math.sin(lat1) * Math.cos(dByR) +\n      Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));\n  var lon = lon1 + Math.atan2(\n      Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1),\n      Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));\n  return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)];\n};\n\ngoog.provide('ol.sphere.NORMAL');\n\ngoog.require('ol.Sphere');\n\n\n/**\n * The normal sphere.\n * @const\n * @type {ol.Sphere}\n */\nol.sphere.NORMAL = new ol.Sphere(6370997);\n\ngoog.provide('ol.proj.Units');\n\ngoog.require('ol.sphere.NORMAL');\n\n\n/**\n * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or\n * `'us-ft'`.\n * @enum {string}\n */\nol.proj.Units = {\n  DEGREES: 'degrees',\n  FEET: 'ft',\n  METERS: 'm',\n  PIXELS: 'pixels',\n  TILE_PIXELS: 'tile-pixels',\n  USFEET: 'us-ft'\n};\n\n\n/**\n * Meters per unit lookup table.\n * @const\n * @type {Object.<ol.proj.Units, number>}\n * @api stable\n */\nol.proj.Units.METERS_PER_UNIT = {};\nol.proj.Units.METERS_PER_UNIT[ol.proj.Units.DEGREES] =\n    2 * Math.PI * ol.sphere.NORMAL.radius / 360;\nol.proj.Units.METERS_PER_UNIT[ol.proj.Units.FEET] = 0.3048;\nol.proj.Units.METERS_PER_UNIT[ol.proj.Units.METERS] = 1;\nol.proj.Units.METERS_PER_UNIT[ol.proj.Units.USFEET] = 1200 / 3937;\n\ngoog.provide('ol.proj.proj4');\n\n\n/**\n * @private\n * @type {proj4}\n */\nol.proj.proj4.cache_ = null;\n\n\n/**\n * Store the proj4 function.\n * @param {proj4} proj4 The proj4 function.\n */\nol.proj.proj4.set = function(proj4) {\n  ol.proj.proj4.cache_ = proj4;\n};\n\n\n/**\n * Get proj4.\n * @return {proj4} The proj4 function set above or available globally.\n */\nol.proj.proj4.get = function() {\n  return ol.proj.proj4.cache_ || window['proj4'];\n};\n\ngoog.provide('ol.proj.Projection');\n\ngoog.require('ol');\ngoog.require('ol.proj.Units');\ngoog.require('ol.proj.proj4');\n\n\n/**\n * @classdesc\n * Projection definition class. One of these is created for each projection\n * supported in the application and stored in the {@link ol.proj} namespace.\n * You can use these in applications, but this is not required, as API params\n * and options use {@link ol.ProjectionLike} which means the simple string\n * code will suffice.\n *\n * You can use {@link ol.proj.get} to retrieve the object for a particular\n * projection.\n *\n * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together\n * with the following aliases:\n * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326,\n *     urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84,\n *     http://www.opengis.net/gml/srs/epsg.xml#4326,\n *     urn:x-ogc:def:crs:EPSG:4326\n * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913,\n *     urn:ogc:def:crs:EPSG:6.18:3:3857,\n *     http://www.opengis.net/gml/srs/epsg.xml#3857\n *\n * If you use proj4js, aliases can be added using `proj4.defs()`; see\n * [documentation](https://github.com/proj4js/proj4js). To set an alternative\n * namespace for proj4, use {@link ol.proj.setProj4}.\n *\n * @constructor\n * @param {olx.ProjectionOptions} options Projection options.\n * @struct\n * @api stable\n */\nol.proj.Projection = function(options) {\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.code_ = options.code;\n\n  /**\n   * @private\n   * @type {ol.proj.Units}\n   */\n  this.units_ = /** @type {ol.proj.Units} */ (options.units);\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.extent_ = options.extent !== undefined ? options.extent : null;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.worldExtent_ = options.worldExtent !== undefined ?\n      options.worldExtent : null;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.axisOrientation_ = options.axisOrientation !== undefined ?\n      options.axisOrientation : 'enu';\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.global_ = options.global !== undefined ? options.global : false;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.canWrapX_ = !!(this.global_ && this.extent_);\n\n  /**\n  * @private\n  * @type {function(number, ol.Coordinate):number|undefined}\n  */\n  this.getPointResolutionFunc_ = options.getPointResolution;\n\n  /**\n   * @private\n   * @type {ol.tilegrid.TileGrid}\n   */\n  this.defaultTileGrid_ = null;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.metersPerUnit_ = options.metersPerUnit;\n\n  var code = options.code;\n  ol.DEBUG && console.assert(code !== undefined,\n      'Option \"code\" is required for constructing instance');\n  if (ol.ENABLE_PROJ4JS) {\n    var proj4js = ol.proj.proj4.get();\n    if (typeof proj4js == 'function') {\n      var def = proj4js.defs(code);\n      if (def !== undefined) {\n        if (def.axis !== undefined && options.axisOrientation === undefined) {\n          this.axisOrientation_ = def.axis;\n        }\n        if (options.metersPerUnit === undefined) {\n          this.metersPerUnit_ = def.to_meter;\n        }\n        if (options.units === undefined) {\n          this.units_ = def.units;\n        }\n      }\n    }\n  }\n\n};\n\n\n/**\n * @return {boolean} The projection is suitable for wrapping the x-axis\n */\nol.proj.Projection.prototype.canWrapX = function() {\n  return this.canWrapX_;\n};\n\n\n/**\n * Get the code for this projection, e.g. 'EPSG:4326'.\n * @return {string} Code.\n * @api stable\n */\nol.proj.Projection.prototype.getCode = function() {\n  return this.code_;\n};\n\n\n/**\n * Get the validity extent for this projection.\n * @return {ol.Extent} Extent.\n * @api stable\n */\nol.proj.Projection.prototype.getExtent = function() {\n  return this.extent_;\n};\n\n\n/**\n * Get the units of this projection.\n * @return {ol.proj.Units} Units.\n * @api stable\n */\nol.proj.Projection.prototype.getUnits = function() {\n  return this.units_;\n};\n\n\n/**\n * Get the amount of meters per unit of this projection.  If the projection is\n * not configured with `metersPerUnit` or a units identifier, the return is\n * `undefined`.\n * @return {number|undefined} Meters.\n * @api stable\n */\nol.proj.Projection.prototype.getMetersPerUnit = function() {\n  return this.metersPerUnit_ || ol.proj.Units.METERS_PER_UNIT[this.units_];\n};\n\n\n/**\n * Get the world extent for this projection.\n * @return {ol.Extent} Extent.\n * @api\n */\nol.proj.Projection.prototype.getWorldExtent = function() {\n  return this.worldExtent_;\n};\n\n\n/**\n * Get the axis orientation of this projection.\n * Example values are:\n * enu - the default easting, northing, elevation.\n * neu - northing, easting, up - useful for \"lat/long\" geographic coordinates,\n *     or south orientated transverse mercator.\n * wnu - westing, northing, up - some planetary coordinate systems have\n *     \"west positive\" coordinate systems\n * @return {string} Axis orientation.\n */\nol.proj.Projection.prototype.getAxisOrientation = function() {\n  return this.axisOrientation_;\n};\n\n\n/**\n * Is this projection a global projection which spans the whole world?\n * @return {boolean} Whether the projection is global.\n * @api stable\n */\nol.proj.Projection.prototype.isGlobal = function() {\n  return this.global_;\n};\n\n\n/**\n* Set if the projection is a global projection which spans the whole world\n* @param {boolean} global Whether the projection is global.\n* @api stable\n*/\nol.proj.Projection.prototype.setGlobal = function(global) {\n  this.global_ = global;\n  this.canWrapX_ = !!(global && this.extent_);\n};\n\n\n/**\n * @return {ol.tilegrid.TileGrid} The default tile grid.\n */\nol.proj.Projection.prototype.getDefaultTileGrid = function() {\n  return this.defaultTileGrid_;\n};\n\n\n/**\n * @param {ol.tilegrid.TileGrid} tileGrid The default tile grid.\n */\nol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) {\n  this.defaultTileGrid_ = tileGrid;\n};\n\n\n/**\n * Set the validity extent for this projection.\n * @param {ol.Extent} extent Extent.\n * @api stable\n */\nol.proj.Projection.prototype.setExtent = function(extent) {\n  this.extent_ = extent;\n  this.canWrapX_ = !!(this.global_ && extent);\n};\n\n\n/**\n * Set the world extent for this projection.\n * @param {ol.Extent} worldExtent World extent\n *     [minlon, minlat, maxlon, maxlat].\n * @api\n */\nol.proj.Projection.prototype.setWorldExtent = function(worldExtent) {\n  this.worldExtent_ = worldExtent;\n};\n\n\n/**\n * Set the getPointResolution function for this projection.\n * @param {function(number, ol.Coordinate):number} func Function\n * @api\n */\nol.proj.Projection.prototype.setGetPointResolution = function(func) {\n  this.getPointResolutionFunc_ = func;\n};\n\n\n/**\n * Get the custom point resolution function for this projection (if set).\n * @return {function(number, ol.Coordinate):number|undefined} The custom point\n * resolution function (if set).\n */\nol.proj.Projection.prototype.getPointResolutionFunc = function() {\n  return this.getPointResolutionFunc_;\n};\n\ngoog.provide('ol.proj.projections');\n\n\n/**\n * @private\n * @type {Object.<string, ol.proj.Projection>}\n */\nol.proj.projections.cache_ = {};\n\n\n/**\n * Clear the projections cache.\n */\nol.proj.projections.clear = function() {\n  ol.proj.projections.cache_ = {};\n};\n\n\n/**\n * Get a cached projection by code.\n * @param {string} code The code for the projection.\n * @return {ol.proj.Projection} The projection (if cached).\n */\nol.proj.projections.get = function(code) {\n  var projections = ol.proj.projections.cache_;\n  return projections[code] || null;\n};\n\n\n/**\n * Add a projection to the cache.\n * @param {string} code The projection code.\n * @param {ol.proj.Projection} projection The projection to cache.\n */\nol.proj.projections.add = function(code, projection) {\n  var projections = ol.proj.projections.cache_;\n  projections[code] = projection;\n};\n\ngoog.provide('ol.proj.transforms');\n\ngoog.require('ol');\ngoog.require('ol.obj');\n\n\n/**\n * @private\n * @type {Object.<string, Object.<string, ol.TransformFunction>>}\n */\nol.proj.transforms.cache_ = {};\n\n\n/**\n * Clear the transform cache.\n */\nol.proj.transforms.clear = function() {\n  ol.proj.transforms.cache_ = {};\n};\n\n\n/**\n * Registers a conversion function to convert coordinates from the source\n * projection to the destination projection.\n *\n * @param {ol.proj.Projection} source Source.\n * @param {ol.proj.Projection} destination Destination.\n * @param {ol.TransformFunction} transformFn Transform.\n */\nol.proj.transforms.add = function(source, destination, transformFn) {\n  var sourceCode = source.getCode();\n  var destinationCode = destination.getCode();\n  var transforms = ol.proj.transforms.cache_;\n  if (!(sourceCode in transforms)) {\n    transforms[sourceCode] = {};\n  }\n  transforms[sourceCode][destinationCode] = transformFn;\n};\n\n\n/**\n * Unregisters the conversion function to convert coordinates from the source\n * projection to the destination projection.  This method is used to clean up\n * cached transforms during testing.\n *\n * @param {ol.proj.Projection} source Source projection.\n * @param {ol.proj.Projection} destination Destination projection.\n * @return {ol.TransformFunction} transformFn The unregistered transform.\n */\nol.proj.transforms.remove = function(source, destination) {\n  var sourceCode = source.getCode();\n  var destinationCode = destination.getCode();\n  var transforms = ol.proj.transforms.cache_;\n  ol.DEBUG && console.assert(sourceCode in transforms,\n      'sourceCode should be in transforms');\n  ol.DEBUG && console.assert(destinationCode in transforms[sourceCode],\n      'destinationCode should be in transforms of sourceCode');\n  var transform = transforms[sourceCode][destinationCode];\n  delete transforms[sourceCode][destinationCode];\n  if (ol.obj.isEmpty(transforms[sourceCode])) {\n    delete transforms[sourceCode];\n  }\n  return transform;\n};\n\n\n/**\n * Get a transform given a source code and a destination code.\n * @param {string} sourceCode The code for the source projection.\n * @param {string} destinationCode The code for the destination projection.\n * @return {ol.TransformFunction|undefined} The transform function (if found).\n */\nol.proj.transforms.get = function(sourceCode, destinationCode) {\n  var transform;\n  var transforms = ol.proj.transforms.cache_;\n  if (sourceCode in transforms && destinationCode in transforms[sourceCode]) {\n    transform = transforms[sourceCode][destinationCode];\n  }\n  return transform;\n};\n\ngoog.provide('ol.proj');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.proj.Projection');\ngoog.require('ol.proj.Units');\ngoog.require('ol.proj.proj4');\ngoog.require('ol.proj.projections');\ngoog.require('ol.proj.transforms');\ngoog.require('ol.sphere.NORMAL');\n\n\n/**\n * Meters per unit lookup table.\n * @const\n * @type {Object.<ol.proj.Units, number>}\n * @api stable\n */\nol.proj.METERS_PER_UNIT = ol.proj.Units.METERS_PER_UNIT;\n\n\nif (ol.ENABLE_PROJ4JS) {\n  /**\n   * Register proj4. If not explicitly registered, it will be assumed that\n   * proj4js will be loaded in the global namespace. For example in a\n   * browserify ES6 environment you could use:\n   *\n   *     import ol from 'openlayers';\n   *     import proj4 from 'proj4';\n   *     ol.proj.setProj4(proj4);\n   *\n   * @param {proj4} proj4 Proj4.\n   * @api\n   */\n  ol.proj.setProj4 = function(proj4) {\n    ol.DEBUG && console.assert(typeof proj4 == 'function',\n        'proj4 argument should be a function');\n    ol.proj.proj4.set(proj4);\n  };\n}\n\n\n/**\n * Get the resolution of the point in degrees or distance units.\n * For projections with degrees as the unit this will simply return the\n * provided resolution. For other projections the point resolution is\n * estimated by transforming the 'point' pixel to EPSG:4326,\n * measuring its width and height on the normal sphere,\n * and taking the average of the width and height.\n * @param {ol.proj.Projection} projection The projection.\n * @param {number} resolution Nominal resolution in projection units.\n * @param {ol.Coordinate} point Point to find adjusted resolution at.\n * @return {number} Point resolution at point in projection units.\n * @api\n */\nol.proj.getPointResolution = function(projection, resolution, point) {\n  var pointResolution;\n  var getter = projection.getPointResolutionFunc();\n  if (getter) {\n    pointResolution = getter(resolution, point);\n  } else {\n    var units = projection.getUnits();\n    if (units == ol.proj.Units.DEGREES) {\n      pointResolution = resolution;\n    } else {\n      // Estimate point resolution by transforming the center pixel to EPSG:4326,\n      // measuring its width and height on the normal sphere, and taking the\n      // average of the width and height.\n      var toEPSG4326 = ol.proj.getTransformFromProjections(projection, ol.proj.get('EPSG:4326'));\n      var vertices = [\n        point[0] - resolution / 2, point[1],\n        point[0] + resolution / 2, point[1],\n        point[0], point[1] - resolution / 2,\n        point[0], point[1] + resolution / 2\n      ];\n      vertices = toEPSG4326(vertices, vertices, 2);\n      var width = ol.sphere.NORMAL.haversineDistance(\n          vertices.slice(0, 2), vertices.slice(2, 4));\n      var height = ol.sphere.NORMAL.haversineDistance(\n          vertices.slice(4, 6), vertices.slice(6, 8));\n      pointResolution = (width + height) / 2;\n      var metersPerUnit = projection.getMetersPerUnit();\n      if (metersPerUnit !== undefined) {\n        pointResolution /= metersPerUnit;\n      }\n    }\n  }\n  return pointResolution;\n};\n\n\n/**\n * Registers transformation functions that don't alter coordinates. Those allow\n * to transform between projections with equal meaning.\n *\n * @param {Array.<ol.proj.Projection>} projections Projections.\n * @api\n */\nol.proj.addEquivalentProjections = function(projections) {\n  ol.proj.addProjections(projections);\n  projections.forEach(function(source) {\n    projections.forEach(function(destination) {\n      if (source !== destination) {\n        ol.proj.transforms.add(source, destination, ol.proj.cloneTransform);\n      }\n    });\n  });\n};\n\n\n/**\n * Registers transformation functions to convert coordinates in any projection\n * in projection1 to any projection in projection2.\n *\n * @param {Array.<ol.proj.Projection>} projections1 Projections with equal\n *     meaning.\n * @param {Array.<ol.proj.Projection>} projections2 Projections with equal\n *     meaning.\n * @param {ol.TransformFunction} forwardTransform Transformation from any\n *   projection in projection1 to any projection in projection2.\n * @param {ol.TransformFunction} inverseTransform Transform from any projection\n *   in projection2 to any projection in projection1..\n */\nol.proj.addEquivalentTransforms = function(projections1, projections2, forwardTransform, inverseTransform) {\n  projections1.forEach(function(projection1) {\n    projections2.forEach(function(projection2) {\n      ol.proj.transforms.add(projection1, projection2, forwardTransform);\n      ol.proj.transforms.add(projection2, projection1, inverseTransform);\n    });\n  });\n};\n\n\n/**\n * Add a Projection object to the list of supported projections that can be\n * looked up by their code.\n *\n * @param {ol.proj.Projection} projection Projection instance.\n * @api stable\n */\nol.proj.addProjection = function(projection) {\n  ol.proj.projections.add(projection.getCode(), projection);\n  ol.proj.transforms.add(projection, projection, ol.proj.cloneTransform);\n};\n\n\n/**\n * @param {Array.<ol.proj.Projection>} projections Projections.\n */\nol.proj.addProjections = function(projections) {\n  var addedProjections = [];\n  projections.forEach(function(projection) {\n    addedProjections.push(ol.proj.addProjection(projection));\n  });\n};\n\n\n/**\n * Clear all cached projections and transforms.\n */\nol.proj.clearAllProjections = function() {\n  ol.proj.projections.clear();\n  ol.proj.transforms.clear();\n};\n\n\n/**\n * @param {ol.proj.Projection|string|undefined} projection Projection.\n * @param {string} defaultCode Default code.\n * @return {ol.proj.Projection} Projection.\n */\nol.proj.createProjection = function(projection, defaultCode) {\n  if (!projection) {\n    return ol.proj.get(defaultCode);\n  } else if (typeof projection === 'string') {\n    return ol.proj.get(projection);\n  } else {\n    return /** @type {ol.proj.Projection} */ (projection);\n  }\n};\n\n\n/**\n * Registers coordinate transform functions to convert coordinates between the\n * source projection and the destination projection.\n * The forward and inverse functions convert coordinate pairs; this function\n * converts these into the functions used internally which also handle\n * extents and coordinate arrays.\n *\n * @param {ol.ProjectionLike} source Source projection.\n * @param {ol.ProjectionLike} destination Destination projection.\n * @param {function(ol.Coordinate): ol.Coordinate} forward The forward transform\n *     function (that is, from the source projection to the destination\n *     projection) that takes a {@link ol.Coordinate} as argument and returns\n *     the transformed {@link ol.Coordinate}.\n * @param {function(ol.Coordinate): ol.Coordinate} inverse The inverse transform\n *     function (that is, from the destination projection to the source\n *     projection) that takes a {@link ol.Coordinate} as argument and returns\n *     the transformed {@link ol.Coordinate}.\n * @api stable\n */\nol.proj.addCoordinateTransforms = function(source, destination, forward, inverse) {\n  var sourceProj = ol.proj.get(source);\n  var destProj = ol.proj.get(destination);\n  ol.proj.transforms.add(sourceProj, destProj,\n      ol.proj.createTransformFromCoordinateTransform(forward));\n  ol.proj.transforms.add(destProj, sourceProj,\n      ol.proj.createTransformFromCoordinateTransform(inverse));\n};\n\n\n/**\n * Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform\n * function.\n * @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate\n *     transform.\n * @return {ol.TransformFunction} Transform function.\n */\nol.proj.createTransformFromCoordinateTransform = function(transform) {\n  return (\n      /**\n       * @param {Array.<number>} input Input.\n       * @param {Array.<number>=} opt_output Output.\n       * @param {number=} opt_dimension Dimension.\n       * @return {Array.<number>} Output.\n       */\n      function(input, opt_output, opt_dimension) {\n        var length = input.length;\n        var dimension = opt_dimension !== undefined ? opt_dimension : 2;\n        var output = opt_output !== undefined ? opt_output : new Array(length);\n        var point, i, j;\n        for (i = 0; i < length; i += dimension) {\n          point = transform([input[i], input[i + 1]]);\n          output[i] = point[0];\n          output[i + 1] = point[1];\n          for (j = dimension - 1; j >= 2; --j) {\n            output[i + j] = input[i + j];\n          }\n        }\n        return output;\n      });\n};\n\n\n/**\n * Transforms a coordinate from longitude/latitude to a different projection.\n * @param {ol.Coordinate} coordinate Coordinate as longitude and latitude, i.e.\n *     an array with longitude as 1st and latitude as 2nd element.\n * @param {ol.ProjectionLike=} opt_projection Target projection. The\n *     default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {ol.Coordinate} Coordinate projected to the target projection.\n * @api stable\n */\nol.proj.fromLonLat = function(coordinate, opt_projection) {\n  return ol.proj.transform(coordinate, 'EPSG:4326',\n      opt_projection !== undefined ? opt_projection : 'EPSG:3857');\n};\n\n\n/**\n * Transforms a coordinate to longitude/latitude.\n * @param {ol.Coordinate} coordinate Projected coordinate.\n * @param {ol.ProjectionLike=} opt_projection Projection of the coordinate.\n *     The default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {ol.Coordinate} Coordinate as longitude and latitude, i.e. an array\n *     with longitude as 1st and latitude as 2nd element.\n * @api stable\n */\nol.proj.toLonLat = function(coordinate, opt_projection) {\n  return ol.proj.transform(coordinate,\n      opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326');\n};\n\n\n/**\n * Fetches a Projection object for the code specified.\n *\n * @param {ol.ProjectionLike} projectionLike Either a code string which is\n *     a combination of authority and identifier such as \"EPSG:4326\", or an\n *     existing projection object, or undefined.\n * @return {ol.proj.Projection} Projection object, or null if not in list.\n * @api stable\n */\nol.proj.get = function(projectionLike) {\n  var projection = null;\n  if (projectionLike instanceof ol.proj.Projection) {\n    projection = projectionLike;\n  } else if (typeof projectionLike === 'string') {\n    var code = projectionLike;\n    projection = ol.proj.projections.get(code);\n    if (ol.ENABLE_PROJ4JS) {\n      var proj4js = ol.proj.proj4.get();\n      if (!projection && typeof proj4js == 'function' &&\n          proj4js.defs(code) !== undefined) {\n        projection = new ol.proj.Projection({code: code});\n        ol.proj.addProjection(projection);\n      }\n    }\n  }\n  return projection;\n};\n\n\n/**\n * Checks if two projections are the same, that is every coordinate in one\n * projection does represent the same geographic point as the same coordinate in\n * the other projection.\n *\n * @param {ol.proj.Projection} projection1 Projection 1.\n * @param {ol.proj.Projection} projection2 Projection 2.\n * @return {boolean} Equivalent.\n * @api\n */\nol.proj.equivalent = function(projection1, projection2) {\n  if (projection1 === projection2) {\n    return true;\n  }\n  var equalUnits = projection1.getUnits() === projection2.getUnits();\n  if (projection1.getCode() === projection2.getCode()) {\n    return equalUnits;\n  } else {\n    var transformFn = ol.proj.getTransformFromProjections(\n        projection1, projection2);\n    return transformFn === ol.proj.cloneTransform && equalUnits;\n  }\n};\n\n\n/**\n * Given the projection-like objects, searches for a transformation\n * function to convert a coordinates array from the source projection to the\n * destination projection.\n *\n * @param {ol.ProjectionLike} source Source.\n * @param {ol.ProjectionLike} destination Destination.\n * @return {ol.TransformFunction} Transform function.\n * @api stable\n */\nol.proj.getTransform = function(source, destination) {\n  var sourceProjection = ol.proj.get(source);\n  var destinationProjection = ol.proj.get(destination);\n  return ol.proj.getTransformFromProjections(\n      sourceProjection, destinationProjection);\n};\n\n\n/**\n * Searches in the list of transform functions for the function for converting\n * coordinates from the source projection to the destination projection.\n *\n * @param {ol.proj.Projection} sourceProjection Source Projection object.\n * @param {ol.proj.Projection} destinationProjection Destination Projection\n *     object.\n * @return {ol.TransformFunction} Transform function.\n */\nol.proj.getTransformFromProjections = function(sourceProjection, destinationProjection) {\n  var sourceCode = sourceProjection.getCode();\n  var destinationCode = destinationProjection.getCode();\n  var transform = ol.proj.transforms.get(sourceCode, destinationCode);\n  if (ol.ENABLE_PROJ4JS && !transform) {\n    var proj4js = ol.proj.proj4.get();\n    if (typeof proj4js == 'function') {\n      var sourceDef = proj4js.defs(sourceCode);\n      var destinationDef = proj4js.defs(destinationCode);\n\n      if (sourceDef !== undefined && destinationDef !== undefined) {\n        if (sourceDef === destinationDef) {\n          ol.proj.addEquivalentProjections([destinationProjection, sourceProjection]);\n        } else {\n          var proj4Transform = proj4js(destinationCode, sourceCode);\n          ol.proj.addCoordinateTransforms(destinationProjection, sourceProjection,\n              proj4Transform.forward, proj4Transform.inverse);\n        }\n        transform = ol.proj.transforms.get(sourceCode, destinationCode);\n      }\n    }\n  }\n  if (!transform) {\n    ol.DEBUG && console.assert(transform, 'transform should be defined');\n    transform = ol.proj.identityTransform;\n  }\n  return transform;\n};\n\n\n/**\n * @param {Array.<number>} input Input coordinate array.\n * @param {Array.<number>=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension.\n * @return {Array.<number>} Input coordinate array (same array as input).\n */\nol.proj.identityTransform = function(input, opt_output, opt_dimension) {\n  if (opt_output !== undefined && input !== opt_output) {\n    // TODO: consider making this a warning instead\n    ol.DEBUG && console.assert(false, 'This should not be used internally.');\n    for (var i = 0, ii = input.length; i < ii; ++i) {\n      opt_output[i] = input[i];\n    }\n    input = opt_output;\n  }\n  return input;\n};\n\n\n/**\n * @param {Array.<number>} input Input coordinate array.\n * @param {Array.<number>=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension.\n * @return {Array.<number>} Output coordinate array (new array, same coordinate\n *     values).\n */\nol.proj.cloneTransform = function(input, opt_output, opt_dimension) {\n  var output;\n  if (opt_output !== undefined) {\n    for (var i = 0, ii = input.length; i < ii; ++i) {\n      opt_output[i] = input[i];\n    }\n    output = opt_output;\n  } else {\n    output = input.slice();\n  }\n  return output;\n};\n\n\n/**\n * Transforms a coordinate from source projection to destination projection.\n * This returns a new coordinate (and does not modify the original).\n *\n * See {@link ol.proj.transformExtent} for extent transformation.\n * See the transform method of {@link ol.geom.Geometry} and its subclasses for\n * geometry transforms.\n *\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {ol.ProjectionLike} source Source projection-like.\n * @param {ol.ProjectionLike} destination Destination projection-like.\n * @return {ol.Coordinate} Coordinate.\n * @api stable\n */\nol.proj.transform = function(coordinate, source, destination) {\n  var transformFn = ol.proj.getTransform(source, destination);\n  return transformFn(coordinate, undefined, coordinate.length);\n};\n\n\n/**\n * Transforms an extent from source projection to destination projection.  This\n * returns a new extent (and does not modify the original).\n *\n * @param {ol.Extent} extent The extent to transform.\n * @param {ol.ProjectionLike} source Source projection-like.\n * @param {ol.ProjectionLike} destination Destination projection-like.\n * @return {ol.Extent} The transformed extent.\n * @api stable\n */\nol.proj.transformExtent = function(extent, source, destination) {\n  var transformFn = ol.proj.getTransform(source, destination);\n  return ol.extent.applyTransform(extent, transformFn);\n};\n\n\n/**\n * Transforms the given point to the destination projection.\n *\n * @param {ol.Coordinate} point Point.\n * @param {ol.proj.Projection} sourceProjection Source projection.\n * @param {ol.proj.Projection} destinationProjection Destination projection.\n * @return {ol.Coordinate} Point.\n */\nol.proj.transformWithProjections = function(point, sourceProjection, destinationProjection) {\n  var transformFn = ol.proj.getTransformFromProjections(\n      sourceProjection, destinationProjection);\n  return transformFn(point);\n};\n\ngoog.provide('ol.geom.Geometry');\n\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.extent');\ngoog.require('ol.functions');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Units');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for vector geometries.\n *\n * To get notified of changes to the geometry, register a listener for the\n * generic `change` event on your geometry instance.\n *\n * @constructor\n * @extends {ol.Object}\n * @api stable\n */\nol.geom.Geometry = function() {\n\n  ol.Object.call(this);\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.extent_ = ol.extent.createEmpty();\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.extentRevision_ = -1;\n\n  /**\n   * @protected\n   * @type {Object.<string, ol.geom.Geometry>}\n   */\n  this.simplifiedGeometryCache = {};\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.simplifiedGeometryRevision = 0;\n\n};\nol.inherits(ol.geom.Geometry, ol.Object);\n\n\n/**\n * Make a complete copy of the geometry.\n * @abstract\n * @return {!ol.geom.Geometry} Clone.\n */\nol.geom.Geometry.prototype.clone = function() {};\n\n\n/**\n * @abstract\n * @param {number} x X.\n * @param {number} y Y.\n * @param {ol.Coordinate} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @return {number} Minimum squared distance.\n */\nol.geom.Geometry.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {};\n\n\n/**\n * Return the closest point of the geometry to the passed point as\n * {@link ol.Coordinate coordinate}.\n * @param {ol.Coordinate} point Point.\n * @param {ol.Coordinate=} opt_closestPoint Closest point.\n * @return {ol.Coordinate} Closest point.\n * @api stable\n */\nol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) {\n  var closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN];\n  this.closestPointXY(point[0], point[1], closestPoint, Infinity);\n  return closestPoint;\n};\n\n\n/**\n * Returns true if this geometry includes the specified coordinate. If the\n * coordinate is on the boundary of the geometry, returns false.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @return {boolean} Contains coordinate.\n * @api\n */\nol.geom.Geometry.prototype.intersectsCoordinate = function(coordinate) {\n  return this.containsXY(coordinate[0], coordinate[1]);\n};\n\n\n/**\n * @abstract\n * @param {ol.Extent} extent Extent.\n * @protected\n * @return {ol.Extent} extent Extent.\n */\nol.geom.Geometry.prototype.computeExtent = function(extent) {};\n\n\n/**\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nol.geom.Geometry.prototype.containsXY = ol.functions.FALSE;\n\n\n/**\n * Get the extent of the geometry.\n * @param {ol.Extent=} opt_extent Extent.\n * @return {ol.Extent} extent Extent.\n * @api stable\n */\nol.geom.Geometry.prototype.getExtent = function(opt_extent) {\n  if (this.extentRevision_ != this.getRevision()) {\n    this.extent_ = this.computeExtent(this.extent_);\n    this.extentRevision_ = this.getRevision();\n  }\n  return ol.extent.returnOrUpdate(this.extent_, opt_extent);\n};\n\n\n/**\n * Rotate the geometry around a given coordinate. This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} angle Rotation angle in radians.\n * @param {ol.Coordinate} anchor The rotation center.\n * @api\n */\nol.geom.Geometry.prototype.rotate = function(angle, anchor) {};\n\n\n/**\n * Scale the geometry (with an optional origin).  This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} sx The scaling factor in the x-direction.\n * @param {number=} opt_sy The scaling factor in the y-direction (defaults to\n *     sx).\n * @param {ol.Coordinate=} opt_anchor The scale origin (defaults to the center\n *     of the geometry extent).\n * @api\n */\nol.geom.Geometry.prototype.scale = function(sx, opt_sy, opt_anchor) {};\n\n\n/**\n * Create a simplified version of this geometry.  For linestrings, this uses\n * the the {@link\n * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm\n * Douglas Peucker} algorithm.  For polygons, a quantization-based\n * simplification is used to preserve topology.\n * @function\n * @param {number} tolerance The tolerance distance for simplification.\n * @return {ol.geom.Geometry} A new, simplified version of the original\n *     geometry.\n * @api\n */\nol.geom.Geometry.prototype.simplify = function(tolerance) {\n  return this.getSimplifiedGeometry(tolerance * tolerance);\n};\n\n\n/**\n * Create a simplified version of this geometry using the Douglas Peucker\n * algorithm.\n * @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm\n * @abstract\n * @param {number} squaredTolerance Squared tolerance.\n * @return {ol.geom.Geometry} Simplified geometry.\n */\nol.geom.Geometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {};\n\n\n/**\n * Get the type of this geometry.\n * @abstract\n * @return {ol.geom.GeometryType} Geometry type.\n */\nol.geom.Geometry.prototype.getType = function() {};\n\n\n/**\n * Apply a transform function to each coordinate of the geometry.\n * The geometry is modified in place.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n * @abstract\n * @param {ol.TransformFunction} transformFn Transform.\n */\nol.geom.Geometry.prototype.applyTransform = function(transformFn) {};\n\n\n/**\n * Test if the geometry and the passed extent intersect.\n * @abstract\n * @param {ol.Extent} extent Extent.\n * @return {boolean} `true` if the geometry and the extent intersect.\n */\nol.geom.Geometry.prototype.intersectsExtent = function(extent) {};\n\n\n/**\n * Translate the geometry.  This modifies the geometry coordinates in place.  If\n * instead you want a new geometry, first `clone()` this geometry.\n * @abstract\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n */\nol.geom.Geometry.prototype.translate = function(deltaX, deltaY) {};\n\n\n/**\n * Transform each coordinate of the geometry from one coordinate reference\n * system to another. The geometry is modified in place.\n * For example, a line will be transformed to a line and a circle to a circle.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n *\n * @param {ol.ProjectionLike} source The current projection.  Can be a\n *     string identifier or a {@link ol.proj.Projection} object.\n * @param {ol.ProjectionLike} destination The desired projection.  Can be a\n *     string identifier or a {@link ol.proj.Projection} object.\n * @return {ol.geom.Geometry} This geometry.  Note that original geometry is\n *     modified in place.\n * @api stable\n */\nol.geom.Geometry.prototype.transform = function(source, destination) {\n  ol.DEBUG && console.assert(\n      ol.proj.get(source).getUnits() !== ol.proj.Units.TILE_PIXELS &&\n      ol.proj.get(destination).getUnits() !== ol.proj.Units.TILE_PIXELS,\n      'cannot transform geometries with TILE_PIXELS units');\n  this.applyTransform(ol.proj.getTransform(source, destination));\n  return this;\n};\n\ngoog.provide('ol.geom.flat.transform');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {ol.Transform} transform Transform.\n * @param {Array.<number>=} opt_dest Destination.\n * @return {Array.<number>} Transformed coordinates.\n */\nol.geom.flat.transform.transform2D = function(flatCoordinates, offset, end, stride, transform, opt_dest) {\n  var dest = opt_dest ? opt_dest : [];\n  var i = 0;\n  var j;\n  for (j = offset; j < end; j += stride) {\n    var x = flatCoordinates[j];\n    var y = flatCoordinates[j + 1];\n    dest[i++] = transform[0] * x + transform[2] * y + transform[4];\n    dest[i++] = transform[1] * x + transform[3] * y + transform[5];\n  }\n  if (opt_dest && dest.length != i) {\n    dest.length = i;\n  }\n  return dest;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} angle Angle.\n * @param {Array.<number>} anchor Rotation anchor point.\n * @param {Array.<number>=} opt_dest Destination.\n * @return {Array.<number>} Transformed coordinates.\n */\nol.geom.flat.transform.rotate = function(flatCoordinates, offset, end, stride, angle, anchor, opt_dest) {\n  var dest = opt_dest ? opt_dest : [];\n  var cos = Math.cos(angle);\n  var sin = Math.sin(angle);\n  var anchorX = anchor[0];\n  var anchorY = anchor[1];\n  var i = 0;\n  for (var j = offset; j < end; j += stride) {\n    var deltaX = flatCoordinates[j] - anchorX;\n    var deltaY = flatCoordinates[j + 1] - anchorY;\n    dest[i++] = anchorX + deltaX * cos - deltaY * sin;\n    dest[i++] = anchorY + deltaX * sin + deltaY * cos;\n    for (var k = j + 2; k < j + stride; ++k) {\n      dest[i++] = flatCoordinates[k];\n    }\n  }\n  if (opt_dest && dest.length != i) {\n    dest.length = i;\n  }\n  return dest;\n};\n\n\n/**\n * Scale the coordinates.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} sx Scale factor in the x-direction.\n * @param {number} sy Scale factor in the y-direction.\n * @param {Array.<number>} anchor Scale anchor point.\n * @param {Array.<number>=} opt_dest Destination.\n * @return {Array.<number>} Transformed coordinates.\n */\nol.geom.flat.transform.scale = function(flatCoordinates, offset, end, stride, sx, sy, anchor, opt_dest) {\n  var dest = opt_dest ? opt_dest : [];\n  var anchorX = anchor[0];\n  var anchorY = anchor[1];\n  var i = 0;\n  for (var j = offset; j < end; j += stride) {\n    var deltaX = flatCoordinates[j] - anchorX;\n    var deltaY = flatCoordinates[j + 1] - anchorY;\n    dest[i++] = anchorX + sx * deltaX;\n    dest[i++] = anchorY + sy * deltaY;\n    for (var k = j + 2; k < j + stride; ++k) {\n      dest[i++] = flatCoordinates[k];\n    }\n  }\n  if (opt_dest && dest.length != i) {\n    dest.length = i;\n  }\n  return dest;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @param {Array.<number>=} opt_dest Destination.\n * @return {Array.<number>} Transformed coordinates.\n */\nol.geom.flat.transform.translate = function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) {\n  var dest = opt_dest ? opt_dest : [];\n  var i = 0;\n  var j, k;\n  for (j = offset; j < end; j += stride) {\n    dest[i++] = flatCoordinates[j] + deltaX;\n    dest[i++] = flatCoordinates[j + 1] + deltaY;\n    for (k = j + 2; k < j + stride; ++k) {\n      dest[i++] = flatCoordinates[k];\n    }\n  }\n  if (opt_dest && dest.length != i) {\n    dest.length = i;\n  }\n  return dest;\n};\n\ngoog.provide('ol.geom.SimpleGeometry');\n\ngoog.require('ol');\ngoog.require('ol.functions');\ngoog.require('ol.extent');\ngoog.require('ol.geom.Geometry');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.flat.transform');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * Abstract base class; only used for creating subclasses; do not instantiate\n * in apps, as cannot be rendered.\n *\n * @constructor\n * @extends {ol.geom.Geometry}\n * @api stable\n */\nol.geom.SimpleGeometry = function() {\n\n  ol.geom.Geometry.call(this);\n\n  /**\n   * @protected\n   * @type {ol.geom.GeometryLayout}\n   */\n  this.layout = ol.geom.GeometryLayout.XY;\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.stride = 2;\n\n  /**\n   * @protected\n   * @type {Array.<number>}\n   */\n  this.flatCoordinates = null;\n\n};\nol.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry);\n\n\n/**\n * @param {number} stride Stride.\n * @private\n * @return {ol.geom.GeometryLayout} layout Layout.\n */\nol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) {\n  var layout;\n  if (stride == 2) {\n    layout = ol.geom.GeometryLayout.XY;\n  } else if (stride == 3) {\n    layout = ol.geom.GeometryLayout.XYZ;\n  } else if (stride == 4) {\n    layout = ol.geom.GeometryLayout.XYZM;\n  }\n  ol.DEBUG && console.assert(layout, 'unsupported stride: ' + stride);\n  return /** @type {ol.geom.GeometryLayout} */ (layout);\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @return {number} Stride.\n */\nol.geom.SimpleGeometry.getStrideForLayout = function(layout) {\n  var stride;\n  if (layout == ol.geom.GeometryLayout.XY) {\n    stride = 2;\n  } else if (layout == ol.geom.GeometryLayout.XYZ || layout == ol.geom.GeometryLayout.XYM) {\n    stride = 3;\n  } else if (layout == ol.geom.GeometryLayout.XYZM) {\n    stride = 4;\n  }\n  ol.DEBUG && console.assert(stride, 'unsupported layout: ' + layout);\n  return /** @type {number} */ (stride);\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.SimpleGeometry.prototype.containsXY = ol.functions.FALSE;\n\n\n/**\n * @inheritDoc\n */\nol.geom.SimpleGeometry.prototype.computeExtent = function(extent) {\n  return ol.extent.createOrUpdateFromFlatCoordinates(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n      extent);\n};\n\n\n/**\n * @abstract\n * @return {Array} Coordinates.\n */\nol.geom.SimpleGeometry.prototype.getCoordinates = function() {};\n\n\n/**\n * Return the first coordinate of the geometry.\n * @return {ol.Coordinate} First coordinate.\n * @api stable\n */\nol.geom.SimpleGeometry.prototype.getFirstCoordinate = function() {\n  return this.flatCoordinates.slice(0, this.stride);\n};\n\n\n/**\n * @return {Array.<number>} Flat coordinates.\n */\nol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() {\n  return this.flatCoordinates;\n};\n\n\n/**\n * Return the last coordinate of the geometry.\n * @return {ol.Coordinate} Last point.\n * @api stable\n */\nol.geom.SimpleGeometry.prototype.getLastCoordinate = function() {\n  return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);\n};\n\n\n/**\n * Return the {@link ol.geom.GeometryLayout layout} of the geometry.\n * @return {ol.geom.GeometryLayout} Layout.\n * @api stable\n */\nol.geom.SimpleGeometry.prototype.getLayout = function() {\n  return this.layout;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.SimpleGeometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {\n  if (this.simplifiedGeometryRevision != this.getRevision()) {\n    ol.obj.clear(this.simplifiedGeometryCache);\n    this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n    this.simplifiedGeometryRevision = this.getRevision();\n  }\n  // If squaredTolerance is negative or if we know that simplification will not\n  // have any effect then just return this.\n  if (squaredTolerance < 0 ||\n      (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&\n       squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {\n    return this;\n  }\n  var key = squaredTolerance.toString();\n  if (this.simplifiedGeometryCache.hasOwnProperty(key)) {\n    return this.simplifiedGeometryCache[key];\n  } else {\n    var simplifiedGeometry =\n        this.getSimplifiedGeometryInternal(squaredTolerance);\n    var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();\n    if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {\n      this.simplifiedGeometryCache[key] = simplifiedGeometry;\n      return simplifiedGeometry;\n    } else {\n      // Simplification did not actually remove any coordinates.  We now know\n      // that any calls to getSimplifiedGeometry with a squaredTolerance less\n      // than or equal to the current squaredTolerance will also not have any\n      // effect.  This allows us to short circuit simplification (saving CPU\n      // cycles) and prevents the cache of simplified geometries from filling\n      // up with useless identical copies of this geometry (saving memory).\n      this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;\n      return this;\n    }\n  }\n};\n\n\n/**\n * @param {number} squaredTolerance Squared tolerance.\n * @return {ol.geom.SimpleGeometry} Simplified geometry.\n * @protected\n */\nol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n  return this;\n};\n\n\n/**\n * @return {number} Stride.\n */\nol.geom.SimpleGeometry.prototype.getStride = function() {\n  return this.stride;\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @protected\n */\nol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal = function(layout, flatCoordinates) {\n  this.stride = ol.geom.SimpleGeometry.getStrideForLayout(layout);\n  this.layout = layout;\n  this.flatCoordinates = flatCoordinates;\n};\n\n\n/**\n * @abstract\n * @param {Array} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n */\nol.geom.SimpleGeometry.prototype.setCoordinates = function(coordinates, opt_layout) {};\n\n\n/**\n * @param {ol.geom.GeometryLayout|undefined} layout Layout.\n * @param {Array} coordinates Coordinates.\n * @param {number} nesting Nesting.\n * @protected\n */\nol.geom.SimpleGeometry.prototype.setLayout = function(layout, coordinates, nesting) {\n  /** @type {number} */\n  var stride;\n  if (layout) {\n    stride = ol.geom.SimpleGeometry.getStrideForLayout(layout);\n  } else {\n    var i;\n    for (i = 0; i < nesting; ++i) {\n      if (coordinates.length === 0) {\n        this.layout = ol.geom.GeometryLayout.XY;\n        this.stride = 2;\n        return;\n      } else {\n        coordinates = /** @type {Array} */ (coordinates[0]);\n      }\n    }\n    stride = coordinates.length;\n    layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride);\n  }\n  this.layout = layout;\n  this.stride = stride;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) {\n  if (this.flatCoordinates) {\n    transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);\n    this.changed();\n  }\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.geom.SimpleGeometry.prototype.rotate = function(angle, anchor) {\n  var flatCoordinates = this.getFlatCoordinates();\n  if (flatCoordinates) {\n    var stride = this.getStride();\n    ol.geom.flat.transform.rotate(\n        flatCoordinates, 0, flatCoordinates.length,\n        stride, angle, anchor, flatCoordinates);\n    this.changed();\n  }\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.geom.SimpleGeometry.prototype.scale = function(sx, opt_sy, opt_anchor) {\n  var sy = opt_sy;\n  if (sy === undefined) {\n    sy = sx;\n  }\n  var anchor = opt_anchor;\n  if (!anchor) {\n    anchor = ol.extent.getCenter(this.getExtent());\n  }\n  var flatCoordinates = this.getFlatCoordinates();\n  if (flatCoordinates) {\n    var stride = this.getStride();\n    ol.geom.flat.transform.scale(\n        flatCoordinates, 0, flatCoordinates.length,\n        stride, sx, sy, anchor, flatCoordinates);\n    this.changed();\n  }\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) {\n  var flatCoordinates = this.getFlatCoordinates();\n  if (flatCoordinates) {\n    var stride = this.getStride();\n    ol.geom.flat.transform.translate(\n        flatCoordinates, 0, flatCoordinates.length, stride,\n        deltaX, deltaY, flatCoordinates);\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry.\n * @param {ol.Transform} transform Transform.\n * @param {Array.<number>=} opt_dest Destination.\n * @return {Array.<number>} Transformed flat coordinates.\n */\nol.geom.SimpleGeometry.transform2D = function(simpleGeometry, transform, opt_dest) {\n  var flatCoordinates = simpleGeometry.getFlatCoordinates();\n  if (!flatCoordinates) {\n    return null;\n  } else {\n    var stride = simpleGeometry.getStride();\n    return ol.geom.flat.transform.transform2D(\n        flatCoordinates, 0, flatCoordinates.length, stride,\n        transform, opt_dest);\n  }\n};\n\ngoog.provide('ol.geom.flat.area');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nol.geom.flat.area.linearRing = function(flatCoordinates, offset, end, stride) {\n  var twiceArea = 0;\n  var x1 = flatCoordinates[end - stride];\n  var y1 = flatCoordinates[end - stride + 1];\n  for (; offset < end; offset += stride) {\n    var x2 = flatCoordinates[offset];\n    var y2 = flatCoordinates[offset + 1];\n    twiceArea += y1 * x2 - x1 * y2;\n    x1 = x2;\n    y1 = y2;\n  }\n  return twiceArea / 2;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nol.geom.flat.area.linearRings = function(flatCoordinates, offset, ends, stride) {\n  var area = 0;\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    area += ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride);\n    offset = end;\n  }\n  return area;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nol.geom.flat.area.linearRingss = function(flatCoordinates, offset, endss, stride) {\n  var area = 0;\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    area +=\n        ol.geom.flat.area.linearRings(flatCoordinates, offset, ends, stride);\n    offset = ends[ends.length - 1];\n  }\n  return area;\n};\n\ngoog.provide('ol.geom.flat.closest');\n\ngoog.require('ol');\ngoog.require('ol.math');\n\n\n/**\n * Returns the point on the 2D line segment flatCoordinates[offset1] to\n * flatCoordinates[offset2] that is closest to the point (x, y).  Extra\n * dimensions are linearly interpolated.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset1 Offset 1.\n * @param {number} offset2 Offset 2.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.<number>} closestPoint Closest point.\n */\nol.geom.flat.closest.point = function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {\n  var x1 = flatCoordinates[offset1];\n  var y1 = flatCoordinates[offset1 + 1];\n  var dx = flatCoordinates[offset2] - x1;\n  var dy = flatCoordinates[offset2 + 1] - y1;\n  var i, offset;\n  if (dx === 0 && dy === 0) {\n    offset = offset1;\n  } else {\n    var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n    if (t > 1) {\n      offset = offset2;\n    } else if (t > 0) {\n      for (i = 0; i < stride; ++i) {\n        closestPoint[i] = ol.math.lerp(flatCoordinates[offset1 + i],\n            flatCoordinates[offset2 + i], t);\n      }\n      closestPoint.length = stride;\n      return;\n    } else {\n      offset = offset1;\n    }\n  }\n  for (i = 0; i < stride; ++i) {\n    closestPoint[i] = flatCoordinates[offset + i];\n  }\n  closestPoint.length = stride;\n};\n\n\n/**\n * Return the squared of the largest distance between any pair of consecutive\n * coordinates.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} maxSquaredDelta Max squared delta.\n * @return {number} Max squared delta.\n */\nol.geom.flat.closest.getMaxSquaredDelta = function(flatCoordinates, offset, end, stride, maxSquaredDelta) {\n  var x1 = flatCoordinates[offset];\n  var y1 = flatCoordinates[offset + 1];\n  for (offset += stride; offset < end; offset += stride) {\n    var x2 = flatCoordinates[offset];\n    var y2 = flatCoordinates[offset + 1];\n    var squaredDelta = ol.math.squaredDistance(x1, y1, x2, y2);\n    if (squaredDelta > maxSquaredDelta) {\n      maxSquaredDelta = squaredDelta;\n    }\n    x1 = x2;\n    y1 = y2;\n  }\n  return maxSquaredDelta;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {number} maxSquaredDelta Max squared delta.\n * @return {number} Max squared delta.\n */\nol.geom.flat.closest.getsMaxSquaredDelta = function(flatCoordinates, offset, ends, stride, maxSquaredDelta) {\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    maxSquaredDelta = ol.geom.flat.closest.getMaxSquaredDelta(\n        flatCoordinates, offset, end, stride, maxSquaredDelta);\n    offset = end;\n  }\n  return maxSquaredDelta;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} maxSquaredDelta Max squared delta.\n * @return {number} Max squared delta.\n */\nol.geom.flat.closest.getssMaxSquaredDelta = function(flatCoordinates, offset, endss, stride, maxSquaredDelta) {\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    maxSquaredDelta = ol.geom.flat.closest.getsMaxSquaredDelta(\n        flatCoordinates, offset, ends, stride, maxSquaredDelta);\n    offset = ends[ends.length - 1];\n  }\n  return maxSquaredDelta;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.<number>} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array.<number>=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nol.geom.flat.closest.getClosestPoint = function(flatCoordinates, offset, end,\n    stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n    opt_tmpPoint) {\n  if (offset == end) {\n    return minSquaredDistance;\n  }\n  var i, squaredDistance;\n  if (maxDelta === 0) {\n    // All points are identical, so just test the first point.\n    squaredDistance = ol.math.squaredDistance(\n        x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);\n    if (squaredDistance < minSquaredDistance) {\n      for (i = 0; i < stride; ++i) {\n        closestPoint[i] = flatCoordinates[offset + i];\n      }\n      closestPoint.length = stride;\n      return squaredDistance;\n    } else {\n      return minSquaredDistance;\n    }\n  }\n  ol.DEBUG && console.assert(maxDelta > 0, 'maxDelta should be larger than 0');\n  var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n  var index = offset + stride;\n  while (index < end) {\n    ol.geom.flat.closest.point(\n        flatCoordinates, index - stride, index, stride, x, y, tmpPoint);\n    squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);\n    if (squaredDistance < minSquaredDistance) {\n      minSquaredDistance = squaredDistance;\n      for (i = 0; i < stride; ++i) {\n        closestPoint[i] = tmpPoint[i];\n      }\n      closestPoint.length = stride;\n      index += stride;\n    } else {\n      // Skip ahead multiple points, because we know that all the skipped\n      // points cannot be any closer than the closest point we have found so\n      // far.  We know this because we know how close the current point is, how\n      // close the closest point we have found so far is, and the maximum\n      // distance between consecutive points.  For example, if we're currently\n      // at distance 10, the best we've found so far is 3, and that the maximum\n      // distance between consecutive points is 2, then we'll need to skip at\n      // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of\n      // finding a closer point.  We use Math.max(..., 1) to ensure that we\n      // always advance at least one point, to avoid an infinite loop.\n      index += stride * Math.max(\n          ((Math.sqrt(squaredDistance) -\n            Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1);\n    }\n  }\n  if (isRing) {\n    // Check the closing segment.\n    ol.geom.flat.closest.point(\n        flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);\n    squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);\n    if (squaredDistance < minSquaredDistance) {\n      minSquaredDistance = squaredDistance;\n      for (i = 0; i < stride; ++i) {\n        closestPoint[i] = tmpPoint[i];\n      }\n      closestPoint.length = stride;\n    }\n  }\n  return minSquaredDistance;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.<number>} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array.<number>=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nol.geom.flat.closest.getsClosestPoint = function(flatCoordinates, offset, ends,\n    stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n    opt_tmpPoint) {\n  var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    minSquaredDistance = ol.geom.flat.closest.getClosestPoint(\n        flatCoordinates, offset, end, stride,\n        maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);\n    offset = end;\n  }\n  return minSquaredDistance;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.<number>} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array.<number>=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nol.geom.flat.closest.getssClosestPoint = function(flatCoordinates, offset,\n    endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n    opt_tmpPoint) {\n  var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    minSquaredDistance = ol.geom.flat.closest.getsClosestPoint(\n        flatCoordinates, offset, ends, stride,\n        maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);\n    offset = ends[ends.length - 1];\n  }\n  return minSquaredDistance;\n};\n\ngoog.provide('ol.geom.flat.deflate');\n\ngoog.require('ol');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nol.geom.flat.deflate.coordinate = function(flatCoordinates, offset, coordinate, stride) {\n  ol.DEBUG && console.assert(coordinate.length == stride,\n      'length of the coordinate array should match stride');\n  var i, ii;\n  for (i = 0, ii = coordinate.length; i < ii; ++i) {\n    flatCoordinates[offset++] = coordinate[i];\n  }\n  return offset;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nol.geom.flat.deflate.coordinates = function(flatCoordinates, offset, coordinates, stride) {\n  var i, ii;\n  for (i = 0, ii = coordinates.length; i < ii; ++i) {\n    var coordinate = coordinates[i];\n    ol.DEBUG && console.assert(coordinate.length == stride,\n        'length of coordinate array should match stride');\n    var j;\n    for (j = 0; j < stride; ++j) {\n      flatCoordinates[offset++] = coordinate[j];\n    }\n  }\n  return offset;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<ol.Coordinate>>} coordinatess Coordinatess.\n * @param {number} stride Stride.\n * @param {Array.<number>=} opt_ends Ends.\n * @return {Array.<number>} Ends.\n */\nol.geom.flat.deflate.coordinatess = function(flatCoordinates, offset, coordinatess, stride, opt_ends) {\n  var ends = opt_ends ? opt_ends : [];\n  var i = 0;\n  var j, jj;\n  for (j = 0, jj = coordinatess.length; j < jj; ++j) {\n    var end = ol.geom.flat.deflate.coordinates(\n        flatCoordinates, offset, coordinatess[j], stride);\n    ends[i++] = end;\n    offset = end;\n  }\n  ends.length = i;\n  return ends;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinatesss Coordinatesss.\n * @param {number} stride Stride.\n * @param {Array.<Array.<number>>=} opt_endss Endss.\n * @return {Array.<Array.<number>>} Endss.\n */\nol.geom.flat.deflate.coordinatesss = function(flatCoordinates, offset, coordinatesss, stride, opt_endss) {\n  var endss = opt_endss ? opt_endss : [];\n  var i = 0;\n  var j, jj;\n  for (j = 0, jj = coordinatesss.length; j < jj; ++j) {\n    var ends = ol.geom.flat.deflate.coordinatess(\n        flatCoordinates, offset, coordinatesss[j], stride, endss[i]);\n    endss[i++] = ends;\n    offset = ends[ends.length - 1];\n  }\n  endss.length = i;\n  return endss;\n};\n\ngoog.provide('ol.geom.flat.inflate');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {Array.<ol.Coordinate>=} opt_coordinates Coordinates.\n * @return {Array.<ol.Coordinate>} Coordinates.\n */\nol.geom.flat.inflate.coordinates = function(flatCoordinates, offset, end, stride, opt_coordinates) {\n  var coordinates = opt_coordinates !== undefined ? opt_coordinates : [];\n  var i = 0;\n  var j;\n  for (j = offset; j < end; j += stride) {\n    coordinates[i++] = flatCoordinates.slice(j, j + stride);\n  }\n  coordinates.length = i;\n  return coordinates;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {Array.<Array.<ol.Coordinate>>=} opt_coordinatess Coordinatess.\n * @return {Array.<Array.<ol.Coordinate>>} Coordinatess.\n */\nol.geom.flat.inflate.coordinatess = function(flatCoordinates, offset, ends, stride, opt_coordinatess) {\n  var coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : [];\n  var i = 0;\n  var j, jj;\n  for (j = 0, jj = ends.length; j < jj; ++j) {\n    var end = ends[j];\n    coordinatess[i++] = ol.geom.flat.inflate.coordinates(\n        flatCoordinates, offset, end, stride, coordinatess[i]);\n    offset = end;\n  }\n  coordinatess.length = i;\n  return coordinatess;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array.<Array.<Array.<ol.Coordinate>>>=} opt_coordinatesss\n *     Coordinatesss.\n * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinatesss.\n */\nol.geom.flat.inflate.coordinatesss = function(flatCoordinates, offset, endss, stride, opt_coordinatesss) {\n  var coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : [];\n  var i = 0;\n  var j, jj;\n  for (j = 0, jj = endss.length; j < jj; ++j) {\n    var ends = endss[j];\n    coordinatesss[i++] = ol.geom.flat.inflate.coordinatess(\n        flatCoordinates, offset, ends, stride, coordinatesss[i]);\n    offset = ends[ends.length - 1];\n  }\n  coordinatesss.length = i;\n  return coordinatesss;\n};\n\n// Based on simplify-js https://github.com/mourner/simplify-js\n// Copyright (c) 2012, Vladimir Agafonkin\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n//\n//    1. Redistributions of source code must retain the above copyright notice,\n//       this list of conditions and the following disclaimer.\n//\n//    2. Redistributions in binary form must reproduce the above copyright\n//       notice, this list of conditions and the following disclaimer in the\n//       documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n// POSSIBILITY OF SUCH DAMAGE.\n\ngoog.provide('ol.geom.flat.simplify');\n\ngoog.require('ol.math');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {boolean} highQuality Highest quality.\n * @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @return {Array.<number>} Simplified line string.\n */\nol.geom.flat.simplify.lineString = function(flatCoordinates, offset, end,\n    stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) {\n  var simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ?\n      opt_simplifiedFlatCoordinates : [];\n  if (!highQuality) {\n    end = ol.geom.flat.simplify.radialDistance(flatCoordinates, offset, end,\n        stride, squaredTolerance,\n        simplifiedFlatCoordinates, 0);\n    flatCoordinates = simplifiedFlatCoordinates;\n    offset = 0;\n    stride = 2;\n  }\n  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(\n      flatCoordinates, offset, end, stride, squaredTolerance,\n      simplifiedFlatCoordinates, 0);\n  return simplifiedFlatCoordinates;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nol.geom.flat.simplify.douglasPeucker = function(flatCoordinates, offset, end,\n    stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n  var n = (end - offset) / stride;\n  if (n < 3) {\n    for (; offset < end; offset += stride) {\n      simplifiedFlatCoordinates[simplifiedOffset++] =\n          flatCoordinates[offset];\n      simplifiedFlatCoordinates[simplifiedOffset++] =\n          flatCoordinates[offset + 1];\n    }\n    return simplifiedOffset;\n  }\n  /** @type {Array.<number>} */\n  var markers = new Array(n);\n  markers[0] = 1;\n  markers[n - 1] = 1;\n  /** @type {Array.<number>} */\n  var stack = [offset, end - stride];\n  var index = 0;\n  var i;\n  while (stack.length > 0) {\n    var last = stack.pop();\n    var first = stack.pop();\n    var maxSquaredDistance = 0;\n    var x1 = flatCoordinates[first];\n    var y1 = flatCoordinates[first + 1];\n    var x2 = flatCoordinates[last];\n    var y2 = flatCoordinates[last + 1];\n    for (i = first + stride; i < last; i += stride) {\n      var x = flatCoordinates[i];\n      var y = flatCoordinates[i + 1];\n      var squaredDistance = ol.math.squaredSegmentDistance(\n          x, y, x1, y1, x2, y2);\n      if (squaredDistance > maxSquaredDistance) {\n        index = i;\n        maxSquaredDistance = squaredDistance;\n      }\n    }\n    if (maxSquaredDistance > squaredTolerance) {\n      markers[(index - offset) / stride] = 1;\n      if (first + stride < index) {\n        stack.push(first, index);\n      }\n      if (index + stride < last) {\n        stack.push(index, last);\n      }\n    }\n  }\n  for (i = 0; i < n; ++i) {\n    if (markers[i]) {\n      simplifiedFlatCoordinates[simplifiedOffset++] =\n          flatCoordinates[offset + i * stride];\n      simplifiedFlatCoordinates[simplifiedOffset++] =\n          flatCoordinates[offset + i * stride + 1];\n    }\n  }\n  return simplifiedOffset;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.<number>} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nol.geom.flat.simplify.douglasPeuckers = function(flatCoordinates, offset,\n    ends, stride, squaredTolerance, simplifiedFlatCoordinates,\n    simplifiedOffset, simplifiedEnds) {\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    simplifiedOffset = ol.geom.flat.simplify.douglasPeucker(\n        flatCoordinates, offset, end, stride, squaredTolerance,\n        simplifiedFlatCoordinates, simplifiedOffset);\n    simplifiedEnds.push(simplifiedOffset);\n    offset = end;\n  }\n  return simplifiedOffset;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nol.geom.flat.simplify.douglasPeuckerss = function(\n    flatCoordinates, offset, endss, stride, squaredTolerance,\n    simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    var simplifiedEnds = [];\n    simplifiedOffset = ol.geom.flat.simplify.douglasPeuckers(\n        flatCoordinates, offset, ends, stride, squaredTolerance,\n        simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);\n    simplifiedEndss.push(simplifiedEnds);\n    offset = ends[ends.length - 1];\n  }\n  return simplifiedOffset;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nol.geom.flat.simplify.radialDistance = function(flatCoordinates, offset, end,\n    stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n  if (end <= offset + stride) {\n    // zero or one point, no simplification possible, so copy and return\n    for (; offset < end; offset += stride) {\n      simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];\n      simplifiedFlatCoordinates[simplifiedOffset++] =\n          flatCoordinates[offset + 1];\n    }\n    return simplifiedOffset;\n  }\n  var x1 = flatCoordinates[offset];\n  var y1 = flatCoordinates[offset + 1];\n  // copy first point\n  simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n  simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n  var x2 = x1;\n  var y2 = y1;\n  for (offset += stride; offset < end; offset += stride) {\n    x2 = flatCoordinates[offset];\n    y2 = flatCoordinates[offset + 1];\n    if (ol.math.squaredDistance(x1, y1, x2, y2) > squaredTolerance) {\n      // copy point at offset\n      simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n      simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n      x1 = x2;\n      y1 = y2;\n    }\n  }\n  if (x2 != x1 || y2 != y1) {\n    // copy last point\n    simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n    simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n  }\n  return simplifiedOffset;\n};\n\n\n/**\n * @param {number} value Value.\n * @param {number} tolerance Tolerance.\n * @return {number} Rounded value.\n */\nol.geom.flat.simplify.snap = function(value, tolerance) {\n  return tolerance * Math.round(value / tolerance);\n};\n\n\n/**\n * Simplifies a line string using an algorithm designed by Tim Schaub.\n * Coordinates are snapped to the nearest value in a virtual grid and\n * consecutive duplicate coordinates are discarded.  This effectively preserves\n * topology as the simplification of any subsection of a line string is\n * independent of the rest of the line string.  This means that, for examples,\n * the common edge between two polygons will be simplified to the same line\n * string independently in both polygons.  This implementation uses a single\n * pass over the coordinates and eliminates intermediate collinear points.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nol.geom.flat.simplify.quantize = function(flatCoordinates, offset, end, stride,\n    tolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n  // do nothing if the line is empty\n  if (offset == end) {\n    return simplifiedOffset;\n  }\n  // snap the first coordinate (P1)\n  var x1 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);\n  var y1 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);\n  offset += stride;\n  // add the first coordinate to the output\n  simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n  simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n  // find the next coordinate that does not snap to the same value as the first\n  // coordinate (P2)\n  var x2, y2;\n  do {\n    x2 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);\n    y2 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);\n    offset += stride;\n    if (offset == end) {\n      // all coordinates snap to the same value, the line collapses to a point\n      // push the last snapped value anyway to ensure that the output contains\n      // at least two points\n      // FIXME should we really return at least two points anyway?\n      simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n      simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n      return simplifiedOffset;\n    }\n  } while (x2 == x1 && y2 == y1);\n  while (offset < end) {\n    var x3, y3;\n    // snap the next coordinate (P3)\n    x3 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);\n    y3 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);\n    offset += stride;\n    // skip P3 if it is equal to P2\n    if (x3 == x2 && y3 == y2) {\n      continue;\n    }\n    // calculate the delta between P1 and P2\n    var dx1 = x2 - x1;\n    var dy1 = y2 - y1;\n    // calculate the delta between P3 and P1\n    var dx2 = x3 - x1;\n    var dy2 = y3 - y1;\n    // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from\n    // P1 in the same direction then P2 is on the straight line between P1 and\n    // P3\n    if ((dx1 * dy2 == dy1 * dx2) &&\n        ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) &&\n        ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) {\n      // discard P2 and set P2 = P3\n      x2 = x3;\n      y2 = y3;\n      continue;\n    }\n    // either P1, P2, and P3 are not colinear, or they are colinear but P3 is\n    // between P3 and P1 or on the opposite half of the line to P2.  add P2,\n    // and continue with P1 = P2 and P2 = P3\n    simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n    simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n    x1 = x2;\n    y1 = y2;\n    x2 = x3;\n    y2 = y3;\n  }\n  // add the last point (P2)\n  simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n  simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n  return simplifiedOffset;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.<number>} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nol.geom.flat.simplify.quantizes = function(\n    flatCoordinates, offset, ends, stride,\n    tolerance,\n    simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    simplifiedOffset = ol.geom.flat.simplify.quantize(\n        flatCoordinates, offset, end, stride,\n        tolerance,\n        simplifiedFlatCoordinates, simplifiedOffset);\n    simplifiedEnds.push(simplifiedOffset);\n    offset = end;\n  }\n  return simplifiedOffset;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat\n *     coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nol.geom.flat.simplify.quantizess = function(\n    flatCoordinates, offset, endss, stride,\n    tolerance,\n    simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    var simplifiedEnds = [];\n    simplifiedOffset = ol.geom.flat.simplify.quantizes(\n        flatCoordinates, offset, ends, stride,\n        tolerance,\n        simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);\n    simplifiedEndss.push(simplifiedEnds);\n    offset = ends[ends.length - 1];\n  }\n  return simplifiedOffset;\n};\n\ngoog.provide('ol.geom.LinearRing');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.area');\ngoog.require('ol.geom.flat.closest');\ngoog.require('ol.geom.flat.deflate');\ngoog.require('ol.geom.flat.inflate');\ngoog.require('ol.geom.flat.simplify');\n\n\n/**\n * @classdesc\n * Linear ring geometry. Only used as part of polygon; cannot be rendered\n * on its own.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.LinearRing = function(coordinates, opt_layout) {\n\n  ol.geom.SimpleGeometry.call(this);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDelta_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDeltaRevision_ = -1;\n\n  this.setCoordinates(coordinates, opt_layout);\n\n};\nol.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry);\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.LinearRing} Clone.\n * @api stable\n */\nol.geom.LinearRing.prototype.clone = function() {\n  var linearRing = new ol.geom.LinearRing(null);\n  linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n  return linearRing;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.LinearRing.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  if (minSquaredDistance <\n      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {\n    return minSquaredDistance;\n  }\n  if (this.maxDeltaRevision_ != this.getRevision()) {\n    this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(\n        this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));\n    this.maxDeltaRevision_ = this.getRevision();\n  }\n  return ol.geom.flat.closest.getClosestPoint(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n      this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * Return the area of the linear ring on projected plane.\n * @return {number} Area (on projected plane).\n * @api stable\n */\nol.geom.LinearRing.prototype.getArea = function() {\n  return ol.geom.flat.area.linearRing(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * Return the coordinates of the linear ring.\n * @return {Array.<ol.Coordinate>} Coordinates.\n * @api stable\n */\nol.geom.LinearRing.prototype.getCoordinates = function() {\n  return ol.geom.flat.inflate.coordinates(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.LinearRing.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n  var simplifiedFlatCoordinates = [];\n  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n      squaredTolerance, simplifiedFlatCoordinates, 0);\n  var simplifiedLinearRing = new ol.geom.LinearRing(null);\n  simplifiedLinearRing.setFlatCoordinates(\n      ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);\n  return simplifiedLinearRing;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.LinearRing.prototype.getType = function() {\n  return ol.geom.GeometryType.LINEAR_RING;\n};\n\n\n/**\n * Set the coordinates of the linear ring.\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.LinearRing.prototype.setCoordinates = function(coordinates, opt_layout) {\n  if (!coordinates) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);\n  } else {\n    this.setLayout(opt_layout, coordinates, 1);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(\n        this.flatCoordinates, 0, coordinates, this.stride);\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n */\nol.geom.LinearRing.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.changed();\n};\n\ngoog.provide('ol.geom.Point');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.deflate');\ngoog.require('ol.math');\n\n\n/**\n * @classdesc\n * Point geometry.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {ol.Coordinate} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.Point = function(coordinates, opt_layout) {\n  ol.geom.SimpleGeometry.call(this);\n  this.setCoordinates(coordinates, opt_layout);\n};\nol.inherits(ol.geom.Point, ol.geom.SimpleGeometry);\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.Point} Clone.\n * @api stable\n */\nol.geom.Point.prototype.clone = function() {\n  var point = new ol.geom.Point(null);\n  point.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n  return point;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Point.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  var flatCoordinates = this.flatCoordinates;\n  var squaredDistance = ol.math.squaredDistance(\n      x, y, flatCoordinates[0], flatCoordinates[1]);\n  if (squaredDistance < minSquaredDistance) {\n    var stride = this.stride;\n    var i;\n    for (i = 0; i < stride; ++i) {\n      closestPoint[i] = flatCoordinates[i];\n    }\n    closestPoint.length = stride;\n    return squaredDistance;\n  } else {\n    return minSquaredDistance;\n  }\n};\n\n\n/**\n * Return the coordinate of the point.\n * @return {ol.Coordinate} Coordinates.\n * @api stable\n */\nol.geom.Point.prototype.getCoordinates = function() {\n  return !this.flatCoordinates ? [] : this.flatCoordinates.slice();\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Point.prototype.computeExtent = function(extent) {\n  return ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates, extent);\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.Point.prototype.getType = function() {\n  return ol.geom.GeometryType.POINT;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.Point.prototype.intersectsExtent = function(extent) {\n  return ol.extent.containsXY(extent,\n      this.flatCoordinates[0], this.flatCoordinates[1]);\n};\n\n\n/**\n * Set the coordinate of the point.\n * @param {ol.Coordinate} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.Point.prototype.setCoordinates = function(coordinates, opt_layout) {\n  if (!coordinates) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);\n  } else {\n    this.setLayout(opt_layout, coordinates, 0);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    this.flatCoordinates.length = ol.geom.flat.deflate.coordinate(\n        this.flatCoordinates, 0, coordinates, this.stride);\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n */\nol.geom.Point.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.changed();\n};\n\ngoog.provide('ol.geom.flat.contains');\n\ngoog.require('ol');\ngoog.require('ol.extent');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {ol.Extent} extent Extent.\n * @return {boolean} Contains extent.\n */\nol.geom.flat.contains.linearRingContainsExtent = function(flatCoordinates, offset, end, stride, extent) {\n  var outside = ol.extent.forEachCorner(extent,\n      /**\n       * @param {ol.Coordinate} coordinate Coordinate.\n       * @return {boolean} Contains (x, y).\n       */\n      function(coordinate) {\n        return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates,\n            offset, end, stride, coordinate[0], coordinate[1]);\n      });\n  return !outside;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nol.geom.flat.contains.linearRingContainsXY = function(flatCoordinates, offset, end, stride, x, y) {\n  // http://geomalgorithms.com/a03-_inclusion.html\n  // Copyright 2000 softSurfer, 2012 Dan Sunday\n  // This code may be freely used and modified for any purpose\n  // providing that this copyright notice is included with it.\n  // SoftSurfer makes no warranty for this code, and cannot be held\n  // liable for any real or imagined damage resulting from its use.\n  // Users of this code must verify correctness for their application.\n  var wn = 0;\n  var x1 = flatCoordinates[end - stride];\n  var y1 = flatCoordinates[end - stride + 1];\n  for (; offset < end; offset += stride) {\n    var x2 = flatCoordinates[offset];\n    var y2 = flatCoordinates[offset + 1];\n    if (y1 <= y) {\n      if (y2 > y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) > 0) {\n        wn++;\n      }\n    } else if (y2 <= y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) < 0) {\n      wn--;\n    }\n    x1 = x2;\n    y1 = y2;\n  }\n  return wn !== 0;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nol.geom.flat.contains.linearRingsContainsXY = function(flatCoordinates, offset, ends, stride, x, y) {\n  ol.DEBUG && console.assert(ends.length > 0, 'ends should not be an empty array');\n  if (ends.length === 0) {\n    return false;\n  }\n  if (!ol.geom.flat.contains.linearRingContainsXY(\n      flatCoordinates, offset, ends[0], stride, x, y)) {\n    return false;\n  }\n  var i, ii;\n  for (i = 1, ii = ends.length; i < ii; ++i) {\n    if (ol.geom.flat.contains.linearRingContainsXY(\n        flatCoordinates, ends[i - 1], ends[i], stride, x, y)) {\n      return false;\n    }\n  }\n  return true;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nol.geom.flat.contains.linearRingssContainsXY = function(flatCoordinates, offset, endss, stride, x, y) {\n  ol.DEBUG && console.assert(endss.length > 0, 'endss should not be an empty array');\n  if (endss.length === 0) {\n    return false;\n  }\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    if (ol.geom.flat.contains.linearRingsContainsXY(\n        flatCoordinates, offset, ends, stride, x, y)) {\n      return true;\n    }\n    offset = ends[ends.length - 1];\n  }\n  return false;\n};\n\ngoog.provide('ol.geom.flat.interiorpoint');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.geom.flat.contains');\n\n\n/**\n * Calculates a point that is likely to lie in the interior of the linear rings.\n * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {Array.<number>} flatCenters Flat centers.\n * @param {number} flatCentersOffset Flat center offset.\n * @param {Array.<number>=} opt_dest Destination.\n * @return {Array.<number>} Destination.\n */\nol.geom.flat.interiorpoint.linearRings = function(flatCoordinates, offset,\n    ends, stride, flatCenters, flatCentersOffset, opt_dest) {\n  var i, ii, x, x1, x2, y1, y2;\n  var y = flatCenters[flatCentersOffset + 1];\n  /** @type {Array.<number>} */\n  var intersections = [];\n  // Calculate intersections with the horizontal line\n  var end = ends[0];\n  x1 = flatCoordinates[end - stride];\n  y1 = flatCoordinates[end - stride + 1];\n  for (i = offset; i < end; i += stride) {\n    x2 = flatCoordinates[i];\n    y2 = flatCoordinates[i + 1];\n    if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {\n      x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;\n      intersections.push(x);\n    }\n    x1 = x2;\n    y1 = y2;\n  }\n  // Find the longest segment of the horizontal line that has its center point\n  // inside the linear ring.\n  var pointX = NaN;\n  var maxSegmentLength = -Infinity;\n  intersections.sort(ol.array.numberSafeCompareFunction);\n  x1 = intersections[0];\n  for (i = 1, ii = intersections.length; i < ii; ++i) {\n    x2 = intersections[i];\n    var segmentLength = Math.abs(x2 - x1);\n    if (segmentLength > maxSegmentLength) {\n      x = (x1 + x2) / 2;\n      if (ol.geom.flat.contains.linearRingsContainsXY(\n          flatCoordinates, offset, ends, stride, x, y)) {\n        pointX = x;\n        maxSegmentLength = segmentLength;\n      }\n    }\n    x1 = x2;\n  }\n  if (isNaN(pointX)) {\n    // There is no horizontal line that has its center point inside the linear\n    // ring.  Use the center of the the linear ring's extent.\n    pointX = flatCenters[flatCentersOffset];\n  }\n  if (opt_dest) {\n    opt_dest.push(pointX, y);\n    return opt_dest;\n  } else {\n    return [pointX, y];\n  }\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array.<number>} flatCenters Flat centers.\n * @return {Array.<number>} Interior points.\n */\nol.geom.flat.interiorpoint.linearRingss = function(flatCoordinates, offset, endss, stride, flatCenters) {\n  ol.DEBUG && console.assert(2 * endss.length == flatCenters.length,\n      'endss.length times 2 should be flatCenters.length');\n  var interiorPoints = [];\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    interiorPoints = ol.geom.flat.interiorpoint.linearRings(flatCoordinates,\n        offset, ends, stride, flatCenters, 2 * i, interiorPoints);\n    offset = ends[ends.length - 1];\n  }\n  return interiorPoints;\n};\n\ngoog.provide('ol.geom.flat.segments');\n\n\n/**\n * This function calls `callback` for each segment of the flat coordinates\n * array. If the callback returns a truthy value the function returns that\n * value immediately. Otherwise the function returns `false`.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function\n *     called for each segment.\n * @param {S=} opt_this The object to be used as the value of 'this'\n *     within callback.\n * @return {T|boolean} Value.\n * @template T,S\n */\nol.geom.flat.segments.forEach = function(flatCoordinates, offset, end, stride, callback, opt_this) {\n  var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]];\n  var point2 = [];\n  var ret;\n  for (; (offset + stride) < end; offset += stride) {\n    point2[0] = flatCoordinates[offset + stride];\n    point2[1] = flatCoordinates[offset + stride + 1];\n    ret = callback.call(opt_this, point1, point2);\n    if (ret) {\n      return ret;\n    }\n    point1[0] = point2[0];\n    point1[1] = point2[1];\n  }\n  return false;\n};\n\ngoog.provide('ol.geom.flat.intersectsextent');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.geom.flat.contains');\ngoog.require('ol.geom.flat.segments');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {ol.Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nol.geom.flat.intersectsextent.lineString = function(flatCoordinates, offset, end, stride, extent) {\n  var coordinatesExtent = ol.extent.extendFlatCoordinates(\n      ol.extent.createEmpty(), flatCoordinates, offset, end, stride);\n  if (!ol.extent.intersects(extent, coordinatesExtent)) {\n    return false;\n  }\n  if (ol.extent.containsExtent(extent, coordinatesExtent)) {\n    return true;\n  }\n  if (coordinatesExtent[0] >= extent[0] &&\n      coordinatesExtent[2] <= extent[2]) {\n    return true;\n  }\n  if (coordinatesExtent[1] >= extent[1] &&\n      coordinatesExtent[3] <= extent[3]) {\n    return true;\n  }\n  return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride,\n      /**\n       * @param {ol.Coordinate} point1 Start point.\n       * @param {ol.Coordinate} point2 End point.\n       * @return {boolean} `true` if the segment and the extent intersect,\n       *     `false` otherwise.\n       */\n      function(point1, point2) {\n        return ol.extent.intersectsSegment(extent, point1, point2);\n      });\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {ol.Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nol.geom.flat.intersectsextent.lineStrings = function(flatCoordinates, offset, ends, stride, extent) {\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    if (ol.geom.flat.intersectsextent.lineString(\n        flatCoordinates, offset, ends[i], stride, extent)) {\n      return true;\n    }\n    offset = ends[i];\n  }\n  return false;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {ol.Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nol.geom.flat.intersectsextent.linearRing = function(flatCoordinates, offset, end, stride, extent) {\n  if (ol.geom.flat.intersectsextent.lineString(\n      flatCoordinates, offset, end, stride, extent)) {\n    return true;\n  }\n  if (ol.geom.flat.contains.linearRingContainsXY(\n      flatCoordinates, offset, end, stride, extent[0], extent[1])) {\n    return true;\n  }\n  if (ol.geom.flat.contains.linearRingContainsXY(\n      flatCoordinates, offset, end, stride, extent[0], extent[3])) {\n    return true;\n  }\n  if (ol.geom.flat.contains.linearRingContainsXY(\n      flatCoordinates, offset, end, stride, extent[2], extent[1])) {\n    return true;\n  }\n  if (ol.geom.flat.contains.linearRingContainsXY(\n      flatCoordinates, offset, end, stride, extent[2], extent[3])) {\n    return true;\n  }\n  return false;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {ol.Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nol.geom.flat.intersectsextent.linearRings = function(flatCoordinates, offset, ends, stride, extent) {\n  ol.DEBUG && console.assert(ends.length > 0, 'ends should not be an empty array');\n  if (!ol.geom.flat.intersectsextent.linearRing(\n      flatCoordinates, offset, ends[0], stride, extent)) {\n    return false;\n  }\n  if (ends.length === 1) {\n    return true;\n  }\n  var i, ii;\n  for (i = 1, ii = ends.length; i < ii; ++i) {\n    if (ol.geom.flat.contains.linearRingContainsExtent(\n        flatCoordinates, ends[i - 1], ends[i], stride, extent)) {\n      return false;\n    }\n  }\n  return true;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @param {ol.Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nol.geom.flat.intersectsextent.linearRingss = function(flatCoordinates, offset, endss, stride, extent) {\n  ol.DEBUG && console.assert(endss.length > 0, 'endss should not be an empty array');\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    if (ol.geom.flat.intersectsextent.linearRings(\n        flatCoordinates, offset, ends, stride, extent)) {\n      return true;\n    }\n    offset = ends[ends.length - 1];\n  }\n  return false;\n};\n\ngoog.provide('ol.geom.flat.reverse');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n */\nol.geom.flat.reverse.coordinates = function(flatCoordinates, offset, end, stride) {\n  while (offset < end - stride) {\n    var i;\n    for (i = 0; i < stride; ++i) {\n      var tmp = flatCoordinates[offset + i];\n      flatCoordinates[offset + i] = flatCoordinates[end - stride + i];\n      flatCoordinates[end - stride + i] = tmp;\n    }\n    offset += stride;\n    end -= stride;\n  }\n};\n\ngoog.provide('ol.geom.flat.orient');\n\ngoog.require('ol');\ngoog.require('ol.geom.flat.reverse');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {boolean} Is clockwise.\n */\nol.geom.flat.orient.linearRingIsClockwise = function(flatCoordinates, offset, end, stride) {\n  // http://tinyurl.com/clockwise-method\n  // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp\n  var edge = 0;\n  var x1 = flatCoordinates[end - stride];\n  var y1 = flatCoordinates[end - stride + 1];\n  for (; offset < end; offset += stride) {\n    var x2 = flatCoordinates[offset];\n    var y2 = flatCoordinates[offset + 1];\n    edge += (x2 - x1) * (y2 + y1);\n    x1 = x2;\n    y1 = y2;\n  }\n  return edge > 0;\n};\n\n\n/**\n * Determines if linear rings are oriented.  By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `opt_right` argument.\n *\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Test for right-hand orientation\n *     (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nol.geom.flat.orient.linearRingsAreOriented = function(flatCoordinates, offset, ends, stride, opt_right) {\n  var right = opt_right !== undefined ? opt_right : false;\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(\n        flatCoordinates, offset, end, stride);\n    if (i === 0) {\n      if ((right && isClockwise) || (!right && !isClockwise)) {\n        return false;\n      }\n    } else {\n      if ((right && !isClockwise) || (!right && isClockwise)) {\n        return false;\n      }\n    }\n    offset = end;\n  }\n  return true;\n};\n\n\n/**\n * Determines if linear rings are oriented.  By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `opt_right` argument.\n *\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Test for right-hand orientation\n *     (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nol.geom.flat.orient.linearRingssAreOriented = function(flatCoordinates, offset, endss, stride, opt_right) {\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    if (!ol.geom.flat.orient.linearRingsAreOriented(\n        flatCoordinates, offset, endss[i], stride, opt_right)) {\n      return false;\n    }\n  }\n  return true;\n};\n\n\n/**\n * Orient coordinates in a flat array of linear rings.  By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings).  To orient according to the\n * right-hand rule, use the `opt_right` argument.\n *\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nol.geom.flat.orient.orientLinearRings = function(flatCoordinates, offset, ends, stride, opt_right) {\n  var right = opt_right !== undefined ? opt_right : false;\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(\n        flatCoordinates, offset, end, stride);\n    var reverse = i === 0 ?\n        (right && isClockwise) || (!right && !isClockwise) :\n        (right && !isClockwise) || (!right && isClockwise);\n    if (reverse) {\n      ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride);\n    }\n    offset = end;\n  }\n  return offset;\n};\n\n\n/**\n * Orient coordinates in a flat array of linear rings.  By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings).  To orient according to the\n * right-hand rule, use the `opt_right` argument.\n *\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nol.geom.flat.orient.orientLinearRingss = function(flatCoordinates, offset, endss, stride, opt_right) {\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    offset = ol.geom.flat.orient.orientLinearRings(\n        flatCoordinates, offset, endss[i], stride, opt_right);\n  }\n  return offset;\n};\n\ngoog.provide('ol.geom.Polygon');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.LinearRing');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.area');\ngoog.require('ol.geom.flat.closest');\ngoog.require('ol.geom.flat.contains');\ngoog.require('ol.geom.flat.deflate');\ngoog.require('ol.geom.flat.inflate');\ngoog.require('ol.geom.flat.interiorpoint');\ngoog.require('ol.geom.flat.intersectsextent');\ngoog.require('ol.geom.flat.orient');\ngoog.require('ol.geom.flat.simplify');\ngoog.require('ol.math');\n\n\n/**\n * @classdesc\n * Polygon geometry.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.Polygon = function(coordinates, opt_layout) {\n\n  ol.geom.SimpleGeometry.call(this);\n\n  /**\n   * @type {Array.<number>}\n   * @private\n   */\n  this.ends_ = [];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.flatInteriorPointRevision_ = -1;\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.flatInteriorPoint_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDelta_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDeltaRevision_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.orientedRevision_ = -1;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.orientedFlatCoordinates_ = null;\n\n  this.setCoordinates(coordinates, opt_layout);\n\n};\nol.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry);\n\n\n/**\n * Append the passed linear ring to this polygon.\n * @param {ol.geom.LinearRing} linearRing Linear ring.\n * @api stable\n */\nol.geom.Polygon.prototype.appendLinearRing = function(linearRing) {\n  ol.DEBUG && console.assert(linearRing.getLayout() == this.layout,\n      'layout of linearRing should match layout');\n  if (!this.flatCoordinates) {\n    this.flatCoordinates = linearRing.getFlatCoordinates().slice();\n  } else {\n    ol.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates());\n  }\n  this.ends_.push(this.flatCoordinates.length);\n  this.changed();\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.Polygon} Clone.\n * @api stable\n */\nol.geom.Polygon.prototype.clone = function() {\n  var polygon = new ol.geom.Polygon(null);\n  polygon.setFlatCoordinates(\n      this.layout, this.flatCoordinates.slice(), this.ends_.slice());\n  return polygon;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Polygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  if (minSquaredDistance <\n      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {\n    return minSquaredDistance;\n  }\n  if (this.maxDeltaRevision_ != this.getRevision()) {\n    this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(\n        this.flatCoordinates, 0, this.ends_, this.stride, 0));\n    this.maxDeltaRevision_ = this.getRevision();\n  }\n  return ol.geom.flat.closest.getsClosestPoint(\n      this.flatCoordinates, 0, this.ends_, this.stride,\n      this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Polygon.prototype.containsXY = function(x, y) {\n  return ol.geom.flat.contains.linearRingsContainsXY(\n      this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);\n};\n\n\n/**\n * Return the area of the polygon on projected plane.\n * @return {number} Area (on projected plane).\n * @api stable\n */\nol.geom.Polygon.prototype.getArea = function() {\n  return ol.geom.flat.area.linearRings(\n      this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);\n};\n\n\n/**\n * Get the coordinate array for this geometry.  This array has the structure\n * of a GeoJSON coordinate array for polygons.\n *\n * @param {boolean=} opt_right Orient coordinates according to the right-hand\n *     rule (counter-clockwise for exterior and clockwise for interior rings).\n *     If `false`, coordinates will be oriented according to the left-hand rule\n *     (clockwise for exterior and counter-clockwise for interior rings).\n *     By default, coordinate orientation will depend on how the geometry was\n *     constructed.\n * @return {Array.<Array.<ol.Coordinate>>} Coordinates.\n * @api stable\n */\nol.geom.Polygon.prototype.getCoordinates = function(opt_right) {\n  var flatCoordinates;\n  if (opt_right !== undefined) {\n    flatCoordinates = this.getOrientedFlatCoordinates().slice();\n    ol.geom.flat.orient.orientLinearRings(\n        flatCoordinates, 0, this.ends_, this.stride, opt_right);\n  } else {\n    flatCoordinates = this.flatCoordinates;\n  }\n\n  return ol.geom.flat.inflate.coordinatess(\n      flatCoordinates, 0, this.ends_, this.stride);\n};\n\n\n/**\n * @return {Array.<number>} Ends.\n */\nol.geom.Polygon.prototype.getEnds = function() {\n  return this.ends_;\n};\n\n\n/**\n * @return {Array.<number>} Interior point.\n */\nol.geom.Polygon.prototype.getFlatInteriorPoint = function() {\n  if (this.flatInteriorPointRevision_ != this.getRevision()) {\n    var flatCenter = ol.extent.getCenter(this.getExtent());\n    this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings(\n        this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,\n        flatCenter, 0);\n    this.flatInteriorPointRevision_ = this.getRevision();\n  }\n  return this.flatInteriorPoint_;\n};\n\n\n/**\n * Return an interior point of the polygon.\n * @return {ol.geom.Point} Interior point.\n * @api stable\n */\nol.geom.Polygon.prototype.getInteriorPoint = function() {\n  return new ol.geom.Point(this.getFlatInteriorPoint());\n};\n\n\n/**\n * Return the number of rings of the polygon,  this includes the exterior\n * ring and any interior rings.\n *\n * @return {number} Number of rings.\n * @api\n */\nol.geom.Polygon.prototype.getLinearRingCount = function() {\n  return this.ends_.length;\n};\n\n\n/**\n * Return the Nth linear ring of the polygon geometry. Return `null` if the\n * given index is out of range.\n * The exterior linear ring is available at index `0` and the interior rings\n * at index `1` and beyond.\n *\n * @param {number} index Index.\n * @return {ol.geom.LinearRing} Linear ring.\n * @api stable\n */\nol.geom.Polygon.prototype.getLinearRing = function(index) {\n  ol.DEBUG && console.assert(0 <= index && index < this.ends_.length,\n      'index should be in between 0 and and length of this.ends_');\n  if (index < 0 || this.ends_.length <= index) {\n    return null;\n  }\n  var linearRing = new ol.geom.LinearRing(null);\n  linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice(\n      index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));\n  return linearRing;\n};\n\n\n/**\n * Return the linear rings of the polygon.\n * @return {Array.<ol.geom.LinearRing>} Linear rings.\n * @api stable\n */\nol.geom.Polygon.prototype.getLinearRings = function() {\n  var layout = this.layout;\n  var flatCoordinates = this.flatCoordinates;\n  var ends = this.ends_;\n  var linearRings = [];\n  var offset = 0;\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    var linearRing = new ol.geom.LinearRing(null);\n    linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));\n    linearRings.push(linearRing);\n    offset = end;\n  }\n  return linearRings;\n};\n\n\n/**\n * @return {Array.<number>} Oriented flat coordinates.\n */\nol.geom.Polygon.prototype.getOrientedFlatCoordinates = function() {\n  if (this.orientedRevision_ != this.getRevision()) {\n    var flatCoordinates = this.flatCoordinates;\n    if (ol.geom.flat.orient.linearRingsAreOriented(\n        flatCoordinates, 0, this.ends_, this.stride)) {\n      this.orientedFlatCoordinates_ = flatCoordinates;\n    } else {\n      this.orientedFlatCoordinates_ = flatCoordinates.slice();\n      this.orientedFlatCoordinates_.length =\n          ol.geom.flat.orient.orientLinearRings(\n              this.orientedFlatCoordinates_, 0, this.ends_, this.stride);\n    }\n    this.orientedRevision_ = this.getRevision();\n  }\n  return this.orientedFlatCoordinates_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Polygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n  var simplifiedFlatCoordinates = [];\n  var simplifiedEnds = [];\n  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizes(\n      this.flatCoordinates, 0, this.ends_, this.stride,\n      Math.sqrt(squaredTolerance),\n      simplifiedFlatCoordinates, 0, simplifiedEnds);\n  var simplifiedPolygon = new ol.geom.Polygon(null);\n  simplifiedPolygon.setFlatCoordinates(\n      ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);\n  return simplifiedPolygon;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.Polygon.prototype.getType = function() {\n  return ol.geom.GeometryType.POLYGON;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.Polygon.prototype.intersectsExtent = function(extent) {\n  return ol.geom.flat.intersectsextent.linearRings(\n      this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);\n};\n\n\n/**\n * Set the coordinates of the polygon.\n * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.Polygon.prototype.setCoordinates = function(coordinates, opt_layout) {\n  if (!coordinates) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);\n  } else {\n    this.setLayout(opt_layout, coordinates, 2);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    var ends = ol.geom.flat.deflate.coordinatess(\n        this.flatCoordinates, 0, coordinates, this.stride, this.ends_);\n    this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {Array.<number>} ends Ends.\n */\nol.geom.Polygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {\n  if (!flatCoordinates) {\n    ol.DEBUG && console.assert(ends && ends.length === 0,\n        'ends must be an empty array');\n  } else if (ends.length === 0) {\n    ol.DEBUG && console.assert(flatCoordinates.length === 0,\n        'flatCoordinates should be an empty array');\n  } else {\n    ol.DEBUG && console.assert(flatCoordinates.length == ends[ends.length - 1],\n        'the length of flatCoordinates should be the last entry of ends');\n  }\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.ends_ = ends;\n  this.changed();\n};\n\n\n/**\n * Create an approximation of a circle on the surface of a sphere.\n * @param {ol.Sphere} sphere The sphere.\n * @param {ol.Coordinate} center Center (`[lon, lat]` in degrees).\n * @param {number} radius The great-circle distance from the center to\n *     the polygon vertices.\n * @param {number=} opt_n Optional number of vertices for the resulting\n *     polygon. Default is `32`.\n * @return {ol.geom.Polygon} The \"circular\" polygon.\n * @api stable\n */\nol.geom.Polygon.circular = function(sphere, center, radius, opt_n) {\n  var n = opt_n ? opt_n : 32;\n  /** @type {Array.<number>} */\n  var flatCoordinates = [];\n  var i;\n  for (i = 0; i < n; ++i) {\n    ol.array.extend(\n        flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n));\n  }\n  flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);\n  var polygon = new ol.geom.Polygon(null);\n  polygon.setFlatCoordinates(\n      ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);\n  return polygon;\n};\n\n\n/**\n * Create a polygon from an extent. The layout used is `XY`.\n * @param {ol.Extent} extent The extent.\n * @return {ol.geom.Polygon} The polygon.\n * @api\n */\nol.geom.Polygon.fromExtent = function(extent) {\n  var minX = extent[0];\n  var minY = extent[1];\n  var maxX = extent[2];\n  var maxY = extent[3];\n  var flatCoordinates =\n      [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY];\n  var polygon = new ol.geom.Polygon(null);\n  polygon.setFlatCoordinates(\n      ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);\n  return polygon;\n};\n\n\n/**\n * Create a regular polygon from a circle.\n * @param {ol.geom.Circle} circle Circle geometry.\n * @param {number=} opt_sides Number of sides of the polygon. Default is 32.\n * @param {number=} opt_angle Start angle for the first vertex of the polygon in\n *     radians. Default is 0.\n * @return {ol.geom.Polygon} Polygon geometry.\n * @api\n */\nol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) {\n  var sides = opt_sides ? opt_sides : 32;\n  var stride = circle.getStride();\n  var layout = circle.getLayout();\n  var polygon = new ol.geom.Polygon(null, layout);\n  var arrayLength = stride * (sides + 1);\n  var flatCoordinates = new Array(arrayLength);\n  for (var i = 0; i < arrayLength; i++) {\n    flatCoordinates[i] = 0;\n  }\n  var ends = [flatCoordinates.length];\n  polygon.setFlatCoordinates(layout, flatCoordinates, ends);\n  ol.geom.Polygon.makeRegular(\n      polygon, circle.getCenter(), circle.getRadius(), opt_angle);\n  return polygon;\n};\n\n\n/**\n * Modify the coordinates of a polygon to make it a regular polygon.\n * @param {ol.geom.Polygon} polygon Polygon geometry.\n * @param {ol.Coordinate} center Center of the regular polygon.\n * @param {number} radius Radius of the regular polygon.\n * @param {number=} opt_angle Start angle for the first vertex of the polygon in\n *     radians. Default is 0.\n */\nol.geom.Polygon.makeRegular = function(polygon, center, radius, opt_angle) {\n  var flatCoordinates = polygon.getFlatCoordinates();\n  var layout = polygon.getLayout();\n  var stride = polygon.getStride();\n  var ends = polygon.getEnds();\n  ol.DEBUG && console.assert(ends.length === 1, 'only 1 ring is supported');\n  var sides = flatCoordinates.length / stride - 1;\n  var startAngle = opt_angle ? opt_angle : 0;\n  var angle, offset;\n  for (var i = 0; i <= sides; ++i) {\n    offset = i * stride;\n    angle = startAngle + (ol.math.modulo(i, sides) * 2 * Math.PI / sides);\n    flatCoordinates[offset] = center[0] + (radius * Math.cos(angle));\n    flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle));\n  }\n  polygon.setFlatCoordinates(layout, flatCoordinates, ends);\n};\n\ngoog.provide('ol.View');\n\ngoog.require('ol');\ngoog.require('ol.CenterConstraint');\ngoog.require('ol.Constraints');\ngoog.require('ol.Object');\ngoog.require('ol.ResolutionConstraint');\ngoog.require('ol.RotationConstraint');\ngoog.require('ol.array');\ngoog.require('ol.asserts');\ngoog.require('ol.coordinate');\ngoog.require('ol.easing');\ngoog.require('ol.extent');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Units');\n\n\n/**\n * @classdesc\n * An ol.View object represents a simple 2D view of the map.\n *\n * This is the object to act upon to change the center, resolution,\n * and rotation of the map.\n *\n * ### The view states\n *\n * An `ol.View` is determined by three states: `center`, `resolution`,\n * and `rotation`. Each state has a corresponding getter and setter, e.g.\n * `getCenter` and `setCenter` for the `center` state.\n *\n * An `ol.View` has a `projection`. The projection determines the\n * coordinate system of the center, and its units determine the units of the\n * resolution (projection units per pixel). The default projection is\n * Spherical Mercator (EPSG:3857).\n *\n * ### The constraints\n *\n * `setCenter`, `setResolution` and `setRotation` can be used to change the\n * states of the view. Any value can be passed to the setters. And the value\n * that is passed to a setter will effectively be the value set in the view,\n * and returned by the corresponding getter.\n *\n * But an `ol.View` object also has a *resolution constraint*, a\n * *rotation constraint* and a *center constraint*.\n *\n * As said above, no constraints are applied when the setters are used to set\n * new states for the view. Applying constraints is done explicitly through\n * the use of the `constrain*` functions (`constrainResolution` and\n * `constrainRotation` and `constrainCenter`).\n *\n * The main users of the constraints are the interactions and the\n * controls. For example, double-clicking on the map changes the view to\n * the \"next\" resolution. And releasing the fingers after pinch-zooming\n * snaps to the closest resolution (with an animation).\n *\n * The *resolution constraint* snaps to specific resolutions. It is\n * determined by the following options: `resolutions`, `maxResolution`,\n * `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three\n * options are ignored. See documentation for each option for more\n * information.\n *\n * The *rotation constraint* snaps to specific angles. It is determined\n * by the following options: `enableRotation` and `constrainRotation`.\n * By default the rotation value is snapped to zero when approaching the\n * horizontal.\n *\n * The *center constraint* is determined by the `extent` option. By\n * default the center is not constrained at all.\n *\n * @constructor\n * @extends {ol.Object}\n * @param {olx.ViewOptions=} opt_options View options.\n * @api stable\n */\nol.View = function(opt_options) {\n  ol.Object.call(this);\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.hints_ = [0, 0];\n\n  /**\n   * @private\n   * @type {Array.<Array.<ol.ViewAnimation>>}\n   */\n  this.animations_ = [];\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.updateAnimationKey_;\n\n  this.updateAnimations_ = this.updateAnimations_.bind(this);\n\n  /**\n   * @type {Object.<string, *>}\n   */\n  var properties = {};\n  properties[ol.View.Property.CENTER] = options.center !== undefined ?\n      options.center : null;\n\n  /**\n   * @private\n   * @const\n   * @type {ol.proj.Projection}\n   */\n  this.projection_ = ol.proj.createProjection(options.projection, 'EPSG:3857');\n\n  var resolutionConstraintInfo = ol.View.createResolutionConstraint_(\n      options);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxResolution_ = resolutionConstraintInfo.maxResolution;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.minResolution_ = resolutionConstraintInfo.minResolution;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.zoomFactor_ = resolutionConstraintInfo.zoomFactor;\n\n  /**\n   * @private\n   * @type {Array.<number>|undefined}\n   */\n  this.resolutions_ = options.resolutions;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.minZoom_ = resolutionConstraintInfo.minZoom;\n\n  var centerConstraint = ol.View.createCenterConstraint_(options);\n  var resolutionConstraint = resolutionConstraintInfo.constraint;\n  var rotationConstraint = ol.View.createRotationConstraint_(options);\n\n  /**\n   * @private\n   * @type {ol.Constraints}\n   */\n  this.constraints_ = new ol.Constraints(\n      centerConstraint, resolutionConstraint, rotationConstraint);\n\n  if (options.resolution !== undefined) {\n    properties[ol.View.Property.RESOLUTION] = options.resolution;\n  } else if (options.zoom !== undefined) {\n    properties[ol.View.Property.RESOLUTION] = this.constrainResolution(\n        this.maxResolution_, options.zoom - this.minZoom_);\n  }\n  properties[ol.View.Property.ROTATION] =\n      options.rotation !== undefined ? options.rotation : 0;\n  this.setProperties(properties);\n};\nol.inherits(ol.View, ol.Object);\n\n\n/**\n * Animate the view.  The view's center, zoom (or resolution), and rotation\n * can be animated for smooth transitions between view states.  For example,\n * to animate the view to a new zoom level:\n *\n *     view.animate({zoom: view.getZoom() + 1});\n *\n * By default, the animation lasts one second and uses in-and-out easing.  You\n * can customize this behavior by including `duration` (in milliseconds) and\n * `easing` options (see {@link ol.easing}).\n *\n * To chain together multiple animations, call the method with multiple\n * animation objects.  For example, to first zoom and then pan:\n *\n *     view.animate({zoom: 10}, {center: [0, 0]});\n *\n * If you provide a function as the last argument to the animate method, it\n * will get called at the end of an animation series.  The callback will be\n * called with `true` if the animation series completed on its own or `false`\n * if it was cancelled.\n *\n * Animations are cancelled by user interactions (e.g. dragging the map) or by\n * calling `view.setCenter()`, `view.setResolution()`, or `view.setRotation()`\n * (or another method that calls one of these).\n *\n * @param {...(olx.AnimationOptions|function(boolean))} var_args Animation\n *     options.  Multiple animations can be run in series by passing multiple\n *     options objects.  To run multiple animations in parallel, call the method\n *     multiple times.  An optional callback can be provided as a final\n *     argument.  The callback will be called with a boolean indicating whether\n *     the animation completed without being cancelled.\n * @api\n */\nol.View.prototype.animate = function(var_args) {\n  var start = Date.now();\n  var center = this.getCenter().slice();\n  var resolution = this.getResolution();\n  var rotation = this.getRotation();\n  var animationCount = arguments.length;\n  var callback;\n  if (animationCount > 1 && typeof arguments[animationCount - 1] === 'function') {\n    callback = arguments[animationCount - 1];\n    --animationCount;\n  }\n  var series = [];\n  for (var i = 0; i < animationCount; ++i) {\n    var options = /** @type olx.AnimationOptions */ (arguments[i]);\n\n    var animation = /** @type {ol.ViewAnimation} */ ({\n      start: start,\n      complete: false,\n      anchor: options.anchor,\n      duration: options.duration !== undefined ? options.duration : 1000,\n      easing: options.easing || ol.easing.inAndOut\n    });\n\n    if (options.center) {\n      animation.sourceCenter = center;\n      animation.targetCenter = options.center;\n      center = animation.targetCenter;\n    }\n\n    if (options.zoom !== undefined) {\n      animation.sourceResolution = resolution;\n      animation.targetResolution = this.constrainResolution(\n            this.maxResolution_, options.zoom - this.minZoom_, 0);\n      resolution = animation.targetResolution;\n    } else if (options.resolution) {\n      animation.sourceResolution = resolution;\n      animation.targetResolution = options.resolution;\n      resolution = animation.targetResolution;\n    }\n\n    if (options.rotation !== undefined) {\n      animation.sourceRotation = rotation;\n      animation.targetRotation = options.rotation;\n      rotation = animation.targetRotation;\n    }\n\n    animation.callback = callback;\n    start += animation.duration;\n    series.push(animation);\n  }\n  this.animations_.push(series);\n  this.setHint(ol.View.Hint.ANIMATING, 1);\n  this.updateAnimations_();\n};\n\n\n/**\n * Determine if the view is being animated.\n * @return {boolean} The view is being animated.\n */\nol.View.prototype.getAnimating = function() {\n  return this.getHints()[ol.View.Hint.ANIMATING] > 0;\n};\n\n\n/**\n * Cancel any ongoing animations.\n */\nol.View.prototype.cancelAnimations = function() {\n  this.setHint(ol.View.Hint.ANIMATING, -this.getHints()[ol.View.Hint.ANIMATING]);\n  for (var i = 0, ii = this.animations_.length; i < ii; ++i) {\n    var series = this.animations_[i];\n    if (series[0].callback) {\n      series[0].callback(false);\n    }\n  }\n  this.animations_.length = 0;\n};\n\n/**\n * Update all animations.\n */\nol.View.prototype.updateAnimations_ = function() {\n  if (this.updateAnimationKey_ !== undefined) {\n    cancelAnimationFrame(this.updateAnimationKey_);\n    this.updateAnimationKey_ = undefined;\n  }\n  if (!this.getAnimating()) {\n    return;\n  }\n  var now = Date.now();\n  var more = false;\n  for (var i = this.animations_.length - 1; i >= 0; --i) {\n    var series = this.animations_[i];\n    var seriesComplete = true;\n    for (var j = 0, jj = series.length; j < jj; ++j) {\n      var animation = series[j];\n      if (animation.complete) {\n        continue;\n      }\n      var elapsed = now - animation.start;\n      var fraction = animation.duration > 0 ? elapsed / animation.duration : 1;\n      if (fraction >= 1) {\n        animation.complete = true;\n        fraction = 1;\n      } else {\n        seriesComplete = false;\n      }\n      var progress = animation.easing(fraction);\n      if (animation.sourceCenter) {\n        var x0 = animation.sourceCenter[0];\n        var y0 = animation.sourceCenter[1];\n        var x1 = animation.targetCenter[0];\n        var y1 = animation.targetCenter[1];\n        var x = x0 + progress * (x1 - x0);\n        var y = y0 + progress * (y1 - y0);\n        this.set(ol.View.Property.CENTER, [x, y]);\n      }\n      if (animation.sourceResolution) {\n        var resolution = animation.sourceResolution +\n            progress * (animation.targetResolution - animation.sourceResolution);\n        if (animation.anchor) {\n          this.set(ol.View.Property.CENTER,\n              this.calculateCenterZoom(resolution, animation.anchor));\n        }\n        this.set(ol.View.Property.RESOLUTION, resolution);\n      }\n      if (animation.sourceRotation !== undefined) {\n        var rotation = animation.sourceRotation +\n            progress * (animation.targetRotation - animation.sourceRotation);\n        if (animation.anchor) {\n          this.set(ol.View.Property.CENTER,\n              this.calculateCenterRotate(rotation, animation.anchor));\n        }\n        this.set(ol.View.Property.ROTATION, rotation);\n      }\n      more = true;\n      if (!animation.complete) {\n        break;\n      }\n    }\n    if (seriesComplete) {\n      this.animations_[i] = null;\n      this.setHint(ol.View.Hint.ANIMATING, -1);\n      var callback = series[0].callback;\n      if (callback) {\n        callback(true);\n      }\n    }\n  }\n  // prune completed series\n  this.animations_ = this.animations_.filter(Boolean);\n  if (more && this.updateAnimationKey_ === undefined) {\n    this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_);\n  }\n};\n\n/**\n * @param {number} rotation Target rotation.\n * @param {ol.Coordinate} anchor Rotation anchor.\n * @return {ol.Coordinate|undefined} Center for rotation and anchor.\n */\nol.View.prototype.calculateCenterRotate = function(rotation, anchor) {\n  var center;\n  var currentCenter = this.getCenter();\n  if (currentCenter !== undefined) {\n    center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]];\n    ol.coordinate.rotate(center, rotation - this.getRotation());\n    ol.coordinate.add(center, anchor);\n  }\n  return center;\n};\n\n\n/**\n * @param {number} resolution Target resolution.\n * @param {ol.Coordinate} anchor Zoom anchor.\n * @return {ol.Coordinate|undefined} Center for resolution and anchor.\n */\nol.View.prototype.calculateCenterZoom = function(resolution, anchor) {\n  var center;\n  var currentCenter = this.getCenter();\n  var currentResolution = this.getResolution();\n  if (currentCenter !== undefined && currentResolution !== undefined) {\n    var x = anchor[0] -\n        resolution * (anchor[0] - currentCenter[0]) / currentResolution;\n    var y = anchor[1] -\n        resolution * (anchor[1] - currentCenter[1]) / currentResolution;\n    center = [x, y];\n  }\n  return center;\n};\n\n\n/**\n * Get the constrained center of this view.\n * @param {ol.Coordinate|undefined} center Center.\n * @return {ol.Coordinate|undefined} Constrained center.\n * @api\n */\nol.View.prototype.constrainCenter = function(center) {\n  return this.constraints_.center(center);\n};\n\n\n/**\n * Get the constrained resolution of this view.\n * @param {number|undefined} resolution Resolution.\n * @param {number=} opt_delta Delta. Default is `0`.\n * @param {number=} opt_direction Direction. Default is `0`.\n * @return {number|undefined} Constrained resolution.\n * @api\n */\nol.View.prototype.constrainResolution = function(\n    resolution, opt_delta, opt_direction) {\n  var delta = opt_delta || 0;\n  var direction = opt_direction || 0;\n  return this.constraints_.resolution(resolution, delta, direction);\n};\n\n\n/**\n * Get the constrained rotation of this view.\n * @param {number|undefined} rotation Rotation.\n * @param {number=} opt_delta Delta. Default is `0`.\n * @return {number|undefined} Constrained rotation.\n * @api\n */\nol.View.prototype.constrainRotation = function(rotation, opt_delta) {\n  var delta = opt_delta || 0;\n  return this.constraints_.rotation(rotation, delta);\n};\n\n\n/**\n * Get the view center.\n * @return {ol.Coordinate|undefined} The center of the view.\n * @observable\n * @api stable\n */\nol.View.prototype.getCenter = function() {\n  return /** @type {ol.Coordinate|undefined} */ (\n      this.get(ol.View.Property.CENTER));\n};\n\n\n/**\n * @param {Array.<number>=} opt_hints Destination array.\n * @return {Array.<number>} Hint.\n */\nol.View.prototype.getHints = function(opt_hints) {\n  if (opt_hints !== undefined) {\n    opt_hints[0] = this.hints_[0];\n    opt_hints[1] = this.hints_[1];\n    return opt_hints;\n  } else {\n    return this.hints_.slice();\n  }\n};\n\n\n/**\n * Calculate the extent for the current view state and the passed size.\n * The size is the pixel dimensions of the box into which the calculated extent\n * should fit. In most cases you want to get the extent of the entire map,\n * that is `map.getSize()`.\n * @param {ol.Size} size Box pixel size.\n * @return {ol.Extent} Extent.\n * @api stable\n */\nol.View.prototype.calculateExtent = function(size) {\n  var center = /** @type {!ol.Coordinate} */ (this.getCenter());\n  ol.asserts.assert(center, 1); // The view center is not defined\n  var resolution = /** @type {!number} */ (this.getResolution());\n  ol.asserts.assert(resolution !== undefined, 2); // The view resolution is not defined\n  var rotation = /** @type {!number} */ (this.getRotation());\n  ol.asserts.assert(rotation !== undefined, 3); // The view rotation is not defined\n\n  return ol.extent.getForViewAndSize(center, resolution, rotation, size);\n};\n\n\n/**\n * Get the maximum resolution of the view.\n * @return {number} The maximum resolution of the view.\n * @api\n */\nol.View.prototype.getMaxResolution = function() {\n  return this.maxResolution_;\n};\n\n\n/**\n * Get the minimum resolution of the view.\n * @return {number} The minimum resolution of the view.\n * @api\n */\nol.View.prototype.getMinResolution = function() {\n  return this.minResolution_;\n};\n\n\n/**\n * Get the view projection.\n * @return {ol.proj.Projection} The projection of the view.\n * @api stable\n */\nol.View.prototype.getProjection = function() {\n  return this.projection_;\n};\n\n\n/**\n * Get the view resolution.\n * @return {number|undefined} The resolution of the view.\n * @observable\n * @api stable\n */\nol.View.prototype.getResolution = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.View.Property.RESOLUTION));\n};\n\n\n/**\n * Get the resolutions for the view. This returns the array of resolutions\n * passed to the constructor of the {ol.View}, or undefined if none were given.\n * @return {Array.<number>|undefined} The resolutions of the view.\n * @api stable\n */\nol.View.prototype.getResolutions = function() {\n  return this.resolutions_;\n};\n\n\n/**\n * Get the resolution for a provided extent (in map units) and size (in pixels).\n * @param {ol.Extent} extent Extent.\n * @param {ol.Size} size Box pixel size.\n * @return {number} The resolution at which the provided extent will render at\n *     the given size.\n */\nol.View.prototype.getResolutionForExtent = function(extent, size) {\n  var xResolution = ol.extent.getWidth(extent) / size[0];\n  var yResolution = ol.extent.getHeight(extent) / size[1];\n  return Math.max(xResolution, yResolution);\n};\n\n\n/**\n * Return a function that returns a value between 0 and 1 for a\n * resolution. Exponential scaling is assumed.\n * @param {number=} opt_power Power.\n * @return {function(number): number} Resolution for value function.\n */\nol.View.prototype.getResolutionForValueFunction = function(opt_power) {\n  var power = opt_power || 2;\n  var maxResolution = this.maxResolution_;\n  var minResolution = this.minResolution_;\n  var max = Math.log(maxResolution / minResolution) / Math.log(power);\n  return (\n      /**\n       * @param {number} value Value.\n       * @return {number} Resolution.\n       */\n      function(value) {\n        var resolution = maxResolution / Math.pow(power, value * max);\n        ol.DEBUG && console.assert(resolution >= minResolution &&\n            resolution <= maxResolution,\n            'calculated resolution outside allowed bounds (%s <= %s <= %s)',\n            minResolution, resolution, maxResolution);\n        return resolution;\n      });\n};\n\n\n/**\n * Get the view rotation.\n * @return {number} The rotation of the view in radians.\n * @observable\n * @api stable\n */\nol.View.prototype.getRotation = function() {\n  return /** @type {number} */ (this.get(ol.View.Property.ROTATION));\n};\n\n\n/**\n * Return a function that returns a resolution for a value between\n * 0 and 1. Exponential scaling is assumed.\n * @param {number=} opt_power Power.\n * @return {function(number): number} Value for resolution function.\n */\nol.View.prototype.getValueForResolutionFunction = function(opt_power) {\n  var power = opt_power || 2;\n  var maxResolution = this.maxResolution_;\n  var minResolution = this.minResolution_;\n  var max = Math.log(maxResolution / minResolution) / Math.log(power);\n  return (\n      /**\n       * @param {number} resolution Resolution.\n       * @return {number} Value.\n       */\n      function(resolution) {\n        var value =\n            (Math.log(maxResolution / resolution) / Math.log(power)) / max;\n        ol.DEBUG && console.assert(value >= 0 && value <= 1,\n            'calculated value (%s) ouside allowed range (0-1)', value);\n        return value;\n      });\n};\n\n\n/**\n * @return {olx.ViewState} View state.\n */\nol.View.prototype.getState = function() {\n  ol.DEBUG && console.assert(this.isDef(),\n      'the view was not defined (had no center and/or resolution)');\n  var center = /** @type {ol.Coordinate} */ (this.getCenter());\n  var projection = this.getProjection();\n  var resolution = /** @type {number} */ (this.getResolution());\n  var rotation = this.getRotation();\n  return /** @type {olx.ViewState} */ ({\n    center: center.slice(),\n    projection: projection !== undefined ? projection : null,\n    resolution: resolution,\n    rotation: rotation\n  });\n};\n\n\n/**\n * Get the current zoom level. Return undefined if the current\n * resolution is undefined or not within the \"resolution constraints\".\n * @return {number|undefined} Zoom.\n * @api stable\n */\nol.View.prototype.getZoom = function() {\n  var zoom;\n  var resolution = this.getResolution();\n  if (resolution !== undefined &&\n      resolution >= this.minResolution_ && resolution <= this.maxResolution_) {\n    var offset = this.minZoom_ || 0;\n    var max, zoomFactor;\n    if (this.resolutions_) {\n      var nearest = ol.array.linearFindNearest(this.resolutions_, resolution, 1);\n      offset += nearest;\n      if (nearest == this.resolutions_.length - 1) {\n        return offset;\n      }\n      max = this.resolutions_[nearest];\n      zoomFactor = max / this.resolutions_[nearest + 1];\n    } else {\n      max = this.maxResolution_;\n      zoomFactor = this.zoomFactor_;\n    }\n    zoom = offset + Math.log(max / resolution) / Math.log(zoomFactor);\n  }\n  return zoom;\n};\n\n\n/**\n * Fit the given geometry or extent based on the given map size and border.\n * The size is pixel dimensions of the box to fit the extent into.\n * In most cases you will want to use the map size, that is `map.getSize()`.\n * Takes care of the map angle.\n * @param {ol.geom.SimpleGeometry|ol.Extent} geometry Geometry.\n * @param {ol.Size} size Box pixel size.\n * @param {olx.view.FitOptions=} opt_options Options.\n * @api\n */\nol.View.prototype.fit = function(geometry, size, opt_options) {\n  if (!(geometry instanceof ol.geom.SimpleGeometry)) {\n    ol.asserts.assert(Array.isArray(geometry),\n        24); // Invalid extent or geometry provided as `geometry`\n    ol.asserts.assert(!ol.extent.isEmpty(geometry),\n        25); // Cannot fit empty extent provided as `geometry`\n    geometry = ol.geom.Polygon.fromExtent(geometry);\n  }\n\n  var options = opt_options || {};\n\n  var padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];\n  var constrainResolution = options.constrainResolution !== undefined ?\n      options.constrainResolution : true;\n  var nearest = options.nearest !== undefined ? options.nearest : false;\n  var minResolution;\n  if (options.minResolution !== undefined) {\n    minResolution = options.minResolution;\n  } else if (options.maxZoom !== undefined) {\n    minResolution = this.constrainResolution(\n        this.maxResolution_, options.maxZoom - this.minZoom_, 0);\n  } else {\n    minResolution = 0;\n  }\n  var coords = geometry.getFlatCoordinates();\n\n  // calculate rotated extent\n  var rotation = this.getRotation();\n  ol.DEBUG && console.assert(rotation !== undefined, 'rotation was not defined');\n  var cosAngle = Math.cos(-rotation);\n  var sinAngle = Math.sin(-rotation);\n  var minRotX = +Infinity;\n  var minRotY = +Infinity;\n  var maxRotX = -Infinity;\n  var maxRotY = -Infinity;\n  var stride = geometry.getStride();\n  for (var i = 0, ii = coords.length; i < ii; i += stride) {\n    var rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle;\n    var rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle;\n    minRotX = Math.min(minRotX, rotX);\n    minRotY = Math.min(minRotY, rotY);\n    maxRotX = Math.max(maxRotX, rotX);\n    maxRotY = Math.max(maxRotY, rotY);\n  }\n\n  // calculate resolution\n  var resolution = this.getResolutionForExtent(\n      [minRotX, minRotY, maxRotX, maxRotY],\n      [size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]);\n  resolution = isNaN(resolution) ? minResolution :\n      Math.max(resolution, minResolution);\n  if (constrainResolution) {\n    var constrainedResolution = this.constrainResolution(resolution, 0, 0);\n    if (!nearest && constrainedResolution < resolution) {\n      constrainedResolution = this.constrainResolution(\n          constrainedResolution, -1, 0);\n    }\n    resolution = constrainedResolution;\n  }\n\n  // calculate center\n  sinAngle = -sinAngle; // go back to original rotation\n  var centerRotX = (minRotX + maxRotX) / 2;\n  var centerRotY = (minRotY + maxRotY) / 2;\n  centerRotX += (padding[1] - padding[3]) / 2 * resolution;\n  centerRotY += (padding[0] - padding[2]) / 2 * resolution;\n  var centerX = centerRotX * cosAngle - centerRotY * sinAngle;\n  var centerY = centerRotY * cosAngle + centerRotX * sinAngle;\n  var center = [centerX, centerY];\n\n  if (options.duration !== undefined) {\n    this.animate({\n      resolution: resolution,\n      center: center,\n      duration: options.duration,\n      easing: options.easing\n    });\n  } else {\n    this.setResolution(resolution);\n    this.setCenter(center);\n  }\n};\n\n\n/**\n * Center on coordinate and view position.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {ol.Size} size Box pixel size.\n * @param {ol.Pixel} position Position on the view to center on.\n * @api\n */\nol.View.prototype.centerOn = function(coordinate, size, position) {\n  // calculate rotated position\n  var rotation = this.getRotation();\n  var cosAngle = Math.cos(-rotation);\n  var sinAngle = Math.sin(-rotation);\n  var rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle;\n  var rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle;\n  var resolution = this.getResolution();\n  rotX += (size[0] / 2 - position[0]) * resolution;\n  rotY += (position[1] - size[1] / 2) * resolution;\n\n  // go back to original angle\n  sinAngle = -sinAngle; // go back to original rotation\n  var centerX = rotX * cosAngle - rotY * sinAngle;\n  var centerY = rotY * cosAngle + rotX * sinAngle;\n\n  this.setCenter([centerX, centerY]);\n};\n\n\n/**\n * @return {boolean} Is defined.\n */\nol.View.prototype.isDef = function() {\n  return !!this.getCenter() && this.getResolution() !== undefined;\n};\n\n\n/**\n * Rotate the view around a given coordinate.\n * @param {number} rotation New rotation value for the view.\n * @param {ol.Coordinate=} opt_anchor The rotation center.\n * @api stable\n */\nol.View.prototype.rotate = function(rotation, opt_anchor) {\n  if (opt_anchor !== undefined) {\n    var center = this.calculateCenterRotate(rotation, opt_anchor);\n    this.setCenter(center);\n  }\n  this.setRotation(rotation);\n};\n\n\n/**\n * Set the center of the current view.\n * @param {ol.Coordinate|undefined} center The center of the view.\n * @observable\n * @api stable\n */\nol.View.prototype.setCenter = function(center) {\n  this.set(ol.View.Property.CENTER, center);\n  if (this.getAnimating()) {\n    this.cancelAnimations();\n  }\n};\n\n\n/**\n * @param {ol.View.Hint} hint Hint.\n * @param {number} delta Delta.\n * @return {number} New value.\n */\nol.View.prototype.setHint = function(hint, delta) {\n  ol.DEBUG && console.assert(0 <= hint && hint < this.hints_.length,\n      'illegal hint (%s), must be between 0 and %s', hint, this.hints_.length);\n  this.hints_[hint] += delta;\n  ol.DEBUG && console.assert(this.hints_[hint] >= 0,\n      'Hint at %s must be positive, was %s', hint, this.hints_[hint]);\n  this.changed();\n  return this.hints_[hint];\n};\n\n\n/**\n * Set the resolution for this view.\n * @param {number|undefined} resolution The resolution of the view.\n * @observable\n * @api stable\n */\nol.View.prototype.setResolution = function(resolution) {\n  this.set(ol.View.Property.RESOLUTION, resolution);\n  if (this.getAnimating()) {\n    this.cancelAnimations();\n  }\n};\n\n\n/**\n * Set the rotation for this view.\n * @param {number} rotation The rotation of the view in radians.\n * @observable\n * @api stable\n */\nol.View.prototype.setRotation = function(rotation) {\n  this.set(ol.View.Property.ROTATION, rotation);\n  if (this.getAnimating()) {\n    this.cancelAnimations();\n  }\n};\n\n\n/**\n * Zoom to a specific zoom level.\n * @param {number} zoom Zoom level.\n * @api stable\n */\nol.View.prototype.setZoom = function(zoom) {\n  var resolution = this.constrainResolution(\n      this.maxResolution_, zoom - this.minZoom_, 0);\n  this.setResolution(resolution);\n};\n\n\n/**\n * @param {olx.ViewOptions} options View options.\n * @private\n * @return {ol.CenterConstraintType} The constraint.\n */\nol.View.createCenterConstraint_ = function(options) {\n  if (options.extent !== undefined) {\n    return ol.CenterConstraint.createExtent(options.extent);\n  } else {\n    return ol.CenterConstraint.none;\n  }\n};\n\n\n/**\n * @private\n * @param {olx.ViewOptions} options View options.\n * @return {{constraint: ol.ResolutionConstraintType, maxResolution: number,\n *     minResolution: number, zoomFactor: number}} The constraint.\n */\nol.View.createResolutionConstraint_ = function(options) {\n  var resolutionConstraint;\n  var maxResolution;\n  var minResolution;\n\n  // TODO: move these to be ol constants\n  // see https://github.com/openlayers/ol3/issues/2076\n  var defaultMaxZoom = 28;\n  var defaultZoomFactor = 2;\n\n  var minZoom = options.minZoom !== undefined ?\n      options.minZoom : ol.DEFAULT_MIN_ZOOM;\n\n  var maxZoom = options.maxZoom !== undefined ?\n      options.maxZoom : defaultMaxZoom;\n\n  var zoomFactor = options.zoomFactor !== undefined ?\n      options.zoomFactor : defaultZoomFactor;\n\n  if (options.resolutions !== undefined) {\n    var resolutions = options.resolutions;\n    maxResolution = resolutions[0];\n    minResolution = resolutions[resolutions.length - 1];\n    resolutionConstraint = ol.ResolutionConstraint.createSnapToResolutions(\n        resolutions);\n  } else {\n    // calculate the default min and max resolution\n    var projection = ol.proj.createProjection(options.projection, 'EPSG:3857');\n    var extent = projection.getExtent();\n    var size = !extent ?\n        // use an extent that can fit the whole world if need be\n        360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /\n            projection.getMetersPerUnit() :\n        Math.max(ol.extent.getWidth(extent), ol.extent.getHeight(extent));\n\n    var defaultMaxResolution = size / ol.DEFAULT_TILE_SIZE / Math.pow(\n        defaultZoomFactor, ol.DEFAULT_MIN_ZOOM);\n\n    var defaultMinResolution = defaultMaxResolution / Math.pow(\n        defaultZoomFactor, defaultMaxZoom - ol.DEFAULT_MIN_ZOOM);\n\n    // user provided maxResolution takes precedence\n    maxResolution = options.maxResolution;\n    if (maxResolution !== undefined) {\n      minZoom = 0;\n    } else {\n      maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom);\n    }\n\n    // user provided minResolution takes precedence\n    minResolution = options.minResolution;\n    if (minResolution === undefined) {\n      if (options.maxZoom !== undefined) {\n        if (options.maxResolution !== undefined) {\n          minResolution = maxResolution / Math.pow(zoomFactor, maxZoom);\n        } else {\n          minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom);\n        }\n      } else {\n        minResolution = defaultMinResolution;\n      }\n    }\n\n    // given discrete zoom levels, minResolution may be different than provided\n    maxZoom = minZoom + Math.floor(\n        Math.log(maxResolution / minResolution) / Math.log(zoomFactor));\n    minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);\n\n    resolutionConstraint = ol.ResolutionConstraint.createSnapToPower(\n        zoomFactor, maxResolution, maxZoom - minZoom);\n  }\n  return {constraint: resolutionConstraint, maxResolution: maxResolution,\n    minResolution: minResolution, minZoom: minZoom, zoomFactor: zoomFactor};\n};\n\n\n/**\n * @private\n * @param {olx.ViewOptions} options View options.\n * @return {ol.RotationConstraintType} Rotation constraint.\n */\nol.View.createRotationConstraint_ = function(options) {\n  var enableRotation = options.enableRotation !== undefined ?\n      options.enableRotation : true;\n  if (enableRotation) {\n    var constrainRotation = options.constrainRotation;\n    if (constrainRotation === undefined || constrainRotation === true) {\n      return ol.RotationConstraint.createSnapToZero();\n    } else if (constrainRotation === false) {\n      return ol.RotationConstraint.none;\n    } else if (typeof constrainRotation === 'number') {\n      return ol.RotationConstraint.createSnapToN(constrainRotation);\n    } else {\n      ol.DEBUG && console.assert(false,\n          'illegal option for constrainRotation (%s)', constrainRotation);\n      return ol.RotationConstraint.none;\n    }\n  } else {\n    return ol.RotationConstraint.disable;\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.View.Property = {\n  CENTER: 'center',\n  RESOLUTION: 'resolution',\n  ROTATION: 'rotation'\n};\n\n\n/**\n * @enum {number}\n */\nol.View.Hint = {\n  ANIMATING: 0,\n  INTERACTING: 1\n};\n\ngoog.provide('ol.animation');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.coordinate');\ngoog.require('ol.easing');\n\n\n/**\n * Deprecated (use {@link ol.View#animate} instead).\n * Generate an animated transition that will \"bounce\" the resolution as it\n * approaches the final value.\n * @param {olx.animation.BounceOptions} options Bounce options.\n * @return {ol.PreRenderFunction} Pre-render function.\n * @api\n */\nol.animation.bounce = function(options) {\n  ol.DEBUG && console.warn('ol.animation.bounce() is deprecated.  Use view.animate() instead.');\n  var resolution = options.resolution;\n  var start = options.start ? options.start : Date.now();\n  var duration = options.duration !== undefined ? options.duration : 1000;\n  var easing = options.easing ?\n      options.easing : ol.easing.upAndDown;\n  return (\n      /**\n       * @param {ol.Map} map Map.\n       * @param {?olx.FrameState} frameState Frame state.\n       * @return {boolean} Run this function in the next frame.\n       */\n      function(map, frameState) {\n        if (frameState.time < start) {\n          frameState.animate = true;\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else if (frameState.time < start + duration) {\n          var delta = easing((frameState.time - start) / duration);\n          var deltaResolution = resolution - frameState.viewState.resolution;\n          frameState.animate = true;\n          frameState.viewState.resolution += delta * deltaResolution;\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else {\n          return false;\n        }\n      });\n};\n\n\n/**\n * Deprecated (use {@link ol.View#animate} instead).\n * Generate an animated transition while updating the view center.\n * @param {olx.animation.PanOptions} options Pan options.\n * @return {ol.PreRenderFunction} Pre-render function.\n * @api\n */\nol.animation.pan = function(options) {\n  ol.DEBUG && console.warn('ol.animation.pan() is deprecated.  Use view.animate() instead.');\n  var source = options.source;\n  var start = options.start ? options.start : Date.now();\n  var sourceX = source[0];\n  var sourceY = source[1];\n  var duration = options.duration !== undefined ? options.duration : 1000;\n  var easing = options.easing ?\n      options.easing : ol.easing.inAndOut;\n  return (\n      /**\n       * @param {ol.Map} map Map.\n       * @param {?olx.FrameState} frameState Frame state.\n       * @return {boolean} Run this function in the next frame.\n       */\n      function(map, frameState) {\n        if (frameState.time < start) {\n          frameState.animate = true;\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else if (frameState.time < start + duration) {\n          var delta = 1 - easing((frameState.time - start) / duration);\n          var deltaX = sourceX - frameState.viewState.center[0];\n          var deltaY = sourceY - frameState.viewState.center[1];\n          frameState.animate = true;\n          frameState.viewState.center[0] += delta * deltaX;\n          frameState.viewState.center[1] += delta * deltaY;\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else {\n          return false;\n        }\n      });\n};\n\n\n/**\n * Deprecated (use {@link ol.View#animate} instead).\n * Generate an animated transition while updating the view rotation.\n * @param {olx.animation.RotateOptions} options Rotate options.\n * @return {ol.PreRenderFunction} Pre-render function.\n * @api\n */\nol.animation.rotate = function(options) {\n  ol.DEBUG && console.warn('ol.animation.rotate() is deprecated.  Use view.animate() instead.');\n  var sourceRotation = options.rotation ? options.rotation : 0;\n  var start = options.start ? options.start : Date.now();\n  var duration = options.duration !== undefined ? options.duration : 1000;\n  var easing = options.easing ?\n      options.easing : ol.easing.inAndOut;\n  var anchor = options.anchor ?\n      options.anchor : null;\n\n  return (\n      /**\n       * @param {ol.Map} map Map.\n       * @param {?olx.FrameState} frameState Frame state.\n       * @return {boolean} Run this function in the next frame.\n       */\n      function(map, frameState) {\n        if (frameState.time < start) {\n          frameState.animate = true;\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else if (frameState.time < start + duration) {\n          var delta = 1 - easing((frameState.time - start) / duration);\n          var deltaRotation =\n              (sourceRotation - frameState.viewState.rotation) * delta;\n          frameState.animate = true;\n          frameState.viewState.rotation += deltaRotation;\n          if (anchor) {\n            var center = frameState.viewState.center;\n            ol.coordinate.sub(center, anchor);\n            ol.coordinate.rotate(center, deltaRotation);\n            ol.coordinate.add(center, anchor);\n          }\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else {\n          return false;\n        }\n      });\n};\n\n\n/**\n * Deprecated (use {@link ol.View#animate} instead).\n * Generate an animated transition while updating the view resolution.\n * @param {olx.animation.ZoomOptions} options Zoom options.\n * @return {ol.PreRenderFunction} Pre-render function.\n * @api\n */\nol.animation.zoom = function(options) {\n  ol.DEBUG && console.warn('ol.animation.zoom() is deprecated.  Use view.animate() instead.');\n  var sourceResolution = options.resolution;\n  var start = options.start ? options.start : Date.now();\n  var duration = options.duration !== undefined ? options.duration : 1000;\n  var easing = options.easing ?\n      options.easing : ol.easing.inAndOut;\n  return (\n      /**\n       * @param {ol.Map} map Map.\n       * @param {?olx.FrameState} frameState Frame state.\n       * @return {boolean} Run this function in the next frame.\n       */\n      function(map, frameState) {\n        if (frameState.time < start) {\n          frameState.animate = true;\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else if (frameState.time < start + duration) {\n          var delta = 1 - easing((frameState.time - start) / duration);\n          var deltaResolution =\n              sourceResolution - frameState.viewState.resolution;\n          frameState.animate = true;\n          frameState.viewState.resolution += delta * deltaResolution;\n          frameState.viewHints[ol.View.Hint.ANIMATING] += 1;\n          return true;\n        } else {\n          return false;\n        }\n      });\n};\n\ngoog.provide('ol.TileRange');\n\n\n/**\n * A representation of a contiguous block of tiles.  A tile range is specified\n * by its min/max tile coordinates and is inclusive of coordinates.\n *\n * @constructor\n * @param {number} minX Minimum X.\n * @param {number} maxX Maximum X.\n * @param {number} minY Minimum Y.\n * @param {number} maxY Maximum Y.\n * @struct\n */\nol.TileRange = function(minX, maxX, minY, maxY) {\n\n  /**\n   * @type {number}\n   */\n  this.minX = minX;\n\n  /**\n   * @type {number}\n   */\n  this.maxX = maxX;\n\n  /**\n   * @type {number}\n   */\n  this.minY = minY;\n\n  /**\n   * @type {number}\n   */\n  this.maxY = maxY;\n\n};\n\n\n/**\n * @param {number} minX Minimum X.\n * @param {number} maxX Maximum X.\n * @param {number} minY Minimum Y.\n * @param {number} maxY Maximum Y.\n * @param {ol.TileRange|undefined} tileRange TileRange.\n * @return {ol.TileRange} Tile range.\n */\nol.TileRange.createOrUpdate = function(minX, maxX, minY, maxY, tileRange) {\n  if (tileRange !== undefined) {\n    tileRange.minX = minX;\n    tileRange.maxX = maxX;\n    tileRange.minY = minY;\n    tileRange.maxY = maxY;\n    return tileRange;\n  } else {\n    return new ol.TileRange(minX, maxX, minY, maxY);\n  }\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @return {boolean} Contains tile coordinate.\n */\nol.TileRange.prototype.contains = function(tileCoord) {\n  return this.containsXY(tileCoord[1], tileCoord[2]);\n};\n\n\n/**\n * @param {ol.TileRange} tileRange Tile range.\n * @return {boolean} Contains.\n */\nol.TileRange.prototype.containsTileRange = function(tileRange) {\n  return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX &&\n      this.minY <= tileRange.minY && tileRange.maxY <= this.maxY;\n};\n\n\n/**\n * @param {number} x Tile coordinate x.\n * @param {number} y Tile coordinate y.\n * @return {boolean} Contains coordinate.\n */\nol.TileRange.prototype.containsXY = function(x, y) {\n  return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY;\n};\n\n\n/**\n * @param {ol.TileRange} tileRange Tile range.\n * @return {boolean} Equals.\n */\nol.TileRange.prototype.equals = function(tileRange) {\n  return this.minX == tileRange.minX && this.minY == tileRange.minY &&\n      this.maxX == tileRange.maxX && this.maxY == tileRange.maxY;\n};\n\n\n/**\n * @param {ol.TileRange} tileRange Tile range.\n */\nol.TileRange.prototype.extend = function(tileRange) {\n  if (tileRange.minX < this.minX) {\n    this.minX = tileRange.minX;\n  }\n  if (tileRange.maxX > this.maxX) {\n    this.maxX = tileRange.maxX;\n  }\n  if (tileRange.minY < this.minY) {\n    this.minY = tileRange.minY;\n  }\n  if (tileRange.maxY > this.maxY) {\n    this.maxY = tileRange.maxY;\n  }\n};\n\n\n/**\n * @return {number} Height.\n */\nol.TileRange.prototype.getHeight = function() {\n  return this.maxY - this.minY + 1;\n};\n\n\n/**\n * @return {ol.Size} Size.\n */\nol.TileRange.prototype.getSize = function() {\n  return [this.getWidth(), this.getHeight()];\n};\n\n\n/**\n * @return {number} Width.\n */\nol.TileRange.prototype.getWidth = function() {\n  return this.maxX - this.minX + 1;\n};\n\n\n/**\n * @param {ol.TileRange} tileRange Tile range.\n * @return {boolean} Intersects.\n */\nol.TileRange.prototype.intersects = function(tileRange) {\n  return this.minX <= tileRange.maxX &&\n      this.maxX >= tileRange.minX &&\n      this.minY <= tileRange.maxY &&\n      this.maxY >= tileRange.minY;\n};\n\ngoog.provide('ol.size');\n\n\n/**\n * Returns a buffered size.\n * @param {ol.Size} size Size.\n * @param {number} buffer Buffer.\n * @param {ol.Size=} opt_size Optional reusable size array.\n * @return {ol.Size} The buffered size.\n */\nol.size.buffer = function(size, buffer, opt_size) {\n  if (opt_size === undefined) {\n    opt_size = [0, 0];\n  }\n  opt_size[0] = size[0] + 2 * buffer;\n  opt_size[1] = size[1] + 2 * buffer;\n  return opt_size;\n};\n\n\n/**\n * Determines if a size has a positive area.\n * @param {ol.Size} size The size to test.\n * @return {boolean} The size has a positive area.\n */\nol.size.hasArea = function(size) {\n  return size[0] > 0 && size[1] > 0;\n};\n\n\n/**\n * Returns a size scaled by a ratio. The result will be an array of integers.\n * @param {ol.Size} size Size.\n * @param {number} ratio Ratio.\n * @param {ol.Size=} opt_size Optional reusable size array.\n * @return {ol.Size} The scaled size.\n */\nol.size.scale = function(size, ratio, opt_size) {\n  if (opt_size === undefined) {\n    opt_size = [0, 0];\n  }\n  opt_size[0] = (size[0] * ratio + 0.5) | 0;\n  opt_size[1] = (size[1] * ratio + 0.5) | 0;\n  return opt_size;\n};\n\n\n/**\n * Returns an `ol.Size` array for the passed in number (meaning: square) or\n * `ol.Size` array.\n * (meaning: non-square),\n * @param {number|ol.Size} size Width and height.\n * @param {ol.Size=} opt_size Optional reusable size array.\n * @return {ol.Size} Size.\n * @api stable\n */\nol.size.toSize = function(size, opt_size) {\n  if (Array.isArray(size)) {\n    return size;\n  } else {\n    if (opt_size === undefined) {\n      opt_size = [size, size];\n    } else {\n      opt_size[0] = opt_size[1] = /** @type {number} */ (size);\n    }\n    return opt_size;\n  }\n};\n\ngoog.provide('ol.tilecoord');\n\n\n/**\n * @param {number} z Z.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {ol.TileCoord=} opt_tileCoord Tile coordinate.\n * @return {ol.TileCoord} Tile coordinate.\n */\nol.tilecoord.createOrUpdate = function(z, x, y, opt_tileCoord) {\n  if (opt_tileCoord !== undefined) {\n    opt_tileCoord[0] = z;\n    opt_tileCoord[1] = x;\n    opt_tileCoord[2] = y;\n    return opt_tileCoord;\n  } else {\n    return [z, x, y];\n  }\n};\n\n\n/**\n * @param {number} z Z.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {string} Key.\n */\nol.tilecoord.getKeyZXY = function(z, x, y) {\n  return z + '/' + x + '/' + y;\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coord.\n * @return {number} Hash.\n */\nol.tilecoord.hash = function(tileCoord) {\n  return (tileCoord[1] << tileCoord[0]) + tileCoord[2];\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coord.\n * @return {string} Quad key.\n */\nol.tilecoord.quadKey = function(tileCoord) {\n  var z = tileCoord[0];\n  var digits = new Array(z);\n  var mask = 1 << (z - 1);\n  var i, charCode;\n  for (i = 0; i < z; ++i) {\n    // 48 is charCode for 0 - '0'.charCodeAt(0)\n    charCode = 48;\n    if (tileCoord[1] & mask) {\n      charCode += 1;\n    }\n    if (tileCoord[2] & mask) {\n      charCode += 2;\n    }\n    digits[i] = String.fromCharCode(charCode);\n    mask >>= 1;\n  }\n  return digits.join('');\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid.\n * @return {boolean} Tile coordinate is within extent and zoom level range.\n */\nol.tilecoord.withinExtentAndZ = function(tileCoord, tileGrid) {\n  var z = tileCoord[0];\n  var x = tileCoord[1];\n  var y = tileCoord[2];\n\n  if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) {\n    return false;\n  }\n  var extent = tileGrid.getExtent();\n  var tileRange;\n  if (!extent) {\n    tileRange = tileGrid.getFullTileRange(z);\n  } else {\n    tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);\n  }\n  if (!tileRange) {\n    return true;\n  } else {\n    return tileRange.containsXY(x, y);\n  }\n};\n\ngoog.provide('ol.tilegrid.TileGrid');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.TileRange');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.math');\ngoog.require('ol.size');\ngoog.require('ol.tilecoord');\n\n\n/**\n * @classdesc\n * Base class for setting the grid pattern for sources accessing tiled-image\n * servers.\n *\n * @constructor\n * @param {olx.tilegrid.TileGridOptions} options Tile grid options.\n * @struct\n * @api stable\n */\nol.tilegrid.TileGrid = function(options) {\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.minZoom = options.minZoom !== undefined ? options.minZoom : 0;\n\n  /**\n   * @private\n   * @type {!Array.<number>}\n   */\n  this.resolutions_ = options.resolutions;\n  ol.asserts.assert(ol.array.isSorted(this.resolutions_, function(a, b) {\n    return b - a;\n  }, true), 17); // `resolutions` must be sorted in descending order\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.maxZoom = this.resolutions_.length - 1;\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.origin_ = options.origin !== undefined ? options.origin : null;\n\n  /**\n   * @private\n   * @type {Array.<ol.Coordinate>}\n   */\n  this.origins_ = null;\n  if (options.origins !== undefined) {\n    this.origins_ = options.origins;\n    ol.asserts.assert(this.origins_.length == this.resolutions_.length,\n        20); // Number of `origins` and `resolutions` must be equal\n  }\n\n  var extent = options.extent;\n\n  if (extent !== undefined &&\n      !this.origin_ && !this.origins_) {\n    this.origin_ = ol.extent.getTopLeft(extent);\n  }\n\n  ol.asserts.assert(\n      (!this.origin_ && this.origins_) || (this.origin_ && !this.origins_),\n      18); // Either `origin` or `origins` must be configured, never both\n\n  /**\n   * @private\n   * @type {Array.<number|ol.Size>}\n   */\n  this.tileSizes_ = null;\n  if (options.tileSizes !== undefined) {\n    this.tileSizes_ = options.tileSizes;\n    ol.asserts.assert(this.tileSizes_.length == this.resolutions_.length,\n        19); // Number of `tileSizes` and `resolutions` must be equal\n  }\n\n  /**\n   * @private\n   * @type {number|ol.Size}\n   */\n  this.tileSize_ = options.tileSize !== undefined ?\n      options.tileSize :\n      !this.tileSizes_ ? ol.DEFAULT_TILE_SIZE : null;\n  ol.asserts.assert(\n      (!this.tileSize_ && this.tileSizes_) ||\n      (this.tileSize_ && !this.tileSizes_),\n      22); // Either `tileSize` or `tileSizes` must be configured, never both\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.extent_ = extent !== undefined ? extent : null;\n\n\n  /**\n   * @private\n   * @type {Array.<ol.TileRange>}\n   */\n  this.fullTileRanges_ = null;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.tmpSize_ = [0, 0];\n\n  if (options.sizes !== undefined) {\n    ol.DEBUG && console.assert(options.sizes.length == this.resolutions_.length,\n        'number of sizes and resolutions must be equal');\n    this.fullTileRanges_ = options.sizes.map(function(size, z) {\n      ol.DEBUG && console.assert(size[0] !== 0, 'width must not be 0');\n      ol.DEBUG && console.assert(size[1] !== 0, 'height must not be 0');\n      var tileRange = new ol.TileRange(\n          Math.min(0, size[0]), Math.max(size[0] - 1, -1),\n          Math.min(0, size[1]), Math.max(size[1] - 1, -1));\n      return tileRange;\n    }, this);\n  } else if (extent) {\n    this.calculateTileRanges_(extent);\n  }\n\n};\n\n\n/**\n * @private\n * @type {ol.TileCoord}\n */\nol.tilegrid.TileGrid.tmpTileCoord_ = [0, 0, 0];\n\n\n/**\n * Call a function with each tile coordinate for a given extent and zoom level.\n *\n * @param {ol.Extent} extent Extent.\n * @param {number} zoom Zoom level.\n * @param {function(ol.TileCoord)} callback Function called with each tile coordinate.\n * @api\n */\nol.tilegrid.TileGrid.prototype.forEachTileCoord = function(extent, zoom, callback) {\n  var tileRange = this.getTileRangeForExtentAndZ(extent, zoom);\n  for (var i = tileRange.minX, ii = tileRange.maxX; i <= ii; ++i) {\n    for (var j = tileRange.minY, jj = tileRange.maxY; j <= jj; ++j) {\n      callback([zoom, i, j]);\n    }\n  }\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {function(this: T, number, ol.TileRange): boolean} callback Callback.\n * @param {T=} opt_this The object to use as `this` in `callback`.\n * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object.\n * @param {ol.Extent=} opt_extent Temporary ol.Extent object.\n * @return {boolean} Callback succeeded.\n * @template T\n */\nol.tilegrid.TileGrid.prototype.forEachTileCoordParentTileRange = function(tileCoord, callback, opt_this, opt_tileRange, opt_extent) {\n  var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent);\n  var z = tileCoord[0] - 1;\n  while (z >= this.minZoom) {\n    if (callback.call(opt_this, z,\n        this.getTileRangeForExtentAndZ(tileCoordExtent, z, opt_tileRange))) {\n      return true;\n    }\n    --z;\n  }\n  return false;\n};\n\n\n/**\n * Get the extent for this tile grid, if it was configured.\n * @return {ol.Extent} Extent.\n */\nol.tilegrid.TileGrid.prototype.getExtent = function() {\n  return this.extent_;\n};\n\n\n/**\n * Get the maximum zoom level for the grid.\n * @return {number} Max zoom.\n * @api\n */\nol.tilegrid.TileGrid.prototype.getMaxZoom = function() {\n  return this.maxZoom;\n};\n\n\n/**\n * Get the minimum zoom level for the grid.\n * @return {number} Min zoom.\n * @api\n */\nol.tilegrid.TileGrid.prototype.getMinZoom = function() {\n  return this.minZoom;\n};\n\n\n/**\n * Get the origin for the grid at the given zoom level.\n * @param {number} z Z.\n * @return {ol.Coordinate} Origin.\n * @api stable\n */\nol.tilegrid.TileGrid.prototype.getOrigin = function(z) {\n  if (this.origin_) {\n    return this.origin_;\n  } else {\n    ol.DEBUG && console.assert(this.minZoom <= z && z <= this.maxZoom,\n        'given z is not in allowed range (%s <= %s <= %s)',\n        this.minZoom, z, this.maxZoom);\n    return this.origins_[z];\n  }\n};\n\n\n/**\n * Get the resolution for the given zoom level.\n * @param {number} z Z.\n * @return {number} Resolution.\n * @api stable\n */\nol.tilegrid.TileGrid.prototype.getResolution = function(z) {\n  ol.DEBUG && console.assert(this.minZoom <= z && z <= this.maxZoom,\n      'given z is not in allowed range (%s <= %s <= %s)',\n      this.minZoom, z, this.maxZoom);\n  return this.resolutions_[z];\n};\n\n\n/**\n * Get the list of resolutions for the tile grid.\n * @return {Array.<number>} Resolutions.\n * @api stable\n */\nol.tilegrid.TileGrid.prototype.getResolutions = function() {\n  return this.resolutions_;\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object.\n * @param {ol.Extent=} opt_extent Temporary ol.Extent object.\n * @return {ol.TileRange} Tile range.\n */\nol.tilegrid.TileGrid.prototype.getTileCoordChildTileRange = function(tileCoord, opt_tileRange, opt_extent) {\n  if (tileCoord[0] < this.maxZoom) {\n    var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent);\n    return this.getTileRangeForExtentAndZ(\n        tileCoordExtent, tileCoord[0] + 1, opt_tileRange);\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @param {number} z Z.\n * @param {ol.TileRange} tileRange Tile range.\n * @param {ol.Extent=} opt_extent Temporary ol.Extent object.\n * @return {ol.Extent} Extent.\n */\nol.tilegrid.TileGrid.prototype.getTileRangeExtent = function(z, tileRange, opt_extent) {\n  var origin = this.getOrigin(z);\n  var resolution = this.getResolution(z);\n  var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);\n  var minX = origin[0] + tileRange.minX * tileSize[0] * resolution;\n  var maxX = origin[0] + (tileRange.maxX + 1) * tileSize[0] * resolution;\n  var minY = origin[1] + tileRange.minY * tileSize[1] * resolution;\n  var maxY = origin[1] + (tileRange.maxY + 1) * tileSize[1] * resolution;\n  return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @param {ol.TileRange=} opt_tileRange Temporary tile range object.\n * @return {ol.TileRange} Tile range.\n */\nol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = function(extent, resolution, opt_tileRange) {\n  var tileCoord = ol.tilegrid.TileGrid.tmpTileCoord_;\n  this.getTileCoordForXYAndResolution_(\n      extent[0], extent[1], resolution, false, tileCoord);\n  var minX = tileCoord[1];\n  var minY = tileCoord[2];\n  this.getTileCoordForXYAndResolution_(\n      extent[2], extent[3], resolution, true, tileCoord);\n  return ol.TileRange.createOrUpdate(\n      minX, tileCoord[1], minY, tileCoord[2], opt_tileRange);\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} z Z.\n * @param {ol.TileRange=} opt_tileRange Temporary tile range object.\n * @return {ol.TileRange} Tile range.\n */\nol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ = function(extent, z, opt_tileRange) {\n  var resolution = this.getResolution(z);\n  return this.getTileRangeForExtentAndResolution(\n      extent, resolution, opt_tileRange);\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @return {ol.Coordinate} Tile center.\n */\nol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) {\n  var origin = this.getOrigin(tileCoord[0]);\n  var resolution = this.getResolution(tileCoord[0]);\n  var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);\n  return [\n    origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution,\n    origin[1] + (tileCoord[2] + 0.5) * tileSize[1] * resolution\n  ];\n};\n\n\n/**\n * Get the extent of a tile coordinate.\n *\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Extent=} opt_extent Temporary extent object.\n * @return {ol.Extent} Extent.\n * @api\n */\nol.tilegrid.TileGrid.prototype.getTileCoordExtent = function(tileCoord, opt_extent) {\n  var origin = this.getOrigin(tileCoord[0]);\n  var resolution = this.getResolution(tileCoord[0]);\n  var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);\n  var minX = origin[0] + tileCoord[1] * tileSize[0] * resolution;\n  var minY = origin[1] + tileCoord[2] * tileSize[1] * resolution;\n  var maxX = minX + tileSize[0] * resolution;\n  var maxY = minY + tileSize[1] * resolution;\n  return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);\n};\n\n\n/**\n * Get the tile coordinate for the given map coordinate and resolution.  This\n * method considers that coordinates that intersect tile boundaries should be\n * assigned the higher tile coordinate.\n *\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} resolution Resolution.\n * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object.\n * @return {ol.TileCoord} Tile coordinate.\n * @api\n */\nol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution = function(coordinate, resolution, opt_tileCoord) {\n  return this.getTileCoordForXYAndResolution_(\n      coordinate[0], coordinate[1], resolution, false, opt_tileCoord);\n};\n\n\n/**\n * @param {number} x X.\n * @param {number} y Y.\n * @param {number} resolution Resolution.\n * @param {boolean} reverseIntersectionPolicy Instead of letting edge\n *     intersections go to the higher tile coordinate, let edge intersections\n *     go to the lower tile coordinate.\n * @param {ol.TileCoord=} opt_tileCoord Temporary ol.TileCoord object.\n * @return {ol.TileCoord} Tile coordinate.\n * @private\n */\nol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function(\n    x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) {\n  var z = this.getZForResolution(resolution);\n  var scale = resolution / this.getResolution(z);\n  var origin = this.getOrigin(z);\n  var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);\n\n  var adjustX = reverseIntersectionPolicy ? 0.5 : 0;\n  var adjustY = reverseIntersectionPolicy ? 0 : 0.5;\n  var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX);\n  var yFromOrigin = Math.floor((y - origin[1]) / resolution + adjustY);\n  var tileCoordX = scale * xFromOrigin / tileSize[0];\n  var tileCoordY = scale * yFromOrigin / tileSize[1];\n\n  if (reverseIntersectionPolicy) {\n    tileCoordX = Math.ceil(tileCoordX) - 1;\n    tileCoordY = Math.ceil(tileCoordY) - 1;\n  } else {\n    tileCoordX = Math.floor(tileCoordX);\n    tileCoordY = Math.floor(tileCoordY);\n  }\n\n  return ol.tilecoord.createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord);\n};\n\n\n/**\n * Get a tile coordinate given a map coordinate and zoom level.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} z Zoom level.\n * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object.\n * @return {ol.TileCoord} Tile coordinate.\n * @api\n */\nol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ = function(coordinate, z, opt_tileCoord) {\n  var resolution = this.getResolution(z);\n  return this.getTileCoordForXYAndResolution_(\n      coordinate[0], coordinate[1], resolution, false, opt_tileCoord);\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @return {number} Tile resolution.\n */\nol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) {\n  ol.DEBUG && console.assert(\n      this.minZoom <= tileCoord[0] && tileCoord[0] <= this.maxZoom,\n      'z of given tilecoord is not in allowed range (%s <= %s <= %s',\n      this.minZoom, tileCoord[0], this.maxZoom);\n  return this.resolutions_[tileCoord[0]];\n};\n\n\n/**\n * Get the tile size for a zoom level. The type of the return value matches the\n * `tileSize` or `tileSizes` that the tile grid was configured with. To always\n * get an `ol.Size`, run the result through `ol.size.toSize()`.\n * @param {number} z Z.\n * @return {number|ol.Size} Tile size.\n * @api stable\n */\nol.tilegrid.TileGrid.prototype.getTileSize = function(z) {\n  if (this.tileSize_) {\n    return this.tileSize_;\n  } else {\n    ol.DEBUG && console.assert(this.minZoom <= z && z <= this.maxZoom,\n        'z is not in allowed range (%s <= %s <= %s',\n        this.minZoom, z, this.maxZoom);\n    return this.tileSizes_[z];\n  }\n};\n\n\n/**\n * @param {number} z Zoom level.\n * @return {ol.TileRange} Extent tile range for the specified zoom level.\n */\nol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) {\n  if (!this.fullTileRanges_) {\n    return null;\n  } else {\n    ol.DEBUG && console.assert(this.minZoom <= z && z <= this.maxZoom,\n        'z is not in allowed range (%s <= %s <= %s',\n        this.minZoom, z, this.maxZoom);\n    return this.fullTileRanges_[z];\n  }\n};\n\n\n/**\n * @param {number} resolution Resolution.\n * @param {number=} opt_direction If 0, the nearest resolution will be used.\n *     If 1, the nearest lower resolution will be used. If -1, the nearest\n *     higher resolution will be used. Default is 0.\n * @return {number} Z.\n * @api\n */\nol.tilegrid.TileGrid.prototype.getZForResolution = function(\n    resolution, opt_direction) {\n  var z = ol.array.linearFindNearest(this.resolutions_, resolution,\n      opt_direction || 0);\n  return ol.math.clamp(z, this.minZoom, this.maxZoom);\n};\n\n\n/**\n * @param {!ol.Extent} extent Extent for this tile grid.\n * @private\n */\nol.tilegrid.TileGrid.prototype.calculateTileRanges_ = function(extent) {\n  var length = this.resolutions_.length;\n  var fullTileRanges = new Array(length);\n  for (var z = this.minZoom; z < length; ++z) {\n    fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z);\n  }\n  this.fullTileRanges_ = fullTileRanges;\n};\n\ngoog.provide('ol.tilegrid');\n\ngoog.require('ol');\ngoog.require('ol.size');\ngoog.require('ol.extent');\ngoog.require('ol.extent.Corner');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Units');\ngoog.require('ol.tilegrid.TileGrid');\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @return {!ol.tilegrid.TileGrid} Default tile grid for the passed projection.\n */\nol.tilegrid.getForProjection = function(projection) {\n  var tileGrid = projection.getDefaultTileGrid();\n  if (!tileGrid) {\n    tileGrid = ol.tilegrid.createForProjection(projection);\n    projection.setDefaultTileGrid(tileGrid);\n  }\n  return tileGrid;\n};\n\n\n/**\n * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.proj.Projection} projection Projection.\n * @return {ol.TileCoord} Tile coordinate.\n */\nol.tilegrid.wrapX = function(tileGrid, tileCoord, projection) {\n  var z = tileCoord[0];\n  var center = tileGrid.getTileCoordCenter(tileCoord);\n  var projectionExtent = ol.tilegrid.extentFromProjection(projection);\n  if (!ol.extent.containsCoordinate(projectionExtent, center)) {\n    var worldWidth = ol.extent.getWidth(projectionExtent);\n    var worldsAway = Math.ceil((projectionExtent[0] - center[0]) / worldWidth);\n    center[0] += worldWidth * worldsAway;\n    return tileGrid.getTileCoordForCoordAndZ(center, z);\n  } else {\n    return tileCoord;\n  }\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number=} opt_maxZoom Maximum zoom level (default is\n *     ol.DEFAULT_MAX_ZOOM).\n * @param {number|ol.Size=} opt_tileSize Tile size (default uses\n *     ol.DEFAULT_TILE_SIZE).\n * @param {ol.extent.Corner=} opt_corner Extent corner (default is\n *     ol.extent.Corner.TOP_LEFT).\n * @return {!ol.tilegrid.TileGrid} TileGrid instance.\n */\nol.tilegrid.createForExtent = function(extent, opt_maxZoom, opt_tileSize, opt_corner) {\n  var corner = opt_corner !== undefined ?\n      opt_corner : ol.extent.Corner.TOP_LEFT;\n\n  var resolutions = ol.tilegrid.resolutionsFromExtent(\n      extent, opt_maxZoom, opt_tileSize);\n\n  return new ol.tilegrid.TileGrid({\n    extent: extent,\n    origin: ol.extent.getCorner(extent, corner),\n    resolutions: resolutions,\n    tileSize: opt_tileSize\n  });\n};\n\n\n/**\n * Creates a tile grid with a standard XYZ tiling scheme.\n * @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options.\n * @return {ol.tilegrid.TileGrid} Tile grid instance.\n * @api\n */\nol.tilegrid.createXYZ = function(opt_options) {\n  var options = /** @type {olx.tilegrid.TileGridOptions} */ ({});\n  ol.obj.assign(options, opt_options !== undefined ?\n      opt_options : /** @type {olx.tilegrid.XYZOptions} */ ({}));\n  if (options.extent === undefined) {\n    options.extent = ol.proj.get('EPSG:3857').getExtent();\n  }\n  options.resolutions = ol.tilegrid.resolutionsFromExtent(\n      options.extent, options.maxZoom, options.tileSize);\n  delete options.maxZoom;\n\n  return new ol.tilegrid.TileGrid(options);\n};\n\n\n/**\n * Create a resolutions array from an extent.  A zoom factor of 2 is assumed.\n * @param {ol.Extent} extent Extent.\n * @param {number=} opt_maxZoom Maximum zoom level (default is\n *     ol.DEFAULT_MAX_ZOOM).\n * @param {number|ol.Size=} opt_tileSize Tile size (default uses\n *     ol.DEFAULT_TILE_SIZE).\n * @return {!Array.<number>} Resolutions array.\n */\nol.tilegrid.resolutionsFromExtent = function(extent, opt_maxZoom, opt_tileSize) {\n  var maxZoom = opt_maxZoom !== undefined ?\n      opt_maxZoom : ol.DEFAULT_MAX_ZOOM;\n\n  var height = ol.extent.getHeight(extent);\n  var width = ol.extent.getWidth(extent);\n\n  var tileSize = ol.size.toSize(opt_tileSize !== undefined ?\n      opt_tileSize : ol.DEFAULT_TILE_SIZE);\n  var maxResolution = Math.max(\n      width / tileSize[0], height / tileSize[1]);\n\n  var length = maxZoom + 1;\n  var resolutions = new Array(length);\n  for (var z = 0; z < length; ++z) {\n    resolutions[z] = maxResolution / Math.pow(2, z);\n  }\n  return resolutions;\n};\n\n\n/**\n * @param {ol.ProjectionLike} projection Projection.\n * @param {number=} opt_maxZoom Maximum zoom level (default is\n *     ol.DEFAULT_MAX_ZOOM).\n * @param {ol.Size=} opt_tileSize Tile size (default uses ol.DEFAULT_TILE_SIZE).\n * @param {ol.extent.Corner=} opt_corner Extent corner (default is\n *     ol.extent.Corner.BOTTOM_LEFT).\n * @return {!ol.tilegrid.TileGrid} TileGrid instance.\n */\nol.tilegrid.createForProjection = function(projection, opt_maxZoom, opt_tileSize, opt_corner) {\n  var extent = ol.tilegrid.extentFromProjection(projection);\n  return ol.tilegrid.createForExtent(\n      extent, opt_maxZoom, opt_tileSize, opt_corner);\n};\n\n\n/**\n * Generate a tile grid extent from a projection.  If the projection has an\n * extent, it is used.  If not, a global extent is assumed.\n * @param {ol.ProjectionLike} projection Projection.\n * @return {ol.Extent} Extent.\n */\nol.tilegrid.extentFromProjection = function(projection) {\n  projection = ol.proj.get(projection);\n  var extent = projection.getExtent();\n  if (!extent) {\n    var half = 180 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /\n        projection.getMetersPerUnit();\n    extent = ol.extent.createOrUpdate(-half, -half, half, half);\n  }\n  return extent;\n};\n\ngoog.provide('ol.Attribution');\n\ngoog.require('ol.TileRange');\ngoog.require('ol.math');\ngoog.require('ol.tilegrid');\n\n\n/**\n * @classdesc\n * An attribution for a layer source.\n *\n * Example:\n *\n *     source: new ol.source.OSM({\n *       attributions: [\n *         new ol.Attribution({\n *           html: 'All maps &copy; ' +\n *               '<a href=\"https://www.opencyclemap.org/\">OpenCycleMap</a>'\n *         }),\n *         ol.source.OSM.ATTRIBUTION\n *       ],\n *     ..\n *\n * @constructor\n * @param {olx.AttributionOptions} options Attribution options.\n * @struct\n * @api stable\n */\nol.Attribution = function(options) {\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.html_ = options.html;\n\n  /**\n   * @private\n   * @type {Object.<string, Array.<ol.TileRange>>}\n   */\n  this.tileRanges_ = options.tileRanges ? options.tileRanges : null;\n\n};\n\n\n/**\n * Get the attribution markup.\n * @return {string} The attribution HTML.\n * @api stable\n */\nol.Attribution.prototype.getHTML = function() {\n  return this.html_;\n};\n\n\n/**\n * @param {Object.<string, ol.TileRange>} tileRanges Tile ranges.\n * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid.\n * @param {!ol.proj.Projection} projection Projection.\n * @return {boolean} Intersects any tile range.\n */\nol.Attribution.prototype.intersectsAnyTileRange = function(tileRanges, tileGrid, projection) {\n  if (!this.tileRanges_) {\n    return true;\n  }\n  var i, ii, tileRange, zKey;\n  for (zKey in tileRanges) {\n    if (!(zKey in this.tileRanges_)) {\n      continue;\n    }\n    tileRange = tileRanges[zKey];\n    var testTileRange;\n    for (i = 0, ii = this.tileRanges_[zKey].length; i < ii; ++i) {\n      testTileRange = this.tileRanges_[zKey][i];\n      if (testTileRange.intersects(tileRange)) {\n        return true;\n      }\n      var extentTileRange = tileGrid.getTileRangeForExtentAndZ(\n          ol.tilegrid.extentFromProjection(projection), parseInt(zKey, 10));\n      var width = extentTileRange.getWidth();\n      if (tileRange.minX < extentTileRange.minX ||\n          tileRange.maxX > extentTileRange.maxX) {\n        if (testTileRange.intersects(new ol.TileRange(\n            ol.math.modulo(tileRange.minX, width),\n            ol.math.modulo(tileRange.maxX, width),\n            tileRange.minY, tileRange.maxY))) {\n          return true;\n        }\n        if (tileRange.getWidth() > width &&\n            testTileRange.intersects(extentTileRange)) {\n          return true;\n        }\n      }\n    }\n  }\n  return false;\n};\n\n/**\n * An implementation of Google Maps' MVCArray.\n * @see https://developers.google.com/maps/documentation/javascript/reference\n */\n\ngoog.provide('ol.Collection');\n\ngoog.require('ol');\ngoog.require('ol.events.Event');\ngoog.require('ol.Object');\n\n\n/**\n * @classdesc\n * An expanded version of standard JS Array, adding convenience methods for\n * manipulation. Add and remove changes to the Collection trigger a Collection\n * event. Note that this does not cover changes to the objects _within_ the\n * Collection; they trigger events on the appropriate object, not on the\n * Collection as a whole.\n *\n * @constructor\n * @extends {ol.Object}\n * @fires ol.Collection.Event\n * @param {!Array.<T>=} opt_array Array.\n * @template T\n * @api stable\n */\nol.Collection = function(opt_array) {\n\n  ol.Object.call(this);\n\n  /**\n   * @private\n   * @type {!Array.<T>}\n   */\n  this.array_ = opt_array ? opt_array : [];\n\n  this.updateLength_();\n\n};\nol.inherits(ol.Collection, ol.Object);\n\n\n/**\n * Remove all elements from the collection.\n * @api stable\n */\nol.Collection.prototype.clear = function() {\n  while (this.getLength() > 0) {\n    this.pop();\n  }\n};\n\n\n/**\n * Add elements to the collection.  This pushes each item in the provided array\n * to the end of the collection.\n * @param {!Array.<T>} arr Array.\n * @return {ol.Collection.<T>} This collection.\n * @api stable\n */\nol.Collection.prototype.extend = function(arr) {\n  var i, ii;\n  for (i = 0, ii = arr.length; i < ii; ++i) {\n    this.push(arr[i]);\n  }\n  return this;\n};\n\n\n/**\n * Iterate over each element, calling the provided callback.\n * @param {function(this: S, T, number, Array.<T>): *} f The function to call\n *     for every element. This function takes 3 arguments (the element, the\n *     index and the array). The return value is ignored.\n * @param {S=} opt_this The object to use as `this` in `f`.\n * @template S\n * @api stable\n */\nol.Collection.prototype.forEach = function(f, opt_this) {\n  this.array_.forEach(f, opt_this);\n};\n\n\n/**\n * Get a reference to the underlying Array object. Warning: if the array\n * is mutated, no events will be dispatched by the collection, and the\n * collection's \"length\" property won't be in sync with the actual length\n * of the array.\n * @return {!Array.<T>} Array.\n * @api stable\n */\nol.Collection.prototype.getArray = function() {\n  return this.array_;\n};\n\n\n/**\n * Get the element at the provided index.\n * @param {number} index Index.\n * @return {T} Element.\n * @api stable\n */\nol.Collection.prototype.item = function(index) {\n  return this.array_[index];\n};\n\n\n/**\n * Get the length of this collection.\n * @return {number} The length of the array.\n * @observable\n * @api stable\n */\nol.Collection.prototype.getLength = function() {\n  return /** @type {number} */ (this.get(ol.Collection.Property.LENGTH));\n};\n\n\n/**\n * Insert an element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api stable\n */\nol.Collection.prototype.insertAt = function(index, elem) {\n  this.array_.splice(index, 0, elem);\n  this.updateLength_();\n  this.dispatchEvent(\n      new ol.Collection.Event(ol.Collection.EventType.ADD, elem));\n};\n\n\n/**\n * Remove the last element of the collection and return it.\n * Return `undefined` if the collection is empty.\n * @return {T|undefined} Element.\n * @api stable\n */\nol.Collection.prototype.pop = function() {\n  return this.removeAt(this.getLength() - 1);\n};\n\n\n/**\n * Insert the provided element at the end of the collection.\n * @param {T} elem Element.\n * @return {number} New length of the collection.\n * @api stable\n */\nol.Collection.prototype.push = function(elem) {\n  var n = this.getLength();\n  this.insertAt(n, elem);\n  return this.getLength();\n};\n\n\n/**\n * Remove the first occurrence of an element from the collection.\n * @param {T} elem Element.\n * @return {T|undefined} The removed element or undefined if none found.\n * @api stable\n */\nol.Collection.prototype.remove = function(elem) {\n  var arr = this.array_;\n  var i, ii;\n  for (i = 0, ii = arr.length; i < ii; ++i) {\n    if (arr[i] === elem) {\n      return this.removeAt(i);\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * Remove the element at the provided index and return it.\n * Return `undefined` if the collection does not contain this index.\n * @param {number} index Index.\n * @return {T|undefined} Value.\n * @api stable\n */\nol.Collection.prototype.removeAt = function(index) {\n  var prev = this.array_[index];\n  this.array_.splice(index, 1);\n  this.updateLength_();\n  this.dispatchEvent(\n      new ol.Collection.Event(ol.Collection.EventType.REMOVE, prev));\n  return prev;\n};\n\n\n/**\n * Set the element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api stable\n */\nol.Collection.prototype.setAt = function(index, elem) {\n  var n = this.getLength();\n  if (index < n) {\n    var prev = this.array_[index];\n    this.array_[index] = elem;\n    this.dispatchEvent(\n        new ol.Collection.Event(ol.Collection.EventType.REMOVE, prev));\n    this.dispatchEvent(\n        new ol.Collection.Event(ol.Collection.EventType.ADD, elem));\n  } else {\n    var j;\n    for (j = n; j < index; ++j) {\n      this.insertAt(j, undefined);\n    }\n    this.insertAt(index, elem);\n  }\n};\n\n\n/**\n * @private\n */\nol.Collection.prototype.updateLength_ = function() {\n  this.set(ol.Collection.Property.LENGTH, this.array_.length);\n};\n\n\n/**\n * @enum {string}\n */\nol.Collection.Property = {\n  LENGTH: 'length'\n};\n\n\n/**\n * @enum {string}\n */\nol.Collection.EventType = {\n  /**\n   * Triggered when an item is added to the collection.\n   * @event ol.Collection.Event#add\n   * @api stable\n   */\n  ADD: 'add',\n  /**\n   * Triggered when an item is removed from the collection.\n   * @event ol.Collection.Event#remove\n   * @api stable\n   */\n  REMOVE: 'remove'\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.Collection} instances are instances of this\n * type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.Collection.Event}\n * @param {ol.Collection.EventType} type Type.\n * @param {*=} opt_element Element.\n */\nol.Collection.Event = function(type, opt_element) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The element that is added to or removed from the collection.\n   * @type {*}\n   * @api stable\n   */\n  this.element = opt_element;\n\n};\nol.inherits(ol.Collection.Event, ol.events.Event);\n\ngoog.provide('ol.color');\n\ngoog.require('ol.asserts');\ngoog.require('ol.math');\n\n\n/**\n * This RegExp matches # followed by 3 or 6 hex digits.\n * @const\n * @type {RegExp}\n * @private\n */\nol.color.HEX_COLOR_RE_ = /^#(?:[0-9a-f]{3}){1,2}$/i;\n\n\n/**\n * Regular expression for matching potential named color style strings.\n * @const\n * @type {RegExp}\n * @private\n */\nol.color.NAMED_COLOR_RE_ = /^([a-z]*)$/i;\n\n\n/**\n * Return the color as an array. This function maintains a cache of calculated\n * arrays which means the result should not be modified.\n * @param {ol.Color|string} color Color.\n * @return {ol.Color} Color.\n * @api\n */\nol.color.asArray = function(color) {\n  if (Array.isArray(color)) {\n    return color;\n  } else {\n    return ol.color.fromString(/** @type {string} */ (color));\n  }\n};\n\n\n/**\n * Return the color as an rgba string.\n * @param {ol.Color|string} color Color.\n * @return {string} Rgba string.\n * @api\n */\nol.color.asString = function(color) {\n  if (typeof color === 'string') {\n    return color;\n  } else {\n    return ol.color.toString(color);\n  }\n};\n\n/**\n * Return named color as an rgba string.\n * @param {string} color Named color.\n * @return {string} Rgb string.\n */\nol.color.fromNamed = function(color) {\n  var el = document.createElement('div');\n  el.style.color = color;\n  document.body.appendChild(el);\n  var rgb = getComputedStyle(el).color;\n  document.body.removeChild(el);\n  return rgb;\n};\n\n\n/**\n * @param {string} s String.\n * @return {ol.Color} Color.\n */\nol.color.fromString = (\n    function() {\n\n      // We maintain a small cache of parsed strings.  To provide cheap LRU-like\n      // semantics, whenever the cache grows too large we simply delete an\n      // arbitrary 25% of the entries.\n\n      /**\n       * @const\n       * @type {number}\n       */\n      var MAX_CACHE_SIZE = 1024;\n\n      /**\n       * @type {Object.<string, ol.Color>}\n       */\n      var cache = {};\n\n      /**\n       * @type {number}\n       */\n      var cacheSize = 0;\n\n      return (\n          /**\n           * @param {string} s String.\n           * @return {ol.Color} Color.\n           */\n          function(s) {\n            var color;\n            if (cache.hasOwnProperty(s)) {\n              color = cache[s];\n            } else {\n              if (cacheSize >= MAX_CACHE_SIZE) {\n                var i = 0;\n                var key;\n                for (key in cache) {\n                  if ((i++ & 3) === 0) {\n                    delete cache[key];\n                    --cacheSize;\n                  }\n                }\n              }\n              color = ol.color.fromStringInternal_(s);\n              cache[s] = color;\n              ++cacheSize;\n            }\n            return color;\n          });\n\n    })();\n\n\n/**\n * @param {string} s String.\n * @private\n * @return {ol.Color} Color.\n */\nol.color.fromStringInternal_ = function(s) {\n  var r, g, b, a, color, parts;\n\n  if (ol.color.NAMED_COLOR_RE_.exec(s)) {\n    s = ol.color.fromNamed(s);\n  }\n\n  if (ol.color.HEX_COLOR_RE_.exec(s)) { // hex\n    var n = s.length - 1; // number of hex digits\n    ol.asserts.assert(n == 3 || n == 6, 54); // Hex color should have 3 or 6 digits\n    var d = n == 3 ? 1 : 2; // number of digits per channel\n    r = parseInt(s.substr(1 + 0 * d, d), 16);\n    g = parseInt(s.substr(1 + 1 * d, d), 16);\n    b = parseInt(s.substr(1 + 2 * d, d), 16);\n    if (d == 1) {\n      r = (r << 4) + r;\n      g = (g << 4) + g;\n      b = (b << 4) + b;\n    }\n    a = 1;\n    color = [r, g, b, a];\n  } else if (s.indexOf('rgba(') == 0) { // rgba()\n    parts = s.slice(5, -1).split(',').map(Number);\n    color = ol.color.normalize(parts);\n  } else if (s.indexOf('rgb(') == 0) { // rgb()\n    parts = s.slice(4, -1).split(',').map(Number);\n    parts.push(1);\n    color = ol.color.normalize(parts);\n  } else {\n    ol.asserts.assert(false, 14); // Invalid color\n  }\n  return /** @type {ol.Color} */ (color);\n};\n\n\n/**\n * @param {ol.Color} color Color.\n * @param {ol.Color=} opt_color Color.\n * @return {ol.Color} Clamped color.\n */\nol.color.normalize = function(color, opt_color) {\n  var result = opt_color || [];\n  result[0] = ol.math.clamp((color[0] + 0.5) | 0, 0, 255);\n  result[1] = ol.math.clamp((color[1] + 0.5) | 0, 0, 255);\n  result[2] = ol.math.clamp((color[2] + 0.5) | 0, 0, 255);\n  result[3] = ol.math.clamp(color[3], 0, 1);\n  return result;\n};\n\n\n/**\n * @param {ol.Color} color Color.\n * @return {string} String.\n */\nol.color.toString = function(color) {\n  var r = color[0];\n  if (r != (r | 0)) {\n    r = (r + 0.5) | 0;\n  }\n  var g = color[1];\n  if (g != (g | 0)) {\n    g = (g + 0.5) | 0;\n  }\n  var b = color[2];\n  if (b != (b | 0)) {\n    b = (b + 0.5) | 0;\n  }\n  var a = color[3] === undefined ? 1 : color[3];\n  return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';\n};\n\ngoog.provide('ol.colorlike');\n\ngoog.require('ol.color');\n\n\n/**\n * @param {ol.Color|ol.ColorLike} color Color.\n * @return {ol.ColorLike} The color as an ol.ColorLike\n * @api\n */\nol.colorlike.asColorLike = function(color) {\n  if (ol.colorlike.isColorLike(color)) {\n    return /** @type {string|CanvasPattern|CanvasGradient} */ (color);\n  } else {\n    return ol.color.asString(/** @type {ol.Color} */ (color));\n  }\n};\n\n\n/**\n * @param {?} color The value that is potentially an ol.ColorLike\n * @return {boolean} Whether the color is an ol.ColorLike\n */\nol.colorlike.isColorLike = function(color) {\n  return (\n      typeof color === 'string' ||\n      color instanceof CanvasPattern ||\n      color instanceof CanvasGradient\n  );\n};\n\ngoog.provide('ol.dom');\n\n\n/**\n * Create an html canvas element and returns its 2d context.\n * @param {number=} opt_width Canvas width.\n * @param {number=} opt_height Canvas height.\n * @return {CanvasRenderingContext2D} The context.\n */\nol.dom.createCanvasContext2D = function(opt_width, opt_height) {\n  var canvas = document.createElement('CANVAS');\n  if (opt_width) {\n    canvas.width = opt_width;\n  }\n  if (opt_height) {\n    canvas.height = opt_height;\n  }\n  return canvas.getContext('2d');\n};\n\n\n/**\n * Get the current computed width for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerWidth(true)`.\n * @param {!Element} element Element.\n * @return {number} The width.\n */\nol.dom.outerWidth = function(element) {\n  var width = element.offsetWidth;\n  var style = element.currentStyle || getComputedStyle(element);\n  width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);\n\n  return width;\n};\n\n\n/**\n * Get the current computed height for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerHeight(true)`.\n * @param {!Element} element Element.\n * @return {number} The height.\n */\nol.dom.outerHeight = function(element) {\n  var height = element.offsetHeight;\n  var style = element.currentStyle || getComputedStyle(element);\n  height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);\n\n  return height;\n};\n\n/**\n * @param {Node} newNode Node to replace old node\n * @param {Node} oldNode The node to be replaced\n */\nol.dom.replaceNode = function(newNode, oldNode) {\n  var parent = oldNode.parentNode;\n  if (parent) {\n    parent.replaceChild(newNode, oldNode);\n  }\n};\n\n/**\n * @param {Node} node The node to remove.\n * @returns {Node} The node that was removed or null.\n */\nol.dom.removeNode = function(node) {\n  return node && node.parentNode ? node.parentNode.removeChild(node) : null;\n};\n\n/**\n * @param {Node} node The node to remove the children from.\n */\nol.dom.removeChildren = function(node) {\n  while (node.lastChild) {\n    node.removeChild(node.lastChild);\n  }\n};\n\ngoog.provide('ol.MapEvent');\n\ngoog.require('ol');\ngoog.require('ol.events.Event');\n\n\n/**\n * @classdesc\n * Events emitted as map events are instances of this type.\n * See {@link ol.Map} for which events trigger a map event.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.MapEvent}\n * @param {string} type Event type.\n * @param {ol.Map} map Map.\n * @param {?olx.FrameState=} opt_frameState Frame state.\n */\nol.MapEvent = function(type, map, opt_frameState) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The map where the event occurred.\n   * @type {ol.Map}\n   * @api stable\n   */\n  this.map = map;\n\n  /**\n   * The frame state at the time of the event.\n   * @type {?olx.FrameState}\n   * @api\n   */\n  this.frameState = opt_frameState !== undefined ? opt_frameState : null;\n\n};\nol.inherits(ol.MapEvent, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.MapEvent.Type = {\n\n  /**\n   * Triggered after a map frame is rendered.\n   * @event ol.MapEvent#postrender\n   * @api\n   */\n  POSTRENDER: 'postrender',\n\n  /**\n   * Triggered after the map is moved.\n   * @event ol.MapEvent#moveend\n   * @api stable\n   */\n  MOVEEND: 'moveend'\n\n};\n\ngoog.provide('ol.control.Control');\n\ngoog.require('ol.events');\ngoog.require('ol');\ngoog.require('ol.MapEvent');\ngoog.require('ol.Object');\ngoog.require('ol.dom');\n\n\n/**\n * @classdesc\n * A control is a visible widget with a DOM element in a fixed position on the\n * screen. They can involve user input (buttons), or be informational only;\n * the position is determined using CSS. By default these are placed in the\n * container with CSS class name `ol-overlaycontainer-stopevent`, but can use\n * any outside DOM element.\n *\n * This is the base class for controls. You can use it for simple custom\n * controls by creating the element with listeners, creating an instance:\n * ```js\n * var myControl = new ol.control.Control({element: myElement});\n * ```\n * and then adding this to the map.\n *\n * The main advantage of having this as a control rather than a simple separate\n * DOM element is that preventing propagation is handled for you. Controls\n * will also be `ol.Object`s in a `ol.Collection`, so you can use their\n * methods.\n *\n * You can also extend this base for your own control class. See\n * examples/custom-controls for an example of how to do this.\n *\n * @constructor\n * @extends {ol.Object}\n * @implements {oli.control.Control}\n * @param {olx.control.ControlOptions} options Control options.\n * @api stable\n */\nol.control.Control = function(options) {\n\n  ol.Object.call(this);\n\n  /**\n   * @protected\n   * @type {Element}\n   */\n  this.element = options.element ? options.element : null;\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.target_ = null;\n\n  /**\n   * @private\n   * @type {ol.Map}\n   */\n  this.map_ = null;\n\n  /**\n   * @protected\n   * @type {!Array.<ol.EventsKey>}\n   */\n  this.listenerKeys = [];\n\n  /**\n   * @type {function(ol.MapEvent)}\n   */\n  this.render = options.render ? options.render : ol.nullFunction;\n\n  if (options.target) {\n    this.setTarget(options.target);\n  }\n\n};\nol.inherits(ol.control.Control, ol.Object);\n\n\n/**\n * @inheritDoc\n */\nol.control.Control.prototype.disposeInternal = function() {\n  ol.dom.removeNode(this.element);\n  ol.Object.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Get the map associated with this control.\n * @return {ol.Map} Map.\n * @api stable\n */\nol.control.Control.prototype.getMap = function() {\n  return this.map_;\n};\n\n\n/**\n * Remove the control from its current map and attach it to the new map.\n * Subclasses may set up event handlers to get notified about changes to\n * the map here.\n * @param {ol.Map} map Map.\n * @api stable\n */\nol.control.Control.prototype.setMap = function(map) {\n  if (this.map_) {\n    ol.dom.removeNode(this.element);\n  }\n  for (var i = 0, ii = this.listenerKeys.length; i < ii; ++i) {\n    ol.events.unlistenByKey(this.listenerKeys[i]);\n  }\n  this.listenerKeys.length = 0;\n  this.map_ = map;\n  if (this.map_) {\n    var target = this.target_ ?\n        this.target_ : map.getOverlayContainerStopEvent();\n    target.appendChild(this.element);\n    if (this.render !== ol.nullFunction) {\n      this.listenerKeys.push(ol.events.listen(map,\n          ol.MapEvent.Type.POSTRENDER, this.render, this));\n    }\n    map.render();\n  }\n};\n\n\n/**\n * This function is used to set a target element for the control. It has no\n * effect if it is called after the control has been added to the map (i.e.\n * after `setMap` is called on the control). If no `target` is set in the\n * options passed to the control constructor and if `setTarget` is not called\n * then the control is added to the map's overlay container.\n * @param {Element|string} target Target.\n * @api\n */\nol.control.Control.prototype.setTarget = function(target) {\n  this.target_ = typeof target === 'string' ?\n    document.getElementById(target) :\n    target;\n};\n\ngoog.provide('ol.css');\n\n\n/**\n * The CSS class for hidden feature.\n *\n * @const\n * @type {string}\n */\nol.css.CLASS_HIDDEN = 'ol-hidden';\n\n\n/**\n * The CSS class that we'll give the DOM elements to have them unselectable.\n *\n * @const\n * @type {string}\n */\nol.css.CLASS_UNSELECTABLE = 'ol-unselectable';\n\n\n/**\n * The CSS class for unsupported feature.\n *\n * @const\n * @type {string}\n */\nol.css.CLASS_UNSUPPORTED = 'ol-unsupported';\n\n\n/**\n * The CSS class for controls.\n *\n * @const\n * @type {string}\n */\nol.css.CLASS_CONTROL = 'ol-control';\n\n// FIXME handle date line wrap\n\ngoog.provide('ol.control.Attribution');\n\ngoog.require('ol');\ngoog.require('ol.dom');\ngoog.require('ol.control.Control');\ngoog.require('ol.css');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * Control to show all the attributions associated with the layer sources\n * in the map. This control is one of the default controls included in maps.\n * By default it will show in the bottom right portion of the map, but this can\n * be changed by using a css selector for `.ol-attribution`.\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.AttributionOptions=} opt_options Attribution options.\n * @api stable\n */\nol.control.Attribution = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.ulElement_ = document.createElement('UL');\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.logoLi_ = document.createElement('LI');\n\n  this.ulElement_.appendChild(this.logoLi_);\n  this.logoLi_.style.display = 'none';\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.collapsible_ = options.collapsible !== undefined ?\n      options.collapsible : true;\n\n  if (!this.collapsible_) {\n    this.collapsed_ = false;\n  }\n\n  var className = options.className !== undefined ? options.className : 'ol-attribution';\n\n  var tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Attributions';\n\n  var collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\\u00BB';\n\n  if (typeof collapseLabel === 'string') {\n    /**\n     * @private\n     * @type {Node}\n     */\n    this.collapseLabel_ = document.createElement('span');\n    this.collapseLabel_.textContent = collapseLabel;\n  } else {\n    this.collapseLabel_ = collapseLabel;\n  }\n\n  var label = options.label !== undefined ? options.label : 'i';\n\n  if (typeof label === 'string') {\n    /**\n     * @private\n     * @type {Node}\n     */\n    this.label_ = document.createElement('span');\n    this.label_.textContent = label;\n  } else {\n    this.label_ = label;\n  }\n\n\n  var activeLabel = (this.collapsible_ && !this.collapsed_) ?\n      this.collapseLabel_ : this.label_;\n  var button = document.createElement('button');\n  button.setAttribute('type', 'button');\n  button.title = tipLabel;\n  button.appendChild(activeLabel);\n\n  ol.events.listen(button, ol.events.EventType.CLICK, this.handleClick_, this);\n\n  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +\n      ol.css.CLASS_CONTROL +\n      (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +\n      (this.collapsible_ ? '' : ' ol-uncollapsible');\n  var element = document.createElement('div');\n  element.className = cssClasses;\n  element.appendChild(this.ulElement_);\n  element.appendChild(button);\n\n  var render = options.render ? options.render : ol.control.Attribution.render;\n\n  ol.control.Control.call(this, {\n    element: element,\n    render: render,\n    target: options.target\n  });\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.renderedVisible_ = true;\n\n  /**\n   * @private\n   * @type {Object.<string, Element>}\n   */\n  this.attributionElements_ = {};\n\n  /**\n   * @private\n   * @type {Object.<string, boolean>}\n   */\n  this.attributionElementRenderedVisible_ = {};\n\n  /**\n   * @private\n   * @type {Object.<string, Element>}\n   */\n  this.logoElements_ = {};\n\n};\nol.inherits(ol.control.Attribution, ol.control.Control);\n\n\n/**\n * @param {?olx.FrameState} frameState Frame state.\n * @return {Array.<Object.<string, ol.Attribution>>} Attributions.\n */\nol.control.Attribution.prototype.getSourceAttributions = function(frameState) {\n  var i, ii, j, jj, tileRanges, source, sourceAttribution,\n      sourceAttributionKey, sourceAttributions, sourceKey;\n  var intersectsTileRange;\n  var layerStatesArray = frameState.layerStatesArray;\n  /** @type {Object.<string, ol.Attribution>} */\n  var attributions = ol.obj.assign({}, frameState.attributions);\n  /** @type {Object.<string, ol.Attribution>} */\n  var hiddenAttributions = {};\n  var uniqueAttributions = {};\n  var projection = /** @type {!ol.proj.Projection} */ (frameState.viewState.projection);\n  for (i = 0, ii = layerStatesArray.length; i < ii; i++) {\n    source = layerStatesArray[i].layer.getSource();\n    if (!source) {\n      continue;\n    }\n    sourceKey = ol.getUid(source).toString();\n    sourceAttributions = source.getAttributions();\n    if (!sourceAttributions) {\n      continue;\n    }\n    for (j = 0, jj = sourceAttributions.length; j < jj; j++) {\n      sourceAttribution = sourceAttributions[j];\n      sourceAttributionKey = ol.getUid(sourceAttribution).toString();\n      if (sourceAttributionKey in attributions) {\n        continue;\n      }\n      tileRanges = frameState.usedTiles[sourceKey];\n      if (tileRanges) {\n        var tileGrid = /** @type {ol.source.Tile} */ (source).getTileGridForProjection(projection);\n        intersectsTileRange = sourceAttribution.intersectsAnyTileRange(\n            tileRanges, tileGrid, projection);\n      } else {\n        intersectsTileRange = false;\n      }\n      if (intersectsTileRange) {\n        if (sourceAttributionKey in hiddenAttributions) {\n          delete hiddenAttributions[sourceAttributionKey];\n        }\n        var html = sourceAttribution.getHTML();\n        if (!(html in uniqueAttributions)) {\n          uniqueAttributions[html] = true;\n          attributions[sourceAttributionKey] = sourceAttribution;\n        }\n      } else {\n        hiddenAttributions[sourceAttributionKey] = sourceAttribution;\n      }\n    }\n  }\n  return [attributions, hiddenAttributions];\n};\n\n\n/**\n * Update the attribution element.\n * @param {ol.MapEvent} mapEvent Map event.\n * @this {ol.control.Attribution}\n * @api\n */\nol.control.Attribution.render = function(mapEvent) {\n  this.updateElement_(mapEvent.frameState);\n};\n\n\n/**\n * @private\n * @param {?olx.FrameState} frameState Frame state.\n */\nol.control.Attribution.prototype.updateElement_ = function(frameState) {\n\n  if (!frameState) {\n    if (this.renderedVisible_) {\n      this.element.style.display = 'none';\n      this.renderedVisible_ = false;\n    }\n    return;\n  }\n\n  var attributions = this.getSourceAttributions(frameState);\n  /** @type {Object.<string, ol.Attribution>} */\n  var visibleAttributions = attributions[0];\n  /** @type {Object.<string, ol.Attribution>} */\n  var hiddenAttributions = attributions[1];\n\n  var attributionElement, attributionKey;\n  for (attributionKey in this.attributionElements_) {\n    if (attributionKey in visibleAttributions) {\n      if (!this.attributionElementRenderedVisible_[attributionKey]) {\n        this.attributionElements_[attributionKey].style.display = '';\n        this.attributionElementRenderedVisible_[attributionKey] = true;\n      }\n      delete visibleAttributions[attributionKey];\n    } else if (attributionKey in hiddenAttributions) {\n      if (this.attributionElementRenderedVisible_[attributionKey]) {\n        this.attributionElements_[attributionKey].style.display = 'none';\n        delete this.attributionElementRenderedVisible_[attributionKey];\n      }\n      delete hiddenAttributions[attributionKey];\n    } else {\n      ol.dom.removeNode(this.attributionElements_[attributionKey]);\n      delete this.attributionElements_[attributionKey];\n      delete this.attributionElementRenderedVisible_[attributionKey];\n    }\n  }\n  for (attributionKey in visibleAttributions) {\n    attributionElement = document.createElement('LI');\n    attributionElement.innerHTML =\n        visibleAttributions[attributionKey].getHTML();\n    this.ulElement_.appendChild(attributionElement);\n    this.attributionElements_[attributionKey] = attributionElement;\n    this.attributionElementRenderedVisible_[attributionKey] = true;\n  }\n  for (attributionKey in hiddenAttributions) {\n    attributionElement = document.createElement('LI');\n    attributionElement.innerHTML =\n        hiddenAttributions[attributionKey].getHTML();\n    attributionElement.style.display = 'none';\n    this.ulElement_.appendChild(attributionElement);\n    this.attributionElements_[attributionKey] = attributionElement;\n  }\n\n  var renderVisible =\n      !ol.obj.isEmpty(this.attributionElementRenderedVisible_) ||\n      !ol.obj.isEmpty(frameState.logos);\n  if (this.renderedVisible_ != renderVisible) {\n    this.element.style.display = renderVisible ? '' : 'none';\n    this.renderedVisible_ = renderVisible;\n  }\n  if (renderVisible &&\n      ol.obj.isEmpty(this.attributionElementRenderedVisible_)) {\n    this.element.classList.add('ol-logo-only');\n  } else {\n    this.element.classList.remove('ol-logo-only');\n  }\n\n  this.insertLogos_(frameState);\n\n};\n\n\n/**\n * @param {?olx.FrameState} frameState Frame state.\n * @private\n */\nol.control.Attribution.prototype.insertLogos_ = function(frameState) {\n\n  var logo;\n  var logos = frameState.logos;\n  var logoElements = this.logoElements_;\n\n  for (logo in logoElements) {\n    if (!(logo in logos)) {\n      ol.dom.removeNode(logoElements[logo]);\n      delete logoElements[logo];\n    }\n  }\n\n  var image, logoElement, logoKey;\n  for (logoKey in logos) {\n    var logoValue = logos[logoKey];\n    if (logoValue instanceof HTMLElement) {\n      this.logoLi_.appendChild(logoValue);\n      logoElements[logoKey] = logoValue;\n    }\n    if (!(logoKey in logoElements)) {\n      image = new Image();\n      image.src = logoKey;\n      if (logoValue === '') {\n        logoElement = image;\n      } else {\n        logoElement = document.createElement('a');\n        logoElement.href = logoValue;\n        logoElement.appendChild(image);\n      }\n      this.logoLi_.appendChild(logoElement);\n      logoElements[logoKey] = logoElement;\n    }\n  }\n\n  this.logoLi_.style.display = !ol.obj.isEmpty(logos) ? '' : 'none';\n\n};\n\n\n/**\n * @param {Event} event The event to handle\n * @private\n */\nol.control.Attribution.prototype.handleClick_ = function(event) {\n  event.preventDefault();\n  this.handleToggle_();\n};\n\n\n/**\n * @private\n */\nol.control.Attribution.prototype.handleToggle_ = function() {\n  this.element.classList.toggle('ol-collapsed');\n  if (this.collapsed_) {\n    ol.dom.replaceNode(this.collapseLabel_, this.label_);\n  } else {\n    ol.dom.replaceNode(this.label_, this.collapseLabel_);\n  }\n  this.collapsed_ = !this.collapsed_;\n};\n\n\n/**\n * Return `true` if the attribution is collapsible, `false` otherwise.\n * @return {boolean} True if the widget is collapsible.\n * @api stable\n */\nol.control.Attribution.prototype.getCollapsible = function() {\n  return this.collapsible_;\n};\n\n\n/**\n * Set whether the attribution should be collapsible.\n * @param {boolean} collapsible True if the widget is collapsible.\n * @api stable\n */\nol.control.Attribution.prototype.setCollapsible = function(collapsible) {\n  if (this.collapsible_ === collapsible) {\n    return;\n  }\n  this.collapsible_ = collapsible;\n  this.element.classList.toggle('ol-uncollapsible');\n  if (!collapsible && this.collapsed_) {\n    this.handleToggle_();\n  }\n};\n\n\n/**\n * Collapse or expand the attribution according to the passed parameter. Will\n * not do anything if the attribution isn't collapsible or if the current\n * collapsed state is already the one requested.\n * @param {boolean} collapsed True if the widget is collapsed.\n * @api stable\n */\nol.control.Attribution.prototype.setCollapsed = function(collapsed) {\n  if (!this.collapsible_ || this.collapsed_ === collapsed) {\n    return;\n  }\n  this.handleToggle_();\n};\n\n\n/**\n * Return `true` when the attribution is currently collapsed or `false`\n * otherwise.\n * @return {boolean} True if the widget is collapsed.\n * @api stable\n */\nol.control.Attribution.prototype.getCollapsed = function() {\n  return this.collapsed_;\n};\n\ngoog.provide('ol.control.FullScreen');\n\ngoog.require('ol');\ngoog.require('ol.control.Control');\ngoog.require('ol.css');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\n\n\n/**\n * @classdesc\n * Provides a button that when clicked fills up the full screen with the map.\n * The full screen source element is by default the element containing the map viewport unless\n * overriden by providing the `source` option. In which case, the dom\n * element introduced using this parameter will be displayed in full screen.\n *\n * When in full screen mode, a close button is shown to exit full screen mode.\n * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to\n * toggle the map in full screen mode.\n *\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.FullScreenOptions=} opt_options Options.\n * @api stable\n */\nol.control.FullScreen = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.cssClassName_ = options.className !== undefined ? options.className :\n      'ol-full-screen';\n\n  var label = options.label !== undefined ? options.label : '\\u2922';\n\n  /**\n   * @private\n   * @type {Node}\n   */\n  this.labelNode_ = typeof label === 'string' ?\n      document.createTextNode(label) : label;\n\n  var labelActive = options.labelActive !== undefined ? options.labelActive : '\\u00d7';\n\n  /**\n   * @private\n   * @type {Node}\n   */\n  this.labelActiveNode_ = typeof labelActive === 'string' ?\n      document.createTextNode(labelActive) : labelActive;\n\n  var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';\n  var button = document.createElement('button');\n  button.className = this.cssClassName_ + '-' + ol.control.FullScreen.isFullScreen();\n  button.setAttribute('type', 'button');\n  button.title = tipLabel;\n  button.appendChild(this.labelNode_);\n\n  ol.events.listen(button, ol.events.EventType.CLICK,\n      this.handleClick_, this);\n\n  var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE +\n      ' ' + ol.css.CLASS_CONTROL + ' ' +\n      (!ol.control.FullScreen.isFullScreenSupported() ? ol.css.CLASS_UNSUPPORTED : '');\n  var element = document.createElement('div');\n  element.className = cssClasses;\n  element.appendChild(button);\n\n  ol.control.Control.call(this, {\n    element: element,\n    target: options.target\n  });\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.keys_ = options.keys !== undefined ? options.keys : false;\n\n  /**\n   * @private\n   * @type {Element|string|undefined}\n   */\n  this.source_ = options.source;\n\n};\nol.inherits(ol.control.FullScreen, ol.control.Control);\n\n\n/**\n * @param {Event} event The event to handle\n * @private\n */\nol.control.FullScreen.prototype.handleClick_ = function(event) {\n  event.preventDefault();\n  this.handleFullScreen_();\n};\n\n\n/**\n * @private\n */\nol.control.FullScreen.prototype.handleFullScreen_ = function() {\n  if (!ol.control.FullScreen.isFullScreenSupported()) {\n    return;\n  }\n  var map = this.getMap();\n  if (!map) {\n    return;\n  }\n  if (ol.control.FullScreen.isFullScreen()) {\n    ol.control.FullScreen.exitFullScreen();\n  } else {\n    var element;\n    if (this.source_) {\n      element = typeof this.source_ === 'string' ?\n        document.getElementById(this.source_) :\n        this.source_;\n    } else {\n      element = map.getTargetElement();\n    }\n    if (this.keys_) {\n      ol.control.FullScreen.requestFullScreenWithKeys(element);\n\n    } else {\n      ol.control.FullScreen.requestFullScreen(element);\n    }\n  }\n};\n\n\n/**\n * @private\n */\nol.control.FullScreen.prototype.handleFullScreenChange_ = function() {\n  var button = this.element.firstElementChild;\n  var map = this.getMap();\n  if (ol.control.FullScreen.isFullScreen()) {\n    button.className = this.cssClassName_ + '-true';\n    ol.dom.replaceNode(this.labelActiveNode_, this.labelNode_);\n  } else {\n    button.className = this.cssClassName_ + '-false';\n    ol.dom.replaceNode(this.labelNode_, this.labelActiveNode_);\n  }\n  if (map) {\n    map.updateSize();\n  }\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.control.FullScreen.prototype.setMap = function(map) {\n  ol.control.Control.prototype.setMap.call(this, map);\n  if (map) {\n    this.listenerKeys.push(ol.events.listen(document,\n        ol.control.FullScreen.getChangeType_(),\n        this.handleFullScreenChange_, this)\n    );\n  }\n};\n\n/**\n * @return {boolean} Fullscreen is supported by the current platform.\n */\nol.control.FullScreen.isFullScreenSupported = function() {\n  var body = document.body;\n  return !!(\n    body.webkitRequestFullscreen ||\n    (body.mozRequestFullScreen && document.mozFullScreenEnabled) ||\n    (body.msRequestFullscreen && document.msFullscreenEnabled) ||\n    (body.requestFullscreen && document.fullscreenEnabled)\n  );\n};\n\n/**\n * @return {boolean} Element is currently in fullscreen.\n */\nol.control.FullScreen.isFullScreen = function() {\n  return !!(\n    document.webkitIsFullScreen || document.mozFullScreen ||\n    document.msFullscreenElement || document.fullscreenElement\n  );\n};\n\n/**\n * Request to fullscreen an element.\n * @param {Node} element Element to request fullscreen\n */\nol.control.FullScreen.requestFullScreen = function(element) {\n  if (element.requestFullscreen) {\n    element.requestFullscreen();\n  } else if (element.msRequestFullscreen) {\n    element.msRequestFullscreen();\n  } else if (element.mozRequestFullScreen) {\n    element.mozRequestFullScreen();\n  } else if (element.webkitRequestFullscreen) {\n    element.webkitRequestFullscreen();\n  }\n};\n\n/**\n * Request to fullscreen an element with keyboard input.\n * @param {Node} element Element to request fullscreen\n */\nol.control.FullScreen.requestFullScreenWithKeys = function(element) {\n  if (element.mozRequestFullScreenWithKeys) {\n    element.mozRequestFullScreenWithKeys();\n  } else if (element.webkitRequestFullscreen) {\n    element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);\n  } else {\n    ol.control.FullScreen.requestFullScreen(element);\n  }\n};\n\n/**\n * Exit fullscreen.\n */\nol.control.FullScreen.exitFullScreen = function() {\n  if (document.exitFullscreen) {\n    document.exitFullscreen();\n  } else if (document.msExitFullscreen) {\n    document.msExitFullscreen();\n  } else if (document.mozCancelFullScreen) {\n    document.mozCancelFullScreen();\n  } else if (document.webkitExitFullscreen) {\n    document.webkitExitFullscreen();\n  }\n};\n\n/**\n * @return {string} Change type.\n * @private\n */\nol.control.FullScreen.getChangeType_ = (function() {\n  var changeType;\n  return function() {\n    if (!changeType) {\n      var body = document.body;\n      if (body.webkitRequestFullscreen) {\n        changeType = 'webkitfullscreenchange';\n      } else if (body.mozRequestFullScreen) {\n        changeType = 'mozfullscreenchange';\n      } else if (body.msRequestFullscreen) {\n        changeType = 'MSFullscreenChange';\n      } else if (body.requestFullscreen) {\n        changeType = 'fullscreenchange';\n      }\n    }\n    return changeType;\n  };\n})();\n\ngoog.provide('ol.control.Rotate');\n\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol');\ngoog.require('ol.control.Control');\ngoog.require('ol.css');\ngoog.require('ol.easing');\n\n\n/**\n * @classdesc\n * A button control to reset rotation to 0.\n * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css\n * selector is added to the button when the rotation is 0.\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.RotateOptions=} opt_options Rotate options.\n * @api stable\n */\nol.control.Rotate = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  var className = options.className !== undefined ? options.className : 'ol-rotate';\n\n  var label = options.label !== undefined ? options.label : '\\u21E7';\n\n  /**\n   * @type {Element}\n   * @private\n   */\n  this.label_ = null;\n\n  if (typeof label === 'string') {\n    this.label_ = document.createElement('span');\n    this.label_.className = 'ol-compass';\n    this.label_.textContent = label;\n  } else {\n    this.label_ = label;\n    this.label_.classList.add('ol-compass');\n  }\n\n  var tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation';\n\n  var button = document.createElement('button');\n  button.className = className + '-reset';\n  button.setAttribute('type', 'button');\n  button.title = tipLabel;\n  button.appendChild(this.label_);\n\n  ol.events.listen(button, ol.events.EventType.CLICK,\n      ol.control.Rotate.prototype.handleClick_, this);\n\n  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +\n      ol.css.CLASS_CONTROL;\n  var element = document.createElement('div');\n  element.className = cssClasses;\n  element.appendChild(button);\n\n  var render = options.render ? options.render : ol.control.Rotate.render;\n\n  this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined;\n\n  ol.control.Control.call(this, {\n    element: element,\n    render: render,\n    target: options.target\n  });\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.rotation_ = undefined;\n\n  if (this.autoHide_) {\n    this.element.classList.add(ol.css.CLASS_HIDDEN);\n  }\n\n};\nol.inherits(ol.control.Rotate, ol.control.Control);\n\n\n/**\n * @param {Event} event The event to handle\n * @private\n */\nol.control.Rotate.prototype.handleClick_ = function(event) {\n  event.preventDefault();\n  if (this.callResetNorth_ !== undefined) {\n    this.callResetNorth_();\n  } else {\n    this.resetNorth_();\n  }\n};\n\n\n/**\n * @private\n */\nol.control.Rotate.prototype.resetNorth_ = function() {\n  var map = this.getMap();\n  var view = map.getView();\n  if (!view) {\n    // the map does not have a view, so we can't act\n    // upon it\n    return;\n  }\n  var currentRotation = view.getRotation();\n  if (currentRotation !== undefined) {\n    if (this.duration_ > 0) {\n      currentRotation = currentRotation % (2 * Math.PI);\n      if (currentRotation < -Math.PI) {\n        currentRotation += 2 * Math.PI;\n      }\n      if (currentRotation > Math.PI) {\n        currentRotation -= 2 * Math.PI;\n      }\n      view.animate({\n        rotation: 0,\n        duration: this.duration_,\n        easing: ol.easing.easeOut\n      });\n    } else {\n      view.setRotation(0);\n    }\n  }\n};\n\n\n/**\n * Update the rotate control element.\n * @param {ol.MapEvent} mapEvent Map event.\n * @this {ol.control.Rotate}\n * @api\n */\nol.control.Rotate.render = function(mapEvent) {\n  var frameState = mapEvent.frameState;\n  if (!frameState) {\n    return;\n  }\n  var rotation = frameState.viewState.rotation;\n  if (rotation != this.rotation_) {\n    var transform = 'rotate(' + rotation + 'rad)';\n    if (this.autoHide_) {\n      var contains = this.element.classList.contains(ol.css.CLASS_HIDDEN);\n      if (!contains && rotation === 0) {\n        this.element.classList.add(ol.css.CLASS_HIDDEN);\n      } else if (contains && rotation !== 0) {\n        this.element.classList.remove(ol.css.CLASS_HIDDEN);\n      }\n    }\n    this.label_.style.msTransform = transform;\n    this.label_.style.webkitTransform = transform;\n    this.label_.style.transform = transform;\n  }\n  this.rotation_ = rotation;\n};\n\ngoog.provide('ol.control.Zoom');\n\ngoog.require('ol');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.control.Control');\ngoog.require('ol.css');\ngoog.require('ol.easing');\n\n\n/**\n * @classdesc\n * A control with 2 buttons, one for zoom in and one for zoom out.\n * This control is one of the default controls of a map. To style this control\n * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.ZoomOptions=} opt_options Zoom options.\n * @api stable\n */\nol.control.Zoom = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  var className = options.className !== undefined ? options.className : 'ol-zoom';\n\n  var delta = options.delta !== undefined ? options.delta : 1;\n\n  var zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';\n  var zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\\u2212';\n\n  var zoomInTipLabel = options.zoomInTipLabel !== undefined ?\n      options.zoomInTipLabel : 'Zoom in';\n  var zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?\n      options.zoomOutTipLabel : 'Zoom out';\n\n  var inElement = document.createElement('button');\n  inElement.className = className + '-in';\n  inElement.setAttribute('type', 'button');\n  inElement.title = zoomInTipLabel;\n  inElement.appendChild(\n    typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel\n  );\n\n  ol.events.listen(inElement, ol.events.EventType.CLICK,\n      ol.control.Zoom.prototype.handleClick_.bind(this, delta));\n\n  var outElement = document.createElement('button');\n  outElement.className = className + '-out';\n  outElement.setAttribute('type', 'button');\n  outElement.title = zoomOutTipLabel;\n  outElement.appendChild(\n    typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel\n  );\n\n  ol.events.listen(outElement, ol.events.EventType.CLICK,\n      ol.control.Zoom.prototype.handleClick_.bind(this, -delta));\n\n  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +\n      ol.css.CLASS_CONTROL;\n  var element = document.createElement('div');\n  element.className = cssClasses;\n  element.appendChild(inElement);\n  element.appendChild(outElement);\n\n  ol.control.Control.call(this, {\n    element: element,\n    target: options.target\n  });\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n};\nol.inherits(ol.control.Zoom, ol.control.Control);\n\n\n/**\n * @param {number} delta Zoom delta.\n * @param {Event} event The event to handle\n * @private\n */\nol.control.Zoom.prototype.handleClick_ = function(delta, event) {\n  event.preventDefault();\n  this.zoomByDelta_(delta);\n};\n\n\n/**\n * @param {number} delta Zoom delta.\n * @private\n */\nol.control.Zoom.prototype.zoomByDelta_ = function(delta) {\n  var map = this.getMap();\n  var view = map.getView();\n  if (!view) {\n    // the map does not have a view, so we can't act\n    // upon it\n    return;\n  }\n  var currentResolution = view.getResolution();\n  if (currentResolution) {\n    var newResolution = view.constrainResolution(currentResolution, delta);\n    if (this.duration_ > 0) {\n      if (view.getAnimating()) {\n        view.cancelAnimations();\n      }\n      view.animate({\n        resolution: newResolution,\n        duration: this.duration_,\n        easing: ol.easing.easeOut\n      });\n    } else {\n      view.setResolution(newResolution);\n    }\n  }\n};\n\ngoog.provide('ol.control');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.control.Attribution');\ngoog.require('ol.control.Rotate');\ngoog.require('ol.control.Zoom');\n\n\n/**\n * Set of controls included in maps by default. Unless configured otherwise,\n * this returns a collection containing an instance of each of the following\n * controls:\n * * {@link ol.control.Zoom}\n * * {@link ol.control.Rotate}\n * * {@link ol.control.Attribution}\n *\n * @param {olx.control.DefaultsOptions=} opt_options Defaults options.\n * @return {ol.Collection.<ol.control.Control>} Controls.\n * @api stable\n */\nol.control.defaults = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  var controls = new ol.Collection();\n\n  var zoomControl = options.zoom !== undefined ? options.zoom : true;\n  if (zoomControl) {\n    controls.push(new ol.control.Zoom(options.zoomOptions));\n  }\n\n  var rotateControl = options.rotate !== undefined ? options.rotate : true;\n  if (rotateControl) {\n    controls.push(new ol.control.Rotate(options.rotateOptions));\n  }\n\n  var attributionControl = options.attribution !== undefined ?\n      options.attribution : true;\n  if (attributionControl) {\n    controls.push(new ol.control.Attribution(options.attributionOptions));\n  }\n\n  return controls;\n\n};\n\n// FIXME should listen on appropriate pane, once it is defined\n\ngoog.provide('ol.control.MousePosition');\n\ngoog.require('ol');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.Object');\ngoog.require('ol.control.Control');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * A control to show the 2D coordinates of the mouse cursor. By default, these\n * are in the view projection, but can be in any supported projection.\n * By default the control is shown in the top right corner of the map, but this\n * can be changed by using the css selector `.ol-mouse-position`.\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.MousePositionOptions=} opt_options Mouse position\n *     options.\n * @api stable\n */\nol.control.MousePosition = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  var element = document.createElement('DIV');\n  element.className = options.className !== undefined ? options.className : 'ol-mouse-position';\n\n  var render = options.render ?\n      options.render : ol.control.MousePosition.render;\n\n  ol.control.Control.call(this, {\n    element: element,\n    render: render,\n    target: options.target\n  });\n\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.control.MousePosition.Property.PROJECTION),\n      this.handleProjectionChanged_, this);\n\n  if (options.coordinateFormat) {\n    this.setCoordinateFormat(options.coordinateFormat);\n  }\n  if (options.projection) {\n    this.setProjection(ol.proj.get(options.projection));\n  }\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.undefinedHTML_ = options.undefinedHTML !== undefined ? options.undefinedHTML : '';\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.renderedHTML_ = element.innerHTML;\n\n  /**\n   * @private\n   * @type {ol.proj.Projection}\n   */\n  this.mapProjection_ = null;\n\n  /**\n   * @private\n   * @type {?ol.TransformFunction}\n   */\n  this.transform_ = null;\n\n  /**\n   * @private\n   * @type {ol.Pixel}\n   */\n  this.lastMouseMovePixel_ = null;\n\n};\nol.inherits(ol.control.MousePosition, ol.control.Control);\n\n\n/**\n * Update the mouseposition element.\n * @param {ol.MapEvent} mapEvent Map event.\n * @this {ol.control.MousePosition}\n * @api\n */\nol.control.MousePosition.render = function(mapEvent) {\n  var frameState = mapEvent.frameState;\n  if (!frameState) {\n    this.mapProjection_ = null;\n  } else {\n    if (this.mapProjection_ != frameState.viewState.projection) {\n      this.mapProjection_ = frameState.viewState.projection;\n      this.transform_ = null;\n    }\n  }\n  this.updateHTML_(this.lastMouseMovePixel_);\n};\n\n\n/**\n * @private\n */\nol.control.MousePosition.prototype.handleProjectionChanged_ = function() {\n  this.transform_ = null;\n};\n\n\n/**\n * Return the coordinate format type used to render the current position or\n * undefined.\n * @return {ol.CoordinateFormatType|undefined} The format to render the current\n *     position in.\n * @observable\n * @api stable\n */\nol.control.MousePosition.prototype.getCoordinateFormat = function() {\n  return /** @type {ol.CoordinateFormatType|undefined} */ (\n      this.get(ol.control.MousePosition.Property.COORDINATE_FORMAT));\n};\n\n\n/**\n * Return the projection that is used to report the mouse position.\n * @return {ol.proj.Projection|undefined} The projection to report mouse\n *     position in.\n * @observable\n * @api stable\n */\nol.control.MousePosition.prototype.getProjection = function() {\n  return /** @type {ol.proj.Projection|undefined} */ (\n      this.get(ol.control.MousePosition.Property.PROJECTION));\n};\n\n\n/**\n * @param {Event} event Browser event.\n * @protected\n */\nol.control.MousePosition.prototype.handleMouseMove = function(event) {\n  var map = this.getMap();\n  this.lastMouseMovePixel_ = map.getEventPixel(event);\n  this.updateHTML_(this.lastMouseMovePixel_);\n};\n\n\n/**\n * @param {Event} event Browser event.\n * @protected\n */\nol.control.MousePosition.prototype.handleMouseOut = function(event) {\n  this.updateHTML_(null);\n  this.lastMouseMovePixel_ = null;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.control.MousePosition.prototype.setMap = function(map) {\n  ol.control.Control.prototype.setMap.call(this, map);\n  if (map) {\n    var viewport = map.getViewport();\n    this.listenerKeys.push(\n        ol.events.listen(viewport, ol.events.EventType.MOUSEMOVE,\n            this.handleMouseMove, this),\n        ol.events.listen(viewport, ol.events.EventType.MOUSEOUT,\n            this.handleMouseOut, this)\n    );\n  }\n};\n\n\n/**\n * Set the coordinate format type used to render the current position.\n * @param {ol.CoordinateFormatType} format The format to render the current\n *     position in.\n * @observable\n * @api stable\n */\nol.control.MousePosition.prototype.setCoordinateFormat = function(format) {\n  this.set(ol.control.MousePosition.Property.COORDINATE_FORMAT, format);\n};\n\n\n/**\n * Set the projection that is used to report the mouse position.\n * @param {ol.proj.Projection} projection The projection to report mouse\n *     position in.\n * @observable\n * @api stable\n */\nol.control.MousePosition.prototype.setProjection = function(projection) {\n  this.set(ol.control.MousePosition.Property.PROJECTION, projection);\n};\n\n\n/**\n * @param {?ol.Pixel} pixel Pixel.\n * @private\n */\nol.control.MousePosition.prototype.updateHTML_ = function(pixel) {\n  var html = this.undefinedHTML_;\n  if (pixel && this.mapProjection_) {\n    if (!this.transform_) {\n      var projection = this.getProjection();\n      if (projection) {\n        this.transform_ = ol.proj.getTransformFromProjections(\n            this.mapProjection_, projection);\n      } else {\n        this.transform_ = ol.proj.identityTransform;\n      }\n    }\n    var map = this.getMap();\n    var coordinate = map.getCoordinateFromPixel(pixel);\n    if (coordinate) {\n      this.transform_(coordinate, coordinate);\n      var coordinateFormat = this.getCoordinateFormat();\n      if (coordinateFormat) {\n        html = coordinateFormat(coordinate);\n      } else {\n        html = coordinate.toString();\n      }\n    }\n  }\n  if (!this.renderedHTML_ || html != this.renderedHTML_) {\n    this.element.innerHTML = html;\n    this.renderedHTML_ = html;\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.control.MousePosition.Property = {\n  PROJECTION: 'projection',\n  COORDINATE_FORMAT: 'coordinateFormat'\n};\n\ngoog.provide('ol.MapBrowserEvent');\n\ngoog.require('ol');\ngoog.require('ol.MapEvent');\ngoog.require('ol.events.EventType');\n\n\n/**\n * @classdesc\n * Events emitted as map browser events are instances of this type.\n * See {@link ol.Map} for which events trigger a map browser event.\n *\n * @constructor\n * @extends {ol.MapEvent}\n * @implements {oli.MapBrowserEvent}\n * @param {string} type Event type.\n * @param {ol.Map} map Map.\n * @param {Event} browserEvent Browser event.\n * @param {boolean=} opt_dragging Is the map currently being dragged?\n * @param {?olx.FrameState=} opt_frameState Frame state.\n */\nol.MapBrowserEvent = function(type, map, browserEvent, opt_dragging,\n    opt_frameState) {\n\n  ol.MapEvent.call(this, type, map, opt_frameState);\n\n  /**\n   * The original browser event.\n   * @const\n   * @type {Event}\n   * @api stable\n   */\n  this.originalEvent = browserEvent;\n\n  /**\n   * The map pixel relative to the viewport corresponding to the original browser event.\n   * @type {ol.Pixel}\n   * @api stable\n   */\n  this.pixel = map.getEventPixel(browserEvent);\n\n  /**\n   * The coordinate in view projection corresponding to the original browser event.\n   * @type {ol.Coordinate}\n   * @api stable\n   */\n  this.coordinate = map.getCoordinateFromPixel(this.pixel);\n\n  /**\n   * Indicates if the map is currently being dragged. Only set for\n   * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`.\n   *\n   * @type {boolean}\n   * @api stable\n   */\n  this.dragging = opt_dragging !== undefined ? opt_dragging : false;\n\n};\nol.inherits(ol.MapBrowserEvent, ol.MapEvent);\n\n\n/**\n * Prevents the default browser action.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault\n * @override\n * @api stable\n */\nol.MapBrowserEvent.prototype.preventDefault = function() {\n  ol.MapEvent.prototype.preventDefault.call(this);\n  this.originalEvent.preventDefault();\n};\n\n\n/**\n * Prevents further propagation of the current event.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation\n * @override\n * @api stable\n */\nol.MapBrowserEvent.prototype.stopPropagation = function() {\n  ol.MapEvent.prototype.stopPropagation.call(this);\n  this.originalEvent.stopPropagation();\n};\n\n\n/**\n * Constants for event names.\n * @enum {string}\n */\nol.MapBrowserEvent.EventType = {\n\n  /**\n   * A true single click with no dragging and no double click. Note that this\n   * event is delayed by 250 ms to ensure that it is not a double click.\n   * @event ol.MapBrowserEvent#singleclick\n   * @api stable\n   */\n  SINGLECLICK: 'singleclick',\n\n  /**\n   * A click with no dragging. A double click will fire two of this.\n   * @event ol.MapBrowserEvent#click\n   * @api stable\n   */\n  CLICK: ol.events.EventType.CLICK,\n\n  /**\n   * A true double click, with no dragging.\n   * @event ol.MapBrowserEvent#dblclick\n   * @api stable\n   */\n  DBLCLICK: ol.events.EventType.DBLCLICK,\n\n  /**\n   * Triggered when a pointer is dragged.\n   * @event ol.MapBrowserEvent#pointerdrag\n   * @api\n   */\n  POINTERDRAG: 'pointerdrag',\n\n  /**\n   * Triggered when a pointer is moved. Note that on touch devices this is\n   * triggered when the map is panned, so is not the same as mousemove.\n   * @event ol.MapBrowserEvent#pointermove\n   * @api stable\n   */\n  POINTERMOVE: 'pointermove',\n\n  POINTERDOWN: 'pointerdown',\n  POINTERUP: 'pointerup',\n  POINTEROVER: 'pointerover',\n  POINTEROUT: 'pointerout',\n  POINTERENTER: 'pointerenter',\n  POINTERLEAVE: 'pointerleave',\n  POINTERCANCEL: 'pointercancel'\n};\n\ngoog.provide('ol.MapBrowserPointerEvent');\n\ngoog.require('ol');\ngoog.require('ol.MapBrowserEvent');\n\n\n/**\n * @constructor\n * @extends {ol.MapBrowserEvent}\n * @param {string} type Event type.\n * @param {ol.Map} map Map.\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @param {boolean=} opt_dragging Is the map currently being dragged?\n * @param {?olx.FrameState=} opt_frameState Frame state.\n */\nol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging,\n    opt_frameState) {\n\n  ol.MapBrowserEvent.call(this, type, map, pointerEvent.originalEvent, opt_dragging,\n      opt_frameState);\n\n  /**\n   * @const\n   * @type {ol.pointer.PointerEvent}\n   */\n  this.pointerEvent = pointerEvent;\n\n};\nol.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent);\n\ngoog.provide('ol.pointer.EventType');\n\n\n/**\n * Constants for event names.\n * @enum {string}\n */\nol.pointer.EventType = {\n  POINTERMOVE: 'pointermove',\n  POINTERDOWN: 'pointerdown',\n  POINTERUP: 'pointerup',\n  POINTEROVER: 'pointerover',\n  POINTEROUT: 'pointerout',\n  POINTERENTER: 'pointerenter',\n  POINTERLEAVE: 'pointerleave',\n  POINTERCANCEL: 'pointercancel'\n};\n\ngoog.provide('ol.webgl');\n\n\n/** Constants taken from goog.webgl\n */\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.ONE = 1;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.SRC_ALPHA = 0x0302;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.COLOR_ATTACHMENT0 = 0x8CE0;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.COLOR_BUFFER_BIT = 0x00004000;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TRIANGLES = 0x0004;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TRIANGLE_STRIP = 0x0005;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.ONE_MINUS_SRC_ALPHA = 0x0303;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.ARRAY_BUFFER = 0x8892;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.ELEMENT_ARRAY_BUFFER = 0x8893;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.STREAM_DRAW = 0x88E0;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.STATIC_DRAW = 0x88E4;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.DYNAMIC_DRAW = 0x88E8;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.CULL_FACE = 0x0B44;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.BLEND = 0x0BE2;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.STENCIL_TEST = 0x0B90;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.DEPTH_TEST = 0x0B71;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.SCISSOR_TEST = 0x0C11;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.UNSIGNED_BYTE = 0x1401;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.UNSIGNED_SHORT = 0x1403;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.UNSIGNED_INT = 0x1405;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.FLOAT = 0x1406;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.RGBA = 0x1908;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.FRAGMENT_SHADER = 0x8B30;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.VERTEX_SHADER = 0x8B31;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.LINK_STATUS = 0x8B82;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.LINEAR = 0x2601;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TEXTURE_MAG_FILTER = 0x2800;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TEXTURE_MIN_FILTER = 0x2801;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TEXTURE_WRAP_S = 0x2802;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TEXTURE_WRAP_T = 0x2803;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TEXTURE_2D = 0x0DE1;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.TEXTURE0 = 0x84C0;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.CLAMP_TO_EDGE = 0x812F;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.COMPILE_STATUS = 0x8B81;\n\n\n/**\n * @const\n * @type {number}\n */\nol.webgl.FRAMEBUFFER = 0x8D40;\n\n\n/** end of goog.webgl constants\n */\n\n\n/**\n * @const\n * @private\n * @type {Array.<string>}\n */\nol.webgl.CONTEXT_IDS_ = [\n  'experimental-webgl',\n  'webgl',\n  'webkit-3d',\n  'moz-webgl'\n];\n\n\n/**\n * @param {HTMLCanvasElement} canvas Canvas.\n * @param {Object=} opt_attributes Attributes.\n * @return {WebGLRenderingContext} WebGL rendering context.\n */\nol.webgl.getContext = function(canvas, opt_attributes) {\n  var context, i, ii = ol.webgl.CONTEXT_IDS_.length;\n  for (i = 0; i < ii; ++i) {\n    try {\n      context = canvas.getContext(ol.webgl.CONTEXT_IDS_[i], opt_attributes);\n      if (context) {\n        return /** @type {!WebGLRenderingContext} */ (context);\n      }\n    } catch (e) {\n      // pass\n    }\n  }\n  return null;\n};\n\ngoog.provide('ol.has');\n\ngoog.require('ol');\ngoog.require('ol.webgl');\n\nvar ua = typeof navigator !== 'undefined' ?\n    navigator.userAgent.toLowerCase() : '';\n\n/**\n * User agent string says we are dealing with Firefox as browser.\n * @type {boolean}\n */\nol.has.FIREFOX = ua.indexOf('firefox') !== -1;\n\n/**\n * User agent string says we are dealing with Safari as browser.\n * @type {boolean}\n */\nol.has.SAFARI = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') == -1;\n\n/**\n * User agent string says we are dealing with a WebKit engine.\n * @type {boolean}\n */\nol.has.WEBKIT = ua.indexOf('webkit') !== -1 && ua.indexOf('edge') == -1;\n\n/**\n * User agent string says we are dealing with a Mac as platform.\n * @type {boolean}\n */\nol.has.MAC = ua.indexOf('macintosh') !== -1;\n\n\n/**\n * The ratio between physical pixels and device-independent pixels\n * (dips) on the device (`window.devicePixelRatio`).\n * @const\n * @type {number}\n * @api stable\n */\nol.has.DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;\n\n\n/**\n * True if the browser's Canvas implementation implements {get,set}LineDash.\n * @type {boolean}\n */\nol.has.CANVAS_LINE_DASH = false;\n\n\n/**\n * True if both the library and browser support Canvas.  Always `false`\n * if `ol.ENABLE_CANVAS` is set to `false` at compile time.\n * @const\n * @type {boolean}\n * @api stable\n */\nol.has.CANVAS = ol.ENABLE_CANVAS && (\n    /**\n     * @return {boolean} Canvas supported.\n     */\n    function() {\n      if (!('HTMLCanvasElement' in window)) {\n        return false;\n      }\n      try {\n        var context = document.createElement('CANVAS').getContext('2d');\n        if (!context) {\n          return false;\n        } else {\n          if (context.setLineDash !== undefined) {\n            ol.has.CANVAS_LINE_DASH = true;\n          }\n          return true;\n        }\n      } catch (e) {\n        return false;\n      }\n    })();\n\n\n/**\n * Indicates if DeviceOrientation is supported in the user's browser.\n * @const\n * @type {boolean}\n * @api stable\n */\nol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in window;\n\n\n/**\n * Is HTML5 geolocation supported in the current browser?\n * @const\n * @type {boolean}\n * @api stable\n */\nol.has.GEOLOCATION = 'geolocation' in navigator;\n\n\n/**\n * True if browser supports touch events.\n * @const\n * @type {boolean}\n * @api stable\n */\nol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in window;\n\n\n/**\n * True if browser supports pointer events.\n * @const\n * @type {boolean}\n */\nol.has.POINTER = 'PointerEvent' in window;\n\n\n/**\n * True if browser supports ms pointer events (IE 10).\n * @const\n * @type {boolean}\n */\nol.has.MSPOINTER = !!(navigator.msPointerEnabled);\n\n\n/**\n * True if both OpenLayers and browser support WebGL.  Always `false`\n * if `ol.ENABLE_WEBGL` is set to `false` at compile time.\n * @const\n * @type {boolean}\n * @api stable\n */\nol.has.WEBGL;\n\n\n(function() {\n  if (ol.ENABLE_WEBGL) {\n    var hasWebGL = false;\n    var textureSize;\n    var /** @type {Array.<string>} */ extensions = [];\n\n    if ('WebGLRenderingContext' in window) {\n      try {\n        var canvas = /** @type {HTMLCanvasElement} */\n            (document.createElement('CANVAS'));\n        var gl = ol.webgl.getContext(canvas, {\n          failIfMajorPerformanceCaveat: true\n        });\n        if (gl) {\n          hasWebGL = true;\n          textureSize = /** @type {number} */\n              (gl.getParameter(gl.MAX_TEXTURE_SIZE));\n          extensions = gl.getSupportedExtensions();\n        }\n      } catch (e) {\n        // pass\n      }\n    }\n    ol.has.WEBGL = hasWebGL;\n    ol.WEBGL_EXTENSIONS = extensions;\n    ol.WEBGL_MAX_TEXTURE_SIZE = textureSize;\n  }\n})();\n\ngoog.provide('ol.pointer.EventSource');\n\n\n/**\n * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.\n * @param {!Object.<string, function(Event)>} mapping Event\n *     mapping.\n * @constructor\n */\nol.pointer.EventSource = function(dispatcher, mapping) {\n  /**\n   * @type {ol.pointer.PointerEventHandler}\n   */\n  this.dispatcher = dispatcher;\n\n  /**\n   * @private\n   * @const\n   * @type {!Object.<string, function(Event)>}\n   */\n  this.mapping_ = mapping;\n};\n\n\n/**\n * List of events supported by this source.\n * @return {Array.<string>} Event names\n */\nol.pointer.EventSource.prototype.getEvents = function() {\n  return Object.keys(this.mapping_);\n};\n\n\n/**\n * Returns a mapping between the supported event types and\n * the handlers that should handle an event.\n * @return {Object.<string, function(Event)>}\n *         Event/Handler mapping\n */\nol.pointer.EventSource.prototype.getMapping = function() {\n  return this.mapping_;\n};\n\n\n/**\n * Returns the handler that should handle a given event type.\n * @param {string} eventType The event type.\n * @return {function(Event)} Handler\n */\nol.pointer.EventSource.prototype.getHandlerForEvent = function(eventType) {\n  return this.mapping_[eventType];\n};\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ngoog.provide('ol.pointer.MouseSource');\n\ngoog.require('ol');\ngoog.require('ol.pointer.EventSource');\n\n\n/**\n * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.\n * @constructor\n * @extends {ol.pointer.EventSource}\n */\nol.pointer.MouseSource = function(dispatcher) {\n  var mapping = {\n    'mousedown': this.mousedown,\n    'mousemove': this.mousemove,\n    'mouseup': this.mouseup,\n    'mouseover': this.mouseover,\n    'mouseout': this.mouseout\n  };\n  ol.pointer.EventSource.call(this, dispatcher, mapping);\n\n  /**\n   * @const\n   * @type {!Object.<string, Event|Object>}\n   */\n  this.pointerMap = dispatcher.pointerMap;\n\n  /**\n   * @const\n   * @type {Array.<ol.Pixel>}\n   */\n  this.lastTouches = [];\n};\nol.inherits(ol.pointer.MouseSource, ol.pointer.EventSource);\n\n\n/**\n * @const\n * @type {number}\n */\nol.pointer.MouseSource.POINTER_ID = 1;\n\n\n/**\n * @const\n * @type {string}\n */\nol.pointer.MouseSource.POINTER_TYPE = 'mouse';\n\n\n/**\n * Radius around touchend that swallows mouse events.\n *\n * @const\n * @type {number}\n */\nol.pointer.MouseSource.DEDUP_DIST = 25;\n\n\n/**\n * Detect if a mouse event was simulated from a touch by\n * checking if previously there was a touch event at the\n * same position.\n *\n * FIXME - Known problem with the native Android browser on\n * Samsung GT-I9100 (Android 4.1.2):\n * In case the page is scrolled, this function does not work\n * correctly when a canvas is used (WebGL or canvas renderer).\n * Mouse listeners on canvas elements (for this browser), create\n * two mouse events: One 'good' and one 'bad' one (on other browsers or\n * when a div is used, there is only one event). For the 'bad' one,\n * clientX/clientY and also pageX/pageY are wrong when the page\n * is scrolled. Because of that, this function can not detect if\n * the events were simulated from a touch event. As result, a\n * pointer event at a wrong position is dispatched, which confuses\n * the map interactions.\n * It is unclear, how one can get the correct position for the event\n * or detect that the positions are invalid.\n *\n * @private\n * @param {Event} inEvent The in event.\n * @return {boolean} True, if the event was generated by a touch.\n */\nol.pointer.MouseSource.prototype.isEventSimulatedFromTouch_ = function(inEvent) {\n  var lts = this.lastTouches;\n  var x = inEvent.clientX, y = inEvent.clientY;\n  for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {\n    // simulated mouse events will be swallowed near a primary touchend\n    var dx = Math.abs(x - t[0]), dy = Math.abs(y - t[1]);\n    if (dx <= ol.pointer.MouseSource.DEDUP_DIST &&\n        dy <= ol.pointer.MouseSource.DEDUP_DIST) {\n      return true;\n    }\n  }\n  return false;\n};\n\n\n/**\n * Creates a copy of the original event that will be used\n * for the fake pointer event.\n *\n * @param {Event} inEvent The in event.\n * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.\n * @return {Object} The copied event.\n */\nol.pointer.MouseSource.prepareEvent = function(inEvent, dispatcher) {\n  var e = dispatcher.cloneEvent(inEvent, inEvent);\n\n  // forward mouse preventDefault\n  var pd = e.preventDefault;\n  e.preventDefault = function() {\n    inEvent.preventDefault();\n    pd();\n  };\n\n  e.pointerId = ol.pointer.MouseSource.POINTER_ID;\n  e.isPrimary = true;\n  e.pointerType = ol.pointer.MouseSource.POINTER_TYPE;\n\n  return e;\n};\n\n\n/**\n * Handler for `mousedown`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MouseSource.prototype.mousedown = function(inEvent) {\n  if (!this.isEventSimulatedFromTouch_(inEvent)) {\n    // TODO(dfreedman) workaround for some elements not sending mouseup\n    // http://crbug/149091\n    if (ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap) {\n      this.cancel(inEvent);\n    }\n    var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);\n    this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()] = inEvent;\n    this.dispatcher.down(e, inEvent);\n  }\n};\n\n\n/**\n * Handler for `mousemove`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MouseSource.prototype.mousemove = function(inEvent) {\n  if (!this.isEventSimulatedFromTouch_(inEvent)) {\n    var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);\n    this.dispatcher.move(e, inEvent);\n  }\n};\n\n\n/**\n * Handler for `mouseup`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MouseSource.prototype.mouseup = function(inEvent) {\n  if (!this.isEventSimulatedFromTouch_(inEvent)) {\n    var p = this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()];\n\n    if (p && p.button === inEvent.button) {\n      var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);\n      this.dispatcher.up(e, inEvent);\n      this.cleanupMouse();\n    }\n  }\n};\n\n\n/**\n * Handler for `mouseover`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MouseSource.prototype.mouseover = function(inEvent) {\n  if (!this.isEventSimulatedFromTouch_(inEvent)) {\n    var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);\n    this.dispatcher.enterOver(e, inEvent);\n  }\n};\n\n\n/**\n * Handler for `mouseout`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MouseSource.prototype.mouseout = function(inEvent) {\n  if (!this.isEventSimulatedFromTouch_(inEvent)) {\n    var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);\n    this.dispatcher.leaveOut(e, inEvent);\n  }\n};\n\n\n/**\n * Dispatches a `pointercancel` event.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MouseSource.prototype.cancel = function(inEvent) {\n  var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);\n  this.dispatcher.cancel(e, inEvent);\n  this.cleanupMouse();\n};\n\n\n/**\n * Remove the mouse from the list of active pointers.\n */\nol.pointer.MouseSource.prototype.cleanupMouse = function() {\n  delete this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()];\n};\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ngoog.provide('ol.pointer.MsSource');\n\ngoog.require('ol');\ngoog.require('ol.pointer.EventSource');\n\n\n/**\n * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.\n * @constructor\n * @extends {ol.pointer.EventSource}\n */\nol.pointer.MsSource = function(dispatcher) {\n  var mapping = {\n    'MSPointerDown': this.msPointerDown,\n    'MSPointerMove': this.msPointerMove,\n    'MSPointerUp': this.msPointerUp,\n    'MSPointerOut': this.msPointerOut,\n    'MSPointerOver': this.msPointerOver,\n    'MSPointerCancel': this.msPointerCancel,\n    'MSGotPointerCapture': this.msGotPointerCapture,\n    'MSLostPointerCapture': this.msLostPointerCapture\n  };\n  ol.pointer.EventSource.call(this, dispatcher, mapping);\n\n  /**\n   * @const\n   * @type {!Object.<string, Event|Object>}\n   */\n  this.pointerMap = dispatcher.pointerMap;\n\n  /**\n   * @const\n   * @type {Array.<string>}\n   */\n  this.POINTER_TYPES = [\n    '',\n    'unavailable',\n    'touch',\n    'pen',\n    'mouse'\n  ];\n};\nol.inherits(ol.pointer.MsSource, ol.pointer.EventSource);\n\n\n/**\n * Creates a copy of the original event that will be used\n * for the fake pointer event.\n *\n * @private\n * @param {Event} inEvent The in event.\n * @return {Object} The copied event.\n */\nol.pointer.MsSource.prototype.prepareEvent_ = function(inEvent) {\n  var e = inEvent;\n  if (typeof inEvent.pointerType === 'number') {\n    e = this.dispatcher.cloneEvent(inEvent, inEvent);\n    e.pointerType = this.POINTER_TYPES[inEvent.pointerType];\n  }\n\n  return e;\n};\n\n\n/**\n * Remove this pointer from the list of active pointers.\n * @param {number} pointerId Pointer identifier.\n */\nol.pointer.MsSource.prototype.cleanup = function(pointerId) {\n  delete this.pointerMap[pointerId.toString()];\n};\n\n\n/**\n * Handler for `msPointerDown`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msPointerDown = function(inEvent) {\n  this.pointerMap[inEvent.pointerId.toString()] = inEvent;\n  var e = this.prepareEvent_(inEvent);\n  this.dispatcher.down(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerMove`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msPointerMove = function(inEvent) {\n  var e = this.prepareEvent_(inEvent);\n  this.dispatcher.move(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerUp`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msPointerUp = function(inEvent) {\n  var e = this.prepareEvent_(inEvent);\n  this.dispatcher.up(e, inEvent);\n  this.cleanup(inEvent.pointerId);\n};\n\n\n/**\n * Handler for `msPointerOut`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msPointerOut = function(inEvent) {\n  var e = this.prepareEvent_(inEvent);\n  this.dispatcher.leaveOut(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerOver`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msPointerOver = function(inEvent) {\n  var e = this.prepareEvent_(inEvent);\n  this.dispatcher.enterOver(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerCancel`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msPointerCancel = function(inEvent) {\n  var e = this.prepareEvent_(inEvent);\n  this.dispatcher.cancel(e, inEvent);\n  this.cleanup(inEvent.pointerId);\n};\n\n\n/**\n * Handler for `msLostPointerCapture`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msLostPointerCapture = function(inEvent) {\n  var e = this.dispatcher.makeEvent('lostpointercapture',\n      inEvent, inEvent);\n  this.dispatcher.dispatchEvent(e);\n};\n\n\n/**\n * Handler for `msGotPointerCapture`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.MsSource.prototype.msGotPointerCapture = function(inEvent) {\n  var e = this.dispatcher.makeEvent('gotpointercapture',\n      inEvent, inEvent);\n  this.dispatcher.dispatchEvent(e);\n};\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ngoog.provide('ol.pointer.NativeSource');\n\ngoog.require('ol');\ngoog.require('ol.pointer.EventSource');\n\n\n/**\n * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.\n * @constructor\n * @extends {ol.pointer.EventSource}\n */\nol.pointer.NativeSource = function(dispatcher) {\n  var mapping = {\n    'pointerdown': this.pointerDown,\n    'pointermove': this.pointerMove,\n    'pointerup': this.pointerUp,\n    'pointerout': this.pointerOut,\n    'pointerover': this.pointerOver,\n    'pointercancel': this.pointerCancel,\n    'gotpointercapture': this.gotPointerCapture,\n    'lostpointercapture': this.lostPointerCapture\n  };\n  ol.pointer.EventSource.call(this, dispatcher, mapping);\n};\nol.inherits(ol.pointer.NativeSource, ol.pointer.EventSource);\n\n\n/**\n * Handler for `pointerdown`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.pointerDown = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointermove`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.pointerMove = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointerup`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.pointerUp = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointerout`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.pointerOut = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointerover`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.pointerOver = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointercancel`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.pointerCancel = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `lostpointercapture`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.lostPointerCapture = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `gotpointercapture`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.NativeSource.prototype.gotPointerCapture = function(inEvent) {\n  this.dispatcher.fireNativeEvent(inEvent);\n};\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ngoog.provide('ol.pointer.PointerEvent');\n\n\ngoog.require('ol');\ngoog.require('ol.events.Event');\n\n\n/**\n * A class for pointer events.\n *\n * This class is used as an abstraction for mouse events,\n * touch events and even native pointer events.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @param {string} type The type of the event to create.\n * @param {Event} originalEvent The event.\n * @param {Object.<string, ?>=} opt_eventDict An optional dictionary of\n *    initial event properties.\n */\nol.pointer.PointerEvent = function(type, originalEvent, opt_eventDict) {\n  ol.events.Event.call(this, type);\n\n  /**\n   * @const\n   * @type {Event}\n   */\n  this.originalEvent = originalEvent;\n\n  var eventDict = opt_eventDict ? opt_eventDict : {};\n\n  /**\n   * @type {number}\n   */\n  this.buttons = this.getButtons_(eventDict);\n\n  /**\n   * @type {number}\n   */\n  this.pressure = this.getPressure_(eventDict, this.buttons);\n\n  // MouseEvent related properties\n\n  /**\n   * @type {boolean}\n   */\n  this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;\n\n  /**\n   * @type {boolean}\n   */\n  this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;\n\n  /**\n   * @type {Object}\n   */\n  this.view = 'view' in eventDict ? eventDict['view'] : null;\n\n  /**\n   * @type {number}\n   */\n  this.detail = 'detail' in eventDict ? eventDict['detail'] : null;\n\n  /**\n   * @type {number}\n   */\n  this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;\n\n  /**\n   * @type {number}\n   */\n  this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;\n\n  /**\n   * @type {number}\n   */\n  this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;\n\n  /**\n   * @type {number}\n   */\n  this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;\n\n  /**\n   * @type {boolean}\n   */\n  this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;\n\n  /**\n   * @type {boolean}\n   */\n  this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;\n\n  /**\n   * @type {boolean}\n   */\n  this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;\n\n  /**\n   * @type {boolean}\n   */\n  this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;\n\n  /**\n   * @type {number}\n   */\n  this.button = 'button' in eventDict ? eventDict['button'] : 0;\n\n  /**\n   * @type {Node}\n   */\n  this.relatedTarget = 'relatedTarget' in eventDict ?\n      eventDict['relatedTarget'] : null;\n\n  // PointerEvent related properties\n\n  /**\n   * @const\n   * @type {number}\n   */\n  this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;\n\n  /**\n   * @type {number}\n   */\n  this.width = 'width' in eventDict ? eventDict['width'] : 0;\n\n  /**\n   * @type {number}\n   */\n  this.height = 'height' in eventDict ? eventDict['height'] : 0;\n\n  /**\n   * @type {number}\n   */\n  this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;\n\n  /**\n   * @type {number}\n   */\n  this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;\n\n  /**\n   * @type {string}\n   */\n  this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';\n\n  /**\n   * @type {number}\n   */\n  this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;\n\n  /**\n   * @type {boolean}\n   */\n  this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;\n\n  // keep the semantics of preventDefault\n  if (originalEvent.preventDefault) {\n    this.preventDefault = function() {\n      originalEvent.preventDefault();\n    };\n  }\n};\nol.inherits(ol.pointer.PointerEvent, ol.events.Event);\n\n\n/**\n * @private\n * @param {Object.<string, ?>} eventDict The event dictionary.\n * @return {number} Button indicator.\n */\nol.pointer.PointerEvent.prototype.getButtons_ = function(eventDict) {\n  // According to the w3c spec,\n  // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button\n  // MouseEvent.button == 0 can mean either no mouse button depressed, or the\n  // left mouse button depressed.\n  //\n  // As of now, the only way to distinguish between the two states of\n  // MouseEvent.button is by using the deprecated MouseEvent.which property, as\n  // this maps mouse buttons to positive integers > 0, and uses 0 to mean that\n  // no mouse button is held.\n  //\n  // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,\n  // but initMouseEvent does not expose an argument with which to set\n  // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set\n  // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations\n  // of app developers.\n  //\n  // The only way to propagate the correct state of MouseEvent.which and\n  // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0\n  // is to call initMouseEvent with a buttonArg value of -1.\n  //\n  // This is fixed with DOM Level 4's use of buttons\n  var buttons;\n  if (eventDict.buttons || ol.pointer.PointerEvent.HAS_BUTTONS) {\n    buttons = eventDict.buttons;\n  } else {\n    switch (eventDict.which) {\n      case 1: buttons = 1; break;\n      case 2: buttons = 4; break;\n      case 3: buttons = 2; break;\n      default: buttons = 0;\n    }\n  }\n  return buttons;\n};\n\n\n/**\n * @private\n * @param {Object.<string, ?>} eventDict The event dictionary.\n * @param {number} buttons Button indicator.\n * @return {number} The pressure.\n */\nol.pointer.PointerEvent.prototype.getPressure_ = function(eventDict, buttons) {\n  // Spec requires that pointers without pressure specified use 0.5 for down\n  // state and 0 for up state.\n  var pressure = 0;\n  if (eventDict.pressure) {\n    pressure = eventDict.pressure;\n  } else {\n    pressure = buttons ? 0.5 : 0;\n  }\n  return pressure;\n};\n\n\n/**\n * Is the `buttons` property supported?\n * @type {boolean}\n */\nol.pointer.PointerEvent.HAS_BUTTONS = false;\n\n\n/**\n * Checks if the `buttons` property is supported.\n */\n(function() {\n  try {\n    var ev = new MouseEvent('click', {buttons: 1});\n    ol.pointer.PointerEvent.HAS_BUTTONS = ev.buttons === 1;\n  } catch (e) {\n    // pass\n  }\n})();\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ngoog.provide('ol.pointer.TouchSource');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.pointer.EventSource');\ngoog.require('ol.pointer.MouseSource');\n\n\n/**\n * @constructor\n * @param {ol.pointer.PointerEventHandler} dispatcher The event handler.\n * @param {ol.pointer.MouseSource} mouseSource Mouse source.\n * @extends {ol.pointer.EventSource}\n */\nol.pointer.TouchSource = function(dispatcher, mouseSource) {\n  var mapping = {\n    'touchstart': this.touchstart,\n    'touchmove': this.touchmove,\n    'touchend': this.touchend,\n    'touchcancel': this.touchcancel\n  };\n  ol.pointer.EventSource.call(this, dispatcher, mapping);\n\n  /**\n   * @const\n   * @type {!Object.<string, Event|Object>}\n   */\n  this.pointerMap = dispatcher.pointerMap;\n\n  /**\n   * @const\n   * @type {ol.pointer.MouseSource}\n   */\n  this.mouseSource = mouseSource;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.firstTouchId_ = undefined;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.clickCount_ = 0;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.resetId_ = undefined;\n};\nol.inherits(ol.pointer.TouchSource, ol.pointer.EventSource);\n\n\n/**\n * Mouse event timeout: This should be long enough to\n * ignore compat mouse events made by touch.\n * @const\n * @type {number}\n */\nol.pointer.TouchSource.DEDUP_TIMEOUT = 2500;\n\n\n/**\n * @const\n * @type {number}\n */\nol.pointer.TouchSource.CLICK_COUNT_TIMEOUT = 200;\n\n\n/**\n * @const\n * @type {string}\n */\nol.pointer.TouchSource.POINTER_TYPE = 'touch';\n\n\n/**\n * @private\n * @param {Touch} inTouch The in touch.\n * @return {boolean} True, if this is the primary touch.\n */\nol.pointer.TouchSource.prototype.isPrimaryTouch_ = function(inTouch) {\n  return this.firstTouchId_ === inTouch.identifier;\n};\n\n\n/**\n * Set primary touch if there are no pointers, or the only pointer is the mouse.\n * @param {Touch} inTouch The in touch.\n * @private\n */\nol.pointer.TouchSource.prototype.setPrimaryTouch_ = function(inTouch) {\n  var count = Object.keys(this.pointerMap).length;\n  if (count === 0 || (count === 1 &&\n      ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap)) {\n    this.firstTouchId_ = inTouch.identifier;\n    this.cancelResetClickCount_();\n  }\n};\n\n\n/**\n * @private\n * @param {Object} inPointer The in pointer object.\n */\nol.pointer.TouchSource.prototype.removePrimaryPointer_ = function(inPointer) {\n  if (inPointer.isPrimary) {\n    this.firstTouchId_ = undefined;\n    this.resetClickCount_();\n  }\n};\n\n\n/**\n * @private\n */\nol.pointer.TouchSource.prototype.resetClickCount_ = function() {\n  this.resetId_ = setTimeout(\n      this.resetClickCountHandler_.bind(this),\n      ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT);\n};\n\n\n/**\n * @private\n */\nol.pointer.TouchSource.prototype.resetClickCountHandler_ = function() {\n  this.clickCount_ = 0;\n  this.resetId_ = undefined;\n};\n\n\n/**\n * @private\n */\nol.pointer.TouchSource.prototype.cancelResetClickCount_ = function() {\n  if (this.resetId_ !== undefined) {\n    clearTimeout(this.resetId_);\n  }\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent Browser event\n * @param {Touch} inTouch Touch event\n * @return {Object} A pointer object.\n */\nol.pointer.TouchSource.prototype.touchToPointer_ = function(browserEvent, inTouch) {\n  var e = this.dispatcher.cloneEvent(browserEvent, inTouch);\n  // Spec specifies that pointerId 1 is reserved for Mouse.\n  // Touch identifiers can start at 0.\n  // Add 2 to the touch identifier for compatibility.\n  e.pointerId = inTouch.identifier + 2;\n  // TODO: check if this is necessary?\n  //e.target = findTarget(e);\n  e.bubbles = true;\n  e.cancelable = true;\n  e.detail = this.clickCount_;\n  e.button = 0;\n  e.buttons = 1;\n  e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;\n  e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;\n  e.pressure = inTouch.webkitForce || inTouch.force || 0.5;\n  e.isPrimary = this.isPrimaryTouch_(inTouch);\n  e.pointerType = ol.pointer.TouchSource.POINTER_TYPE;\n\n  // make sure that the properties that are different for\n  // each `Touch` object are not copied from the BrowserEvent object\n  e.clientX = inTouch.clientX;\n  e.clientY = inTouch.clientY;\n  e.screenX = inTouch.screenX;\n  e.screenY = inTouch.screenY;\n\n  return e;\n};\n\n\n/**\n * @private\n * @param {Event} inEvent Touch event\n * @param {function(Event, Object)} inFunction In function.\n */\nol.pointer.TouchSource.prototype.processTouches_ = function(inEvent, inFunction) {\n  var touches = Array.prototype.slice.call(\n      inEvent.changedTouches);\n  var count = touches.length;\n  function preventDefault() {\n    inEvent.preventDefault();\n  }\n  var i, pointer;\n  for (i = 0; i < count; ++i) {\n    pointer = this.touchToPointer_(inEvent, touches[i]);\n    // forward touch preventDefaults\n    pointer.preventDefault = preventDefault;\n    inFunction.call(this, inEvent, pointer);\n  }\n};\n\n\n/**\n * @private\n * @param {TouchList} touchList The touch list.\n * @param {number} searchId Search identifier.\n * @return {boolean} True, if the `Touch` with the given id is in the list.\n */\nol.pointer.TouchSource.prototype.findTouch_ = function(touchList, searchId) {\n  var l = touchList.length;\n  var touch;\n  for (var i = 0; i < l; i++) {\n    touch = touchList[i];\n    if (touch.identifier === searchId) {\n      return true;\n    }\n  }\n  return false;\n};\n\n\n/**\n * In some instances, a touchstart can happen without a touchend. This\n * leaves the pointermap in a broken state.\n * Therefore, on every touchstart, we remove the touches that did not fire a\n * touchend event.\n * To keep state globally consistent, we fire a pointercancel for\n * this \"abandoned\" touch\n *\n * @private\n * @param {Event} inEvent The in event.\n */\nol.pointer.TouchSource.prototype.vacuumTouches_ = function(inEvent) {\n  var touchList = inEvent.touches;\n  // pointerMap.getCount() should be < touchList.length here,\n  // as the touchstart has not been processed yet.\n  var keys = Object.keys(this.pointerMap);\n  var count = keys.length;\n  if (count >= touchList.length) {\n    var d = [];\n    var i, key, value;\n    for (i = 0; i < count; ++i) {\n      key = keys[i];\n      value = this.pointerMap[key];\n      // Never remove pointerId == 1, which is mouse.\n      // Touch identifiers are 2 smaller than their pointerId, which is the\n      // index in pointermap.\n      if (key != ol.pointer.MouseSource.POINTER_ID &&\n          !this.findTouch_(touchList, key - 2)) {\n        d.push(value.out);\n      }\n    }\n    for (i = 0; i < d.length; ++i) {\n      this.cancelOut_(inEvent, d[i]);\n    }\n  }\n};\n\n\n/**\n * Handler for `touchstart`, triggers `pointerover`,\n * `pointerenter` and `pointerdown` events.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.TouchSource.prototype.touchstart = function(inEvent) {\n  this.vacuumTouches_(inEvent);\n  this.setPrimaryTouch_(inEvent.changedTouches[0]);\n  this.dedupSynthMouse_(inEvent);\n  this.clickCount_++;\n  this.processTouches_(inEvent, this.overDown_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent The event.\n * @param {Object} inPointer The in pointer object.\n */\nol.pointer.TouchSource.prototype.overDown_ = function(browserEvent, inPointer) {\n  this.pointerMap[inPointer.pointerId] = {\n    target: inPointer.target,\n    out: inPointer,\n    outTarget: inPointer.target\n  };\n  this.dispatcher.over(inPointer, browserEvent);\n  this.dispatcher.enter(inPointer, browserEvent);\n  this.dispatcher.down(inPointer, browserEvent);\n};\n\n\n/**\n * Handler for `touchmove`.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.TouchSource.prototype.touchmove = function(inEvent) {\n  inEvent.preventDefault();\n  this.processTouches_(inEvent, this.moveOverOut_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent The event.\n * @param {Object} inPointer The in pointer.\n */\nol.pointer.TouchSource.prototype.moveOverOut_ = function(browserEvent, inPointer) {\n  var event = inPointer;\n  var pointer = this.pointerMap[event.pointerId];\n  // a finger drifted off the screen, ignore it\n  if (!pointer) {\n    return;\n  }\n  var outEvent = pointer.out;\n  var outTarget = pointer.outTarget;\n  this.dispatcher.move(event, browserEvent);\n  if (outEvent && outTarget !== event.target) {\n    outEvent.relatedTarget = event.target;\n    event.relatedTarget = outTarget;\n    // recover from retargeting by shadow\n    outEvent.target = outTarget;\n    if (event.target) {\n      this.dispatcher.leaveOut(outEvent, browserEvent);\n      this.dispatcher.enterOver(event, browserEvent);\n    } else {\n      // clean up case when finger leaves the screen\n      event.target = outTarget;\n      event.relatedTarget = null;\n      this.cancelOut_(browserEvent, event);\n    }\n  }\n  pointer.out = event;\n  pointer.outTarget = event.target;\n};\n\n\n/**\n * Handler for `touchend`, triggers `pointerup`,\n * `pointerout` and `pointerleave` events.\n *\n * @param {Event} inEvent The event.\n */\nol.pointer.TouchSource.prototype.touchend = function(inEvent) {\n  this.dedupSynthMouse_(inEvent);\n  this.processTouches_(inEvent, this.upOut_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent An event.\n * @param {Object} inPointer The inPointer object.\n */\nol.pointer.TouchSource.prototype.upOut_ = function(browserEvent, inPointer) {\n  this.dispatcher.up(inPointer, browserEvent);\n  this.dispatcher.out(inPointer, browserEvent);\n  this.dispatcher.leave(inPointer, browserEvent);\n  this.cleanUpPointer_(inPointer);\n};\n\n\n/**\n * Handler for `touchcancel`, triggers `pointercancel`,\n * `pointerout` and `pointerleave` events.\n *\n * @param {Event} inEvent The in event.\n */\nol.pointer.TouchSource.prototype.touchcancel = function(inEvent) {\n  this.processTouches_(inEvent, this.cancelOut_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent The event.\n * @param {Object} inPointer The in pointer.\n */\nol.pointer.TouchSource.prototype.cancelOut_ = function(browserEvent, inPointer) {\n  this.dispatcher.cancel(inPointer, browserEvent);\n  this.dispatcher.out(inPointer, browserEvent);\n  this.dispatcher.leave(inPointer, browserEvent);\n  this.cleanUpPointer_(inPointer);\n};\n\n\n/**\n * @private\n * @param {Object} inPointer The inPointer object.\n */\nol.pointer.TouchSource.prototype.cleanUpPointer_ = function(inPointer) {\n  delete this.pointerMap[inPointer.pointerId];\n  this.removePrimaryPointer_(inPointer);\n};\n\n\n/**\n * Prevent synth mouse events from creating pointer events.\n *\n * @private\n * @param {Event} inEvent The in event.\n */\nol.pointer.TouchSource.prototype.dedupSynthMouse_ = function(inEvent) {\n  var lts = this.mouseSource.lastTouches;\n  var t = inEvent.changedTouches[0];\n  // only the primary finger will synth mouse events\n  if (this.isPrimaryTouch_(t)) {\n    // remember x/y of last touch\n    var lt = [t.clientX, t.clientY];\n    lts.push(lt);\n\n    setTimeout(function() {\n      // remove touch after timeout\n      ol.array.remove(lts, lt);\n    }, ol.pointer.TouchSource.DEDUP_TIMEOUT);\n  }\n};\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ngoog.provide('ol.pointer.PointerEventHandler');\n\ngoog.require('ol');\ngoog.require('ol.events');\ngoog.require('ol.events.EventTarget');\n\ngoog.require('ol.has');\ngoog.require('ol.pointer.EventType');\ngoog.require('ol.pointer.MouseSource');\ngoog.require('ol.pointer.MsSource');\ngoog.require('ol.pointer.NativeSource');\ngoog.require('ol.pointer.PointerEvent');\ngoog.require('ol.pointer.TouchSource');\n\n\n/**\n * @constructor\n * @extends {ol.events.EventTarget}\n * @param {Element|HTMLDocument} element Viewport element.\n */\nol.pointer.PointerEventHandler = function(element) {\n  ol.events.EventTarget.call(this);\n\n  /**\n   * @const\n   * @private\n   * @type {Element|HTMLDocument}\n   */\n  this.element_ = element;\n\n  /**\n   * @const\n   * @type {!Object.<string, Event|Object>}\n   */\n  this.pointerMap = {};\n\n  /**\n   * @type {Object.<string, function(Event)>}\n   * @private\n   */\n  this.eventMap_ = {};\n\n  /**\n   * @type {Array.<ol.pointer.EventSource>}\n   * @private\n   */\n  this.eventSourceList_ = [];\n\n  this.registerSources();\n};\nol.inherits(ol.pointer.PointerEventHandler, ol.events.EventTarget);\n\n\n/**\n * Set up the event sources (mouse, touch and native pointers)\n * that generate pointer events.\n */\nol.pointer.PointerEventHandler.prototype.registerSources = function() {\n  if (ol.has.POINTER) {\n    this.registerSource('native', new ol.pointer.NativeSource(this));\n  } else if (ol.has.MSPOINTER) {\n    this.registerSource('ms', new ol.pointer.MsSource(this));\n  } else {\n    var mouseSource = new ol.pointer.MouseSource(this);\n    this.registerSource('mouse', mouseSource);\n\n    if (ol.has.TOUCH) {\n      this.registerSource('touch',\n          new ol.pointer.TouchSource(this, mouseSource));\n    }\n  }\n\n  // register events on the viewport element\n  this.register_();\n};\n\n\n/**\n * Add a new event source that will generate pointer events.\n *\n * @param {string} name A name for the event source\n * @param {ol.pointer.EventSource} source The source event.\n */\nol.pointer.PointerEventHandler.prototype.registerSource = function(name, source) {\n  var s = source;\n  var newEvents = s.getEvents();\n\n  if (newEvents) {\n    newEvents.forEach(function(e) {\n      var handler = s.getHandlerForEvent(e);\n\n      if (handler) {\n        this.eventMap_[e] = handler.bind(s);\n      }\n    }, this);\n    this.eventSourceList_.push(s);\n  }\n};\n\n\n/**\n * Set up the events for all registered event sources.\n * @private\n */\nol.pointer.PointerEventHandler.prototype.register_ = function() {\n  var l = this.eventSourceList_.length;\n  var eventSource;\n  for (var i = 0; i < l; i++) {\n    eventSource = this.eventSourceList_[i];\n    this.addEvents_(eventSource.getEvents());\n  }\n};\n\n\n/**\n * Remove all registered events.\n * @private\n */\nol.pointer.PointerEventHandler.prototype.unregister_ = function() {\n  var l = this.eventSourceList_.length;\n  var eventSource;\n  for (var i = 0; i < l; i++) {\n    eventSource = this.eventSourceList_[i];\n    this.removeEvents_(eventSource.getEvents());\n  }\n};\n\n\n/**\n * Calls the right handler for a new event.\n * @private\n * @param {Event} inEvent Browser event.\n */\nol.pointer.PointerEventHandler.prototype.eventHandler_ = function(inEvent) {\n  var type = inEvent.type;\n  var handler = this.eventMap_[type];\n  if (handler) {\n    handler(inEvent);\n  }\n};\n\n\n/**\n * Setup listeners for the given events.\n * @private\n * @param {Array.<string>} events List of events.\n */\nol.pointer.PointerEventHandler.prototype.addEvents_ = function(events) {\n  events.forEach(function(eventName) {\n    ol.events.listen(this.element_, eventName, this.eventHandler_, this);\n  }, this);\n};\n\n\n/**\n * Unregister listeners for the given events.\n * @private\n * @param {Array.<string>} events List of events.\n */\nol.pointer.PointerEventHandler.prototype.removeEvents_ = function(events) {\n  events.forEach(function(e) {\n    ol.events.unlisten(this.element_, e, this.eventHandler_, this);\n  }, this);\n};\n\n\n/**\n * Returns a snapshot of inEvent, with writable properties.\n *\n * @param {Event} event Browser event.\n * @param {Event|Touch} inEvent An event that contains\n *    properties to copy.\n * @return {Object} An object containing shallow copies of\n *    `inEvent`'s properties.\n */\nol.pointer.PointerEventHandler.prototype.cloneEvent = function(event, inEvent) {\n  var eventCopy = {}, p;\n  for (var i = 0, ii = ol.pointer.PointerEventHandler.CLONE_PROPS.length; i < ii; i++) {\n    p = ol.pointer.PointerEventHandler.CLONE_PROPS[i][0];\n    eventCopy[p] = event[p] || inEvent[p] || ol.pointer.PointerEventHandler.CLONE_PROPS[i][1];\n  }\n\n  return eventCopy;\n};\n\n\n// EVENTS\n\n\n/**\n * Triggers a 'pointerdown' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.down = function(data, event) {\n  this.fireEvent(ol.pointer.EventType.POINTERDOWN, data, event);\n};\n\n\n/**\n * Triggers a 'pointermove' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.move = function(data, event) {\n  this.fireEvent(ol.pointer.EventType.POINTERMOVE, data, event);\n};\n\n\n/**\n * Triggers a 'pointerup' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.up = function(data, event) {\n  this.fireEvent(ol.pointer.EventType.POINTERUP, data, event);\n};\n\n\n/**\n * Triggers a 'pointerenter' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.enter = function(data, event) {\n  data.bubbles = false;\n  this.fireEvent(ol.pointer.EventType.POINTERENTER, data, event);\n};\n\n\n/**\n * Triggers a 'pointerleave' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.leave = function(data, event) {\n  data.bubbles = false;\n  this.fireEvent(ol.pointer.EventType.POINTERLEAVE, data, event);\n};\n\n\n/**\n * Triggers a 'pointerover' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.over = function(data, event) {\n  data.bubbles = true;\n  this.fireEvent(ol.pointer.EventType.POINTEROVER, data, event);\n};\n\n\n/**\n * Triggers a 'pointerout' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.out = function(data, event) {\n  data.bubbles = true;\n  this.fireEvent(ol.pointer.EventType.POINTEROUT, data, event);\n};\n\n\n/**\n * Triggers a 'pointercancel' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.cancel = function(data, event) {\n  this.fireEvent(ol.pointer.EventType.POINTERCANCEL, data, event);\n};\n\n\n/**\n * Triggers a combination of 'pointerout' and 'pointerleave' events.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.leaveOut = function(data, event) {\n  this.out(data, event);\n  if (!this.contains_(data.target, data.relatedTarget)) {\n    this.leave(data, event);\n  }\n};\n\n\n/**\n * Triggers a combination of 'pointerover' and 'pointerevents' events.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.enterOver = function(data, event) {\n  this.over(data, event);\n  if (!this.contains_(data.target, data.relatedTarget)) {\n    this.enter(data, event);\n  }\n};\n\n\n/**\n * @private\n * @param {Element} container The container element.\n * @param {Element} contained The contained element.\n * @return {boolean} Returns true if the container element\n *   contains the other element.\n */\nol.pointer.PointerEventHandler.prototype.contains_ = function(container, contained) {\n  if (!container || !contained) {\n    return false;\n  }\n  return container.contains(contained);\n};\n\n\n// EVENT CREATION AND TRACKING\n/**\n * Creates a new Event of type `inType`, based on the information in\n * `data`.\n *\n * @param {string} inType A string representing the type of event to create.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n * @return {ol.pointer.PointerEvent} A PointerEvent of type `inType`.\n */\nol.pointer.PointerEventHandler.prototype.makeEvent = function(inType, data, event) {\n  return new ol.pointer.PointerEvent(inType, event, data);\n};\n\n\n/**\n * Make and dispatch an event in one call.\n * @param {string} inType A string representing the type of event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nol.pointer.PointerEventHandler.prototype.fireEvent = function(inType, data, event) {\n  var e = this.makeEvent(inType, data, event);\n  this.dispatchEvent(e);\n};\n\n\n/**\n * Creates a pointer event from a native pointer event\n * and dispatches this event.\n * @param {Event} event A platform event with a target.\n */\nol.pointer.PointerEventHandler.prototype.fireNativeEvent = function(event) {\n  var e = this.makeEvent(event.type, event, event);\n  this.dispatchEvent(e);\n};\n\n\n/**\n * Wrap a native mouse event into a pointer event.\n * This proxy method is required for the legacy IE support.\n * @param {string} eventType The pointer event type.\n * @param {Event} event The event.\n * @return {ol.pointer.PointerEvent} The wrapped event.\n */\nol.pointer.PointerEventHandler.prototype.wrapMouseEvent = function(eventType, event) {\n  var pointerEvent = this.makeEvent(\n      eventType, ol.pointer.MouseSource.prepareEvent(event, this), event);\n  return pointerEvent;\n};\n\n\n/**\n * @inheritDoc\n */\nol.pointer.PointerEventHandler.prototype.disposeInternal = function() {\n  this.unregister_();\n  ol.events.EventTarget.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Properties to copy when cloning an event, with default values.\n * @type {Array.<Array>}\n */\nol.pointer.PointerEventHandler.CLONE_PROPS = [\n  // MouseEvent\n  ['bubbles', false],\n  ['cancelable', false],\n  ['view', null],\n  ['detail', null],\n  ['screenX', 0],\n  ['screenY', 0],\n  ['clientX', 0],\n  ['clientY', 0],\n  ['ctrlKey', false],\n  ['altKey', false],\n  ['shiftKey', false],\n  ['metaKey', false],\n  ['button', 0],\n  ['relatedTarget', null],\n  // DOM Level 3\n  ['buttons', 0],\n  // PointerEvent\n  ['pointerId', 0],\n  ['width', 0],\n  ['height', 0],\n  ['pressure', 0],\n  ['tiltX', 0],\n  ['tiltY', 0],\n  ['pointerType', ''],\n  ['hwTimestamp', 0],\n  ['isPrimary', false],\n  // event instance\n  ['type', ''],\n  ['target', null],\n  ['currentTarget', null],\n  ['which', 0]\n];\n\ngoog.provide('ol.MapBrowserEventHandler');\n\ngoog.require('ol');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.MapBrowserPointerEvent');\ngoog.require('ol.events');\ngoog.require('ol.events.EventTarget');\ngoog.require('ol.pointer.EventType');\ngoog.require('ol.pointer.PointerEventHandler');\n\n\n/**\n * @param {ol.Map} map The map with the viewport to listen to events on.\n * @constructor\n * @extends {ol.events.EventTarget}\n */\nol.MapBrowserEventHandler = function(map) {\n\n  ol.events.EventTarget.call(this);\n\n  /**\n   * This is the element that we will listen to the real events on.\n   * @type {ol.Map}\n   * @private\n   */\n  this.map_ = map;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.clickTimeoutId_ = 0;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.dragging_ = false;\n\n  /**\n   * @type {!Array.<ol.EventsKey>}\n   * @private\n   */\n  this.dragListenerKeys_ = [];\n\n  /**\n   * The most recent \"down\" type event (or null if none have occurred).\n   * Set on pointerdown.\n   * @type {ol.pointer.PointerEvent}\n   * @private\n   */\n  this.down_ = null;\n\n  var element = this.map_.getViewport();\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.activePointers_ = 0;\n\n  /**\n   * @type {!Object.<number, boolean>}\n   * @private\n   */\n  this.trackedTouches_ = {};\n\n  /**\n   * Event handler which generates pointer events for\n   * the viewport element.\n   *\n   * @type {ol.pointer.PointerEventHandler}\n   * @private\n   */\n  this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element);\n\n  /**\n   * Event handler which generates pointer events for\n   * the document (used when dragging).\n   *\n   * @type {ol.pointer.PointerEventHandler}\n   * @private\n   */\n  this.documentPointerEventHandler_ = null;\n\n  /**\n   * @type {?ol.EventsKey}\n   * @private\n   */\n  this.pointerdownListenerKey_ = ol.events.listen(this.pointerEventHandler_,\n      ol.pointer.EventType.POINTERDOWN,\n      this.handlePointerDown_, this);\n\n  /**\n   * @type {?ol.EventsKey}\n   * @private\n   */\n  this.relayedListenerKey_ = ol.events.listen(this.pointerEventHandler_,\n      ol.pointer.EventType.POINTERMOVE,\n      this.relayEvent_, this);\n\n};\nol.inherits(ol.MapBrowserEventHandler, ol.events.EventTarget);\n\n\n/**\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @private\n */\nol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) {\n  var newEvent = new ol.MapBrowserPointerEvent(\n      ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent);\n  this.dispatchEvent(newEvent);\n  if (this.clickTimeoutId_ !== 0) {\n    // double-click\n    clearTimeout(this.clickTimeoutId_);\n    this.clickTimeoutId_ = 0;\n    newEvent = new ol.MapBrowserPointerEvent(\n        ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent);\n    this.dispatchEvent(newEvent);\n  } else {\n    // click\n    this.clickTimeoutId_ = setTimeout(function() {\n      this.clickTimeoutId_ = 0;\n      var newEvent = new ol.MapBrowserPointerEvent(\n          ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent);\n      this.dispatchEvent(newEvent);\n    }.bind(this), 250);\n  }\n};\n\n\n/**\n * Keeps track on how many pointers are currently active.\n *\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @private\n */\nol.MapBrowserEventHandler.prototype.updateActivePointers_ = function(pointerEvent) {\n  var event = pointerEvent;\n\n  if (event.type == ol.MapBrowserEvent.EventType.POINTERUP ||\n      event.type == ol.MapBrowserEvent.EventType.POINTERCANCEL) {\n    delete this.trackedTouches_[event.pointerId];\n  } else if (event.type == ol.MapBrowserEvent.EventType.POINTERDOWN) {\n    this.trackedTouches_[event.pointerId] = true;\n  }\n  this.activePointers_ = Object.keys(this.trackedTouches_).length;\n};\n\n\n/**\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @private\n */\nol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) {\n  this.updateActivePointers_(pointerEvent);\n  var newEvent = new ol.MapBrowserPointerEvent(\n      ol.MapBrowserEvent.EventType.POINTERUP, this.map_, pointerEvent);\n  this.dispatchEvent(newEvent);\n\n  // We emulate click events on left mouse button click, touch contact, and pen\n  // contact. isMouseActionButton returns true in these cases (evt.button is set\n  // to 0).\n  // See http://www.w3.org/TR/pointerevents/#button-states\n  if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) {\n    ol.DEBUG && console.assert(this.down_, 'this.down_ must be truthy');\n    this.emulateClick_(this.down_);\n  }\n\n  ol.DEBUG && console.assert(this.activePointers_ >= 0,\n      'this.activePointers_ should be equal to or larger than 0');\n  if (this.activePointers_ === 0) {\n    this.dragListenerKeys_.forEach(ol.events.unlistenByKey);\n    this.dragListenerKeys_.length = 0;\n    this.dragging_ = false;\n    this.down_ = null;\n    this.documentPointerEventHandler_.dispose();\n    this.documentPointerEventHandler_ = null;\n  }\n};\n\n\n/**\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @return {boolean} If the left mouse button was pressed.\n * @private\n */\nol.MapBrowserEventHandler.prototype.isMouseActionButton_ = function(pointerEvent) {\n  return pointerEvent.button === 0;\n};\n\n\n/**\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @private\n */\nol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent) {\n  this.updateActivePointers_(pointerEvent);\n  var newEvent = new ol.MapBrowserPointerEvent(\n      ol.MapBrowserEvent.EventType.POINTERDOWN, this.map_, pointerEvent);\n  this.dispatchEvent(newEvent);\n\n  this.down_ = pointerEvent;\n\n  if (this.dragListenerKeys_.length === 0) {\n    /* Set up a pointer event handler on the `document`,\n     * which is required when the pointer is moved outside\n     * the viewport when dragging.\n     */\n    this.documentPointerEventHandler_ =\n        new ol.pointer.PointerEventHandler(document);\n\n    this.dragListenerKeys_.push(\n      ol.events.listen(this.documentPointerEventHandler_,\n          ol.MapBrowserEvent.EventType.POINTERMOVE,\n          this.handlePointerMove_, this),\n      ol.events.listen(this.documentPointerEventHandler_,\n          ol.MapBrowserEvent.EventType.POINTERUP,\n          this.handlePointerUp_, this),\n      /* Note that the listener for `pointercancel is set up on\n       * `pointerEventHandler_` and not `documentPointerEventHandler_` like\n       * the `pointerup` and `pointermove` listeners.\n       *\n       * The reason for this is the following: `TouchSource.vacuumTouches_()`\n       * issues `pointercancel` events, when there was no `touchend` for a\n       * `touchstart`. Now, let's say a first `touchstart` is registered on\n       * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up.\n       * But `documentPointerEventHandler_` doesn't know about the first\n       * `touchstart`. If there is no `touchend` for the `touchstart`, we can\n       * only receive a `touchcancel` from `pointerEventHandler_`, because it is\n       * only registered there.\n       */\n      ol.events.listen(this.pointerEventHandler_,\n          ol.MapBrowserEvent.EventType.POINTERCANCEL,\n          this.handlePointerUp_, this)\n    );\n  }\n};\n\n\n/**\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @private\n */\nol.MapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) {\n  // Fix IE10 on windows Surface : When you tap the tablet, it triggers\n  // multiple pointermove events between pointerdown and pointerup with\n  // the exact same coordinates of the pointerdown event. To avoid a\n  // 'false' touchmove event to be dispatched , we test if the pointer\n  // effectively moved.\n  if (this.isMoving_(pointerEvent)) {\n    this.dragging_ = true;\n    var newEvent = new ol.MapBrowserPointerEvent(\n        ol.MapBrowserEvent.EventType.POINTERDRAG, this.map_, pointerEvent,\n        this.dragging_);\n    this.dispatchEvent(newEvent);\n  }\n\n  // Some native android browser triggers mousemove events during small period\n  // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or\n  // https://code.google.com/p/android/issues/detail?id=19827\n  // ex: Galaxy Tab P3110 + Android 4.1.1\n  pointerEvent.preventDefault();\n};\n\n\n/**\n * Wrap and relay a pointer event.  Note that this requires that the type\n * string for the MapBrowserPointerEvent matches the PointerEvent type.\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @private\n */\nol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) {\n  var dragging = !!(this.down_ && this.isMoving_(pointerEvent));\n  this.dispatchEvent(new ol.MapBrowserPointerEvent(\n      pointerEvent.type, this.map_, pointerEvent, dragging));\n};\n\n\n/**\n * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.\n * @return {boolean} Is moving.\n * @private\n */\nol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) {\n  return pointerEvent.clientX != this.down_.clientX ||\n      pointerEvent.clientY != this.down_.clientY;\n};\n\n\n/**\n * @inheritDoc\n */\nol.MapBrowserEventHandler.prototype.disposeInternal = function() {\n  if (this.relayedListenerKey_) {\n    ol.events.unlistenByKey(this.relayedListenerKey_);\n    this.relayedListenerKey_ = null;\n  }\n  if (this.pointerdownListenerKey_) {\n    ol.events.unlistenByKey(this.pointerdownListenerKey_);\n    this.pointerdownListenerKey_ = null;\n  }\n\n  this.dragListenerKeys_.forEach(ol.events.unlistenByKey);\n  this.dragListenerKeys_.length = 0;\n\n  if (this.documentPointerEventHandler_) {\n    this.documentPointerEventHandler_.dispose();\n    this.documentPointerEventHandler_ = null;\n  }\n  if (this.pointerEventHandler_) {\n    this.pointerEventHandler_.dispose();\n    this.pointerEventHandler_ = null;\n  }\n  ol.events.EventTarget.prototype.disposeInternal.call(this);\n};\n\ngoog.provide('ol.Tile');\n\ngoog.require('ol');\ngoog.require('ol.events.EventTarget');\ngoog.require('ol.events.EventType');\n\n\n/**\n * @classdesc\n * Base class for tiles.\n *\n * @constructor\n * @extends {ol.events.EventTarget}\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Tile.State} state State.\n */\nol.Tile = function(tileCoord, state) {\n\n  ol.events.EventTarget.call(this);\n\n  /**\n   * @type {ol.TileCoord}\n   */\n  this.tileCoord = tileCoord;\n\n  /**\n   * @protected\n   * @type {ol.Tile.State}\n   */\n  this.state = state;\n\n  /**\n   * An \"interim\" tile for this tile. The interim tile may be used while this\n   * one is loading, for \"smooth\" transitions when changing params/dimensions\n   * on the source.\n   * @type {ol.Tile}\n   */\n  this.interimTile = null;\n\n  /**\n   * A key assigned to the tile. This is used by the tile source to determine\n   * if this tile can effectively be used, or if a new tile should be created\n   * and this one be used as an interim tile for this new tile.\n   * @type {string}\n   */\n  this.key = '';\n\n};\nol.inherits(ol.Tile, ol.events.EventTarget);\n\n\n/**\n * @protected\n */\nol.Tile.prototype.changed = function() {\n  this.dispatchEvent(ol.events.EventType.CHANGE);\n};\n\n\n/**\n * Get the HTML image element for this tile (may be a Canvas, Image, or Video).\n * @abstract\n * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.\n */\nol.Tile.prototype.getImage = function() {};\n\n\n/**\n * @return {string} Key.\n */\nol.Tile.prototype.getKey = function() {\n  return this.key + '/' + this.tileCoord;\n};\n\n/**\n * Get the interim tile most suitable for rendering using the chain of interim\n * tiles. This corresponds to the  most recent tile that has been loaded, if no\n * such tile exists, the original tile is returned.\n * @return {!ol.Tile} Best tile for rendering.\n */\nol.Tile.prototype.getInterimTile = function() {\n  if (!this.interimTile) {\n    //empty chain\n    return this;\n  }\n  var tile = this.interimTile;\n\n  // find the first loaded tile and return it. Since the chain is sorted in\n  // decreasing order of creation time, there is no need to search the remainder\n  // of the list (all those tiles correspond to older requests and will be\n  // cleaned up by refreshInterimChain)\n  do {\n    if (tile.getState() == ol.Tile.State.LOADED) {\n      return tile;\n    }\n    tile = tile.interimTile;\n  } while (tile);\n\n  // we can not find a better tile\n  return this;\n};\n\n/**\n * Goes through the chain of interim tiles and discards sections of the chain\n * that are no longer relevant.\n */\nol.Tile.prototype.refreshInterimChain = function() {\n  if (!this.interimTile) {\n    return;\n  }\n\n  var tile = this.interimTile;\n  var prev = this;\n\n  do {\n    if (tile.getState() == ol.Tile.State.LOADED) {\n      //we have a loaded tile, we can discard the rest of the list\n      //we would could abort any LOADING tile request\n      //older than this tile (i.e. any LOADING tile following this entry in the chain)\n      tile.interimTile = null;\n      break;\n    } else if (tile.getState() == ol.Tile.State.LOADING) {\n      //keep this LOADING tile any loaded tiles later in the chain are\n      //older than this tile, so we're still interested in the request\n      prev = tile;\n    } else if (tile.getState() == ol.Tile.State.IDLE) {\n      //the head of the list is the most current tile, we don't need\n      //to start any other requests for this chain\n      prev.interimTile = tile.interimTile;\n    } else {\n      prev = tile;\n    }\n    tile = prev.interimTile;\n  } while (tile);\n};\n\n/**\n * Get the tile coordinate for this tile.\n * @return {ol.TileCoord} The tile coordinate.\n * @api\n */\nol.Tile.prototype.getTileCoord = function() {\n  return this.tileCoord;\n};\n\n\n/**\n * @return {ol.Tile.State} State.\n */\nol.Tile.prototype.getState = function() {\n  return this.state;\n};\n\n\n/**\n * Load the image or retry if loading previously failed.\n * Loading is taken care of by the tile queue, and calling this method is\n * only needed for preloading or for reloading in case of an error.\n * @abstract\n * @api\n */\nol.Tile.prototype.load = function() {};\n\n\n/**\n * @enum {number}\n */\nol.Tile.State = {\n  IDLE: 0,\n  LOADING: 1,\n  LOADED: 2,\n  ERROR: 3,\n  EMPTY: 4,\n  ABORT: 5\n};\n\ngoog.provide('ol.structs.PriorityQueue');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.obj');\n\n\n/**\n * Priority queue.\n *\n * The implementation is inspired from the Closure Library's Heap class and\n * Python's heapq module.\n *\n * @see http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html\n * @see http://hg.python.org/cpython/file/2.7/Lib/heapq.py\n *\n * @constructor\n * @param {function(T): number} priorityFunction Priority function.\n * @param {function(T): string} keyFunction Key function.\n * @struct\n * @template T\n */\nol.structs.PriorityQueue = function(priorityFunction, keyFunction) {\n\n  /**\n   * @type {function(T): number}\n   * @private\n   */\n  this.priorityFunction_ = priorityFunction;\n\n  /**\n   * @type {function(T): string}\n   * @private\n   */\n  this.keyFunction_ = keyFunction;\n\n  /**\n   * @type {Array.<T>}\n   * @private\n   */\n  this.elements_ = [];\n\n  /**\n   * @type {Array.<number>}\n   * @private\n   */\n  this.priorities_ = [];\n\n  /**\n   * @type {Object.<string, boolean>}\n   * @private\n   */\n  this.queuedElements_ = {};\n\n};\n\n\n/**\n * @const\n * @type {number}\n */\nol.structs.PriorityQueue.DROP = Infinity;\n\n\nif (ol.DEBUG) {\n  /**\n   * FIXME empty description for jsdoc\n   */\n  ol.structs.PriorityQueue.prototype.assertValid = function() {\n    var elements = this.elements_;\n    var priorities = this.priorities_;\n    var n = elements.length;\n    console.assert(priorities.length == n);\n    var i, priority;\n    for (i = 0; i < (n >> 1) - 1; ++i) {\n      priority = priorities[i];\n      console.assert(priority <= priorities[this.getLeftChildIndex_(i)],\n          'priority smaller than or equal to priority of left child (%s <= %s)',\n          priority, priorities[this.getLeftChildIndex_(i)]);\n      console.assert(priority <= priorities[this.getRightChildIndex_(i)],\n          'priority smaller than or equal to priority of right child (%s <= %s)',\n          priority, priorities[this.getRightChildIndex_(i)]);\n    }\n  };\n}\n\n\n/**\n * FIXME empty description for jsdoc\n */\nol.structs.PriorityQueue.prototype.clear = function() {\n  this.elements_.length = 0;\n  this.priorities_.length = 0;\n  ol.obj.clear(this.queuedElements_);\n};\n\n\n/**\n * Remove and return the highest-priority element. O(log N).\n * @return {T} Element.\n */\nol.structs.PriorityQueue.prototype.dequeue = function() {\n  var elements = this.elements_;\n  ol.DEBUG && console.assert(elements.length > 0,\n      'must have elements in order to be able to dequeue');\n  var priorities = this.priorities_;\n  var element = elements[0];\n  if (elements.length == 1) {\n    elements.length = 0;\n    priorities.length = 0;\n  } else {\n    elements[0] = elements.pop();\n    priorities[0] = priorities.pop();\n    this.siftUp_(0);\n  }\n  var elementKey = this.keyFunction_(element);\n  ol.DEBUG && console.assert(elementKey in this.queuedElements_,\n      'key %s is not listed as queued', elementKey);\n  delete this.queuedElements_[elementKey];\n  return element;\n};\n\n\n/**\n * Enqueue an element. O(log N).\n * @param {T} element Element.\n * @return {boolean} The element was added to the queue.\n */\nol.structs.PriorityQueue.prototype.enqueue = function(element) {\n  ol.asserts.assert(!(this.keyFunction_(element) in this.queuedElements_),\n      31); // Tried to enqueue an `element` that was already added to the queue\n  var priority = this.priorityFunction_(element);\n  if (priority != ol.structs.PriorityQueue.DROP) {\n    this.elements_.push(element);\n    this.priorities_.push(priority);\n    this.queuedElements_[this.keyFunction_(element)] = true;\n    this.siftDown_(0, this.elements_.length - 1);\n    return true;\n  }\n  return false;\n};\n\n\n/**\n * @return {number} Count.\n */\nol.structs.PriorityQueue.prototype.getCount = function() {\n  return this.elements_.length;\n};\n\n\n/**\n * Gets the index of the left child of the node at the given index.\n * @param {number} index The index of the node to get the left child for.\n * @return {number} The index of the left child.\n * @private\n */\nol.structs.PriorityQueue.prototype.getLeftChildIndex_ = function(index) {\n  return index * 2 + 1;\n};\n\n\n/**\n * Gets the index of the right child of the node at the given index.\n * @param {number} index The index of the node to get the right child for.\n * @return {number} The index of the right child.\n * @private\n */\nol.structs.PriorityQueue.prototype.getRightChildIndex_ = function(index) {\n  return index * 2 + 2;\n};\n\n\n/**\n * Gets the index of the parent of the node at the given index.\n * @param {number} index The index of the node to get the parent for.\n * @return {number} The index of the parent.\n * @private\n */\nol.structs.PriorityQueue.prototype.getParentIndex_ = function(index) {\n  return (index - 1) >> 1;\n};\n\n\n/**\n * Make this a heap. O(N).\n * @private\n */\nol.structs.PriorityQueue.prototype.heapify_ = function() {\n  var i;\n  for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) {\n    this.siftUp_(i);\n  }\n};\n\n\n/**\n * @return {boolean} Is empty.\n */\nol.structs.PriorityQueue.prototype.isEmpty = function() {\n  return this.elements_.length === 0;\n};\n\n\n/**\n * @param {string} key Key.\n * @return {boolean} Is key queued.\n */\nol.structs.PriorityQueue.prototype.isKeyQueued = function(key) {\n  return key in this.queuedElements_;\n};\n\n\n/**\n * @param {T} element Element.\n * @return {boolean} Is queued.\n */\nol.structs.PriorityQueue.prototype.isQueued = function(element) {\n  return this.isKeyQueued(this.keyFunction_(element));\n};\n\n\n/**\n * @param {number} index The index of the node to move down.\n * @private\n */\nol.structs.PriorityQueue.prototype.siftUp_ = function(index) {\n  var elements = this.elements_;\n  var priorities = this.priorities_;\n  var count = elements.length;\n  var element = elements[index];\n  var priority = priorities[index];\n  var startIndex = index;\n\n  while (index < (count >> 1)) {\n    var lIndex = this.getLeftChildIndex_(index);\n    var rIndex = this.getRightChildIndex_(index);\n\n    var smallerChildIndex = rIndex < count &&\n        priorities[rIndex] < priorities[lIndex] ?\n        rIndex : lIndex;\n\n    elements[index] = elements[smallerChildIndex];\n    priorities[index] = priorities[smallerChildIndex];\n    index = smallerChildIndex;\n  }\n\n  elements[index] = element;\n  priorities[index] = priority;\n  this.siftDown_(startIndex, index);\n};\n\n\n/**\n * @param {number} startIndex The index of the root.\n * @param {number} index The index of the node to move up.\n * @private\n */\nol.structs.PriorityQueue.prototype.siftDown_ = function(startIndex, index) {\n  var elements = this.elements_;\n  var priorities = this.priorities_;\n  var element = elements[index];\n  var priority = priorities[index];\n\n  while (index > startIndex) {\n    var parentIndex = this.getParentIndex_(index);\n    if (priorities[parentIndex] > priority) {\n      elements[index] = elements[parentIndex];\n      priorities[index] = priorities[parentIndex];\n      index = parentIndex;\n    } else {\n      break;\n    }\n  }\n  elements[index] = element;\n  priorities[index] = priority;\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nol.structs.PriorityQueue.prototype.reprioritize = function() {\n  var priorityFunction = this.priorityFunction_;\n  var elements = this.elements_;\n  var priorities = this.priorities_;\n  var index = 0;\n  var n = elements.length;\n  var element, i, priority;\n  for (i = 0; i < n; ++i) {\n    element = elements[i];\n    priority = priorityFunction(element);\n    if (priority == ol.structs.PriorityQueue.DROP) {\n      delete this.queuedElements_[this.keyFunction_(element)];\n    } else {\n      priorities[index] = priority;\n      elements[index++] = element;\n    }\n  }\n  elements.length = index;\n  priorities.length = index;\n  this.heapify_();\n};\n\ngoog.provide('ol.TileQueue');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.structs.PriorityQueue');\n\n\n/**\n * @constructor\n * @extends {ol.structs.PriorityQueue.<Array>}\n * @param {ol.TilePriorityFunction} tilePriorityFunction\n *     Tile priority function.\n * @param {function(): ?} tileChangeCallback\n *     Function called on each tile change event.\n * @struct\n */\nol.TileQueue = function(tilePriorityFunction, tileChangeCallback) {\n\n  ol.structs.PriorityQueue.call(\n      this,\n      /**\n       * @param {Array} element Element.\n       * @return {number} Priority.\n       */\n      function(element) {\n        return tilePriorityFunction.apply(null, element);\n      },\n      /**\n       * @param {Array} element Element.\n       * @return {string} Key.\n       */\n      function(element) {\n        return /** @type {ol.Tile} */ (element[0]).getKey();\n      });\n\n  /**\n   * @private\n   * @type {function(): ?}\n   */\n  this.tileChangeCallback_ = tileChangeCallback;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.tilesLoading_ = 0;\n\n  /**\n   * @private\n   * @type {!Object.<string,boolean>}\n   */\n  this.tilesLoadingKeys_ = {};\n\n};\nol.inherits(ol.TileQueue, ol.structs.PriorityQueue);\n\n\n/**\n * @inheritDoc\n */\nol.TileQueue.prototype.enqueue = function(element) {\n  var added = ol.structs.PriorityQueue.prototype.enqueue.call(this, element);\n  if (added) {\n    var tile = element[0];\n    ol.events.listen(tile, ol.events.EventType.CHANGE,\n        this.handleTileChange, this);\n  }\n  return added;\n};\n\n\n/**\n * @return {number} Number of tiles loading.\n */\nol.TileQueue.prototype.getTilesLoading = function() {\n  return this.tilesLoading_;\n};\n\n\n/**\n * @param {ol.events.Event} event Event.\n * @protected\n */\nol.TileQueue.prototype.handleTileChange = function(event) {\n  var tile = /** @type {ol.Tile} */ (event.target);\n  var state = tile.getState();\n  if (state === ol.Tile.State.LOADED || state === ol.Tile.State.ERROR ||\n      state === ol.Tile.State.EMPTY || state === ol.Tile.State.ABORT) {\n    ol.events.unlisten(tile, ol.events.EventType.CHANGE,\n        this.handleTileChange, this);\n    var tileKey = tile.getKey();\n    if (tileKey in this.tilesLoadingKeys_) {\n      delete this.tilesLoadingKeys_[tileKey];\n      --this.tilesLoading_;\n    }\n    this.tileChangeCallback_();\n  }\n  ol.DEBUG && console.assert(Object.keys(this.tilesLoadingKeys_).length === this.tilesLoading_);\n};\n\n\n/**\n * @param {number} maxTotalLoading Maximum number tiles to load simultaneously.\n * @param {number} maxNewLoads Maximum number of new tiles to load.\n */\nol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {\n  var newLoads = 0;\n  var tile, tileKey;\n  while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&\n         this.getCount() > 0) {\n    tile = /** @type {ol.Tile} */ (this.dequeue()[0]);\n    tileKey = tile.getKey();\n    if (tile.getState() === ol.Tile.State.IDLE && !(tileKey in this.tilesLoadingKeys_)) {\n      this.tilesLoadingKeys_[tileKey] = true;\n      ++this.tilesLoading_;\n      ++newLoads;\n      tile.load();\n    }\n    ol.DEBUG && console.assert(Object.keys(this.tilesLoadingKeys_).length === this.tilesLoading_);\n  }\n};\n\ngoog.provide('ol.Kinetic');\n\n\n/**\n * @classdesc\n * Implementation of inertial deceleration for map movement.\n *\n * @constructor\n * @param {number} decay Rate of decay (must be negative).\n * @param {number} minVelocity Minimum velocity (pixels/millisecond).\n * @param {number} delay Delay to consider to calculate the kinetic\n *     initial values (milliseconds).\n * @struct\n * @api\n */\nol.Kinetic = function(decay, minVelocity, delay) {\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.decay_ = decay;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.minVelocity_ = minVelocity;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.delay_ = delay;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.points_ = [];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.angle_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.initialVelocity_ = 0;\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nol.Kinetic.prototype.begin = function() {\n  this.points_.length = 0;\n  this.angle_ = 0;\n  this.initialVelocity_ = 0;\n};\n\n\n/**\n * @param {number} x X.\n * @param {number} y Y.\n */\nol.Kinetic.prototype.update = function(x, y) {\n  this.points_.push(x, y, Date.now());\n};\n\n\n/**\n * @return {boolean} Whether we should do kinetic animation.\n */\nol.Kinetic.prototype.end = function() {\n  if (this.points_.length < 6) {\n    // at least 2 points are required (i.e. there must be at least 6 elements\n    // in the array)\n    return false;\n  }\n  var delay = Date.now() - this.delay_;\n  var lastIndex = this.points_.length - 3;\n  if (this.points_[lastIndex + 2] < delay) {\n    // the last tracked point is too old, which means that the user stopped\n    // panning before releasing the map\n    return false;\n  }\n\n  // get the first point which still falls into the delay time\n  var firstIndex = lastIndex - 3;\n  while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {\n    firstIndex -= 3;\n  }\n  var duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];\n  var dx = this.points_[lastIndex] - this.points_[firstIndex];\n  var dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];\n  this.angle_ = Math.atan2(dy, dx);\n  this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration;\n  return this.initialVelocity_ > this.minVelocity_;\n};\n\n\n/**\n * @private\n * @return {number} Duration of animation (milliseconds).\n */\nol.Kinetic.prototype.getDuration_ = function() {\n  return Math.log(this.minVelocity_ / this.initialVelocity_) / this.decay_;\n};\n\n\n/**\n * @return {number} Total distance travelled (pixels).\n */\nol.Kinetic.prototype.getDistance = function() {\n  return (this.minVelocity_ - this.initialVelocity_) / this.decay_;\n};\n\n\n/**\n * @return {number} Angle of the kinetic panning animation (radians).\n */\nol.Kinetic.prototype.getAngle = function() {\n  return this.angle_;\n};\n\n// FIXME factor out key precondition (shift et. al)\n\ngoog.provide('ol.interaction.Interaction');\n\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.easing');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * User actions that change the state of the map. Some are similar to controls,\n * but are not associated with a DOM element.\n * For example, {@link ol.interaction.KeyboardZoom} is functionally the same as\n * {@link ol.control.Zoom}, but triggered by a keyboard event not a button\n * element event.\n * Although interactions do not have a DOM element, some of them do render\n * vectors and so are visible on the screen.\n *\n * @constructor\n * @param {olx.interaction.InteractionOptions} options Options.\n * @extends {ol.Object}\n * @api\n */\nol.interaction.Interaction = function(options) {\n\n  ol.Object.call(this);\n\n  /**\n   * @private\n   * @type {ol.Map}\n   */\n  this.map_ = null;\n\n  this.setActive(true);\n\n  /**\n   * @type {function(ol.MapBrowserEvent):boolean}\n   */\n  this.handleEvent = options.handleEvent;\n\n};\nol.inherits(ol.interaction.Interaction, ol.Object);\n\n\n/**\n * Return whether the interaction is currently active.\n * @return {boolean} `true` if the interaction is active, `false` otherwise.\n * @observable\n * @api\n */\nol.interaction.Interaction.prototype.getActive = function() {\n  return /** @type {boolean} */ (\n      this.get(ol.interaction.Interaction.Property.ACTIVE));\n};\n\n\n/**\n * Get the map associated with this interaction.\n * @return {ol.Map} Map.\n * @api\n */\nol.interaction.Interaction.prototype.getMap = function() {\n  return this.map_;\n};\n\n\n/**\n * Activate or deactivate the interaction.\n * @param {boolean} active Active.\n * @observable\n * @api\n */\nol.interaction.Interaction.prototype.setActive = function(active) {\n  this.set(ol.interaction.Interaction.Property.ACTIVE, active);\n};\n\n\n/**\n * Remove the interaction from its current map and attach it to the new map.\n * Subclasses may set up event handlers to get notified about changes to\n * the map here.\n * @param {ol.Map} map Map.\n */\nol.interaction.Interaction.prototype.setMap = function(map) {\n  this.map_ = map;\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {ol.View} view View.\n * @param {ol.Coordinate} delta Delta.\n * @param {number=} opt_duration Duration.\n */\nol.interaction.Interaction.pan = function(map, view, delta, opt_duration) {\n  var currentCenter = view.getCenter();\n  if (currentCenter) {\n    var center = view.constrainCenter(\n        [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]);\n    if (opt_duration) {\n      view.animate({\n        duration: opt_duration,\n        easing: ol.easing.linear,\n        center: center\n      });\n    } else {\n      view.setCenter(center);\n    }\n  }\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {ol.View} view View.\n * @param {number|undefined} rotation Rotation.\n * @param {ol.Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nol.interaction.Interaction.rotate = function(map, view, rotation, opt_anchor, opt_duration) {\n  rotation = view.constrainRotation(rotation, 0);\n  ol.interaction.Interaction.rotateWithoutConstraints(\n      map, view, rotation, opt_anchor, opt_duration);\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {ol.View} view View.\n * @param {number|undefined} rotation Rotation.\n * @param {ol.Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nol.interaction.Interaction.rotateWithoutConstraints = function(map, view, rotation, opt_anchor, opt_duration) {\n  if (rotation !== undefined) {\n    var currentRotation = view.getRotation();\n    var currentCenter = view.getCenter();\n    if (currentRotation !== undefined && currentCenter && opt_duration > 0) {\n      view.animate({\n        rotation: rotation,\n        anchor: opt_anchor,\n        duration: opt_duration,\n        easing: ol.easing.easeOut\n      });\n    } else {\n      view.rotate(rotation, opt_anchor);\n    }\n  }\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {ol.View} view View.\n * @param {number|undefined} resolution Resolution to go to.\n * @param {ol.Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n * @param {number=} opt_direction Zooming direction; > 0 indicates\n *     zooming out, in which case the constraints system will select\n *     the largest nearest resolution; < 0 indicates zooming in, in\n *     which case the constraints system will select the smallest\n *     nearest resolution; == 0 indicates that the zooming direction\n *     is unknown/not relevant, in which case the constraints system\n *     will select the nearest resolution. If not defined 0 is\n *     assumed.\n */\nol.interaction.Interaction.zoom = function(map, view, resolution, opt_anchor, opt_duration, opt_direction) {\n  resolution = view.constrainResolution(resolution, 0, opt_direction);\n  ol.interaction.Interaction.zoomWithoutConstraints(\n      map, view, resolution, opt_anchor, opt_duration);\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {ol.View} view View.\n * @param {number} delta Delta from previous zoom level.\n * @param {ol.Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nol.interaction.Interaction.zoomByDelta = function(map, view, delta, opt_anchor, opt_duration) {\n  var currentResolution = view.getResolution();\n  var resolution = view.constrainResolution(currentResolution, delta, 0);\n  ol.interaction.Interaction.zoomWithoutConstraints(\n      map, view, resolution, opt_anchor, opt_duration);\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {ol.View} view View.\n * @param {number|undefined} resolution Resolution to go to.\n * @param {ol.Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nol.interaction.Interaction.zoomWithoutConstraints = function(map, view, resolution, opt_anchor, opt_duration) {\n  if (resolution) {\n    var currentResolution = view.getResolution();\n    var currentCenter = view.getCenter();\n    if (currentResolution !== undefined && currentCenter &&\n        resolution !== currentResolution && opt_duration) {\n      view.animate({\n        resolution: resolution,\n        anchor: opt_anchor,\n        duration: opt_duration,\n        easing: ol.easing.easeOut\n      });\n    } else {\n      if (opt_anchor) {\n        var center = view.calculateCenterZoom(resolution, opt_anchor);\n        view.setCenter(center);\n      }\n      view.setResolution(resolution);\n    }\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.interaction.Interaction.Property = {\n  ACTIVE: 'active'\n};\n\ngoog.provide('ol.interaction.DoubleClickZoom');\n\ngoog.require('ol');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.interaction.Interaction');\n\n\n/**\n * @classdesc\n * Allows the user to zoom by double-clicking on the map.\n *\n * @constructor\n * @extends {ol.interaction.Interaction}\n * @param {olx.interaction.DoubleClickZoomOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.DoubleClickZoom = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.delta_ = options.delta ? options.delta : 1;\n\n  ol.interaction.Interaction.call(this, {\n    handleEvent: ol.interaction.DoubleClickZoom.handleEvent\n  });\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n};\nol.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction);\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a\n * doubleclick) and eventually zooms the map.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.DoubleClickZoom}\n * @api\n */\nol.interaction.DoubleClickZoom.handleEvent = function(mapBrowserEvent) {\n  var stopEvent = false;\n  var browserEvent = mapBrowserEvent.originalEvent;\n  if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK) {\n    var map = mapBrowserEvent.map;\n    var anchor = mapBrowserEvent.coordinate;\n    var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;\n    var view = map.getView();\n    ol.interaction.Interaction.zoomByDelta(\n        map, view, delta, anchor, this.duration_);\n    mapBrowserEvent.preventDefault();\n    stopEvent = true;\n  }\n  return !stopEvent;\n};\n\ngoog.provide('ol.events.condition');\n\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.asserts');\ngoog.require('ol.functions');\ngoog.require('ol.has');\n\n\n/**\n * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when\n * additionally the shift-key is pressed).\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the alt key is pressed.\n * @api stable\n */\nol.events.condition.altKeyOnly = function(mapBrowserEvent) {\n  var originalEvent = mapBrowserEvent.originalEvent;\n  return (\n      originalEvent.altKey &&\n      !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n      !originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise\n * (e.g. when additionally the platform-modifier-key is pressed).\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the alt and shift keys are pressed.\n * @api stable\n */\nol.events.condition.altShiftKeysOnly = function(mapBrowserEvent) {\n  var originalEvent = mapBrowserEvent.originalEvent;\n  return (\n      originalEvent.altKey &&\n      !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n      originalEvent.shiftKey);\n};\n\n\n/**\n * Return always true.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True.\n * @function\n * @api stable\n */\nol.events.condition.always = ol.functions.TRUE;\n\n\n/**\n * Return `true` if the event is a `click` event, `false` otherwise.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event is a map `click` event.\n * @api stable\n */\nol.events.condition.click = function(mapBrowserEvent) {\n  return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.CLICK;\n};\n\n\n/**\n * Return `true` if the event has an \"action\"-producing mouse button.\n *\n * By definition, this includes left-click on windows/linux, and left-click\n * without the ctrl key on Macs.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} The result.\n */\nol.events.condition.mouseActionButton = function(mapBrowserEvent) {\n  var originalEvent = mapBrowserEvent.originalEvent;\n  return originalEvent.button == 0 &&\n      !(ol.has.WEBKIT && ol.has.MAC && originalEvent.ctrlKey);\n};\n\n\n/**\n * Return always false.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} False.\n * @function\n * @api stable\n */\nol.events.condition.never = ol.functions.FALSE;\n\n\n/**\n * Return `true` if the browser event is a `pointermove` event, `false`\n * otherwise.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the browser event is a `pointermove` event.\n * @api\n */\nol.events.condition.pointerMove = function(mapBrowserEvent) {\n  return mapBrowserEvent.type == 'pointermove';\n};\n\n\n/**\n * Return `true` if the event is a map `singleclick` event, `false` otherwise.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event is a map `singleclick` event.\n * @api stable\n */\nol.events.condition.singleClick = function(mapBrowserEvent) {\n  return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK;\n};\n\n\n/**\n * Return `true` if the event is a map `dblclick` event, `false` otherwise.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event is a map `dblclick` event.\n * @api stable\n */\nol.events.condition.doubleClick = function(mapBrowserEvent) {\n  return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK;\n};\n\n\n/**\n * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is\n * pressed.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True only if there no modifier keys are pressed.\n * @api stable\n */\nol.events.condition.noModifierKeys = function(mapBrowserEvent) {\n  var originalEvent = mapBrowserEvent.originalEvent;\n  return (\n      !originalEvent.altKey &&\n      !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n      !originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if only the platform-modifier-key (the meta-key on Mac,\n * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally\n * the shift-key is pressed).\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the platform modifier key is pressed.\n * @api stable\n */\nol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) {\n  var originalEvent = mapBrowserEvent.originalEvent;\n  return (\n      !originalEvent.altKey &&\n      (ol.has.MAC ? originalEvent.metaKey : originalEvent.ctrlKey) &&\n      !originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when\n * additionally the alt-key is pressed).\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the shift key is pressed.\n * @api stable\n */\nol.events.condition.shiftKeyOnly = function(mapBrowserEvent) {\n  var originalEvent = mapBrowserEvent.originalEvent;\n  return (\n      !originalEvent.altKey &&\n      !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n      originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if the target element is not editable, i.e. not a `<input>`-,\n * `<select>`- or `<textarea>`-element, `false` otherwise.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True only if the target element is not editable.\n * @api\n */\nol.events.condition.targetNotEditable = function(mapBrowserEvent) {\n  var target = mapBrowserEvent.originalEvent.target;\n  var tagName = target.tagName;\n  return (\n      tagName !== 'INPUT' &&\n      tagName !== 'SELECT' &&\n      tagName !== 'TEXTAREA');\n};\n\n\n/**\n * Return `true` if the event originates from a mouse device.\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event originates from a mouse device.\n * @api stable\n */\nol.events.condition.mouseOnly = function(mapBrowserEvent) {\n  ol.asserts.assert(mapBrowserEvent.pointerEvent, 56); // mapBrowserEvent must originate from a pointer event\n  // see http://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType\n  return /** @type {ol.MapBrowserEvent} */ (mapBrowserEvent).pointerEvent.pointerType == 'mouse';\n};\n\n\n/**\n * Return `true` if the event originates from a primary pointer in\n * contact with the surface or if the left mouse button is pressed.\n * @see http://www.w3.org/TR/pointerevents/#button-states\n *\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event originates from a primary pointer.\n * @api\n */\nol.events.condition.primaryAction = function(mapBrowserEvent) {\n  var pointerEvent = mapBrowserEvent.pointerEvent;\n  return pointerEvent.isPrimary && pointerEvent.button === 0;\n};\n\ngoog.provide('ol.interaction.Pointer');\n\ngoog.require('ol');\ngoog.require('ol.functions');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.MapBrowserPointerEvent');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * Base class that calls user-defined functions on `down`, `move` and `up`\n * events. This class also manages \"drag sequences\".\n *\n * When the `handleDownEvent` user function returns `true` a drag sequence is\n * started. During a drag sequence the `handleDragEvent` user function is\n * called on `move` events. The drag sequence ends when the `handleUpEvent`\n * user function is called and returns `false`.\n *\n * @constructor\n * @param {olx.interaction.PointerOptions=} opt_options Options.\n * @extends {ol.interaction.Interaction}\n * @api\n */\nol.interaction.Pointer = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  var handleEvent = options.handleEvent ?\n      options.handleEvent : ol.interaction.Pointer.handleEvent;\n\n  ol.interaction.Interaction.call(this, {\n    handleEvent: handleEvent\n  });\n\n  /**\n   * @type {function(ol.MapBrowserPointerEvent):boolean}\n   * @private\n   */\n  this.handleDownEvent_ = options.handleDownEvent ?\n      options.handleDownEvent : ol.interaction.Pointer.handleDownEvent;\n\n  /**\n   * @type {function(ol.MapBrowserPointerEvent)}\n   * @private\n   */\n  this.handleDragEvent_ = options.handleDragEvent ?\n      options.handleDragEvent : ol.interaction.Pointer.handleDragEvent;\n\n  /**\n   * @type {function(ol.MapBrowserPointerEvent)}\n   * @private\n   */\n  this.handleMoveEvent_ = options.handleMoveEvent ?\n      options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent;\n\n  /**\n   * @type {function(ol.MapBrowserPointerEvent):boolean}\n   * @private\n   */\n  this.handleUpEvent_ = options.handleUpEvent ?\n      options.handleUpEvent : ol.interaction.Pointer.handleUpEvent;\n\n  /**\n   * @type {boolean}\n   * @protected\n   */\n  this.handlingDownUpSequence = false;\n\n  /**\n   * @type {Object.<number, ol.pointer.PointerEvent>}\n   * @private\n   */\n  this.trackedPointers_ = {};\n\n  /**\n   * @type {Array.<ol.pointer.PointerEvent>}\n   * @protected\n   */\n  this.targetPointers = [];\n\n};\nol.inherits(ol.interaction.Pointer, ol.interaction.Interaction);\n\n\n/**\n * @param {Array.<ol.pointer.PointerEvent>} pointerEvents List of events.\n * @return {ol.Pixel} Centroid pixel.\n */\nol.interaction.Pointer.centroid = function(pointerEvents) {\n  var length = pointerEvents.length;\n  var clientX = 0;\n  var clientY = 0;\n  for (var i = 0; i < length; i++) {\n    clientX += pointerEvents[i].clientX;\n    clientY += pointerEvents[i].clientY;\n  }\n  return [clientX / length, clientY / length];\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Whether the event is a pointerdown, pointerdrag\n *     or pointerup event.\n * @private\n */\nol.interaction.Pointer.prototype.isPointerDraggingEvent_ = function(mapBrowserEvent) {\n  var type = mapBrowserEvent.type;\n  return (\n      type === ol.MapBrowserEvent.EventType.POINTERDOWN ||\n      type === ol.MapBrowserEvent.EventType.POINTERDRAG ||\n      type === ol.MapBrowserEvent.EventType.POINTERUP);\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @private\n */\nol.interaction.Pointer.prototype.updateTrackedPointers_ = function(mapBrowserEvent) {\n  if (this.isPointerDraggingEvent_(mapBrowserEvent)) {\n    var event = mapBrowserEvent.pointerEvent;\n\n    if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) {\n      delete this.trackedPointers_[event.pointerId];\n    } else if (mapBrowserEvent.type ==\n        ol.MapBrowserEvent.EventType.POINTERDOWN) {\n      this.trackedPointers_[event.pointerId] = event;\n    } else if (event.pointerId in this.trackedPointers_) {\n      // update only when there was a pointerdown event for this pointer\n      this.trackedPointers_[event.pointerId] = event;\n    }\n    this.targetPointers = ol.obj.getValues(this.trackedPointers_);\n  }\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.Pointer}\n */\nol.interaction.Pointer.handleDragEvent = ol.nullFunction;\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Capture dragging.\n * @this {ol.interaction.Pointer}\n */\nol.interaction.Pointer.handleUpEvent = ol.functions.FALSE;\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Capture dragging.\n * @this {ol.interaction.Pointer}\n */\nol.interaction.Pointer.handleDownEvent = ol.functions.FALSE;\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.Pointer}\n */\nol.interaction.Pointer.handleMoveEvent = ol.nullFunction;\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} and may call into\n * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are\n * detected.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.Pointer}\n * @api\n */\nol.interaction.Pointer.handleEvent = function(mapBrowserEvent) {\n  if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {\n    return true;\n  }\n\n  var stopEvent = false;\n  this.updateTrackedPointers_(mapBrowserEvent);\n  if (this.handlingDownUpSequence) {\n    if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDRAG) {\n      this.handleDragEvent_(mapBrowserEvent);\n    } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) {\n      this.handlingDownUpSequence = this.handleUpEvent_(mapBrowserEvent);\n    }\n  }\n  if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDOWN) {\n    var handled = this.handleDownEvent_(mapBrowserEvent);\n    this.handlingDownUpSequence = handled;\n    stopEvent = this.shouldStopEvent(handled);\n  } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE) {\n    this.handleMoveEvent_(mapBrowserEvent);\n  }\n  return !stopEvent;\n};\n\n\n/**\n * This method is used to determine if \"down\" events should be propagated to\n * other interactions or should be stopped.\n *\n * The method receives the return code of the \"handleDownEvent\" function.\n *\n * By default this function is the \"identity\" function. It's overidden in\n * child classes.\n *\n * @param {boolean} handled Was the event handled by the interaction?\n * @return {boolean} Should the event be stopped?\n * @protected\n */\nol.interaction.Pointer.prototype.shouldStopEvent = function(handled) {\n  return handled;\n};\n\ngoog.provide('ol.interaction.DragPan');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.coordinate');\ngoog.require('ol.easing');\ngoog.require('ol.events.condition');\ngoog.require('ol.functions');\ngoog.require('ol.interaction.Pointer');\n\n\n/**\n * @classdesc\n * Allows the user to pan the map by dragging the map.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @param {olx.interaction.DragPanOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.DragPan = function(opt_options) {\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.DragPan.handleDownEvent_,\n    handleDragEvent: ol.interaction.DragPan.handleDragEvent_,\n    handleUpEvent: ol.interaction.DragPan.handleUpEvent_\n  });\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {ol.Kinetic|undefined}\n   */\n  this.kinetic_ = options.kinetic;\n\n  /**\n   * @type {ol.Pixel}\n   */\n  this.lastCentroid = null;\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ?\n      options.condition : ol.events.condition.noModifierKeys;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.noKinetic_ = false;\n\n};\nol.inherits(ol.interaction.DragPan, ol.interaction.Pointer);\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.DragPan}\n * @private\n */\nol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) {\n  ol.DEBUG && console.assert(this.targetPointers.length >= 1,\n      'the length of this.targetPointers should be more than 1');\n  var centroid =\n      ol.interaction.Pointer.centroid(this.targetPointers);\n  if (this.kinetic_) {\n    this.kinetic_.update(centroid[0], centroid[1]);\n  }\n  if (this.lastCentroid) {\n    var deltaX = this.lastCentroid[0] - centroid[0];\n    var deltaY = centroid[1] - this.lastCentroid[1];\n    var map = mapBrowserEvent.map;\n    var view = map.getView();\n    var viewState = view.getState();\n    var center = [deltaX, deltaY];\n    ol.coordinate.scale(center, viewState.resolution);\n    ol.coordinate.rotate(center, viewState.rotation);\n    ol.coordinate.add(center, viewState.center);\n    center = view.constrainCenter(center);\n    view.setCenter(center);\n  }\n  this.lastCentroid = centroid;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.DragPan}\n * @private\n */\nol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) {\n  var map = mapBrowserEvent.map;\n  var view = map.getView();\n  if (this.targetPointers.length === 0) {\n    if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {\n      var distance = this.kinetic_.getDistance();\n      var angle = this.kinetic_.getAngle();\n      var center = /** @type {!ol.Coordinate} */ (view.getCenter());\n      var centerpx = map.getPixelFromCoordinate(center);\n      var dest = map.getCoordinateFromPixel([\n        centerpx[0] - distance * Math.cos(angle),\n        centerpx[1] - distance * Math.sin(angle)\n      ]);\n      view.animate({\n        center: view.constrainCenter(dest),\n        duration: 500,\n        easing: ol.easing.easeOut\n      });\n    }\n    view.setHint(ol.View.Hint.INTERACTING, -1);\n    return false;\n  } else {\n    this.lastCentroid = null;\n    return true;\n  }\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.DragPan}\n * @private\n */\nol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) {\n  if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {\n    var map = mapBrowserEvent.map;\n    var view = map.getView();\n    this.lastCentroid = null;\n    if (!this.handlingDownUpSequence) {\n      view.setHint(ol.View.Hint.INTERACTING, 1);\n    }\n    // stop any current animation\n    view.setCenter(mapBrowserEvent.frameState.viewState.center);\n    if (this.kinetic_) {\n      this.kinetic_.begin();\n    }\n    // No kinetic as soon as more than one pointer on the screen is\n    // detected. This is to prevent nasty pans after pinch.\n    this.noKinetic_ = this.targetPointers.length > 1;\n    return true;\n  } else {\n    return false;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.DragPan.prototype.shouldStopEvent = ol.functions.FALSE;\n\ngoog.provide('ol.interaction.DragRotate');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.events.condition');\ngoog.require('ol.functions');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.interaction.Pointer');\n\n\n/**\n * @classdesc\n * Allows the user to rotate the map by clicking and dragging on the map,\n * normally combined with an {@link ol.events.condition} that limits\n * it to when the alt and shift keys are held down.\n *\n * This interaction is only supported for mouse devices.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @param {olx.interaction.DragRotateOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.DragRotate = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.DragRotate.handleDownEvent_,\n    handleDragEvent: ol.interaction.DragRotate.handleDragEvent_,\n    handleUpEvent: ol.interaction.DragRotate.handleUpEvent_\n  });\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ?\n      options.condition : ol.events.condition.altShiftKeysOnly;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.lastAngle_ = undefined;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 250;\n};\nol.inherits(ol.interaction.DragRotate, ol.interaction.Pointer);\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.DragRotate}\n * @private\n */\nol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return;\n  }\n\n  var map = mapBrowserEvent.map;\n  var size = map.getSize();\n  var offset = mapBrowserEvent.pixel;\n  var theta =\n      Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);\n  if (this.lastAngle_ !== undefined) {\n    var delta = theta - this.lastAngle_;\n    var view = map.getView();\n    var rotation = view.getRotation();\n    ol.interaction.Interaction.rotateWithoutConstraints(\n        map, view, rotation - delta);\n  }\n  this.lastAngle_ = theta;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.DragRotate}\n * @private\n */\nol.interaction.DragRotate.handleUpEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return true;\n  }\n\n  var map = mapBrowserEvent.map;\n  var view = map.getView();\n  view.setHint(ol.View.Hint.INTERACTING, -1);\n  var rotation = view.getRotation();\n  ol.interaction.Interaction.rotate(map, view, rotation,\n      undefined, this.duration_);\n  return false;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.DragRotate}\n * @private\n */\nol.interaction.DragRotate.handleDownEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return false;\n  }\n\n  if (ol.events.condition.mouseActionButton(mapBrowserEvent) &&\n      this.condition_(mapBrowserEvent)) {\n    var map = mapBrowserEvent.map;\n    map.getView().setHint(ol.View.Hint.INTERACTING, 1);\n    this.lastAngle_ = undefined;\n    return true;\n  } else {\n    return false;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.DragRotate.prototype.shouldStopEvent = ol.functions.FALSE;\n\n// FIXME add rotation\n\ngoog.provide('ol.render.Box');\n\ngoog.require('ol');\ngoog.require('ol.Disposable');\ngoog.require('ol.geom.Polygon');\n\n\n/**\n * @constructor\n * @extends {ol.Disposable}\n * @param {string} className CSS class name.\n */\nol.render.Box = function(className) {\n\n  /**\n   * @type {ol.geom.Polygon}\n   * @private\n   */\n  this.geometry_ = null;\n\n  /**\n   * @type {HTMLDivElement}\n   * @private\n   */\n  this.element_ = /** @type {HTMLDivElement} */ (document.createElement('div'));\n  this.element_.style.position = 'absolute';\n  this.element_.className = 'ol-box ' + className;\n\n  /**\n   * @private\n   * @type {ol.Map}\n   */\n  this.map_ = null;\n\n  /**\n   * @private\n   * @type {ol.Pixel}\n   */\n  this.startPixel_ = null;\n\n  /**\n   * @private\n   * @type {ol.Pixel}\n   */\n  this.endPixel_ = null;\n\n};\nol.inherits(ol.render.Box, ol.Disposable);\n\n\n/**\n * @inheritDoc\n */\nol.render.Box.prototype.disposeInternal = function() {\n  this.setMap(null);\n};\n\n\n/**\n * @private\n */\nol.render.Box.prototype.render_ = function() {\n  var startPixel = this.startPixel_;\n  var endPixel = this.endPixel_;\n  var px = 'px';\n  var style = this.element_.style;\n  style.left = Math.min(startPixel[0], endPixel[0]) + px;\n  style.top = Math.min(startPixel[1], endPixel[1]) + px;\n  style.width = Math.abs(endPixel[0] - startPixel[0]) + px;\n  style.height = Math.abs(endPixel[1] - startPixel[1]) + px;\n};\n\n\n/**\n * @param {ol.Map} map Map.\n */\nol.render.Box.prototype.setMap = function(map) {\n  if (this.map_) {\n    this.map_.getOverlayContainer().removeChild(this.element_);\n    var style = this.element_.style;\n    style.left = style.top = style.width = style.height = 'inherit';\n  }\n  this.map_ = map;\n  if (this.map_) {\n    this.map_.getOverlayContainer().appendChild(this.element_);\n  }\n};\n\n\n/**\n * @param {ol.Pixel} startPixel Start pixel.\n * @param {ol.Pixel} endPixel End pixel.\n */\nol.render.Box.prototype.setPixels = function(startPixel, endPixel) {\n  this.startPixel_ = startPixel;\n  this.endPixel_ = endPixel;\n  this.createOrUpdateGeometry();\n  this.render_();\n};\n\n\n/**\n * Creates or updates the cached geometry.\n */\nol.render.Box.prototype.createOrUpdateGeometry = function() {\n  var startPixel = this.startPixel_;\n  var endPixel = this.endPixel_;\n  var pixels = [\n    startPixel,\n    [startPixel[0], endPixel[1]],\n    endPixel,\n    [endPixel[0], startPixel[1]]\n  ];\n  var coordinates = pixels.map(this.map_.getCoordinateFromPixel, this.map_);\n  // close the polygon\n  coordinates[4] = coordinates[0].slice();\n  if (!this.geometry_) {\n    this.geometry_ = new ol.geom.Polygon([coordinates]);\n  } else {\n    this.geometry_.setCoordinates([coordinates]);\n  }\n};\n\n\n/**\n * @return {ol.geom.Polygon} Geometry.\n */\nol.render.Box.prototype.getGeometry = function() {\n  return this.geometry_;\n};\n\n// FIXME draw drag box\ngoog.provide('ol.interaction.DragBox');\n\ngoog.require('ol.events.Event');\ngoog.require('ol');\ngoog.require('ol.events.condition');\ngoog.require('ol.interaction.Pointer');\ngoog.require('ol.render.Box');\n\n\n/**\n * @const\n * @type {number}\n */\nol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED =\n    ol.DRAG_BOX_HYSTERESIS_PIXELS *\n    ol.DRAG_BOX_HYSTERESIS_PIXELS;\n\n\n/**\n * @classdesc\n * Allows the user to draw a vector box by clicking and dragging on the map,\n * normally combined with an {@link ol.events.condition} that limits\n * it to when the shift or other key is held down. This is used, for example,\n * for zooming to a specific area of the map\n * (see {@link ol.interaction.DragZoom} and\n * {@link ol.interaction.DragRotateAndZoom}).\n *\n * This interaction is only supported for mouse devices.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @fires ol.interaction.DragBox.Event\n * @param {olx.interaction.DragBoxOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.DragBox = function(opt_options) {\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.DragBox.handleDownEvent_,\n    handleDragEvent: ol.interaction.DragBox.handleDragEvent_,\n    handleUpEvent: ol.interaction.DragBox.handleUpEvent_\n  });\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @type {ol.render.Box}\n   * @private\n   */\n  this.box_ = new ol.render.Box(options.className || 'ol-dragbox');\n\n  /**\n   * @type {ol.Pixel}\n   * @private\n   */\n  this.startPixel_ = null;\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ?\n      options.condition : ol.events.condition.always;\n\n  /**\n   * @private\n   * @type {ol.DragBoxEndConditionType}\n   */\n  this.boxEndCondition_ = options.boxEndCondition ?\n      options.boxEndCondition : ol.interaction.DragBox.defaultBoxEndCondition;\n};\nol.inherits(ol.interaction.DragBox, ol.interaction.Pointer);\n\n\n/**\n * The default condition for determining whether the boxend event\n * should fire.\n * @param  {ol.MapBrowserEvent} mapBrowserEvent The originating MapBrowserEvent\n *  leading to the box end.\n * @param  {ol.Pixel} startPixel      The starting pixel of the box.\n * @param  {ol.Pixel} endPixel        The end pixel of the box.\n * @return {boolean} Whether or not the boxend condition should be fired.\n */\nol.interaction.DragBox.defaultBoxEndCondition = function(mapBrowserEvent,\n    startPixel, endPixel) {\n  var width = endPixel[0] - startPixel[0];\n  var height = endPixel[1] - startPixel[1];\n  return width * width + height * height >=\n      ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.DragBox}\n * @private\n */\nol.interaction.DragBox.handleDragEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return;\n  }\n\n  this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel);\n\n  this.dispatchEvent(new ol.interaction.DragBox.Event(ol.interaction.DragBox.EventType.BOXDRAG,\n    mapBrowserEvent.coordinate, mapBrowserEvent));\n};\n\n\n/**\n * Returns geometry of last drawn box.\n * @return {ol.geom.Polygon} Geometry.\n * @api stable\n */\nol.interaction.DragBox.prototype.getGeometry = function() {\n  return this.box_.getGeometry();\n};\n\n\n/**\n * To be overriden by child classes.\n * FIXME: use constructor option instead of relying on overridding.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @protected\n */\nol.interaction.DragBox.prototype.onBoxEnd = ol.nullFunction;\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.DragBox}\n * @private\n */\nol.interaction.DragBox.handleUpEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return true;\n  }\n\n  this.box_.setMap(null);\n\n  if (this.boxEndCondition_(mapBrowserEvent,\n      this.startPixel_, mapBrowserEvent.pixel)) {\n    this.onBoxEnd(mapBrowserEvent);\n    this.dispatchEvent(new ol.interaction.DragBox.Event(ol.interaction.DragBox.EventType.BOXEND,\n        mapBrowserEvent.coordinate, mapBrowserEvent));\n  }\n  return false;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.DragBox}\n * @private\n */\nol.interaction.DragBox.handleDownEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return false;\n  }\n\n  if (ol.events.condition.mouseActionButton(mapBrowserEvent) &&\n      this.condition_(mapBrowserEvent)) {\n    this.startPixel_ = mapBrowserEvent.pixel;\n    this.box_.setMap(mapBrowserEvent.map);\n    this.box_.setPixels(this.startPixel_, this.startPixel_);\n    this.dispatchEvent(new ol.interaction.DragBox.Event(ol.interaction.DragBox.EventType.BOXSTART,\n        mapBrowserEvent.coordinate, mapBrowserEvent));\n    return true;\n  } else {\n    return false;\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.interaction.DragBox.EventType = {\n  /**\n   * Triggered upon drag box start.\n   * @event ol.interaction.DragBox.Event#boxstart\n   * @api stable\n   */\n  BOXSTART: 'boxstart',\n\n  /**\n   * Triggered on drag when box is active.\n   * @event ol.interaction.DragBox.Event#boxdrag\n   * @api\n   */\n  BOXDRAG: 'boxdrag',\n\n  /**\n   * Triggered upon drag box end.\n   * @event ol.interaction.DragBox.Event#boxend\n   * @api stable\n   */\n  BOXEND: 'boxend'\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.interaction.DragBox} instances are instances of\n * this type.\n *\n * @param {string} type The event type.\n * @param {ol.Coordinate} coordinate The event coordinate.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Originating event.\n * @extends {ol.events.Event}\n * @constructor\n * @implements {oli.DragBoxEvent}\n */\nol.interaction.DragBox.Event = function(type, coordinate, mapBrowserEvent) {\n  ol.events.Event.call(this, type);\n\n  /**\n   * The coordinate of the drag event.\n   * @const\n   * @type {ol.Coordinate}\n   * @api stable\n   */\n  this.coordinate = coordinate;\n\n  /**\n   * @const\n   * @type {ol.MapBrowserEvent}\n   * @api\n   */\n  this.mapBrowserEvent = mapBrowserEvent;\n\n};\nol.inherits(ol.interaction.DragBox.Event, ol.events.Event);\n\ngoog.provide('ol.interaction.DragZoom');\n\ngoog.require('ol');\ngoog.require('ol.easing');\ngoog.require('ol.events.condition');\ngoog.require('ol.extent');\ngoog.require('ol.interaction.DragBox');\n\n\n/**\n * @classdesc\n * Allows the user to zoom the map by clicking and dragging on the map,\n * normally combined with an {@link ol.events.condition} that limits\n * it to when a key, shift by default, is held down.\n *\n * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or\n * your custom one configured with `className`.\n *\n * @constructor\n * @extends {ol.interaction.DragBox}\n * @param {olx.interaction.DragZoomOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.DragZoom = function(opt_options) {\n  var options = opt_options ? opt_options : {};\n\n  var condition = options.condition ?\n      options.condition : ol.events.condition.shiftKeyOnly;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 200;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.out_ = options.out !== undefined ? options.out : false;\n\n  ol.interaction.DragBox.call(this, {\n    condition: condition,\n    className: options.className || 'ol-dragzoom'\n  });\n\n};\nol.inherits(ol.interaction.DragZoom, ol.interaction.DragBox);\n\n\n/**\n * @inheritDoc\n */\nol.interaction.DragZoom.prototype.onBoxEnd = function() {\n  var map = this.getMap();\n\n  var view = /** @type {!ol.View} */ (map.getView());\n\n  var size = /** @type {!ol.Size} */ (map.getSize());\n\n  var extent = this.getGeometry().getExtent();\n\n  if (this.out_) {\n    var mapExtent = view.calculateExtent(size);\n    var boxPixelExtent = ol.extent.createOrUpdateFromCoordinates([\n      map.getPixelFromCoordinate(ol.extent.getBottomLeft(extent)),\n      map.getPixelFromCoordinate(ol.extent.getTopRight(extent))]);\n    var factor = view.getResolutionForExtent(boxPixelExtent, size);\n\n    ol.extent.scaleFromCenter(mapExtent, 1 / factor);\n    extent = mapExtent;\n  }\n\n  var resolution = view.constrainResolution(\n      view.getResolutionForExtent(extent, size));\n\n  view.animate({\n    resolution: resolution,\n    center: ol.extent.getCenter(extent),\n    duration: this.duration_,\n    easing: ol.easing.easeOut\n  });\n\n};\n\ngoog.provide('ol.events.KeyCode');\n\n/**\n * @enum {number}\n * @const\n */\nol.events.KeyCode = {\n  LEFT: 37,\n  UP: 38,\n  RIGHT: 39,\n  DOWN: 40\n};\n\ngoog.provide('ol.interaction.KeyboardPan');\n\ngoog.require('ol');\ngoog.require('ol.coordinate');\ngoog.require('ol.events.EventType');\ngoog.require('ol.events.KeyCode');\ngoog.require('ol.events.condition');\ngoog.require('ol.interaction.Interaction');\n\n\n/**\n * @classdesc\n * Allows the user to pan the map using keyboard arrows.\n * Note that, although this interaction is by default included in maps,\n * the keys can only be used when browser focus is on the element to which\n * the keyboard events are attached. By default, this is the map div,\n * though you can change this with the `keyboardEventTarget` in\n * {@link ol.Map}. `document` never loses focus but, for any other element,\n * focus will have to be on, and returned to, this element if the keys are to\n * function.\n * See also {@link ol.interaction.KeyboardZoom}.\n *\n * @constructor\n * @extends {ol.interaction.Interaction}\n * @param {olx.interaction.KeyboardPanOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.KeyboardPan = function(opt_options) {\n\n  ol.interaction.Interaction.call(this, {\n    handleEvent: ol.interaction.KeyboardPan.handleEvent\n  });\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.\n   * @return {boolean} Combined condition result.\n   */\n  this.defaultCondition_ = function(mapBrowserEvent) {\n    return ol.events.condition.noModifierKeys(mapBrowserEvent) &&\n      ol.events.condition.targetNotEditable(mapBrowserEvent);\n  };\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition !== undefined ?\n      options.condition : this.defaultCondition_;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 100;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.pixelDelta_ = options.pixelDelta !== undefined ?\n      options.pixelDelta : 128;\n\n};\nol.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction);\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} if it was a\n * `KeyEvent`, and decides the direction to pan to (if an arrow key was\n * pressed).\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.KeyboardPan}\n * @api\n */\nol.interaction.KeyboardPan.handleEvent = function(mapBrowserEvent) {\n  var stopEvent = false;\n  if (mapBrowserEvent.type == ol.events.EventType.KEYDOWN) {\n    var keyEvent = mapBrowserEvent.originalEvent;\n    var keyCode = keyEvent.keyCode;\n    if (this.condition_(mapBrowserEvent) &&\n        (keyCode == ol.events.KeyCode.DOWN ||\n        keyCode == ol.events.KeyCode.LEFT ||\n        keyCode == ol.events.KeyCode.RIGHT ||\n        keyCode == ol.events.KeyCode.UP)) {\n      var map = mapBrowserEvent.map;\n      var view = map.getView();\n      var mapUnitsDelta = view.getResolution() * this.pixelDelta_;\n      var deltaX = 0, deltaY = 0;\n      if (keyCode == ol.events.KeyCode.DOWN) {\n        deltaY = -mapUnitsDelta;\n      } else if (keyCode == ol.events.KeyCode.LEFT) {\n        deltaX = -mapUnitsDelta;\n      } else if (keyCode == ol.events.KeyCode.RIGHT) {\n        deltaX = mapUnitsDelta;\n      } else {\n        deltaY = mapUnitsDelta;\n      }\n      var delta = [deltaX, deltaY];\n      ol.coordinate.rotate(delta, view.getRotation());\n      ol.interaction.Interaction.pan(map, view, delta, this.duration_);\n      mapBrowserEvent.preventDefault();\n      stopEvent = true;\n    }\n  }\n  return !stopEvent;\n};\n\ngoog.provide('ol.interaction.KeyboardZoom');\n\ngoog.require('ol');\ngoog.require('ol.events.EventType');\ngoog.require('ol.events.condition');\ngoog.require('ol.interaction.Interaction');\n\n\n/**\n * @classdesc\n * Allows the user to zoom the map using keyboard + and -.\n * Note that, although this interaction is by default included in maps,\n * the keys can only be used when browser focus is on the element to which\n * the keyboard events are attached. By default, this is the map div,\n * though you can change this with the `keyboardEventTarget` in\n * {@link ol.Map}. `document` never loses focus but, for any other element,\n * focus will have to be on, and returned to, this element if the keys are to\n * function.\n * See also {@link ol.interaction.KeyboardPan}.\n *\n * @constructor\n * @param {olx.interaction.KeyboardZoomOptions=} opt_options Options.\n * @extends {ol.interaction.Interaction}\n * @api stable\n */\nol.interaction.KeyboardZoom = function(opt_options) {\n\n  ol.interaction.Interaction.call(this, {\n    handleEvent: ol.interaction.KeyboardZoom.handleEvent\n  });\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ? options.condition :\n          ol.events.condition.targetNotEditable;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.delta_ = options.delta ? options.delta : 1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 100;\n\n};\nol.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction);\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} if it was a\n * `KeyEvent`, and decides whether to zoom in or out (depending on whether the\n * key pressed was '+' or '-').\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.KeyboardZoom}\n * @api\n */\nol.interaction.KeyboardZoom.handleEvent = function(mapBrowserEvent) {\n  var stopEvent = false;\n  if (mapBrowserEvent.type == ol.events.EventType.KEYDOWN ||\n      mapBrowserEvent.type == ol.events.EventType.KEYPRESS) {\n    var keyEvent = mapBrowserEvent.originalEvent;\n    var charCode = keyEvent.charCode;\n    if (this.condition_(mapBrowserEvent) &&\n        (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0))) {\n      var map = mapBrowserEvent.map;\n      var delta = (charCode == '+'.charCodeAt(0)) ? this.delta_ : -this.delta_;\n      var view = map.getView();\n      ol.interaction.Interaction.zoomByDelta(\n          map, view, delta, undefined, this.duration_);\n      mapBrowserEvent.preventDefault();\n      stopEvent = true;\n    }\n  }\n  return !stopEvent;\n};\n\ngoog.provide('ol.interaction.MouseWheelZoom');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.easing');\ngoog.require('ol.events.EventType');\ngoog.require('ol.has');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.math');\n\n\n/**\n * @classdesc\n * Allows the user to zoom the map by scrolling the mouse wheel.\n *\n * @constructor\n * @extends {ol.interaction.Interaction}\n * @param {olx.interaction.MouseWheelZoomOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.MouseWheelZoom = function(opt_options) {\n\n  ol.interaction.Interaction.call(this, {\n    handleEvent: ol.interaction.MouseWheelZoom.handleEvent\n  });\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.delta_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.timeout_ = options.timeout !== undefined ? options.timeout : 80;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true;\n\n  /**\n   * @private\n   * @type {?ol.Coordinate}\n   */\n  this.lastAnchor_ = null;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.startTime_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.timeoutId_ = undefined;\n\n  /**\n   * @private\n   * @type {ol.interaction.MouseWheelZoom.Mode|undefined}\n   */\n  this.mode_ = undefined;\n\n  /**\n   * Trackpad events separated by this delay will be considered separate\n   * interactions.\n   * @type {number}\n   */\n  this.trackpadEventGap_ = 400;\n\n  /**\n   * @type {number|undefined}\n   */\n  this.trackpadTimeoutId_ = undefined;\n\n  /**\n   * The number of delta values per zoom level\n   * @private\n   * @type {number}\n   */\n  this.trackpadDeltaPerZoom_ = 300;\n\n  /**\n   * The zoom factor by which scroll zooming is allowed to exceed the limits.\n   * @private\n   * @type {number}\n   */\n  this.trackpadZoomBuffer_ = 1.5;\n\n};\nol.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction);\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a\n * mousewheel-event) and eventually zooms the map.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} Allow event propagation.\n * @this {ol.interaction.MouseWheelZoom}\n * @api\n */\nol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) {\n  var type = mapBrowserEvent.type;\n  if (type !== ol.events.EventType.WHEEL && type !== ol.events.EventType.MOUSEWHEEL) {\n    return true;\n  }\n\n  mapBrowserEvent.preventDefault();\n\n  var map = mapBrowserEvent.map;\n  var wheelEvent = /** @type {WheelEvent} */ (mapBrowserEvent.originalEvent);\n\n  if (this.useAnchor_) {\n    this.lastAnchor_ = mapBrowserEvent.coordinate;\n  }\n\n  // Delta normalisation inspired by\n  // https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js\n  var delta;\n  if (mapBrowserEvent.type == ol.events.EventType.WHEEL) {\n    delta = wheelEvent.deltaY;\n    if (ol.has.FIREFOX &&\n        wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {\n      delta /= ol.has.DEVICE_PIXEL_RATIO;\n    }\n    if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) {\n      delta *= 40;\n    }\n  } else if (mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) {\n    delta = -wheelEvent.wheelDeltaY;\n    if (ol.has.SAFARI) {\n      delta /= 3;\n    }\n  }\n\n  if (delta === 0) {\n    return false;\n  }\n\n  var now = Date.now();\n\n  if (this.startTime_ === undefined) {\n    this.startTime_ = now;\n  }\n\n  if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) {\n    this.mode_ = Math.abs(delta) < 4 ?\n        ol.interaction.MouseWheelZoom.Mode.TRACKPAD :\n        ol.interaction.MouseWheelZoom.Mode.WHEEL;\n  }\n\n  if (this.mode_ === ol.interaction.MouseWheelZoom.Mode.TRACKPAD) {\n    var view = map.getView();\n    if (this.trackpadTimeoutId_) {\n      clearTimeout(this.trackpadTimeoutId_);\n    } else {\n      view.setHint(ol.View.Hint.INTERACTING, 1);\n    }\n    this.trackpadTimeoutId_ = setTimeout(this.decrementInteractingHint_.bind(this), this.trackpadEventGap_);\n    var resolution = view.getResolution() * Math.pow(2, delta / this.trackpadDeltaPerZoom_);\n    var minResolution = view.getMinResolution();\n    var maxResolution = view.getMaxResolution();\n    var rebound = 0;\n    if (resolution < minResolution) {\n      resolution = Math.max(resolution, minResolution / this.trackpadZoomBuffer_);\n      rebound = 1;\n    } else if (resolution > maxResolution) {\n      resolution = Math.min(resolution, maxResolution * this.trackpadZoomBuffer_);\n      rebound = -1;\n    }\n    if (this.lastAnchor_) {\n      var center = view.calculateCenterZoom(resolution, this.lastAnchor_);\n      view.setCenter(center);\n    }\n    view.setResolution(resolution);\n    if (rebound > 0) {\n      view.animate({\n        resolution: minResolution,\n        easing: ol.easing.easeOut,\n        anchor: this.lastAnchor_,\n        duration: 500\n      });\n    } else if (rebound < 0) {\n      view.animate({\n        resolution: maxResolution,\n        easing: ol.easing.easeOut,\n        anchor: this.lastAnchor_,\n        duration: 500\n      });\n    }\n    this.startTime_ = now;\n    return false;\n  }\n\n  this.delta_ += delta;\n\n  var timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);\n\n  clearTimeout(this.timeoutId_);\n  this.timeoutId_ = setTimeout(this.handleWheelZoom_.bind(this, map), timeLeft);\n\n  return false;\n};\n\n\n/**\n * @private\n */\nol.interaction.MouseWheelZoom.prototype.decrementInteractingHint_ = function() {\n  this.trackpadTimeoutId_ = undefined;\n  var view = this.getMap().getView();\n  view.setHint(ol.View.Hint.INTERACTING, -1);\n};\n\n\n/**\n * @private\n * @param {ol.Map} map Map.\n */\nol.interaction.MouseWheelZoom.prototype.handleWheelZoom_ = function(map) {\n  var view = map.getView();\n  if (view.getAnimating()) {\n    view.cancelAnimations();\n  }\n  var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA;\n  var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta);\n  ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_,\n      this.duration_);\n  this.mode_ = undefined;\n  this.delta_ = 0;\n  this.lastAnchor_ = null;\n  this.startTime_ = undefined;\n  this.timeoutId_ = undefined;\n};\n\n\n/**\n * Enable or disable using the mouse's location as an anchor when zooming\n * @param {boolean} useAnchor true to zoom to the mouse's location, false\n * to zoom to the center of the map\n * @api\n */\nol.interaction.MouseWheelZoom.prototype.setMouseAnchor = function(useAnchor) {\n  this.useAnchor_ = useAnchor;\n  if (!useAnchor) {\n    this.lastAnchor_ = null;\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.interaction.MouseWheelZoom.Mode = {\n  TRACKPAD: 'trackpad',\n  WHEEL: 'wheel'\n};\n\ngoog.provide('ol.interaction.PinchRotate');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.functions');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.interaction.Pointer');\n\n\n/**\n * @classdesc\n * Allows the user to rotate the map by twisting with two fingers\n * on a touch screen.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @param {olx.interaction.PinchRotateOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.PinchRotate = function(opt_options) {\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_,\n    handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_,\n    handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_\n  });\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.anchor_ = null;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.lastAngle_ = undefined;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.rotating_ = false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.rotationDelta_ = 0.0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.threshold_ = options.threshold !== undefined ? options.threshold : 0.3;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n};\nol.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer);\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.PinchRotate}\n * @private\n */\nol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) {\n  ol.DEBUG && console.assert(this.targetPointers.length >= 2,\n      'length of this.targetPointers should be greater than or equal to 2');\n  var rotationDelta = 0.0;\n\n  var touch0 = this.targetPointers[0];\n  var touch1 = this.targetPointers[1];\n\n  // angle between touches\n  var angle = Math.atan2(\n      touch1.clientY - touch0.clientY,\n      touch1.clientX - touch0.clientX);\n\n  if (this.lastAngle_ !== undefined) {\n    var delta = angle - this.lastAngle_;\n    this.rotationDelta_ += delta;\n    if (!this.rotating_ &&\n        Math.abs(this.rotationDelta_) > this.threshold_) {\n      this.rotating_ = true;\n    }\n    rotationDelta = delta;\n  }\n  this.lastAngle_ = angle;\n\n  var map = mapBrowserEvent.map;\n\n  // rotate anchor point.\n  // FIXME: should be the intersection point between the lines:\n  //     touch0,touch1 and previousTouch0,previousTouch1\n  var viewportPosition = map.getViewport().getBoundingClientRect();\n  var centroid = ol.interaction.Pointer.centroid(this.targetPointers);\n  centroid[0] -= viewportPosition.left;\n  centroid[1] -= viewportPosition.top;\n  this.anchor_ = map.getCoordinateFromPixel(centroid);\n\n  // rotate\n  if (this.rotating_) {\n    var view = map.getView();\n    var rotation = view.getRotation();\n    map.render();\n    ol.interaction.Interaction.rotateWithoutConstraints(map, view,\n        rotation + rotationDelta, this.anchor_);\n  }\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.PinchRotate}\n * @private\n */\nol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) {\n  if (this.targetPointers.length < 2) {\n    var map = mapBrowserEvent.map;\n    var view = map.getView();\n    view.setHint(ol.View.Hint.INTERACTING, -1);\n    if (this.rotating_) {\n      var rotation = view.getRotation();\n      ol.interaction.Interaction.rotate(\n          map, view, rotation, this.anchor_, this.duration_);\n    }\n    return false;\n  } else {\n    return true;\n  }\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.PinchRotate}\n * @private\n */\nol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) {\n  if (this.targetPointers.length >= 2) {\n    var map = mapBrowserEvent.map;\n    this.anchor_ = null;\n    this.lastAngle_ = undefined;\n    this.rotating_ = false;\n    this.rotationDelta_ = 0.0;\n    if (!this.handlingDownUpSequence) {\n      map.getView().setHint(ol.View.Hint.INTERACTING, 1);\n    }\n    return true;\n  } else {\n    return false;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.PinchRotate.prototype.shouldStopEvent = ol.functions.FALSE;\n\ngoog.provide('ol.interaction.PinchZoom');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.functions');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.interaction.Pointer');\n\n\n/**\n * @classdesc\n * Allows the user to zoom the map by pinching with two fingers\n * on a touch screen.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @param {olx.interaction.PinchZoomOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.PinchZoom = function(opt_options) {\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.PinchZoom.handleDownEvent_,\n    handleDragEvent: ol.interaction.PinchZoom.handleDragEvent_,\n    handleUpEvent: ol.interaction.PinchZoom.handleUpEvent_\n  });\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.constrainResolution_ = options.constrainResolution || false;\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.anchor_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 400;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.lastDistance_ = undefined;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.lastScaleDelta_ = 1;\n\n};\nol.inherits(ol.interaction.PinchZoom, ol.interaction.Pointer);\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.PinchZoom}\n * @private\n */\nol.interaction.PinchZoom.handleDragEvent_ = function(mapBrowserEvent) {\n  ol.DEBUG && console.assert(this.targetPointers.length >= 2,\n      'length of this.targetPointers should be 2 or more');\n  var scaleDelta = 1.0;\n\n  var touch0 = this.targetPointers[0];\n  var touch1 = this.targetPointers[1];\n  var dx = touch0.clientX - touch1.clientX;\n  var dy = touch0.clientY - touch1.clientY;\n\n  // distance between touches\n  var distance = Math.sqrt(dx * dx + dy * dy);\n\n  if (this.lastDistance_ !== undefined) {\n    scaleDelta = this.lastDistance_ / distance;\n  }\n  this.lastDistance_ = distance;\n  if (scaleDelta != 1.0) {\n    this.lastScaleDelta_ = scaleDelta;\n  }\n\n  var map = mapBrowserEvent.map;\n  var view = map.getView();\n  var resolution = view.getResolution();\n\n  // scale anchor point.\n  var viewportPosition = map.getViewport().getBoundingClientRect();\n  var centroid = ol.interaction.Pointer.centroid(this.targetPointers);\n  centroid[0] -= viewportPosition.left;\n  centroid[1] -= viewportPosition.top;\n  this.anchor_ = map.getCoordinateFromPixel(centroid);\n\n  // scale, bypass the resolution constraint\n  map.render();\n  ol.interaction.Interaction.zoomWithoutConstraints(\n      map, view, resolution * scaleDelta, this.anchor_);\n\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.PinchZoom}\n * @private\n */\nol.interaction.PinchZoom.handleUpEvent_ = function(mapBrowserEvent) {\n  if (this.targetPointers.length < 2) {\n    var map = mapBrowserEvent.map;\n    var view = map.getView();\n    view.setHint(ol.View.Hint.INTERACTING, -1);\n    if (this.constrainResolution_) {\n      var resolution = view.getResolution();\n      // Zoom to final resolution, with an animation, and provide a\n      // direction not to zoom out/in if user was pinching in/out.\n      // Direction is > 0 if pinching out, and < 0 if pinching in.\n      var direction = this.lastScaleDelta_ - 1;\n      ol.interaction.Interaction.zoom(map, view, resolution,\n          this.anchor_, this.duration_, direction);\n    }\n    return false;\n  } else {\n    return true;\n  }\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.PinchZoom}\n * @private\n */\nol.interaction.PinchZoom.handleDownEvent_ = function(mapBrowserEvent) {\n  if (this.targetPointers.length >= 2) {\n    var map = mapBrowserEvent.map;\n    this.anchor_ = null;\n    this.lastDistance_ = undefined;\n    this.lastScaleDelta_ = 1;\n    if (!this.handlingDownUpSequence) {\n      map.getView().setHint(ol.View.Hint.INTERACTING, 1);\n    }\n    return true;\n  } else {\n    return false;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.PinchZoom.prototype.shouldStopEvent = ol.functions.FALSE;\n\ngoog.provide('ol.interaction');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.Kinetic');\ngoog.require('ol.interaction.DoubleClickZoom');\ngoog.require('ol.interaction.DragPan');\ngoog.require('ol.interaction.DragRotate');\ngoog.require('ol.interaction.DragZoom');\ngoog.require('ol.interaction.KeyboardPan');\ngoog.require('ol.interaction.KeyboardZoom');\ngoog.require('ol.interaction.MouseWheelZoom');\ngoog.require('ol.interaction.PinchRotate');\ngoog.require('ol.interaction.PinchZoom');\n\n\n/**\n * Set of interactions included in maps by default. Specific interactions can be\n * excluded by setting the appropriate option to false in the constructor\n * options, but the order of the interactions is fixed.  If you want to specify\n * a different order for interactions, you will need to create your own\n * {@link ol.interaction.Interaction} instances and insert them into a\n * {@link ol.Collection} in the order you want before creating your\n * {@link ol.Map} instance. The default set of interactions, in sequence, is:\n * * {@link ol.interaction.DragRotate}\n * * {@link ol.interaction.DoubleClickZoom}\n * * {@link ol.interaction.DragPan}\n * * {@link ol.interaction.PinchRotate}\n * * {@link ol.interaction.PinchZoom}\n * * {@link ol.interaction.KeyboardPan}\n * * {@link ol.interaction.KeyboardZoom}\n * * {@link ol.interaction.MouseWheelZoom}\n * * {@link ol.interaction.DragZoom}\n *\n * @param {olx.interaction.DefaultsOptions=} opt_options Defaults options.\n * @return {ol.Collection.<ol.interaction.Interaction>} A collection of\n * interactions to be used with the ol.Map constructor's interactions option.\n * @api stable\n */\nol.interaction.defaults = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  var interactions = new ol.Collection();\n\n  var kinetic = new ol.Kinetic(-0.005, 0.05, 100);\n\n  var altShiftDragRotate = options.altShiftDragRotate !== undefined ?\n      options.altShiftDragRotate : true;\n  if (altShiftDragRotate) {\n    interactions.push(new ol.interaction.DragRotate());\n  }\n\n  var doubleClickZoom = options.doubleClickZoom !== undefined ?\n      options.doubleClickZoom : true;\n  if (doubleClickZoom) {\n    interactions.push(new ol.interaction.DoubleClickZoom({\n      delta: options.zoomDelta,\n      duration: options.zoomDuration\n    }));\n  }\n\n  var dragPan = options.dragPan !== undefined ? options.dragPan : true;\n  if (dragPan) {\n    interactions.push(new ol.interaction.DragPan({\n      kinetic: kinetic\n    }));\n  }\n\n  var pinchRotate = options.pinchRotate !== undefined ? options.pinchRotate :\n      true;\n  if (pinchRotate) {\n    interactions.push(new ol.interaction.PinchRotate());\n  }\n\n  var pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true;\n  if (pinchZoom) {\n    interactions.push(new ol.interaction.PinchZoom({\n      duration: options.zoomDuration\n    }));\n  }\n\n  var keyboard = options.keyboard !== undefined ? options.keyboard : true;\n  if (keyboard) {\n    interactions.push(new ol.interaction.KeyboardPan());\n    interactions.push(new ol.interaction.KeyboardZoom({\n      delta: options.zoomDelta,\n      duration: options.zoomDuration\n    }));\n  }\n\n  var mouseWheelZoom = options.mouseWheelZoom !== undefined ?\n      options.mouseWheelZoom : true;\n  if (mouseWheelZoom) {\n    interactions.push(new ol.interaction.MouseWheelZoom({\n      duration: options.zoomDuration\n    }));\n  }\n\n  var shiftDragZoom = options.shiftDragZoom !== undefined ?\n      options.shiftDragZoom : true;\n  if (shiftDragZoom) {\n    interactions.push(new ol.interaction.DragZoom({\n      duration: options.zoomDuration\n    }));\n  }\n\n  return interactions;\n\n};\n\ngoog.provide('ol.layer.Base');\n\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.math');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Note that with `ol.layer.Base` and all its subclasses, any property set in\n * the options is set as a {@link ol.Object} property on the layer object, so\n * is observable, and has get/set accessors.\n *\n * @constructor\n * @extends {ol.Object}\n * @param {olx.layer.BaseOptions} options Layer options.\n * @api stable\n */\nol.layer.Base = function(options) {\n\n  ol.Object.call(this);\n\n  /**\n   * @type {Object.<string, *>}\n   */\n  var properties = ol.obj.assign({}, options);\n  properties[ol.layer.Base.Property.OPACITY] =\n      options.opacity !== undefined ? options.opacity : 1;\n  properties[ol.layer.Base.Property.VISIBLE] =\n      options.visible !== undefined ? options.visible : true;\n  properties[ol.layer.Base.Property.Z_INDEX] =\n      options.zIndex !== undefined ? options.zIndex : 0;\n  properties[ol.layer.Base.Property.MAX_RESOLUTION] =\n      options.maxResolution !== undefined ? options.maxResolution : Infinity;\n  properties[ol.layer.Base.Property.MIN_RESOLUTION] =\n      options.minResolution !== undefined ? options.minResolution : 0;\n\n  this.setProperties(properties);\n\n  /**\n   * @type {ol.LayerState}\n   * @private\n   */\n  this.state_ = /** @type {ol.LayerState} */ ({\n    layer: /** @type {ol.layer.Layer} */ (this),\n    managed: true\n  });\n\n};\nol.inherits(ol.layer.Base, ol.Object);\n\n\n/**\n * @return {ol.LayerState} Layer state.\n */\nol.layer.Base.prototype.getLayerState = function() {\n  this.state_.opacity = ol.math.clamp(this.getOpacity(), 0, 1);\n  this.state_.sourceState = this.getSourceState();\n  this.state_.visible = this.getVisible();\n  this.state_.extent = this.getExtent();\n  this.state_.zIndex = this.getZIndex();\n  this.state_.maxResolution = this.getMaxResolution();\n  this.state_.minResolution = Math.max(this.getMinResolution(), 0);\n\n  return this.state_;\n};\n\n\n/**\n * @abstract\n * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be\n *     modified in place).\n * @return {Array.<ol.layer.Layer>} Array of layers.\n */\nol.layer.Base.prototype.getLayersArray = function(opt_array) {};\n\n\n/**\n * @abstract\n * @param {Array.<ol.LayerState>=} opt_states Optional list of layer\n *     states (to be modified in place).\n * @return {Array.<ol.LayerState>} List of layer states.\n */\nol.layer.Base.prototype.getLayerStatesArray = function(opt_states) {};\n\n\n/**\n * Return the {@link ol.Extent extent} of the layer or `undefined` if it\n * will be visible regardless of extent.\n * @return {ol.Extent|undefined} The layer extent.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.getExtent = function() {\n  return /** @type {ol.Extent|undefined} */ (\n      this.get(ol.layer.Base.Property.EXTENT));\n};\n\n\n/**\n * Return the maximum resolution of the layer.\n * @return {number} The maximum resolution of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.getMaxResolution = function() {\n  return /** @type {number} */ (\n      this.get(ol.layer.Base.Property.MAX_RESOLUTION));\n};\n\n\n/**\n * Return the minimum resolution of the layer.\n * @return {number} The minimum resolution of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.getMinResolution = function() {\n  return /** @type {number} */ (\n      this.get(ol.layer.Base.Property.MIN_RESOLUTION));\n};\n\n\n/**\n * Return the opacity of the layer (between 0 and 1).\n * @return {number} The opacity of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.getOpacity = function() {\n  return /** @type {number} */ (this.get(ol.layer.Base.Property.OPACITY));\n};\n\n\n/**\n * @abstract\n * @return {ol.source.State} Source state.\n */\nol.layer.Base.prototype.getSourceState = function() {};\n\n\n/**\n * Return the visibility of the layer (`true` or `false`).\n * @return {boolean} The visibility of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.getVisible = function() {\n  return /** @type {boolean} */ (this.get(ol.layer.Base.Property.VISIBLE));\n};\n\n\n/**\n * Return the Z-index of the layer, which is used to order layers before\n * rendering. The default Z-index is 0.\n * @return {number} The Z-index of the layer.\n * @observable\n * @api\n */\nol.layer.Base.prototype.getZIndex = function() {\n  return /** @type {number} */ (this.get(ol.layer.Base.Property.Z_INDEX));\n};\n\n\n/**\n * Set the extent at which the layer is visible.  If `undefined`, the layer\n * will be visible at all extents.\n * @param {ol.Extent|undefined} extent The extent of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.setExtent = function(extent) {\n  this.set(ol.layer.Base.Property.EXTENT, extent);\n};\n\n\n/**\n * Set the maximum resolution at which the layer is visible.\n * @param {number} maxResolution The maximum resolution of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.setMaxResolution = function(maxResolution) {\n  this.set(ol.layer.Base.Property.MAX_RESOLUTION, maxResolution);\n};\n\n\n/**\n * Set the minimum resolution at which the layer is visible.\n * @param {number} minResolution The minimum resolution of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.setMinResolution = function(minResolution) {\n  this.set(ol.layer.Base.Property.MIN_RESOLUTION, minResolution);\n};\n\n\n/**\n * Set the opacity of the layer, allowed values range from 0 to 1.\n * @param {number} opacity The opacity of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.setOpacity = function(opacity) {\n  this.set(ol.layer.Base.Property.OPACITY, opacity);\n};\n\n\n/**\n * Set the visibility of the layer (`true` or `false`).\n * @param {boolean} visible The visibility of the layer.\n * @observable\n * @api stable\n */\nol.layer.Base.prototype.setVisible = function(visible) {\n  this.set(ol.layer.Base.Property.VISIBLE, visible);\n};\n\n\n/**\n * Set Z-index of the layer, which is used to order layers before rendering.\n * The default Z-index is 0.\n * @param {number} zindex The z-index of the layer.\n * @observable\n * @api\n */\nol.layer.Base.prototype.setZIndex = function(zindex) {\n  this.set(ol.layer.Base.Property.Z_INDEX, zindex);\n};\n\n\n/**\n * @enum {string}\n */\nol.layer.Base.Property = {\n  OPACITY: 'opacity',\n  VISIBLE: 'visible',\n  EXTENT: 'extent',\n  Z_INDEX: 'zIndex',\n  MAX_RESOLUTION: 'maxResolution',\n  MIN_RESOLUTION: 'minResolution',\n  SOURCE: 'source'\n};\n\ngoog.provide('ol.source.State');\n\n\n/**\n * State of the source, one of 'undefined', 'loading', 'ready' or 'error'.\n * @enum {string}\n */\nol.source.State = {\n  UNDEFINED: 'undefined',\n  LOADING: 'loading',\n  READY: 'ready',\n  ERROR: 'error'\n};\n\n\ngoog.provide('ol.layer.Group');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.Collection');\ngoog.require('ol.Object');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.layer.Base');\ngoog.require('ol.obj');\ngoog.require('ol.source.State');\n\n\n/**\n * @classdesc\n * A {@link ol.Collection} of layers that are handled together.\n *\n * A generic `change` event is triggered when the group/Collection changes.\n *\n * @constructor\n * @extends {ol.layer.Base}\n * @param {olx.layer.GroupOptions=} opt_options Layer options.\n * @api stable\n */\nol.layer.Group = function(opt_options) {\n\n  var options = opt_options || {};\n  var baseOptions = /** @type {olx.layer.GroupOptions} */\n      (ol.obj.assign({}, options));\n  delete baseOptions.layers;\n\n  var layers = options.layers;\n\n  ol.layer.Base.call(this, baseOptions);\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.layersListenerKeys_ = [];\n\n  /**\n   * @private\n   * @type {Object.<string, Array.<ol.EventsKey>>}\n   */\n  this.listenerKeys_ = {};\n\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.layer.Group.Property.LAYERS),\n      this.handleLayersChanged_, this);\n\n  if (layers) {\n    if (Array.isArray(layers)) {\n      layers = new ol.Collection(layers.slice());\n    } else {\n      ol.asserts.assert(layers instanceof ol.Collection,\n          43); // Expected `layers` to be an array or an `ol.Collection`\n      layers = layers;\n    }\n  } else {\n    layers = new ol.Collection();\n  }\n\n  this.setLayers(layers);\n\n};\nol.inherits(ol.layer.Group, ol.layer.Base);\n\n\n/**\n * @private\n */\nol.layer.Group.prototype.handleLayerChange_ = function() {\n  if (this.getVisible()) {\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.events.Event} event Event.\n * @private\n */\nol.layer.Group.prototype.handleLayersChanged_ = function(event) {\n  this.layersListenerKeys_.forEach(ol.events.unlistenByKey);\n  this.layersListenerKeys_.length = 0;\n\n  var layers = this.getLayers();\n  this.layersListenerKeys_.push(\n      ol.events.listen(layers, ol.Collection.EventType.ADD,\n          this.handleLayersAdd_, this),\n      ol.events.listen(layers, ol.Collection.EventType.REMOVE,\n          this.handleLayersRemove_, this));\n\n  for (var id in this.listenerKeys_) {\n    this.listenerKeys_[id].forEach(ol.events.unlistenByKey);\n  }\n  ol.obj.clear(this.listenerKeys_);\n\n  var layersArray = layers.getArray();\n  var i, ii, layer;\n  for (i = 0, ii = layersArray.length; i < ii; i++) {\n    layer = layersArray[i];\n    this.listenerKeys_[ol.getUid(layer).toString()] = [\n      ol.events.listen(layer, ol.Object.EventType.PROPERTYCHANGE,\n          this.handleLayerChange_, this),\n      ol.events.listen(layer, ol.events.EventType.CHANGE,\n          this.handleLayerChange_, this)\n    ];\n  }\n\n  this.changed();\n};\n\n\n/**\n * @param {ol.Collection.Event} collectionEvent Collection event.\n * @private\n */\nol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) {\n  var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);\n  var key = ol.getUid(layer).toString();\n  ol.DEBUG && console.assert(!(key in this.listenerKeys_),\n      'listeners already registered');\n  this.listenerKeys_[key] = [\n    ol.events.listen(layer, ol.Object.EventType.PROPERTYCHANGE,\n        this.handleLayerChange_, this),\n    ol.events.listen(layer, ol.events.EventType.CHANGE,\n        this.handleLayerChange_, this)\n  ];\n  this.changed();\n};\n\n\n/**\n * @param {ol.Collection.Event} collectionEvent Collection event.\n * @private\n */\nol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) {\n  var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);\n  var key = ol.getUid(layer).toString();\n  ol.DEBUG && console.assert(key in this.listenerKeys_, 'no listeners to unregister');\n  this.listenerKeys_[key].forEach(ol.events.unlistenByKey);\n  delete this.listenerKeys_[key];\n  this.changed();\n};\n\n\n/**\n * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers}\n * in this group.\n * @return {!ol.Collection.<ol.layer.Base>} Collection of\n *   {@link ol.layer.Base layers} that are part of this group.\n * @observable\n * @api stable\n */\nol.layer.Group.prototype.getLayers = function() {\n  return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get(\n      ol.layer.Group.Property.LAYERS));\n};\n\n\n/**\n * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers}\n * in this group.\n * @param {!ol.Collection.<ol.layer.Base>} layers Collection of\n *   {@link ol.layer.Base layers} that are part of this group.\n * @observable\n * @api stable\n */\nol.layer.Group.prototype.setLayers = function(layers) {\n  this.set(ol.layer.Group.Property.LAYERS, layers);\n};\n\n\n/**\n * @inheritDoc\n */\nol.layer.Group.prototype.getLayersArray = function(opt_array) {\n  var array = opt_array !== undefined ? opt_array : [];\n  this.getLayers().forEach(function(layer) {\n    layer.getLayersArray(array);\n  });\n  return array;\n};\n\n\n/**\n * @inheritDoc\n */\nol.layer.Group.prototype.getLayerStatesArray = function(opt_states) {\n  var states = opt_states !== undefined ? opt_states : [];\n\n  var pos = states.length;\n\n  this.getLayers().forEach(function(layer) {\n    layer.getLayerStatesArray(states);\n  });\n\n  var ownLayerState = this.getLayerState();\n  var i, ii, layerState;\n  for (i = pos, ii = states.length; i < ii; i++) {\n    layerState = states[i];\n    layerState.opacity *= ownLayerState.opacity;\n    layerState.visible = layerState.visible && ownLayerState.visible;\n    layerState.maxResolution = Math.min(\n        layerState.maxResolution, ownLayerState.maxResolution);\n    layerState.minResolution = Math.max(\n        layerState.minResolution, ownLayerState.minResolution);\n    if (ownLayerState.extent !== undefined) {\n      if (layerState.extent !== undefined) {\n        layerState.extent = ol.extent.getIntersection(\n            layerState.extent, ownLayerState.extent);\n      } else {\n        layerState.extent = ownLayerState.extent;\n      }\n    }\n  }\n\n  return states;\n};\n\n\n/**\n * @inheritDoc\n */\nol.layer.Group.prototype.getSourceState = function() {\n  return ol.source.State.READY;\n};\n\n/**\n * @enum {string}\n */\nol.layer.Group.Property = {\n  LAYERS: 'layers'\n};\n\ngoog.provide('ol.proj.EPSG3857');\n\ngoog.require('ol');\ngoog.require('ol.math');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Projection');\ngoog.require('ol.proj.Units');\n\n\n/**\n * @classdesc\n * Projection object for web/spherical Mercator (EPSG:3857).\n *\n * @constructor\n * @extends {ol.proj.Projection}\n * @param {string} code Code.\n * @private\n */\nol.proj.EPSG3857_ = function(code) {\n  ol.proj.Projection.call(this, {\n    code: code,\n    units: ol.proj.Units.METERS,\n    extent: ol.proj.EPSG3857.EXTENT,\n    global: true,\n    worldExtent: ol.proj.EPSG3857.WORLD_EXTENT,\n    getPointResolution: function(resolution, point) {\n      return resolution / ol.math.cosh(point[1] / ol.proj.EPSG3857.RADIUS);\n    }\n  });\n};\nol.inherits(ol.proj.EPSG3857_, ol.proj.Projection);\n\n\n/**\n * @const\n * @type {number}\n */\nol.proj.EPSG3857.RADIUS = 6378137;\n\n\n/**\n * @const\n * @type {number}\n */\nol.proj.EPSG3857.HALF_SIZE = Math.PI * ol.proj.EPSG3857.RADIUS;\n\n\n/**\n * @const\n * @type {ol.Extent}\n */\nol.proj.EPSG3857.EXTENT = [\n  -ol.proj.EPSG3857.HALF_SIZE, -ol.proj.EPSG3857.HALF_SIZE,\n  ol.proj.EPSG3857.HALF_SIZE, ol.proj.EPSG3857.HALF_SIZE\n];\n\n\n/**\n * @const\n * @type {ol.Extent}\n */\nol.proj.EPSG3857.WORLD_EXTENT = [-180, -85, 180, 85];\n\n\n/**\n * Lists several projection codes with the same meaning as EPSG:3857.\n *\n * @type {Array.<string>}\n */\nol.proj.EPSG3857.CODES = [\n  'EPSG:3857',\n  'EPSG:102100',\n  'EPSG:102113',\n  'EPSG:900913',\n  'urn:ogc:def:crs:EPSG:6.18:3:3857',\n  'urn:ogc:def:crs:EPSG::3857',\n  'http://www.opengis.net/gml/srs/epsg.xml#3857'\n];\n\n\n/**\n * Projections equal to EPSG:3857.\n *\n * @const\n * @type {Array.<ol.proj.Projection>}\n */\nol.proj.EPSG3857.PROJECTIONS = ol.proj.EPSG3857.CODES.map(function(code) {\n  return new ol.proj.EPSG3857_(code);\n});\n\n\n/**\n * Transformation from EPSG:4326 to EPSG:3857.\n *\n * @param {Array.<number>} input Input array of coordinate values.\n * @param {Array.<number>=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension (default is `2`).\n * @return {Array.<number>} Output array of coordinate values.\n */\nol.proj.EPSG3857.fromEPSG4326 = function(input, opt_output, opt_dimension) {\n  var length = input.length,\n      dimension = opt_dimension > 1 ? opt_dimension : 2,\n      output = opt_output;\n  if (output === undefined) {\n    if (dimension > 2) {\n      // preserve values beyond second dimension\n      output = input.slice();\n    } else {\n      output = new Array(length);\n    }\n  }\n  ol.DEBUG && console.assert(output.length % dimension === 0,\n      'modulus of output.length with dimension should be 0');\n  var halfSize = ol.proj.EPSG3857.HALF_SIZE;\n  for (var i = 0; i < length; i += dimension) {\n    output[i] = halfSize * input[i] / 180;\n    var y = ol.proj.EPSG3857.RADIUS *\n        Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360));\n    if (y > halfSize) {\n      y = halfSize;\n    } else if (y < -halfSize) {\n      y = -halfSize;\n    }\n    output[i + 1] = y;\n  }\n  return output;\n};\n\n\n/**\n * Transformation from EPSG:3857 to EPSG:4326.\n *\n * @param {Array.<number>} input Input array of coordinate values.\n * @param {Array.<number>=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension (default is `2`).\n * @return {Array.<number>} Output array of coordinate values.\n */\nol.proj.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) {\n  var length = input.length,\n      dimension = opt_dimension > 1 ? opt_dimension : 2,\n      output = opt_output;\n  if (output === undefined) {\n    if (dimension > 2) {\n      // preserve values beyond second dimension\n      output = input.slice();\n    } else {\n      output = new Array(length);\n    }\n  }\n  ol.DEBUG && console.assert(output.length % dimension === 0,\n      'modulus of output.length with dimension should be 0');\n  for (var i = 0; i < length; i += dimension) {\n    output[i] = 180 * input[i] / ol.proj.EPSG3857.HALF_SIZE;\n    output[i + 1] = 360 * Math.atan(\n        Math.exp(input[i + 1] / ol.proj.EPSG3857.RADIUS)) / Math.PI - 90;\n  }\n  return output;\n};\n\ngoog.provide('ol.sphere.WGS84');\n\ngoog.require('ol.Sphere');\n\n\n/**\n * A sphere with radius equal to the semi-major axis of the WGS84 ellipsoid.\n * @const\n * @type {ol.Sphere}\n */\nol.sphere.WGS84 = new ol.Sphere(6378137);\n\ngoog.provide('ol.proj.EPSG4326');\n\ngoog.require('ol');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Projection');\ngoog.require('ol.proj.Units');\ngoog.require('ol.sphere.WGS84');\n\n\n/**\n * @classdesc\n * Projection object for WGS84 geographic coordinates (EPSG:4326).\n *\n * Note that OpenLayers does not strictly comply with the EPSG definition.\n * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x).\n * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates.\n *\n * @constructor\n * @extends {ol.proj.Projection}\n * @param {string} code Code.\n * @param {string=} opt_axisOrientation Axis orientation.\n * @private\n */\nol.proj.EPSG4326_ = function(code, opt_axisOrientation) {\n  ol.proj.Projection.call(this, {\n    code: code,\n    units: ol.proj.Units.DEGREES,\n    extent: ol.proj.EPSG4326.EXTENT,\n    axisOrientation: opt_axisOrientation,\n    global: true,\n    metersPerUnit: ol.proj.EPSG4326.METERS_PER_UNIT,\n    worldExtent: ol.proj.EPSG4326.EXTENT\n  });\n};\nol.inherits(ol.proj.EPSG4326_, ol.proj.Projection);\n\n\n/**\n * Extent of the EPSG:4326 projection which is the whole world.\n *\n * @const\n * @type {ol.Extent}\n */\nol.proj.EPSG4326.EXTENT = [-180, -90, 180, 90];\n\n\n/**\n * @const\n * @type {number}\n */\nol.proj.EPSG4326.METERS_PER_UNIT = Math.PI * ol.sphere.WGS84.radius / 180;\n\n\n/**\n * Projections equal to EPSG:4326.\n *\n * @const\n * @type {Array.<ol.proj.Projection>}\n */\nol.proj.EPSG4326.PROJECTIONS = [\n  new ol.proj.EPSG4326_('CRS:84'),\n  new ol.proj.EPSG4326_('EPSG:4326', 'neu'),\n  new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG::4326', 'neu'),\n  new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),\n  new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:1.3:CRS84'),\n  new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:2:84'),\n  new ol.proj.EPSG4326_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),\n  new ol.proj.EPSG4326_('urn:x-ogc:def:crs:EPSG:4326', 'neu')\n];\n\ngoog.provide('ol.proj.common');\n\ngoog.require('ol.proj');\ngoog.require('ol.proj.EPSG3857');\ngoog.require('ol.proj.EPSG4326');\n\n\n/**\n * FIXME empty description for jsdoc\n * @api\n */\nol.proj.common.add = function() {\n  // Add transformations that don't alter coordinates to convert within set of\n  // projections with equal meaning.\n  ol.proj.addEquivalentProjections(ol.proj.EPSG3857.PROJECTIONS);\n  ol.proj.addEquivalentProjections(ol.proj.EPSG4326.PROJECTIONS);\n  // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like\n  // coordinates and back.\n  ol.proj.addEquivalentTransforms(\n      ol.proj.EPSG4326.PROJECTIONS,\n      ol.proj.EPSG3857.PROJECTIONS,\n      ol.proj.EPSG3857.fromEPSG4326,\n      ol.proj.EPSG3857.toEPSG4326);\n};\n\ngoog.provide('ol.renderer.Type');\n\n\n/**\n * Available renderers: `'canvas'` or `'webgl'`.\n * @enum {string}\n */\nol.renderer.Type = {\n  CANVAS: 'canvas',\n  WEBGL: 'webgl'\n};\n\ngoog.provide('ol.render.Event');\n\ngoog.require('ol');\ngoog.require('ol.events.Event');\n\n\n/**\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.render.Event}\n * @param {ol.render.Event.Type} type Type.\n * @param {ol.render.VectorContext=} opt_vectorContext Vector context.\n * @param {olx.FrameState=} opt_frameState Frame state.\n * @param {?CanvasRenderingContext2D=} opt_context Context.\n * @param {?ol.webgl.Context=} opt_glContext WebGL Context.\n */\nol.render.Event = function(\n    type, opt_vectorContext, opt_frameState, opt_context,\n    opt_glContext) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * For canvas, this is an instance of {@link ol.render.canvas.Immediate}.\n   * @type {ol.render.VectorContext|undefined}\n   * @api\n   */\n  this.vectorContext = opt_vectorContext;\n\n  /**\n   * An object representing the current render frame state.\n   * @type {olx.FrameState|undefined}\n   * @api\n   */\n  this.frameState = opt_frameState;\n\n  /**\n   * Canvas context. Only available when a Canvas renderer is used, null\n   * otherwise.\n   * @type {CanvasRenderingContext2D|null|undefined}\n   * @api\n   */\n  this.context = opt_context;\n\n  /**\n   * WebGL context. Only available when a WebGL renderer is used, null\n   * otherwise.\n   * @type {ol.webgl.Context|null|undefined}\n   * @api\n   */\n  this.glContext = opt_glContext;\n\n};\nol.inherits(ol.render.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.render.Event.Type = {\n  /**\n   * @event ol.render.Event#postcompose\n   * @api\n   */\n  POSTCOMPOSE: 'postcompose',\n  /**\n   * @event ol.render.Event#precompose\n   * @api\n   */\n  PRECOMPOSE: 'precompose',\n  /**\n   * @event ol.render.Event#render\n   * @api\n   */\n  RENDER: 'render'\n};\n\ngoog.provide('ol.layer.Layer');\n\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.layer.Base');\ngoog.require('ol.obj');\ngoog.require('ol.render.Event');\ngoog.require('ol.source.State');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * A visual representation of raster or vector map data.\n * Layers group together those properties that pertain to how the data is to be\n * displayed, irrespective of the source of that data.\n *\n * Layers are usually added to a map with {@link ol.Map#addLayer}. Components\n * like {@link ol.interaction.Select} use unmanaged layers internally. These\n * unmanaged layers are associated with the map using\n * {@link ol.layer.Layer#setMap} instead.\n *\n * A generic `change` event is fired when the state of the source changes.\n *\n * @constructor\n * @extends {ol.layer.Base}\n * @fires ol.render.Event\n * @param {olx.layer.LayerOptions} options Layer options.\n * @api stable\n */\nol.layer.Layer = function(options) {\n\n  var baseOptions = ol.obj.assign({}, options);\n  delete baseOptions.source;\n\n  ol.layer.Base.call(this, /** @type {olx.layer.BaseOptions} */ (baseOptions));\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.mapPrecomposeKey_ = null;\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.mapRenderKey_ = null;\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.sourceChangeKey_ = null;\n\n  if (options.map) {\n    this.setMap(options.map);\n  }\n\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.layer.Base.Property.SOURCE),\n      this.handleSourcePropertyChange_, this);\n\n  var source = options.source ? options.source : null;\n  this.setSource(source);\n};\nol.inherits(ol.layer.Layer, ol.layer.Base);\n\n\n/**\n * Return `true` if the layer is visible, and if the passed resolution is\n * between the layer's minResolution and maxResolution. The comparison is\n * inclusive for `minResolution` and exclusive for `maxResolution`.\n * @param {ol.LayerState} layerState Layer state.\n * @param {number} resolution Resolution.\n * @return {boolean} The layer is visible at the given resolution.\n */\nol.layer.Layer.visibleAtResolution = function(layerState, resolution) {\n  return layerState.visible && resolution >= layerState.minResolution &&\n      resolution < layerState.maxResolution;\n};\n\n\n/**\n * @inheritDoc\n */\nol.layer.Layer.prototype.getLayersArray = function(opt_array) {\n  var array = opt_array ? opt_array : [];\n  array.push(this);\n  return array;\n};\n\n\n/**\n * @inheritDoc\n */\nol.layer.Layer.prototype.getLayerStatesArray = function(opt_states) {\n  var states = opt_states ? opt_states : [];\n  states.push(this.getLayerState());\n  return states;\n};\n\n\n/**\n * Get the layer source.\n * @return {ol.source.Source} The layer source (or `null` if not yet set).\n * @observable\n * @api stable\n */\nol.layer.Layer.prototype.getSource = function() {\n  var source = this.get(ol.layer.Base.Property.SOURCE);\n  return /** @type {ol.source.Source} */ (source) || null;\n};\n\n\n/**\n  * @inheritDoc\n  */\nol.layer.Layer.prototype.getSourceState = function() {\n  var source = this.getSource();\n  return !source ? ol.source.State.UNDEFINED : source.getState();\n};\n\n\n/**\n * @private\n */\nol.layer.Layer.prototype.handleSourceChange_ = function() {\n  this.changed();\n};\n\n\n/**\n * @private\n */\nol.layer.Layer.prototype.handleSourcePropertyChange_ = function() {\n  if (this.sourceChangeKey_) {\n    ol.events.unlistenByKey(this.sourceChangeKey_);\n    this.sourceChangeKey_ = null;\n  }\n  var source = this.getSource();\n  if (source) {\n    this.sourceChangeKey_ = ol.events.listen(source,\n        ol.events.EventType.CHANGE, this.handleSourceChange_, this);\n  }\n  this.changed();\n};\n\n\n/**\n * Sets the layer to be rendered on top of other layers on a map. The map will\n * not manage this layer in its layers collection, and the callback in\n * {@link ol.Map#forEachLayerAtPixel} will receive `null` as layer. This\n * is useful for temporary layers. To remove an unmanaged layer from the map,\n * use `#setMap(null)`.\n *\n * To add the layer to a map and have it managed by the map, use\n * {@link ol.Map#addLayer} instead.\n * @param {ol.Map} map Map.\n * @api\n */\nol.layer.Layer.prototype.setMap = function(map) {\n  if (this.mapPrecomposeKey_) {\n    ol.events.unlistenByKey(this.mapPrecomposeKey_);\n    this.mapPrecomposeKey_ = null;\n  }\n  if (!map) {\n    this.changed();\n  }\n  if (this.mapRenderKey_) {\n    ol.events.unlistenByKey(this.mapRenderKey_);\n    this.mapRenderKey_ = null;\n  }\n  if (map) {\n    this.mapPrecomposeKey_ = ol.events.listen(\n        map, ol.render.Event.Type.PRECOMPOSE, function(evt) {\n          var layerState = this.getLayerState();\n          layerState.managed = false;\n          layerState.zIndex = Infinity;\n          evt.frameState.layerStatesArray.push(layerState);\n          evt.frameState.layerStates[ol.getUid(this)] = layerState;\n        }, this);\n    this.mapRenderKey_ = ol.events.listen(\n        this, ol.events.EventType.CHANGE, map.render, map);\n    this.changed();\n  }\n};\n\n\n/**\n * Set the layer source.\n * @param {ol.source.Source} source The layer source.\n * @observable\n * @api stable\n */\nol.layer.Layer.prototype.setSource = function(source) {\n  this.set(ol.layer.Base.Property.SOURCE, source);\n};\n\ngoog.provide('ol.style.IconImageCache');\n\ngoog.require('ol');\ngoog.require('ol.color');\n\n\n/**\n * @constructor\n */\nol.style.IconImageCache = function() {\n\n  /**\n   * @type {Object.<string, ol.style.IconImage>}\n   * @private\n   */\n  this.cache_ = {};\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.cacheSize_ = 0;\n\n  /**\n   * @const\n   * @type {number}\n   * @private\n   */\n  this.maxCacheSize_ = 32;\n};\n\n\n/**\n * @param {string} src Src.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.Color} color Color.\n * @return {string} Cache key.\n */\nol.style.IconImageCache.getKey = function(src, crossOrigin, color) {\n  ol.DEBUG && console.assert(crossOrigin !== undefined,\n      'argument crossOrigin must be defined');\n  var colorString = color ? ol.color.asString(color) : 'null';\n  return crossOrigin + ':' + src + ':' + colorString;\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nol.style.IconImageCache.prototype.clear = function() {\n  this.cache_ = {};\n  this.cacheSize_ = 0;\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nol.style.IconImageCache.prototype.expire = function() {\n  if (this.cacheSize_ > this.maxCacheSize_) {\n    var i = 0;\n    var key, iconImage;\n    for (key in this.cache_) {\n      iconImage = this.cache_[key];\n      if ((i++ & 3) === 0 && !iconImage.hasListener()) {\n        delete this.cache_[key];\n        --this.cacheSize_;\n      }\n    }\n  }\n};\n\n\n/**\n * @param {string} src Src.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.Color} color Color.\n * @return {ol.style.IconImage} Icon image.\n */\nol.style.IconImageCache.prototype.get = function(src, crossOrigin, color) {\n  var key = ol.style.IconImageCache.getKey(src, crossOrigin, color);\n  return key in this.cache_ ? this.cache_[key] : null;\n};\n\n\n/**\n * @param {string} src Src.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.Color} color Color.\n * @param {ol.style.IconImage} iconImage Icon image.\n */\nol.style.IconImageCache.prototype.set = function(src, crossOrigin, color,\n                                                 iconImage) {\n  var key = ol.style.IconImageCache.getKey(src, crossOrigin, color);\n  this.cache_[key] = iconImage;\n  ++this.cacheSize_;\n};\n\ngoog.provide('ol.style');\n\ngoog.require('ol.style.IconImageCache');\n\nol.style.iconImageCache = new ol.style.IconImageCache();\n\ngoog.provide('ol.transform');\n\ngoog.require('ol.asserts');\n\n\n/**\n * Collection of affine 2d transformation functions. The functions work on an\n * array of 6 elements. The element order is compatible with the [SVGMatrix\n * interface](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix) and is\n * a subset (elements a to f) of a 3x3 martrix:\n * ```\n * [ a c e ]\n * [ b d f ]\n * [ 0 0 1 ]\n * ```\n */\n\n\n/**\n * @private\n * @type {ol.Transform}\n */\nol.transform.tmp_ = new Array(6);\n\n\n/**\n * Create an identity transform.\n * @return {!ol.Transform} Identity transform.\n */\nol.transform.create = function() {\n  return [1, 0, 0, 1, 0, 0];\n};\n\n\n/**\n * Resets the given transform to an identity transform.\n * @param {!ol.Transform} transform Transform.\n * @return {!ol.Transform} Transform.\n */\nol.transform.reset = function(transform) {\n  return ol.transform.set(transform, 1, 0, 0, 1, 0, 0);\n};\n\n\n/**\n * Multiply the underlying matrices of two transforms and return the result in\n * the first transform.\n * @param {!ol.Transform} transform1 Transform parameters of matrix 1.\n * @param {!ol.Transform} transform2 Transform parameters of matrix 2.\n * @return {!ol.Transform} transform1 multiplied with transform2.\n */\nol.transform.multiply = function(transform1, transform2) {\n  var a1 = transform1[0];\n  var b1 = transform1[1];\n  var c1 = transform1[2];\n  var d1 = transform1[3];\n  var e1 = transform1[4];\n  var f1 = transform1[5];\n  var a2 = transform2[0];\n  var b2 = transform2[1];\n  var c2 = transform2[2];\n  var d2 = transform2[3];\n  var e2 = transform2[4];\n  var f2 = transform2[5];\n\n  transform1[0] = a1 * a2 + c1 * b2;\n  transform1[1] = b1 * a2 + d1 * b2;\n  transform1[2] = a1 * c2 + c1 * d2;\n  transform1[3] = b1 * c2 + d1 * d2;\n  transform1[4] = a1 * e2 + c1 * f2 + e1;\n  transform1[5] = b1 * e2 + d1 * f2 + f1;\n\n  return transform1;\n};\n\n/**\n * Set the transform components a-f on a given transform.\n * @param {!ol.Transform} transform Transform.\n * @param {number} a The a component of the transform.\n * @param {number} b The b component of the transform.\n * @param {number} c The c component of the transform.\n * @param {number} d The d component of the transform.\n * @param {number} e The e component of the transform.\n * @param {number} f The f component of the transform.\n * @return {!ol.Transform} Matrix with transform applied.\n */\nol.transform.set = function(transform, a, b, c, d, e, f) {\n  transform[0] = a;\n  transform[1] = b;\n  transform[2] = c;\n  transform[3] = d;\n  transform[4] = e;\n  transform[5] = f;\n  return transform;\n};\n\n\n/**\n * Set transform on one matrix from another matrix.\n * @param {!ol.Transform} transform1 Matrix to set transform to.\n * @param {!ol.Transform} transform2 Matrix to set transform from.\n * @return {!ol.Transform} transform1 with transform from transform2 applied.\n */\nol.transform.setFromArray = function(transform1, transform2) {\n  transform1[0] = transform2[0];\n  transform1[1] = transform2[1];\n  transform1[2] = transform2[2];\n  transform1[3] = transform2[3];\n  transform1[4] = transform2[4];\n  transform1[5] = transform2[5];\n  return transform1;\n};\n\n\n/**\n * Transforms the given coordinate with the given transform returning the\n * resulting, transformed coordinate. The coordinate will be modified in-place.\n *\n * @param {ol.Transform} transform The transformation.\n * @param {ol.Coordinate|ol.Pixel} coordinate The coordinate to transform.\n * @return {ol.Coordinate|ol.Pixel} return coordinate so that operations can be\n *     chained together.\n */\nol.transform.apply = function(transform, coordinate) {\n  var x = coordinate[0], y = coordinate[1];\n  coordinate[0] = transform[0] * x + transform[2] * y + transform[4];\n  coordinate[1] = transform[1] * x + transform[3] * y + transform[5];\n  return coordinate;\n};\n\n\n/**\n * Applies rotation to the given transform.\n * @param {!ol.Transform} transform Transform.\n * @param {number} angle Angle in radians.\n * @return {!ol.Transform} The rotated transform.\n */\nol.transform.rotate = function(transform, angle) {\n  var cos = Math.cos(angle);\n  var sin = Math.sin(angle);\n  return ol.transform.multiply(transform,\n      ol.transform.set(ol.transform.tmp_, cos, sin, -sin, cos, 0, 0));\n};\n\n\n/**\n * Applies scale to a given transform.\n * @param {!ol.Transform} transform Transform.\n * @param {number} x Scale factor x.\n * @param {number} y Scale factor y.\n * @return {!ol.Transform} The scaled transform.\n */\nol.transform.scale = function(transform, x, y) {\n  return ol.transform.multiply(transform,\n      ol.transform.set(ol.transform.tmp_, x, 0, 0, y, 0, 0));\n};\n\n\n/**\n * Applies translation to the given transform.\n * @param {!ol.Transform} transform Transform.\n * @param {number} dx Translation x.\n * @param {number} dy Translation y.\n * @return {!ol.Transform} The translated transform.\n */\nol.transform.translate = function(transform, dx, dy) {\n  return ol.transform.multiply(transform,\n      ol.transform.set(ol.transform.tmp_, 1, 0, 0, 1, dx, dy));\n};\n\n\n/**\n * Creates a composite transform given an initial translation, scale, rotation, and\n * final translation (in that order only, not commutative).\n * @param {!ol.Transform} transform The transform (will be modified in place).\n * @param {number} dx1 Initial translation x.\n * @param {number} dy1 Initial translation y.\n * @param {number} sx Scale factor x.\n * @param {number} sy Scale factor y.\n * @param {number} angle Rotation (in counter-clockwise radians).\n * @param {number} dx2 Final translation x.\n * @param {number} dy2 Final translation y.\n * @return {!ol.Transform} The composite transform.\n */\nol.transform.compose = function(transform, dx1, dy1, sx, sy, angle, dx2, dy2) {\n  var sin = Math.sin(angle);\n  var cos = Math.cos(angle);\n  transform[0] = sx * cos;\n  transform[1] = sy * sin;\n  transform[2] = -sx * sin;\n  transform[3] = sy * cos;\n  transform[4] = dx2 * sx * cos - dy2 * sx * sin + dx1;\n  transform[5] = dx2 * sy * sin + dy2 * sy * cos + dy1;\n  return transform;\n};\n\n\n/**\n * Invert the given transform.\n * @param {!ol.Transform} transform Transform.\n * @return {!ol.Transform} Inverse of the transform.\n */\nol.transform.invert = function(transform) {\n  var det = ol.transform.determinant(transform);\n  ol.asserts.assert(det !== 0, 32); // Transformation matrix cannot be inverted\n\n  var a = transform[0];\n  var b = transform[1];\n  var c = transform[2];\n  var d = transform[3];\n  var e = transform[4];\n  var f = transform[5];\n\n  transform[0] = d / det;\n  transform[1] = -b / det;\n  transform[2] = -c / det;\n  transform[3] = a / det;\n  transform[4] = (c * f - d * e) / det;\n  transform[5] = -(a * f - b * e) / det;\n\n  return transform;\n};\n\n\n/**\n * Returns the determinant of the given matrix.\n * @param {!ol.Transform} mat Matrix.\n * @return {number} Determinant.\n */\nol.transform.determinant = function(mat) {\n  return mat[0] * mat[3] - mat[1] * mat[2];\n};\n\ngoog.provide('ol.renderer.Map');\n\ngoog.require('ol');\ngoog.require('ol.Disposable');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.functions');\ngoog.require('ol.layer.Layer');\ngoog.require('ol.style');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.Disposable}\n * @param {Element} container Container.\n * @param {ol.Map} map Map.\n * @struct\n */\nol.renderer.Map = function(container, map) {\n\n  ol.Disposable.call(this);\n\n\n  /**\n   * @private\n   * @type {ol.Map}\n   */\n  this.map_ = map;\n\n  /**\n   * @private\n   * @type {Object.<string, ol.renderer.Layer>}\n   */\n  this.layerRenderers_ = {};\n\n  /**\n   * @private\n   * @type {Object.<string, ol.EventsKey>}\n   */\n  this.layerRendererListeners_ = {};\n\n};\nol.inherits(ol.renderer.Map, ol.Disposable);\n\n\n/**\n * @param {olx.FrameState} frameState FrameState.\n * @protected\n */\nol.renderer.Map.prototype.calculateMatrices2D = function(frameState) {\n  var viewState = frameState.viewState;\n  var coordinateToPixelTransform = frameState.coordinateToPixelTransform;\n  var pixelToCoordinateTransform = frameState.pixelToCoordinateTransform;\n  ol.DEBUG && console.assert(coordinateToPixelTransform,\n      'frameState has a coordinateToPixelTransform');\n\n  ol.transform.compose(coordinateToPixelTransform,\n      frameState.size[0] / 2, frameState.size[1] / 2,\n      1 / viewState.resolution, -1 / viewState.resolution,\n      -viewState.rotation,\n      -viewState.center[0], -viewState.center[1]);\n\n  ol.transform.invert(\n      ol.transform.setFromArray(pixelToCoordinateTransform, coordinateToPixelTransform));\n};\n\n\n/**\n * @abstract\n * @param {ol.layer.Layer} layer Layer.\n * @protected\n * @return {ol.renderer.Layer} layerRenderer Layer renderer.\n */\nol.renderer.Map.prototype.createLayerRenderer = function(layer) {};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.Map.prototype.disposeInternal = function() {\n  for (var id in this.layerRenderers_) {\n    this.layerRenderers_[id].dispose();\n  }\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {olx.FrameState} frameState Frame state.\n * @private\n */\nol.renderer.Map.expireIconCache_ = function(map, frameState) {\n  var cache = ol.style.iconImageCache;\n  cache.expire();\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {olx.FrameState} frameState FrameState.\n * @param {number} hitTolerance Hit tolerance in pixels.\n * @param {function(this: S, (ol.Feature|ol.render.Feature),\n *     ol.layer.Layer): T} callback Feature callback.\n * @param {S} thisArg Value to use as `this` when executing `callback`.\n * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter\n *     function, only layers which are visible and for which this function\n *     returns `true` will be tested for features.  By default, all visible\n *     layers will be tested.\n * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`.\n * @return {T|undefined} Callback result.\n * @template S,T,U\n */\nol.renderer.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg,\n        layerFilter, thisArg2) {\n  var result;\n  var viewState = frameState.viewState;\n  var viewResolution = viewState.resolution;\n\n  /**\n   * @param {ol.Feature|ol.render.Feature} feature Feature.\n   * @param {ol.layer.Layer} layer Layer.\n   * @return {?} Callback result.\n   */\n  function forEachFeatureAtCoordinate(feature, layer) {\n    var key = ol.getUid(feature).toString();\n    var managed = frameState.layerStates[ol.getUid(layer)].managed;\n    if (!(key in frameState.skippedFeatureUids && !managed)) {\n      return callback.call(thisArg, feature, managed ? layer : null);\n    }\n  }\n\n  var projection = viewState.projection;\n\n  var translatedCoordinate = coordinate;\n  if (projection.canWrapX()) {\n    var projectionExtent = projection.getExtent();\n    var worldWidth = ol.extent.getWidth(projectionExtent);\n    var x = coordinate[0];\n    if (x < projectionExtent[0] || x > projectionExtent[2]) {\n      var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);\n      translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]];\n    }\n  }\n\n  var layerStates = frameState.layerStatesArray;\n  var numLayers = layerStates.length;\n  var i;\n  for (i = numLayers - 1; i >= 0; --i) {\n    var layerState = layerStates[i];\n    var layer = layerState.layer;\n    if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&\n        layerFilter.call(thisArg2, layer)) {\n      var layerRenderer = this.getLayerRenderer(layer);\n      if (layer.getSource()) {\n        result = layerRenderer.forEachFeatureAtCoordinate(\n            layer.getSource().getWrapX() ? translatedCoordinate : coordinate,\n            frameState, hitTolerance, forEachFeatureAtCoordinate, thisArg);\n      }\n      if (result) {\n        return result;\n      }\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @abstract\n * @param {ol.Pixel} pixel Pixel.\n * @param {olx.FrameState} frameState FrameState.\n * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer\n *     callback.\n * @param {S} thisArg Value to use as `this` when executing `callback`.\n * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter\n *     function, only layers which are visible and for which this function\n *     returns `true` will be tested for features.  By default, all visible\n *     layers will be tested.\n * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`.\n * @return {T|undefined} Callback result.\n * @template S,T,U\n */\nol.renderer.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,\n        layerFilter, thisArg2) {};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {olx.FrameState} frameState FrameState.\n * @param {number} hitTolerance Hit tolerance in pixels.\n * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter\n *     function, only layers which are visible and for which this function\n *     returns `true` will be tested for features.  By default, all visible\n *     layers will be tested.\n * @param {U} thisArg Value to use as `this` when executing `layerFilter`.\n * @return {boolean} Is there a feature at the given coordinate?\n * @template U\n */\nol.renderer.Map.prototype.hasFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, layerFilter, thisArg) {\n  var hasFeature = this.forEachFeatureAtCoordinate(\n      coordinate, frameState, hitTolerance, ol.functions.TRUE, this, layerFilter, thisArg);\n\n  return hasFeature !== undefined;\n};\n\n\n/**\n * @param {ol.layer.Layer} layer Layer.\n * @protected\n * @return {ol.renderer.Layer} Layer renderer.\n */\nol.renderer.Map.prototype.getLayerRenderer = function(layer) {\n  var layerKey = ol.getUid(layer).toString();\n  if (layerKey in this.layerRenderers_) {\n    return this.layerRenderers_[layerKey];\n  } else {\n    var layerRenderer = this.createLayerRenderer(layer);\n    this.layerRenderers_[layerKey] = layerRenderer;\n    this.layerRendererListeners_[layerKey] = ol.events.listen(layerRenderer,\n        ol.events.EventType.CHANGE, this.handleLayerRendererChange_, this);\n\n    return layerRenderer;\n  }\n};\n\n\n/**\n * @param {string} layerKey Layer key.\n * @protected\n * @return {ol.renderer.Layer} Layer renderer.\n */\nol.renderer.Map.prototype.getLayerRendererByKey = function(layerKey) {\n  ol.DEBUG && console.assert(layerKey in this.layerRenderers_,\n      'given layerKey (%s) exists in layerRenderers', layerKey);\n  return this.layerRenderers_[layerKey];\n};\n\n\n/**\n * @protected\n * @return {Object.<string, ol.renderer.Layer>} Layer renderers.\n */\nol.renderer.Map.prototype.getLayerRenderers = function() {\n  return this.layerRenderers_;\n};\n\n\n/**\n * @return {ol.Map} Map.\n */\nol.renderer.Map.prototype.getMap = function() {\n  return this.map_;\n};\n\n\n/**\n * @abstract\n * @return {string} Type\n */\nol.renderer.Map.prototype.getType = function() {};\n\n\n/**\n * Handle changes in a layer renderer.\n * @private\n */\nol.renderer.Map.prototype.handleLayerRendererChange_ = function() {\n  this.map_.render();\n};\n\n\n/**\n * @param {string} layerKey Layer key.\n * @return {ol.renderer.Layer} Layer renderer.\n * @private\n */\nol.renderer.Map.prototype.removeLayerRendererByKey_ = function(layerKey) {\n  ol.DEBUG && console.assert(layerKey in this.layerRenderers_,\n      'given layerKey (%s) exists in layerRenderers', layerKey);\n  var layerRenderer = this.layerRenderers_[layerKey];\n  delete this.layerRenderers_[layerKey];\n\n  ol.DEBUG && console.assert(layerKey in this.layerRendererListeners_,\n      'given layerKey (%s) exists in layerRendererListeners', layerKey);\n  ol.events.unlistenByKey(this.layerRendererListeners_[layerKey]);\n  delete this.layerRendererListeners_[layerKey];\n\n  return layerRenderer;\n};\n\n\n/**\n * Render.\n * @param {?olx.FrameState} frameState Frame state.\n */\nol.renderer.Map.prototype.renderFrame = ol.nullFunction;\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {olx.FrameState} frameState Frame state.\n * @private\n */\nol.renderer.Map.prototype.removeUnusedLayerRenderers_ = function(map, frameState) {\n  var layerKey;\n  for (layerKey in this.layerRenderers_) {\n    if (!frameState || !(layerKey in frameState.layerStates)) {\n      this.removeLayerRendererByKey_(layerKey).dispose();\n    }\n  }\n};\n\n\n/**\n * @param {olx.FrameState} frameState Frame state.\n * @protected\n */\nol.renderer.Map.prototype.scheduleExpireIconCache = function(frameState) {\n  frameState.postRenderFunctions.push(\n    /** @type {ol.PostRenderFunction} */ (ol.renderer.Map.expireIconCache_)\n  );\n};\n\n\n/**\n * @param {!olx.FrameState} frameState Frame state.\n * @protected\n */\nol.renderer.Map.prototype.scheduleRemoveUnusedLayerRenderers = function(frameState) {\n  var layerKey;\n  for (layerKey in this.layerRenderers_) {\n    if (!(layerKey in frameState.layerStates)) {\n      frameState.postRenderFunctions.push(\n        /** @type {ol.PostRenderFunction} */ (this.removeUnusedLayerRenderers_.bind(this))\n      );\n      return;\n    }\n  }\n};\n\n\n/**\n * @param {ol.LayerState} state1 First layer state.\n * @param {ol.LayerState} state2 Second layer state.\n * @return {number} The zIndex difference.\n */\nol.renderer.Map.sortByZIndex = function(state1, state2) {\n  return state1.zIndex - state2.zIndex;\n};\n\ngoog.provide('ol.layer.Image');\n\ngoog.require('ol');\ngoog.require('ol.layer.Layer');\n\n\n/**\n * @classdesc\n * Server-rendered images that are available for arbitrary extents and\n * resolutions.\n * Note that any property set in the options is set as a {@link ol.Object}\n * property on the layer object; for example, setting `title: 'My Title'` in the\n * options means that `title` is observable, and has get/set accessors.\n *\n * @constructor\n * @extends {ol.layer.Layer}\n * @fires ol.render.Event\n * @param {olx.layer.ImageOptions=} opt_options Layer options.\n * @api stable\n */\nol.layer.Image = function(opt_options) {\n  var options = opt_options ? opt_options : {};\n  ol.layer.Layer.call(this,  /** @type {olx.layer.LayerOptions} */ (options));\n};\nol.inherits(ol.layer.Image, ol.layer.Layer);\n\n\n/**\n * Return the associated {@link ol.source.Image source} of the image layer.\n * @function\n * @return {ol.source.Image} Source.\n * @api stable\n */\nol.layer.Image.prototype.getSource;\n\ngoog.provide('ol.layer.Tile');\n\ngoog.require('ol');\ngoog.require('ol.layer.Layer');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * For layer sources that provide pre-rendered, tiled images in grids that are\n * organized by zoom levels for specific resolutions.\n * Note that any property set in the options is set as a {@link ol.Object}\n * property on the layer object; for example, setting `title: 'My Title'` in the\n * options means that `title` is observable, and has get/set accessors.\n *\n * @constructor\n * @extends {ol.layer.Layer}\n * @fires ol.render.Event\n * @param {olx.layer.TileOptions=} opt_options Tile layer options.\n * @api stable\n */\nol.layer.Tile = function(opt_options) {\n  var options = opt_options ? opt_options : {};\n\n  var baseOptions = ol.obj.assign({}, options);\n\n  delete baseOptions.preload;\n  delete baseOptions.useInterimTilesOnError;\n  ol.layer.Layer.call(this,  /** @type {olx.layer.LayerOptions} */ (baseOptions));\n\n  this.setPreload(options.preload !== undefined ? options.preload : 0);\n  this.setUseInterimTilesOnError(options.useInterimTilesOnError !== undefined ?\n      options.useInterimTilesOnError : true);\n};\nol.inherits(ol.layer.Tile, ol.layer.Layer);\n\n\n/**\n * Return the level as number to which we will preload tiles up to.\n * @return {number} The level to preload tiles up to.\n * @observable\n * @api\n */\nol.layer.Tile.prototype.getPreload = function() {\n  return /** @type {number} */ (this.get(ol.layer.Tile.Property.PRELOAD));\n};\n\n\n/**\n * Return the associated {@link ol.source.Tile tilesource} of the layer.\n * @function\n * @return {ol.source.Tile} Source.\n * @api stable\n */\nol.layer.Tile.prototype.getSource;\n\n\n/**\n * Set the level as number to which we will preload tiles up to.\n * @param {number} preload The level to preload tiles up to.\n * @observable\n * @api\n */\nol.layer.Tile.prototype.setPreload = function(preload) {\n  this.set(ol.layer.Tile.Property.PRELOAD, preload);\n};\n\n\n/**\n * Whether we use interim tiles on error.\n * @return {boolean} Use interim tiles on error.\n * @observable\n * @api\n */\nol.layer.Tile.prototype.getUseInterimTilesOnError = function() {\n  return /** @type {boolean} */ (\n      this.get(ol.layer.Tile.Property.USE_INTERIM_TILES_ON_ERROR));\n};\n\n\n/**\n * Set whether we use interim tiles on error.\n * @param {boolean} useInterimTilesOnError Use interim tiles on error.\n * @observable\n * @api\n */\nol.layer.Tile.prototype.setUseInterimTilesOnError = function(useInterimTilesOnError) {\n  this.set(\n      ol.layer.Tile.Property.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);\n};\n\n\n/**\n * @enum {string}\n */\nol.layer.Tile.Property = {\n  PRELOAD: 'preload',\n  USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError'\n};\n\ngoog.provide('ol.ImageBase');\n\ngoog.require('ol');\ngoog.require('ol.events.EventTarget');\ngoog.require('ol.events.EventType');\n\n\n/**\n * @constructor\n * @extends {ol.events.EventTarget}\n * @param {ol.Extent} extent Extent.\n * @param {number|undefined} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Image.State} state State.\n * @param {Array.<ol.Attribution>} attributions Attributions.\n */\nol.ImageBase = function(extent, resolution, pixelRatio, state, attributions) {\n\n  ol.events.EventTarget.call(this);\n\n  /**\n   * @private\n   * @type {Array.<ol.Attribution>}\n   */\n  this.attributions_ = attributions;\n\n  /**\n   * @protected\n   * @type {ol.Extent}\n   */\n  this.extent = extent;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.pixelRatio_ = pixelRatio;\n\n  /**\n   * @protected\n   * @type {number|undefined}\n   */\n  this.resolution = resolution;\n\n  /**\n   * @protected\n   * @type {ol.Image.State}\n   */\n  this.state = state;\n\n};\nol.inherits(ol.ImageBase, ol.events.EventTarget);\n\n\n/**\n * @protected\n */\nol.ImageBase.prototype.changed = function() {\n  this.dispatchEvent(ol.events.EventType.CHANGE);\n};\n\n\n/**\n * @return {Array.<ol.Attribution>} Attributions.\n */\nol.ImageBase.prototype.getAttributions = function() {\n  return this.attributions_;\n};\n\n\n/**\n * @return {ol.Extent} Extent.\n */\nol.ImageBase.prototype.getExtent = function() {\n  return this.extent;\n};\n\n\n/**\n * @abstract\n * @param {Object=} opt_context Object.\n * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image.\n */\nol.ImageBase.prototype.getImage = function(opt_context) {};\n\n\n/**\n * @return {number} PixelRatio.\n */\nol.ImageBase.prototype.getPixelRatio = function() {\n  return this.pixelRatio_;\n};\n\n\n/**\n * @return {number} Resolution.\n */\nol.ImageBase.prototype.getResolution = function() {\n  ol.DEBUG && console.assert(this.resolution !== undefined, 'resolution not yet set');\n  return /** @type {number} */ (this.resolution);\n};\n\n\n/**\n * @return {ol.Image.State} State.\n */\nol.ImageBase.prototype.getState = function() {\n  return this.state;\n};\n\n\n/**\n * Load not yet loaded URI.\n * @abstract\n */\nol.ImageBase.prototype.load = function() {};\n\ngoog.provide('ol.Image');\n\ngoog.require('ol');\ngoog.require('ol.ImageBase');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\n\n\n/**\n * @constructor\n * @extends {ol.ImageBase}\n * @param {ol.Extent} extent Extent.\n * @param {number|undefined} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {Array.<ol.Attribution>} attributions Attributions.\n * @param {string} src Image source URI.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.\n */\nol.Image = function(extent, resolution, pixelRatio, attributions, src,\n    crossOrigin, imageLoadFunction) {\n\n  ol.ImageBase.call(this, extent, resolution, pixelRatio, ol.Image.State.IDLE,\n      attributions);\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.src_ = src;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement|Image|HTMLVideoElement}\n   */\n  this.image_ = new Image();\n  if (crossOrigin !== null) {\n    this.image_.crossOrigin = crossOrigin;\n  }\n\n  /**\n   * @private\n   * @type {Object.<number, (HTMLCanvasElement|Image|HTMLVideoElement)>}\n   */\n  this.imageByContext_ = {};\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.imageListenerKeys_ = null;\n\n  /**\n   * @protected\n   * @type {ol.Image.State}\n   */\n  this.state = ol.Image.State.IDLE;\n\n  /**\n   * @private\n   * @type {ol.ImageLoadFunctionType}\n   */\n  this.imageLoadFunction_ = imageLoadFunction;\n\n};\nol.inherits(ol.Image, ol.ImageBase);\n\n\n/**\n * Get the HTML image element (may be a Canvas, Image, or Video).\n * @param {Object=} opt_context Object.\n * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image.\n * @api\n */\nol.Image.prototype.getImage = function(opt_context) {\n  if (opt_context !== undefined) {\n    var image;\n    var key = ol.getUid(opt_context);\n    if (key in this.imageByContext_) {\n      return this.imageByContext_[key];\n    } else if (ol.obj.isEmpty(this.imageByContext_)) {\n      image = this.image_;\n    } else {\n      image = /** @type {Image} */ (this.image_.cloneNode(false));\n    }\n    this.imageByContext_[key] = image;\n    return image;\n  } else {\n    return this.image_;\n  }\n};\n\n\n/**\n * Tracks loading or read errors.\n *\n * @private\n */\nol.Image.prototype.handleImageError_ = function() {\n  this.state = ol.Image.State.ERROR;\n  this.unlistenImage_();\n  this.changed();\n};\n\n\n/**\n * Tracks successful image load.\n *\n * @private\n */\nol.Image.prototype.handleImageLoad_ = function() {\n  if (this.resolution === undefined) {\n    this.resolution = ol.extent.getHeight(this.extent) / this.image_.height;\n  }\n  this.state = ol.Image.State.LOADED;\n  this.unlistenImage_();\n  this.changed();\n};\n\n\n/**\n * Load the image or retry if loading previously failed.\n * Loading is taken care of by the tile queue, and calling this method is\n * only needed for preloading or for reloading in case of an error.\n * @api\n */\nol.Image.prototype.load = function() {\n  if (this.state == ol.Image.State.IDLE || this.state == ol.Image.State.ERROR) {\n    this.state = ol.Image.State.LOADING;\n    this.changed();\n    ol.DEBUG && console.assert(!this.imageListenerKeys_,\n        'this.imageListenerKeys_ should be null');\n    this.imageListenerKeys_ = [\n      ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,\n          this.handleImageError_, this),\n      ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,\n          this.handleImageLoad_, this)\n    ];\n    this.imageLoadFunction_(this, this.src_);\n  }\n};\n\n\n/**\n * @param {HTMLCanvasElement|Image|HTMLVideoElement} image Image.\n */\nol.Image.prototype.setImage = function(image) {\n  this.image_ = image;\n};\n\n\n/**\n * Discards event handlers which listen for load completion or errors.\n *\n * @private\n */\nol.Image.prototype.unlistenImage_ = function() {\n  this.imageListenerKeys_.forEach(ol.events.unlistenByKey);\n  this.imageListenerKeys_ = null;\n};\n\n\n/**\n * @enum {number}\n */\nol.Image.State = {\n  IDLE: 0,\n  LOADING: 1,\n  LOADED: 2,\n  ERROR: 3\n};\n\ngoog.provide('ol.render.canvas');\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.canvas.defaultFont = '10px sans-serif';\n\n\n/**\n * @const\n * @type {ol.Color}\n */\nol.render.canvas.defaultFillStyle = [0, 0, 0, 1];\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.canvas.defaultLineCap = 'round';\n\n\n/**\n * @const\n * @type {Array.<number>}\n */\nol.render.canvas.defaultLineDash = [];\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.canvas.defaultLineJoin = 'round';\n\n\n/**\n * @const\n * @type {number}\n */\nol.render.canvas.defaultMiterLimit = 10;\n\n\n/**\n * @const\n * @type {ol.Color}\n */\nol.render.canvas.defaultStrokeStyle = [0, 0, 0, 1];\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.canvas.defaultTextAlign = 'center';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.canvas.defaultTextBaseline = 'middle';\n\n\n/**\n * @const\n * @type {number}\n */\nol.render.canvas.defaultLineWidth = 1;\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} rotation Rotation.\n * @param {number} offsetX X offset.\n * @param {number} offsetY Y offset.\n */\nol.render.canvas.rotateAtOffset = function(context, rotation, offsetX, offsetY) {\n  if (rotation !== 0) {\n    context.translate(offsetX, offsetY);\n    context.rotate(rotation);\n    context.translate(-offsetX, -offsetY);\n  }\n};\n\ngoog.provide('ol.style.Image');\n\n\n/**\n * @classdesc\n * A base class used for creating subclasses and not instantiated in\n * apps. Base class for {@link ol.style.Icon}, {@link ol.style.Circle} and\n * {@link ol.style.RegularShape}.\n *\n * @constructor\n * @param {ol.StyleImageOptions} options Options.\n * @api\n */\nol.style.Image = function(options) {\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.opacity_ = options.opacity;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.rotateWithView_ = options.rotateWithView;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.rotation_ = options.rotation;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.scale_ = options.scale;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.snapToPixel_ = options.snapToPixel;\n\n};\n\n\n/**\n * Get the symbolizer opacity.\n * @return {number} Opacity.\n * @api\n */\nol.style.Image.prototype.getOpacity = function() {\n  return this.opacity_;\n};\n\n\n/**\n * Determine whether the symbolizer rotates with the map.\n * @return {boolean} Rotate with map.\n * @api\n */\nol.style.Image.prototype.getRotateWithView = function() {\n  return this.rotateWithView_;\n};\n\n\n/**\n * Get the symoblizer rotation.\n * @return {number} Rotation.\n * @api\n */\nol.style.Image.prototype.getRotation = function() {\n  return this.rotation_;\n};\n\n\n/**\n * Get the symbolizer scale.\n * @return {number} Scale.\n * @api\n */\nol.style.Image.prototype.getScale = function() {\n  return this.scale_;\n};\n\n\n/**\n * Determine whether the symbolizer should be snapped to a pixel.\n * @return {boolean} The symbolizer should snap to a pixel.\n * @api\n */\nol.style.Image.prototype.getSnapToPixel = function() {\n  return this.snapToPixel_;\n};\n\n\n/**\n * Get the anchor point in pixels. The anchor determines the center point for the\n * symbolizer.\n * @abstract\n * @return {Array.<number>} Anchor.\n */\nol.style.Image.prototype.getAnchor = function() {};\n\n\n/**\n * Get the image element for the symbolizer.\n * @abstract\n * @param {number} pixelRatio Pixel ratio.\n * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.\n */\nol.style.Image.prototype.getImage = function(pixelRatio) {};\n\n\n/**\n * @abstract\n * @param {number} pixelRatio Pixel ratio.\n * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.\n */\nol.style.Image.prototype.getHitDetectionImage = function(pixelRatio) {};\n\n\n/**\n * @abstract\n * @return {ol.Image.State} Image state.\n */\nol.style.Image.prototype.getImageState = function() {};\n\n\n/**\n * @abstract\n * @return {ol.Size} Image size.\n */\nol.style.Image.prototype.getImageSize = function() {};\n\n\n/**\n * @abstract\n * @return {ol.Size} Size of the hit-detection image.\n */\nol.style.Image.prototype.getHitDetectionImageSize = function() {};\n\n\n/**\n * Get the origin of the symbolizer.\n * @abstract\n * @return {Array.<number>} Origin.\n */\nol.style.Image.prototype.getOrigin = function() {};\n\n\n/**\n * Get the size of the symbolizer (in pixels).\n * @abstract\n * @return {ol.Size} Size.\n */\nol.style.Image.prototype.getSize = function() {};\n\n\n/**\n * Set the opacity.\n *\n * @param {number} opacity Opacity.\n * @api\n */\nol.style.Image.prototype.setOpacity = function(opacity) {\n  this.opacity_ = opacity;\n};\n\n\n/**\n * Set whether to rotate the style with the view.\n *\n * @param {boolean} rotateWithView Rotate with map.\n */\nol.style.Image.prototype.setRotateWithView = function(rotateWithView) {\n  this.rotateWithView_ = rotateWithView;\n};\n\n\n/**\n * Set the rotation.\n *\n * @param {number} rotation Rotation.\n * @api\n */\nol.style.Image.prototype.setRotation = function(rotation) {\n  this.rotation_ = rotation;\n};\n\n\n/**\n * Set the scale.\n *\n * @param {number} scale Scale.\n * @api\n */\nol.style.Image.prototype.setScale = function(scale) {\n  this.scale_ = scale;\n};\n\n\n/**\n * Set whether to snap the image to the closest pixel.\n *\n * @param {boolean} snapToPixel Snap to pixel?\n */\nol.style.Image.prototype.setSnapToPixel = function(snapToPixel) {\n  this.snapToPixel_ = snapToPixel;\n};\n\n\n/**\n * @abstract\n * @param {function(this: T, ol.events.Event)} listener Listener function.\n * @param {T} thisArg Value to use as `this` when executing `listener`.\n * @return {ol.EventsKey|undefined} Listener key.\n * @template T\n */\nol.style.Image.prototype.listenImageChange = function(listener, thisArg) {};\n\n\n/**\n * Load not yet loaded URI.\n * @abstract\n */\nol.style.Image.prototype.load = function() {};\n\n\n/**\n * @abstract\n * @param {function(this: T, ol.events.Event)} listener Listener function.\n * @param {T} thisArg Value to use as `this` when executing `listener`.\n * @template T\n */\nol.style.Image.prototype.unlistenImageChange = function(listener, thisArg) {};\n\ngoog.provide('ol.style.RegularShape');\n\ngoog.require('ol');\ngoog.require('ol.colorlike');\ngoog.require('ol.dom');\ngoog.require('ol.has');\ngoog.require('ol.Image');\ngoog.require('ol.render.canvas');\ngoog.require('ol.style.Image');\n\n\n/**\n * @classdesc\n * Set regular shape style for vector features. The resulting shape will be\n * a regular polygon when `radius` is provided, or a star when `radius1` and\n * `radius2` are provided.\n *\n * @constructor\n * @param {olx.style.RegularShapeOptions} options Options.\n * @extends {ol.style.Image}\n * @api\n */\nol.style.RegularShape = function(options) {\n\n  ol.DEBUG && console.assert(\n      options.radius !== undefined || options.radius1 !== undefined,\n      'must provide either \"radius\" or \"radius1\"');\n\n  /**\n   * @private\n   * @type {Array.<string>}\n   */\n  this.checksums_ = null;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = null;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.hitDetectionCanvas_ = null;\n\n  /**\n   * @private\n   * @type {ol.style.Fill}\n   */\n  this.fill_ = options.fill !== undefined ? options.fill : null;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.origin_ = [0, 0];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.points_ = options.points;\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.radius_ = /** @type {number} */ (options.radius !== undefined ?\n      options.radius : options.radius1);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.radius2_ =\n      options.radius2 !== undefined ? options.radius2 : this.radius_;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.angle_ = options.angle !== undefined ? options.angle : 0;\n\n  /**\n   * @private\n   * @type {ol.style.Stroke}\n   */\n  this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.anchor_ = null;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.size_ = null;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.imageSize_ = null;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.hitDetectionImageSize_ = null;\n\n  /**\n   * @protected\n   * @type {ol.style.AtlasManager|undefined}\n   */\n  this.atlasManager_ = options.atlasManager;\n\n  this.render_(this.atlasManager_);\n\n  /**\n   * @type {boolean}\n   */\n  var snapToPixel = options.snapToPixel !== undefined ?\n      options.snapToPixel : true;\n\n  /**\n   * @type {boolean}\n   */\n  var rotateWithView = options.rotateWithView !== undefined ?\n      options.rotateWithView : false;\n\n  ol.style.Image.call(this, {\n    opacity: 1,\n    rotateWithView: rotateWithView,\n    rotation: options.rotation !== undefined ? options.rotation : 0,\n    scale: 1,\n    snapToPixel: snapToPixel\n  });\n\n};\nol.inherits(ol.style.RegularShape, ol.style.Image);\n\n\n/**\n * Clones the style. If an atlasmanager was provided to the original style it will be used in the cloned style, too.\n * @return {ol.style.RegularShape} The cloned style.\n * @api\n */\nol.style.RegularShape.prototype.clone = function() {\n  var style = new ol.style.RegularShape({\n    fill: this.getFill() ? this.getFill().clone() : undefined,\n    points: this.getRadius2() !== this.getRadius() ? this.getPoints() / 2 : this.getPoints(),\n    radius: this.getRadius(),\n    radius2: this.getRadius2(),\n    angle: this.getAngle(),\n    snapToPixel: this.getSnapToPixel(),\n    stroke: this.getStroke() ?  this.getStroke().clone() : undefined,\n    rotation: this.getRotation(),\n    rotateWithView: this.getRotateWithView(),\n    atlasManager: this.atlasManager_\n  });\n  style.setOpacity(this.getOpacity());\n  style.setScale(this.getScale());\n  return style;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.style.RegularShape.prototype.getAnchor = function() {\n  return this.anchor_;\n};\n\n\n/**\n * Get the angle used in generating the shape.\n * @return {number} Shape's rotation in radians.\n * @api\n */\nol.style.RegularShape.prototype.getAngle = function() {\n  return this.angle_;\n};\n\n\n/**\n * Get the fill style for the shape.\n * @return {ol.style.Fill} Fill style.\n * @api\n */\nol.style.RegularShape.prototype.getFill = function() {\n  return this.fill_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.RegularShape.prototype.getHitDetectionImage = function(pixelRatio) {\n  return this.hitDetectionCanvas_;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.style.RegularShape.prototype.getImage = function(pixelRatio) {\n  return this.canvas_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.RegularShape.prototype.getImageSize = function() {\n  return this.imageSize_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.RegularShape.prototype.getHitDetectionImageSize = function() {\n  return this.hitDetectionImageSize_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.RegularShape.prototype.getImageState = function() {\n  return ol.Image.State.LOADED;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.style.RegularShape.prototype.getOrigin = function() {\n  return this.origin_;\n};\n\n\n/**\n * Get the number of points for generating the shape.\n * @return {number} Number of points for stars and regular polygons.\n * @api\n */\nol.style.RegularShape.prototype.getPoints = function() {\n  return this.points_;\n};\n\n\n/**\n * Get the (primary) radius for the shape.\n * @return {number} Radius.\n * @api\n */\nol.style.RegularShape.prototype.getRadius = function() {\n  return this.radius_;\n};\n\n\n/**\n * Get the secondary radius for the shape.\n * @return {number} Radius2.\n * @api\n */\nol.style.RegularShape.prototype.getRadius2 = function() {\n  return this.radius2_;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.style.RegularShape.prototype.getSize = function() {\n  return this.size_;\n};\n\n\n/**\n * Get the stroke style for the shape.\n * @return {ol.style.Stroke} Stroke style.\n * @api\n */\nol.style.RegularShape.prototype.getStroke = function() {\n  return this.stroke_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.RegularShape.prototype.listenImageChange = ol.nullFunction;\n\n\n/**\n * @inheritDoc\n */\nol.style.RegularShape.prototype.load = ol.nullFunction;\n\n\n/**\n * @inheritDoc\n */\nol.style.RegularShape.prototype.unlistenImageChange = ol.nullFunction;\n\n\n/**\n * @protected\n * @param {ol.style.AtlasManager|undefined} atlasManager An atlas manager.\n */\nol.style.RegularShape.prototype.render_ = function(atlasManager) {\n  var imageSize;\n  var lineCap = '';\n  var lineJoin = '';\n  var miterLimit = 0;\n  var lineDash = null;\n  var strokeStyle;\n  var strokeWidth = 0;\n\n  if (this.stroke_) {\n    strokeStyle = ol.colorlike.asColorLike(this.stroke_.getColor());\n    strokeWidth = this.stroke_.getWidth();\n    if (strokeWidth === undefined) {\n      strokeWidth = ol.render.canvas.defaultLineWidth;\n    }\n    lineDash = this.stroke_.getLineDash();\n    if (!ol.has.CANVAS_LINE_DASH) {\n      lineDash = null;\n    }\n    lineJoin = this.stroke_.getLineJoin();\n    if (lineJoin === undefined) {\n      lineJoin = ol.render.canvas.defaultLineJoin;\n    }\n    lineCap = this.stroke_.getLineCap();\n    if (lineCap === undefined) {\n      lineCap = ol.render.canvas.defaultLineCap;\n    }\n    miterLimit = this.stroke_.getMiterLimit();\n    if (miterLimit === undefined) {\n      miterLimit = ol.render.canvas.defaultMiterLimit;\n    }\n  }\n\n  var size = 2 * (this.radius_ + strokeWidth) + 1;\n\n  /** @type {ol.RegularShapeRenderOptions} */\n  var renderOptions = {\n    strokeStyle: strokeStyle,\n    strokeWidth: strokeWidth,\n    size: size,\n    lineCap: lineCap,\n    lineDash: lineDash,\n    lineJoin: lineJoin,\n    miterLimit: miterLimit\n  };\n\n  if (atlasManager === undefined) {\n    // no atlas manager is used, create a new canvas\n    var context = ol.dom.createCanvasContext2D(size, size);\n    this.canvas_ = context.canvas;\n\n    // canvas.width and height are rounded to the closest integer\n    size = this.canvas_.width;\n    imageSize = size;\n\n    this.draw_(renderOptions, context, 0, 0);\n\n    this.createHitDetectionCanvas_(renderOptions);\n  } else {\n    // an atlas manager is used, add the symbol to an atlas\n    size = Math.round(size);\n\n    var hasCustomHitDetectionImage = !this.fill_;\n    var renderHitDetectionCallback;\n    if (hasCustomHitDetectionImage) {\n      // render the hit-detection image into a separate atlas image\n      renderHitDetectionCallback =\n          this.drawHitDetectionCanvas_.bind(this, renderOptions);\n    }\n\n    var id = this.getChecksum();\n    var info = atlasManager.add(\n        id, size, size, this.draw_.bind(this, renderOptions),\n        renderHitDetectionCallback);\n    ol.DEBUG && console.assert(info, 'shape size is too large');\n\n    this.canvas_ = info.image;\n    this.origin_ = [info.offsetX, info.offsetY];\n    imageSize = info.image.width;\n\n    if (hasCustomHitDetectionImage) {\n      this.hitDetectionCanvas_ = info.hitImage;\n      this.hitDetectionImageSize_ =\n          [info.hitImage.width, info.hitImage.height];\n    } else {\n      this.hitDetectionCanvas_ = this.canvas_;\n      this.hitDetectionImageSize_ = [imageSize, imageSize];\n    }\n  }\n\n  this.anchor_ = [size / 2, size / 2];\n  this.size_ = [size, size];\n  this.imageSize_ = [imageSize, imageSize];\n};\n\n\n/**\n * @private\n * @param {ol.RegularShapeRenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The rendering context.\n * @param {number} x The origin for the symbol (x).\n * @param {number} y The origin for the symbol (y).\n */\nol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) {\n  var i, angle0, radiusC;\n  // reset transform\n  context.setTransform(1, 0, 0, 1, 0, 0);\n\n  // then move to (x, y)\n  context.translate(x, y);\n\n  context.beginPath();\n\n  if (this.points_ === Infinity) {\n    context.arc(\n        renderOptions.size / 2, renderOptions.size / 2,\n        this.radius_, 0, 2 * Math.PI, true);\n  } else {\n    if (this.radius2_ !== this.radius_) {\n      this.points_ = 2 * this.points_;\n    }\n    for (i = 0; i <= this.points_; i++) {\n      angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;\n      radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;\n      context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),\n                     renderOptions.size / 2 + radiusC * Math.sin(angle0));\n    }\n  }\n\n\n  if (this.fill_) {\n    context.fillStyle = ol.colorlike.asColorLike(this.fill_.getColor());\n    context.fill();\n  }\n  if (this.stroke_) {\n    context.strokeStyle = renderOptions.strokeStyle;\n    context.lineWidth = renderOptions.strokeWidth;\n    if (renderOptions.lineDash) {\n      context.setLineDash(renderOptions.lineDash);\n    }\n    context.lineCap = renderOptions.lineCap;\n    context.lineJoin = renderOptions.lineJoin;\n    context.miterLimit = renderOptions.miterLimit;\n    context.stroke();\n  }\n  context.closePath();\n};\n\n\n/**\n * @private\n * @param {ol.RegularShapeRenderOptions} renderOptions Render options.\n */\nol.style.RegularShape.prototype.createHitDetectionCanvas_ = function(renderOptions) {\n  this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size];\n  if (this.fill_) {\n    this.hitDetectionCanvas_ = this.canvas_;\n    return;\n  }\n\n  // if no fill style is set, create an extra hit-detection image with a\n  // default fill style\n  var context = ol.dom.createCanvasContext2D(renderOptions.size, renderOptions.size);\n  this.hitDetectionCanvas_ = context.canvas;\n\n  this.drawHitDetectionCanvas_(renderOptions, context, 0, 0);\n};\n\n\n/**\n * @private\n * @param {ol.RegularShapeRenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The context.\n * @param {number} x The origin for the symbol (x).\n * @param {number} y The origin for the symbol (y).\n */\nol.style.RegularShape.prototype.drawHitDetectionCanvas_ = function(renderOptions, context, x, y) {\n  // reset transform\n  context.setTransform(1, 0, 0, 1, 0, 0);\n\n  // then move to (x, y)\n  context.translate(x, y);\n\n  context.beginPath();\n\n  if (this.points_ === Infinity) {\n    context.arc(\n        renderOptions.size / 2, renderOptions.size / 2,\n        this.radius_, 0, 2 * Math.PI, true);\n  } else {\n    if (this.radius2_ !== this.radius_) {\n      this.points_ = 2 * this.points_;\n    }\n    var i, radiusC, angle0;\n    for (i = 0; i <= this.points_; i++) {\n      angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;\n      radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;\n      context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),\n                     renderOptions.size / 2 + radiusC * Math.sin(angle0));\n    }\n  }\n\n  context.fillStyle = ol.render.canvas.defaultFillStyle;\n  context.fill();\n  if (this.stroke_) {\n    context.strokeStyle = renderOptions.strokeStyle;\n    context.lineWidth = renderOptions.strokeWidth;\n    if (renderOptions.lineDash) {\n      context.setLineDash(renderOptions.lineDash);\n    }\n    context.stroke();\n  }\n  context.closePath();\n};\n\n\n/**\n * @return {string} The checksum.\n */\nol.style.RegularShape.prototype.getChecksum = function() {\n  var strokeChecksum = this.stroke_ ?\n      this.stroke_.getChecksum() : '-';\n  var fillChecksum = this.fill_ ?\n      this.fill_.getChecksum() : '-';\n\n  var recalculate = !this.checksums_ ||\n      (strokeChecksum != this.checksums_[1] ||\n      fillChecksum != this.checksums_[2] ||\n      this.radius_ != this.checksums_[3] ||\n      this.radius2_ != this.checksums_[4] ||\n      this.angle_ != this.checksums_[5] ||\n      this.points_ != this.checksums_[6]);\n\n  if (recalculate) {\n    var checksum = 'r' + strokeChecksum + fillChecksum +\n        (this.radius_ !== undefined ? this.radius_.toString() : '-') +\n        (this.radius2_ !== undefined ? this.radius2_.toString() : '-') +\n        (this.angle_ !== undefined ? this.angle_.toString() : '-') +\n        (this.points_ !== undefined ? this.points_.toString() : '-');\n    this.checksums_ = [checksum, strokeChecksum, fillChecksum,\n      this.radius_, this.radius2_, this.angle_, this.points_];\n  }\n\n  return this.checksums_[0];\n};\n\ngoog.provide('ol.style.Circle');\n\ngoog.require('ol');\ngoog.require('ol.style.RegularShape');\n\n\n/**\n * @classdesc\n * Set circle style for vector features.\n *\n * @constructor\n * @param {olx.style.CircleOptions=} opt_options Options.\n * @extends {ol.style.RegularShape}\n * @api\n */\nol.style.Circle = function(opt_options) {\n\n  var options = opt_options || {};\n\n  ol.style.RegularShape.call(this, {\n    points: Infinity,\n    fill: options.fill,\n    radius: options.radius,\n    snapToPixel: options.snapToPixel,\n    stroke: options.stroke,\n    atlasManager: options.atlasManager\n  });\n\n};\nol.inherits(ol.style.Circle, ol.style.RegularShape);\n\n\n/**\n * Clones the style.  If an atlasmanager was provided to the original style it will be used in the cloned style, too.\n * @return {ol.style.Circle} The cloned style.\n * @api\n */\nol.style.Circle.prototype.clone = function() {\n  var style = new ol.style.Circle({\n    fill: this.getFill() ? this.getFill().clone() : undefined,\n    stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n    radius: this.getRadius(),\n    snapToPixel: this.getSnapToPixel(),\n    atlasManager: this.atlasManager_\n  });\n  style.setOpacity(this.getOpacity());\n  style.setScale(this.getScale());\n  return style;\n};\n\n\n/**\n * Set the circle radius.\n *\n * @param {number} radius Circle radius.\n * @api\n */\nol.style.Circle.prototype.setRadius = function(radius) {\n  this.radius_ = radius;\n  this.render_(this.atlasManager_);\n};\n\ngoog.provide('ol.style.Fill');\n\ngoog.require('ol');\ngoog.require('ol.color');\n\n\n/**\n * @classdesc\n * Set fill style for vector features.\n *\n * @constructor\n * @param {olx.style.FillOptions=} opt_options Options.\n * @api\n */\nol.style.Fill = function(opt_options) {\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {ol.Color|ol.ColorLike}\n   */\n  this.color_ = options.color !== undefined ? options.color : null;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.checksum_ = undefined;\n};\n\n\n/**\n * Clones the style. The color is not cloned if it is an {@link ol.ColorLike}.\n * @return {ol.style.Fill} The cloned style.\n * @api\n */\nol.style.Fill.prototype.clone = function() {\n  var color = this.getColor();\n  return new ol.style.Fill({\n    color: (color && color.slice) ? color.slice() : color || undefined\n  });\n};\n\n\n/**\n * Get the fill color.\n * @return {ol.Color|ol.ColorLike} Color.\n * @api\n */\nol.style.Fill.prototype.getColor = function() {\n  return this.color_;\n};\n\n\n/**\n * Set the color.\n *\n * @param {ol.Color|ol.ColorLike} color Color.\n * @api\n */\nol.style.Fill.prototype.setColor = function(color) {\n  this.color_ = color;\n  this.checksum_ = undefined;\n};\n\n\n/**\n * @return {string} The checksum.\n */\nol.style.Fill.prototype.getChecksum = function() {\n  if (this.checksum_ === undefined) {\n    if (\n        this.color_ instanceof CanvasPattern ||\n        this.color_ instanceof CanvasGradient\n    ) {\n      this.checksum_ = ol.getUid(this.color_).toString();\n    } else {\n      this.checksum_ = 'f' + (this.color_ ?\n          ol.color.asString(this.color_) : '-');\n    }\n  }\n\n  return this.checksum_;\n};\n\ngoog.provide('ol.style.Stroke');\n\ngoog.require('ol');\n\n\n/**\n * @classdesc\n * Set stroke style for vector features.\n * Note that the defaults given are the Canvas defaults, which will be used if\n * option is not defined. The `get` functions return whatever was entered in\n * the options; they will not return the default.\n *\n * @constructor\n * @param {olx.style.StrokeOptions=} opt_options Options.\n * @api\n */\nol.style.Stroke = function(opt_options) {\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {ol.Color|ol.ColorLike}\n   */\n  this.color_ = options.color !== undefined ? options.color : null;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.lineCap_ = options.lineCap;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.lineJoin_ = options.lineJoin;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.miterLimit_ = options.miterLimit;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.width_ = options.width;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.checksum_ = undefined;\n};\n\n\n/**\n * Clones the style.\n * @return {ol.style.Stroke} The cloned style.\n * @api\n */\nol.style.Stroke.prototype.clone = function() {\n  var color = this.getColor();\n  return new ol.style.Stroke({\n    color: (color && color.slice) ? color.slice() : color || undefined,\n    lineCap: this.getLineCap(),\n    lineDash: this.getLineDash() ? this.getLineDash().slice() : undefined,\n    lineJoin: this.getLineJoin(),\n    miterLimit: this.getMiterLimit(),\n    width: this.getWidth()\n  });\n};\n\n\n/**\n * Get the stroke color.\n * @return {ol.Color|ol.ColorLike} Color.\n * @api\n */\nol.style.Stroke.prototype.getColor = function() {\n  return this.color_;\n};\n\n\n/**\n * Get the line cap type for the stroke.\n * @return {string|undefined} Line cap.\n * @api\n */\nol.style.Stroke.prototype.getLineCap = function() {\n  return this.lineCap_;\n};\n\n\n/**\n * Get the line dash style for the stroke.\n * @return {Array.<number>} Line dash.\n * @api\n */\nol.style.Stroke.prototype.getLineDash = function() {\n  return this.lineDash_;\n};\n\n\n/**\n * Get the line join type for the stroke.\n * @return {string|undefined} Line join.\n * @api\n */\nol.style.Stroke.prototype.getLineJoin = function() {\n  return this.lineJoin_;\n};\n\n\n/**\n * Get the miter limit for the stroke.\n * @return {number|undefined} Miter limit.\n * @api\n */\nol.style.Stroke.prototype.getMiterLimit = function() {\n  return this.miterLimit_;\n};\n\n\n/**\n * Get the stroke width.\n * @return {number|undefined} Width.\n * @api\n */\nol.style.Stroke.prototype.getWidth = function() {\n  return this.width_;\n};\n\n\n/**\n * Set the color.\n *\n * @param {ol.Color|ol.ColorLike} color Color.\n * @api\n */\nol.style.Stroke.prototype.setColor = function(color) {\n  this.color_ = color;\n  this.checksum_ = undefined;\n};\n\n\n/**\n * Set the line cap.\n *\n * @param {string|undefined} lineCap Line cap.\n * @api\n */\nol.style.Stroke.prototype.setLineCap = function(lineCap) {\n  this.lineCap_ = lineCap;\n  this.checksum_ = undefined;\n};\n\n\n/**\n * Set the line dash.\n *\n * Please note that Internet Explorer 10 and lower [do not support][mdn] the\n * `setLineDash` method on the `CanvasRenderingContext2D` and therefore this\n * property will have no visual effect in these browsers.\n *\n * [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility\n *\n * @param {Array.<number>} lineDash Line dash.\n * @api\n */\nol.style.Stroke.prototype.setLineDash = function(lineDash) {\n  this.lineDash_ = lineDash;\n  this.checksum_ = undefined;\n};\n\n\n/**\n * Set the line join.\n *\n * @param {string|undefined} lineJoin Line join.\n * @api\n */\nol.style.Stroke.prototype.setLineJoin = function(lineJoin) {\n  this.lineJoin_ = lineJoin;\n  this.checksum_ = undefined;\n};\n\n\n/**\n * Set the miter limit.\n *\n * @param {number|undefined} miterLimit Miter limit.\n * @api\n */\nol.style.Stroke.prototype.setMiterLimit = function(miterLimit) {\n  this.miterLimit_ = miterLimit;\n  this.checksum_ = undefined;\n};\n\n\n/**\n * Set the width.\n *\n * @param {number|undefined} width Width.\n * @api\n */\nol.style.Stroke.prototype.setWidth = function(width) {\n  this.width_ = width;\n  this.checksum_ = undefined;\n};\n\n\n/**\n * @return {string} The checksum.\n */\nol.style.Stroke.prototype.getChecksum = function() {\n  if (this.checksum_ === undefined) {\n    this.checksum_ = 's';\n    if (this.color_) {\n      if (typeof this.color_ === 'string') {\n        this.checksum_ += this.color_;\n      } else {\n        this.checksum_ += ol.getUid(this.color_).toString();\n      }\n    } else {\n      this.checksum_ += '-';\n    }\n    this.checksum_ += ',' +\n        (this.lineCap_ !== undefined ?\n            this.lineCap_.toString() : '-') + ',' +\n        (this.lineDash_ ?\n            this.lineDash_.toString() : '-') + ',' +\n        (this.lineJoin_ !== undefined ?\n            this.lineJoin_ : '-') + ',' +\n        (this.miterLimit_ !== undefined ?\n            this.miterLimit_.toString() : '-') + ',' +\n        (this.width_ !== undefined ?\n            this.width_.toString() : '-');\n  }\n\n  return this.checksum_;\n};\n\ngoog.provide('ol.style.Style');\n\ngoog.require('ol.asserts');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.style.Circle');\ngoog.require('ol.style.Fill');\ngoog.require('ol.style.Stroke');\n\n\n/**\n * @classdesc\n * Container for vector feature rendering styles. Any changes made to the style\n * or its children through `set*()` methods will not take effect until the\n * feature or layer that uses the style is re-rendered.\n *\n * @constructor\n * @struct\n * @param {olx.style.StyleOptions=} opt_options Style options.\n * @api\n */\nol.style.Style = function(opt_options) {\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {string|ol.geom.Geometry|ol.StyleGeometryFunction}\n   */\n  this.geometry_ = null;\n\n  /**\n   * @private\n   * @type {!ol.StyleGeometryFunction}\n   */\n  this.geometryFunction_ = ol.style.Style.defaultGeometryFunction;\n\n  if (options.geometry !== undefined) {\n    this.setGeometry(options.geometry);\n  }\n\n  /**\n   * @private\n   * @type {ol.style.Fill}\n   */\n  this.fill_ = options.fill !== undefined ? options.fill : null;\n\n  /**\n   * @private\n   * @type {ol.style.Image}\n   */\n  this.image_ = options.image !== undefined ? options.image : null;\n\n  /**\n   * @private\n   * @type {ol.style.Stroke}\n   */\n  this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n  /**\n   * @private\n   * @type {ol.style.Text}\n   */\n  this.text_ = options.text !== undefined ? options.text : null;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.zIndex_ = options.zIndex;\n\n};\n\n\n/**\n * Clones the style.\n * @return {ol.style.Style} The cloned style.\n * @api\n */\nol.style.Style.prototype.clone = function() {\n  var geometry = this.getGeometry();\n  if (geometry && geometry.clone) {\n    geometry = geometry.clone();\n  }\n  return new ol.style.Style({\n    geometry: geometry,\n    fill: this.getFill() ? this.getFill().clone() : undefined,\n    image: this.getImage() ? this.getImage().clone() : undefined,\n    stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n    text: this.getText() ? this.getText().clone() : undefined,\n    zIndex: this.getZIndex()\n  });\n};\n\n\n/**\n * Get the geometry to be rendered.\n * @return {string|ol.geom.Geometry|ol.StyleGeometryFunction}\n * Feature property or geometry or function that returns the geometry that will\n * be rendered with this style.\n * @api\n */\nol.style.Style.prototype.getGeometry = function() {\n  return this.geometry_;\n};\n\n\n/**\n * Get the function used to generate a geometry for rendering.\n * @return {!ol.StyleGeometryFunction} Function that is called with a feature\n * and returns the geometry to render instead of the feature's geometry.\n * @api\n */\nol.style.Style.prototype.getGeometryFunction = function() {\n  return this.geometryFunction_;\n};\n\n\n/**\n * Get the fill style.\n * @return {ol.style.Fill} Fill style.\n * @api\n */\nol.style.Style.prototype.getFill = function() {\n  return this.fill_;\n};\n\n\n/**\n * Set the fill style.\n * @param {ol.style.Fill} fill Fill style.\n * @api\n */\nol.style.Style.prototype.setFill = function(fill) {\n  this.fill_ = fill;\n};\n\n\n/**\n * Get the image style.\n * @return {ol.style.Image} Image style.\n * @api\n */\nol.style.Style.prototype.getImage = function() {\n  return this.image_;\n};\n\n\n/**\n * Set the image style.\n * @param {ol.style.Image} image Image style.\n * @api\n */\nol.style.Style.prototype.setImage = function(image) {\n  this.image_ = image;\n};\n\n\n/**\n * Get the stroke style.\n * @return {ol.style.Stroke} Stroke style.\n * @api\n */\nol.style.Style.prototype.getStroke = function() {\n  return this.stroke_;\n};\n\n\n/**\n * Set the stroke style.\n * @param {ol.style.Stroke} stroke Stroke style.\n * @api\n */\nol.style.Style.prototype.setStroke = function(stroke) {\n  this.stroke_ = stroke;\n};\n\n\n/**\n * Get the text style.\n * @return {ol.style.Text} Text style.\n * @api\n */\nol.style.Style.prototype.getText = function() {\n  return this.text_;\n};\n\n\n/**\n * Set the text style.\n * @param {ol.style.Text} text Text style.\n * @api\n */\nol.style.Style.prototype.setText = function(text) {\n  this.text_ = text;\n};\n\n\n/**\n * Get the z-index for the style.\n * @return {number|undefined} ZIndex.\n * @api\n */\nol.style.Style.prototype.getZIndex = function() {\n  return this.zIndex_;\n};\n\n\n/**\n * Set a geometry that is rendered instead of the feature's geometry.\n *\n * @param {string|ol.geom.Geometry|ol.StyleGeometryFunction} geometry\n *     Feature property or geometry or function returning a geometry to render\n *     for this style.\n * @api\n */\nol.style.Style.prototype.setGeometry = function(geometry) {\n  if (typeof geometry === 'function') {\n    this.geometryFunction_ = geometry;\n  } else if (typeof geometry === 'string') {\n    this.geometryFunction_ = function(feature) {\n      return /** @type {ol.geom.Geometry} */ (feature.get(geometry));\n    };\n  } else if (!geometry) {\n    this.geometryFunction_ = ol.style.Style.defaultGeometryFunction;\n  } else if (geometry !== undefined) {\n    this.geometryFunction_ = function() {\n      return /** @type {ol.geom.Geometry} */ (geometry);\n    };\n  }\n  this.geometry_ = geometry;\n};\n\n\n/**\n * Set the z-index.\n *\n * @param {number|undefined} zIndex ZIndex.\n * @api\n */\nol.style.Style.prototype.setZIndex = function(zIndex) {\n  this.zIndex_ = zIndex;\n};\n\n\n/**\n * Convert the provided object into a style function.  Functions passed through\n * unchanged.  Arrays of ol.style.Style or single style objects wrapped in a\n * new style function.\n * @param {ol.StyleFunction|Array.<ol.style.Style>|ol.style.Style} obj\n *     A style function, a single style, or an array of styles.\n * @return {ol.StyleFunction} A style function.\n */\nol.style.Style.createFunction = function(obj) {\n  var styleFunction;\n\n  if (typeof obj === 'function') {\n    styleFunction = obj;\n  } else {\n    /**\n     * @type {Array.<ol.style.Style>}\n     */\n    var styles;\n    if (Array.isArray(obj)) {\n      styles = obj;\n    } else {\n      ol.asserts.assert(obj instanceof ol.style.Style,\n          41); // Expected an `ol.style.Style` or an array of `ol.style.Style`\n      styles = [obj];\n    }\n    styleFunction = function() {\n      return styles;\n    };\n  }\n  return styleFunction;\n};\n\n\n/**\n * @type {Array.<ol.style.Style>}\n * @private\n */\nol.style.Style.default_ = null;\n\n\n/**\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @param {number} resolution Resolution.\n * @return {Array.<ol.style.Style>} Style.\n */\nol.style.Style.defaultFunction = function(feature, resolution) {\n  // We don't use an immediately-invoked function\n  // and a closure so we don't get an error at script evaluation time in\n  // browsers that do not support Canvas. (ol.style.Circle does\n  // canvas.getContext('2d') at construction time, which will cause an.error\n  // in such browsers.)\n  if (!ol.style.Style.default_) {\n    var fill = new ol.style.Fill({\n      color: 'rgba(255,255,255,0.4)'\n    });\n    var stroke = new ol.style.Stroke({\n      color: '#3399CC',\n      width: 1.25\n    });\n    ol.style.Style.default_ = [\n      new ol.style.Style({\n        image: new ol.style.Circle({\n          fill: fill,\n          stroke: stroke,\n          radius: 5\n        }),\n        fill: fill,\n        stroke: stroke\n      })\n    ];\n  }\n  return ol.style.Style.default_;\n};\n\n\n/**\n * Default styles for editing features.\n * @return {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} Styles\n */\nol.style.Style.createDefaultEditing = function() {\n  /** @type {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} */\n  var styles = {};\n  var white = [255, 255, 255, 1];\n  var blue = [0, 153, 255, 1];\n  var width = 3;\n  styles[ol.geom.GeometryType.POLYGON] = [\n    new ol.style.Style({\n      fill: new ol.style.Fill({\n        color: [255, 255, 255, 0.5]\n      })\n    })\n  ];\n  styles[ol.geom.GeometryType.MULTI_POLYGON] =\n      styles[ol.geom.GeometryType.POLYGON];\n\n  styles[ol.geom.GeometryType.LINE_STRING] = [\n    new ol.style.Style({\n      stroke: new ol.style.Stroke({\n        color: white,\n        width: width + 2\n      })\n    }),\n    new ol.style.Style({\n      stroke: new ol.style.Stroke({\n        color: blue,\n        width: width\n      })\n    })\n  ];\n  styles[ol.geom.GeometryType.MULTI_LINE_STRING] =\n      styles[ol.geom.GeometryType.LINE_STRING];\n\n  styles[ol.geom.GeometryType.CIRCLE] =\n      styles[ol.geom.GeometryType.POLYGON].concat(\n          styles[ol.geom.GeometryType.LINE_STRING]\n      );\n\n\n  styles[ol.geom.GeometryType.POINT] = [\n    new ol.style.Style({\n      image: new ol.style.Circle({\n        radius: width * 2,\n        fill: new ol.style.Fill({\n          color: blue\n        }),\n        stroke: new ol.style.Stroke({\n          color: white,\n          width: width / 2\n        })\n      }),\n      zIndex: Infinity\n    })\n  ];\n  styles[ol.geom.GeometryType.MULTI_POINT] =\n      styles[ol.geom.GeometryType.POINT];\n\n  styles[ol.geom.GeometryType.GEOMETRY_COLLECTION] =\n      styles[ol.geom.GeometryType.POLYGON].concat(\n          styles[ol.geom.GeometryType.LINE_STRING],\n          styles[ol.geom.GeometryType.POINT]\n      );\n\n  return styles;\n};\n\n\n/**\n * Function that is called with a feature and returns its default geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature to get the geometry\n *     for.\n * @return {ol.geom.Geometry|ol.render.Feature|undefined} Geometry to render.\n */\nol.style.Style.defaultGeometryFunction = function(feature) {\n  return feature.getGeometry();\n};\n\ngoog.provide('ol.layer.Vector');\n\ngoog.require('ol');\ngoog.require('ol.layer.Layer');\ngoog.require('ol.obj');\ngoog.require('ol.style.Style');\n\n\n/**\n * @classdesc\n * Vector data that is rendered client-side.\n * Note that any property set in the options is set as a {@link ol.Object}\n * property on the layer object; for example, setting `title: 'My Title'` in the\n * options means that `title` is observable, and has get/set accessors.\n *\n * @constructor\n * @extends {ol.layer.Layer}\n * @fires ol.render.Event\n * @param {olx.layer.VectorOptions=} opt_options Options.\n * @api stable\n */\nol.layer.Vector = function(opt_options) {\n\n  var options = opt_options ?\n      opt_options : /** @type {olx.layer.VectorOptions} */ ({});\n\n  ol.DEBUG && console.assert(\n      options.renderOrder === undefined || !options.renderOrder ||\n      typeof options.renderOrder === 'function',\n      'renderOrder must be a comparator function');\n\n  var baseOptions = ol.obj.assign({}, options);\n\n  delete baseOptions.style;\n  delete baseOptions.renderBuffer;\n  delete baseOptions.updateWhileAnimating;\n  delete baseOptions.updateWhileInteracting;\n  ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.renderBuffer_ = options.renderBuffer !== undefined ?\n      options.renderBuffer : 100;\n\n  /**\n   * User provided style.\n   * @type {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}\n   * @private\n   */\n  this.style_ = null;\n\n  /**\n   * Style function for use within the library.\n   * @type {ol.StyleFunction|undefined}\n   * @private\n   */\n  this.styleFunction_ = undefined;\n\n  this.setStyle(options.style);\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.updateWhileAnimating_ = options.updateWhileAnimating !== undefined ?\n      options.updateWhileAnimating : false;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.updateWhileInteracting_ = options.updateWhileInteracting !== undefined ?\n      options.updateWhileInteracting : false;\n\n};\nol.inherits(ol.layer.Vector, ol.layer.Layer);\n\n\n/**\n * @return {number|undefined} Render buffer.\n */\nol.layer.Vector.prototype.getRenderBuffer = function() {\n  return this.renderBuffer_;\n};\n\n\n/**\n * @return {function(ol.Feature, ol.Feature): number|null|undefined} Render\n *     order.\n */\nol.layer.Vector.prototype.getRenderOrder = function() {\n  return /** @type {function(ol.Feature, ol.Feature):number|null|undefined} */ (\n      this.get(ol.layer.Vector.Property.RENDER_ORDER));\n};\n\n\n/**\n * Return the associated {@link ol.source.Vector vectorsource} of the layer.\n * @function\n * @return {ol.source.Vector} Source.\n * @api stable\n */\nol.layer.Vector.prototype.getSource;\n\n\n/**\n * Get the style for features.  This returns whatever was passed to the `style`\n * option at construction or to the `setStyle` method.\n * @return {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}\n *     Layer style.\n * @api stable\n */\nol.layer.Vector.prototype.getStyle = function() {\n  return this.style_;\n};\n\n\n/**\n * Get the style function.\n * @return {ol.StyleFunction|undefined} Layer style function.\n * @api stable\n */\nol.layer.Vector.prototype.getStyleFunction = function() {\n  return this.styleFunction_;\n};\n\n\n/**\n * @return {boolean} Whether the rendered layer should be updated while\n *     animating.\n */\nol.layer.Vector.prototype.getUpdateWhileAnimating = function() {\n  return this.updateWhileAnimating_;\n};\n\n\n/**\n * @return {boolean} Whether the rendered layer should be updated while\n *     interacting.\n */\nol.layer.Vector.prototype.getUpdateWhileInteracting = function() {\n  return this.updateWhileInteracting_;\n};\n\n\n/**\n * @param {function(ol.Feature, ol.Feature):number|null|undefined} renderOrder\n *     Render order.\n */\nol.layer.Vector.prototype.setRenderOrder = function(renderOrder) {\n  ol.DEBUG && console.assert(\n      renderOrder === undefined || !renderOrder ||\n      typeof renderOrder === 'function',\n      'renderOrder must be a comparator function');\n  this.set(ol.layer.Vector.Property.RENDER_ORDER, renderOrder);\n};\n\n\n/**\n * Set the style for features.  This can be a single style object, an array\n * of styles, or a function that takes a feature and resolution and returns\n * an array of styles. If it is `undefined` the default style is used. If\n * it is `null` the layer has no style (a `null` style), so only features\n * that have their own styles will be rendered in the layer. See\n * {@link ol.style} for information on the default style.\n * @param {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|null|undefined}\n *     style Layer style.\n * @api stable\n */\nol.layer.Vector.prototype.setStyle = function(style) {\n  this.style_ = style !== undefined ? style : ol.style.Style.defaultFunction;\n  this.styleFunction_ = style === null ?\n      undefined : ol.style.Style.createFunction(this.style_);\n  this.changed();\n};\n\n\n/**\n * @enum {string}\n */\nol.layer.Vector.Property = {\n  RENDER_ORDER: 'renderOrder'\n};\n\ngoog.provide('ol.layer.VectorTile');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.layer.Tile');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * Layer for vector tile data that is rendered client-side.\n * Note that any property set in the options is set as a {@link ol.Object}\n * property on the layer object; for example, setting `title: 'My Title'` in the\n * options means that `title` is observable, and has get/set accessors.\n *\n * @constructor\n * @extends {ol.layer.Vector}\n * @param {olx.layer.VectorTileOptions=} opt_options Options.\n * @api\n */\nol.layer.VectorTile = function(opt_options) {\n  var options = opt_options ? opt_options : {};\n\n  var baseOptions = ol.obj.assign({}, options);\n\n  delete baseOptions.preload;\n  delete baseOptions.useInterimTilesOnError;\n  ol.layer.Vector.call(this,  /** @type {olx.layer.VectorOptions} */ (baseOptions));\n\n  this.setPreload(options.preload ? options.preload : 0);\n  this.setUseInterimTilesOnError(options.useInterimTilesOnError ?\n      options.useInterimTilesOnError : true);\n\n  ol.asserts.assert(options.renderMode == undefined ||\n      options.renderMode == ol.layer.VectorTile.RenderType.IMAGE ||\n      options.renderMode == ol.layer.VectorTile.RenderType.HYBRID ||\n      options.renderMode == ol.layer.VectorTile.RenderType.VECTOR,\n      28); // `renderMode` must be `'image'`, `'hybrid'` or `'vector'`\n\n  /**\n   * @private\n   * @type {ol.layer.VectorTile.RenderType|string}\n   */\n  this.renderMode_ = options.renderMode || ol.layer.VectorTile.RenderType.HYBRID;\n\n};\nol.inherits(ol.layer.VectorTile, ol.layer.Vector);\n\n\n/**\n * Return the level as number to which we will preload tiles up to.\n * @return {number} The level to preload tiles up to.\n * @observable\n * @api\n */\nol.layer.VectorTile.prototype.getPreload = function() {\n  return /** @type {number} */ (this.get(ol.layer.VectorTile.Property.PRELOAD));\n};\n\n\n/**\n * @return {ol.layer.VectorTile.RenderType|string} The render mode.\n */\nol.layer.VectorTile.prototype.getRenderMode = function() {\n  return this.renderMode_;\n};\n\n\n/**\n * Whether we use interim tiles on error.\n * @return {boolean} Use interim tiles on error.\n * @observable\n * @api\n */\nol.layer.VectorTile.prototype.getUseInterimTilesOnError = function() {\n  return /** @type {boolean} */ (\n      this.get(ol.layer.VectorTile.Property.USE_INTERIM_TILES_ON_ERROR));\n};\n\n\n/**\n * Set the level as number to which we will preload tiles up to.\n * @param {number} preload The level to preload tiles up to.\n * @observable\n * @api\n */\nol.layer.VectorTile.prototype.setPreload = function(preload) {\n  this.set(ol.layer.Tile.Property.PRELOAD, preload);\n};\n\n\n/**\n * Set whether we use interim tiles on error.\n * @param {boolean} useInterimTilesOnError Use interim tiles on error.\n * @observable\n * @api\n */\nol.layer.VectorTile.prototype.setUseInterimTilesOnError = function(useInterimTilesOnError) {\n  this.set(\n      ol.layer.Tile.Property.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);\n};\n\n\n/**\n * @enum {string}\n */\nol.layer.VectorTile.Property = {\n  PRELOAD: 'preload',\n  USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError'\n};\n\n\n/**\n * @enum {string}\n * Render mode for vector tiles:\n *  * `'image'`: Vector tiles are rendered as images. Great performance, but\n *    point symbols and texts are always rotated with the view and pixels are\n *    scaled during zoom animations.\n *  * `'hybrid'`: Polygon and line elements are rendered as images, so pixels\n *    are scaled during zoom animations. Point symbols and texts are accurately\n *    rendered as vectors and can stay upright on rotated views.\n *  * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering\n *    even during animations, but slower performance than the other options.\n * @api\n */\nol.layer.VectorTile.RenderType = {\n  IMAGE: 'image',\n  HYBRID: 'hybrid',\n  VECTOR: 'vector'\n};\n\ngoog.provide('ol.render.VectorContext');\n\n\n/**\n * Context for drawing geometries.  A vector context is available on render\n * events and does not need to be constructed directly.\n * @constructor\n * @struct\n * @api\n */\nol.render.VectorContext = function() {\n};\n\n\n/**\n * Render a geometry.\n *\n * @abstract\n * @param {ol.geom.Geometry} geometry The geometry to render.\n */\nol.render.VectorContext.prototype.drawGeometry = function(geometry) {};\n\n\n/**\n * Set the rendering style.\n *\n * @abstract\n * @param {ol.style.Style} style The rendering style.\n */\nol.render.VectorContext.prototype.setStyle = function(style) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.Circle} circleGeometry Circle geometry.\n * @param {ol.Feature} feature Feature,\n */\nol.render.VectorContext.prototype.drawCircle = function(circleGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.Feature} feature Feature.\n * @param {ol.style.Style} style Style.\n */\nol.render.VectorContext.prototype.drawFeature = function(feature, style) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry\n *     collection.\n * @param {ol.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawGeometryCollection = function(geometryCollectionGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line\n *     string geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawLineString = function(lineStringGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry\n *     MultiLineString geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint\n *     geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawMultiPoint = function(multiPointGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawPoint = function(pointGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon\n *     geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawPolygon = function(polygonGeometry, feature) {};\n\n\n/**\n * @abstract\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.VectorContext.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) {};\n\n\n/**\n * @abstract\n * @param {ol.style.Fill} fillStyle Fill style.\n * @param {ol.style.Stroke} strokeStyle Stroke style.\n */\nol.render.VectorContext.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {};\n\n\n/**\n * @abstract\n * @param {ol.style.Image} imageStyle Image style.\n */\nol.render.VectorContext.prototype.setImageStyle = function(imageStyle) {};\n\n\n/**\n * @abstract\n * @param {ol.style.Text} textStyle Text style.\n */\nol.render.VectorContext.prototype.setTextStyle = function(textStyle) {};\n\n// FIXME test, especially polygons with holes and multipolygons\n// FIXME need to handle large thick features (where pixel size matters)\n// FIXME add offset and end to ol.geom.flat.transform.transform2D?\n\ngoog.provide('ol.render.canvas.Immediate');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.colorlike');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.transform');\ngoog.require('ol.has');\ngoog.require('ol.render.VectorContext');\ngoog.require('ol.render.canvas');\ngoog.require('ol.transform');\n\n\n/**\n * @classdesc\n * A concrete subclass of {@link ol.render.VectorContext} that implements\n * direct rendering of features and geometries to an HTML5 Canvas context.\n * Instances of this class are created internally by the library and\n * provided to application code as vectorContext member of the\n * {@link ol.render.Event} object associated with postcompose, precompose and\n * render events emitted by layers and maps.\n *\n * @constructor\n * @extends {ol.render.VectorContext}\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Extent} extent Extent.\n * @param {ol.Transform} transform Transform.\n * @param {number} viewRotation View rotation.\n * @struct\n */\nol.render.canvas.Immediate = function(context, pixelRatio, extent, transform, viewRotation) {\n  ol.render.VectorContext.call(this);\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.context_ = context;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.pixelRatio_ = pixelRatio;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.extent_ = extent;\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.transform_ = transform;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.viewRotation_ = viewRotation;\n\n  /**\n   * @private\n   * @type {?ol.CanvasFillState}\n   */\n  this.contextFillState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasStrokeState}\n   */\n  this.contextStrokeState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasTextState}\n   */\n  this.contextTextState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasFillState}\n   */\n  this.fillState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasStrokeState}\n   */\n  this.strokeState_ = null;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement|HTMLVideoElement|Image}\n   */\n  this.image_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageAnchorX_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageAnchorY_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageHeight_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageOpacity_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageOriginX_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageOriginY_ = 0;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.imageRotateWithView_ = false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageRotation_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageScale_ = 0;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.imageSnapToPixel_ = false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.imageWidth_ = 0;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.text_ = '';\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textOffsetX_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textOffsetY_ = 0;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.textRotateWithView_ = false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textRotation_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textScale_ = 0;\n\n  /**\n   * @private\n   * @type {?ol.CanvasFillState}\n   */\n  this.textFillState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasStrokeState}\n   */\n  this.textStrokeState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasTextState}\n   */\n  this.textState_ = null;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.pixelCoordinates_ = [];\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.tmpLocalTransform_ = ol.transform.create();\n\n};\nol.inherits(ol.render.canvas.Immediate, ol.render.VectorContext);\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @private\n */\nol.render.canvas.Immediate.prototype.drawImages_ = function(flatCoordinates, offset, end, stride) {\n  if (!this.image_) {\n    return;\n  }\n  ol.DEBUG && console.assert(offset === 0, 'offset should be 0');\n  ol.DEBUG && console.assert(end == flatCoordinates.length,\n      'end should be equal to the length of flatCoordinates');\n  var pixelCoordinates = ol.geom.flat.transform.transform2D(\n      flatCoordinates, offset, end, 2, this.transform_,\n      this.pixelCoordinates_);\n  var context = this.context_;\n  var localTransform = this.tmpLocalTransform_;\n  var alpha = context.globalAlpha;\n  if (this.imageOpacity_ != 1) {\n    context.globalAlpha = alpha * this.imageOpacity_;\n  }\n  var rotation = this.imageRotation_;\n  if (this.imageRotateWithView_) {\n    rotation += this.viewRotation_;\n  }\n  var i, ii;\n  for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) {\n    var x = pixelCoordinates[i] - this.imageAnchorX_;\n    var y = pixelCoordinates[i + 1] - this.imageAnchorY_;\n    if (this.imageSnapToPixel_) {\n      x = Math.round(x);\n      y = Math.round(y);\n    }\n    if (rotation !== 0 || this.imageScale_ != 1) {\n      var centerX = x + this.imageAnchorX_;\n      var centerY = y + this.imageAnchorY_;\n      ol.transform.compose(localTransform,\n          centerX, centerY,\n          this.imageScale_, this.imageScale_,\n          rotation,\n          -centerX, -centerY);\n      context.setTransform.apply(context, localTransform);\n    }\n    context.drawImage(this.image_, this.imageOriginX_, this.imageOriginY_,\n        this.imageWidth_, this.imageHeight_, x, y,\n        this.imageWidth_, this.imageHeight_);\n  }\n  if (rotation !== 0 || this.imageScale_ != 1) {\n    context.setTransform(1, 0, 0, 1, 0, 0);\n  }\n  if (this.imageOpacity_ != 1) {\n    context.globalAlpha = alpha;\n  }\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @private\n */\nol.render.canvas.Immediate.prototype.drawText_ = function(flatCoordinates, offset, end, stride) {\n  if (!this.textState_ || this.text_ === '') {\n    return;\n  }\n  if (this.textFillState_) {\n    this.setContextFillState_(this.textFillState_);\n  }\n  if (this.textStrokeState_) {\n    this.setContextStrokeState_(this.textStrokeState_);\n  }\n  this.setContextTextState_(this.textState_);\n  ol.DEBUG && console.assert(offset === 0, 'offset should be 0');\n  ol.DEBUG && console.assert(end == flatCoordinates.length,\n      'end should be equal to the length of flatCoordinates');\n  var pixelCoordinates = ol.geom.flat.transform.transform2D(\n      flatCoordinates, offset, end, stride, this.transform_,\n      this.pixelCoordinates_);\n  var context = this.context_;\n  var rotation = this.textRotation_;\n  if (this.textRotateWithView_) {\n    rotation += this.viewRotation_;\n  }\n  for (; offset < end; offset += stride) {\n    var x = pixelCoordinates[offset] + this.textOffsetX_;\n    var y = pixelCoordinates[offset + 1] + this.textOffsetY_;\n    if (rotation !== 0 || this.textScale_ != 1) {\n      var localTransform = ol.transform.compose(this.tmpLocalTransform_,\n          x, y,\n          this.textScale_, this.textScale_,\n          rotation,\n          -x, -y);\n      context.setTransform.apply(context, localTransform);\n    }\n    if (this.textStrokeState_) {\n      context.strokeText(this.text_, x, y);\n    }\n    if (this.textFillState_) {\n      context.fillText(this.text_, x, y);\n    }\n  }\n  if (rotation !== 0 || this.textScale_ != 1) {\n    context.setTransform(1, 0, 0, 1, 0, 0);\n  }\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {boolean} close Close.\n * @private\n * @return {number} end End.\n */\nol.render.canvas.Immediate.prototype.moveToLineTo_ = function(flatCoordinates, offset, end, stride, close) {\n  var context = this.context_;\n  var pixelCoordinates = ol.geom.flat.transform.transform2D(\n      flatCoordinates, offset, end, stride, this.transform_,\n      this.pixelCoordinates_);\n  context.moveTo(pixelCoordinates[0], pixelCoordinates[1]);\n  var length = pixelCoordinates.length;\n  if (close) {\n    length -= 2;\n  }\n  for (var i = 2; i < length; i += 2) {\n    context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]);\n  }\n  if (close) {\n    context.closePath();\n  }\n  return end;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @private\n * @return {number} End.\n */\nol.render.canvas.Immediate.prototype.drawRings_ = function(flatCoordinates, offset, ends, stride) {\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    offset = this.moveToLineTo_(\n        flatCoordinates, offset, ends[i], stride, true);\n  }\n  return offset;\n};\n\n\n/**\n * Render a circle geometry into the canvas.  Rendering is immediate and uses\n * the current fill and stroke styles.\n *\n * @param {ol.geom.Circle} geometry Circle geometry.\n * @api\n */\nol.render.canvas.Immediate.prototype.drawCircle = function(geometry) {\n  if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {\n    return;\n  }\n  if (this.fillState_ || this.strokeState_) {\n    if (this.fillState_) {\n      this.setContextFillState_(this.fillState_);\n    }\n    if (this.strokeState_) {\n      this.setContextStrokeState_(this.strokeState_);\n    }\n    var pixelCoordinates = ol.geom.SimpleGeometry.transform2D(\n        geometry, this.transform_, this.pixelCoordinates_);\n    var dx = pixelCoordinates[2] - pixelCoordinates[0];\n    var dy = pixelCoordinates[3] - pixelCoordinates[1];\n    var radius = Math.sqrt(dx * dx + dy * dy);\n    var context = this.context_;\n    context.beginPath();\n    context.arc(\n        pixelCoordinates[0], pixelCoordinates[1], radius, 0, 2 * Math.PI);\n    if (this.fillState_) {\n      context.fill();\n    }\n    if (this.strokeState_) {\n      context.stroke();\n    }\n  }\n  if (this.text_ !== '') {\n    this.drawText_(geometry.getCenter(), 0, 2, 2);\n  }\n};\n\n\n/**\n * Set the rendering style.  Note that since this is an immediate rendering API,\n * any `zIndex` on the provided style will be ignored.\n *\n * @param {ol.style.Style} style The rendering style.\n * @api\n */\nol.render.canvas.Immediate.prototype.setStyle = function(style) {\n  this.setFillStrokeStyle(style.getFill(), style.getStroke());\n  this.setImageStyle(style.getImage());\n  this.setTextStyle(style.getText());\n};\n\n\n/**\n * Render a geometry into the canvas.  Call\n * {@link ol.render.canvas.Immediate#setStyle} first to set the rendering style.\n *\n * @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render.\n * @api\n */\nol.render.canvas.Immediate.prototype.drawGeometry = function(geometry) {\n  var type = geometry.getType();\n  switch (type) {\n    case ol.geom.GeometryType.POINT:\n      this.drawPoint(/** @type {ol.geom.Point} */ (geometry));\n      break;\n    case ol.geom.GeometryType.LINE_STRING:\n      this.drawLineString(/** @type {ol.geom.LineString} */ (geometry));\n      break;\n    case ol.geom.GeometryType.POLYGON:\n      this.drawPolygon(/** @type {ol.geom.Polygon} */ (geometry));\n      break;\n    case ol.geom.GeometryType.MULTI_POINT:\n      this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry));\n      break;\n    case ol.geom.GeometryType.MULTI_LINE_STRING:\n      this.drawMultiLineString(/** @type {ol.geom.MultiLineString} */ (geometry));\n      break;\n    case ol.geom.GeometryType.MULTI_POLYGON:\n      this.drawMultiPolygon(/** @type {ol.geom.MultiPolygon} */ (geometry));\n      break;\n    case ol.geom.GeometryType.GEOMETRY_COLLECTION:\n      this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry));\n      break;\n    case ol.geom.GeometryType.CIRCLE:\n      this.drawCircle(/** @type {ol.geom.Circle} */ (geometry));\n      break;\n    default:\n      ol.DEBUG && console.assert(false, 'Unsupported geometry type: ' + type);\n  }\n};\n\n\n/**\n * Render a feature into the canvas.  Note that any `zIndex` on the provided\n * style will be ignored - features are rendered immediately in the order that\n * this method is called.  If you need `zIndex` support, you should be using an\n * {@link ol.layer.Vector} instead.\n *\n * @param {ol.Feature} feature Feature.\n * @param {ol.style.Style} style Style.\n * @api\n */\nol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) {\n  var geometry = style.getGeometryFunction()(feature);\n  if (!geometry ||\n      !ol.extent.intersects(this.extent_, geometry.getExtent())) {\n    return;\n  }\n  this.setStyle(style);\n  this.drawGeometry(geometry);\n};\n\n\n/**\n * Render a GeometryCollection to the canvas.  Rendering is immediate and\n * uses the current styles appropriate for each geometry in the collection.\n *\n * @param {ol.geom.GeometryCollection} geometry Geometry collection.\n */\nol.render.canvas.Immediate.prototype.drawGeometryCollection = function(geometry) {\n  var geometries = geometry.getGeometriesArray();\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    this.drawGeometry(geometries[i]);\n  }\n};\n\n\n/**\n * Render a Point geometry into the canvas.  Rendering is immediate and uses\n * the current style.\n *\n * @param {ol.geom.Point|ol.render.Feature} geometry Point geometry.\n */\nol.render.canvas.Immediate.prototype.drawPoint = function(geometry) {\n  var flatCoordinates = geometry.getFlatCoordinates();\n  var stride = geometry.getStride();\n  if (this.image_) {\n    this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);\n  }\n  if (this.text_ !== '') {\n    this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);\n  }\n};\n\n\n/**\n * Render a MultiPoint geometry  into the canvas.  Rendering is immediate and\n * uses the current style.\n *\n * @param {ol.geom.MultiPoint|ol.render.Feature} geometry MultiPoint geometry.\n */\nol.render.canvas.Immediate.prototype.drawMultiPoint = function(geometry) {\n  var flatCoordinates = geometry.getFlatCoordinates();\n  var stride = geometry.getStride();\n  if (this.image_) {\n    this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);\n  }\n  if (this.text_ !== '') {\n    this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);\n  }\n};\n\n\n/**\n * Render a LineString into the canvas.  Rendering is immediate and uses\n * the current style.\n *\n * @param {ol.geom.LineString|ol.render.Feature} geometry LineString geometry.\n */\nol.render.canvas.Immediate.prototype.drawLineString = function(geometry) {\n  if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {\n    return;\n  }\n  if (this.strokeState_) {\n    this.setContextStrokeState_(this.strokeState_);\n    var context = this.context_;\n    var flatCoordinates = geometry.getFlatCoordinates();\n    context.beginPath();\n    this.moveToLineTo_(flatCoordinates, 0, flatCoordinates.length,\n        geometry.getStride(), false);\n    context.stroke();\n  }\n  if (this.text_ !== '') {\n    var flatMidpoint = geometry.getFlatMidpoint();\n    this.drawText_(flatMidpoint, 0, 2, 2);\n  }\n};\n\n\n/**\n * Render a MultiLineString geometry into the canvas.  Rendering is immediate\n * and uses the current style.\n *\n * @param {ol.geom.MultiLineString|ol.render.Feature} geometry MultiLineString\n *     geometry.\n */\nol.render.canvas.Immediate.prototype.drawMultiLineString = function(geometry) {\n  var geometryExtent = geometry.getExtent();\n  if (!ol.extent.intersects(this.extent_, geometryExtent)) {\n    return;\n  }\n  if (this.strokeState_) {\n    this.setContextStrokeState_(this.strokeState_);\n    var context = this.context_;\n    var flatCoordinates = geometry.getFlatCoordinates();\n    var offset = 0;\n    var ends = geometry.getEnds();\n    var stride = geometry.getStride();\n    context.beginPath();\n    var i, ii;\n    for (i = 0, ii = ends.length; i < ii; ++i) {\n      offset = this.moveToLineTo_(\n          flatCoordinates, offset, ends[i], stride, false);\n    }\n    context.stroke();\n  }\n  if (this.text_ !== '') {\n    var flatMidpoints = geometry.getFlatMidpoints();\n    this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2);\n  }\n};\n\n\n/**\n * Render a Polygon geometry into the canvas.  Rendering is immediate and uses\n * the current style.\n *\n * @param {ol.geom.Polygon|ol.render.Feature} geometry Polygon geometry.\n */\nol.render.canvas.Immediate.prototype.drawPolygon = function(geometry) {\n  if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {\n    return;\n  }\n  if (this.strokeState_ || this.fillState_) {\n    if (this.fillState_) {\n      this.setContextFillState_(this.fillState_);\n    }\n    if (this.strokeState_) {\n      this.setContextStrokeState_(this.strokeState_);\n    }\n    var context = this.context_;\n    context.beginPath();\n    this.drawRings_(geometry.getOrientedFlatCoordinates(),\n        0, geometry.getEnds(), geometry.getStride());\n    if (this.fillState_) {\n      context.fill();\n    }\n    if (this.strokeState_) {\n      context.stroke();\n    }\n  }\n  if (this.text_ !== '') {\n    var flatInteriorPoint = geometry.getFlatInteriorPoint();\n    this.drawText_(flatInteriorPoint, 0, 2, 2);\n  }\n};\n\n\n/**\n * Render MultiPolygon geometry into the canvas.  Rendering is immediate and\n * uses the current style.\n * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry.\n */\nol.render.canvas.Immediate.prototype.drawMultiPolygon = function(geometry) {\n  if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {\n    return;\n  }\n  if (this.strokeState_ || this.fillState_) {\n    if (this.fillState_) {\n      this.setContextFillState_(this.fillState_);\n    }\n    if (this.strokeState_) {\n      this.setContextStrokeState_(this.strokeState_);\n    }\n    var context = this.context_;\n    var flatCoordinates = geometry.getOrientedFlatCoordinates();\n    var offset = 0;\n    var endss = geometry.getEndss();\n    var stride = geometry.getStride();\n    var i, ii;\n    context.beginPath();\n    for (i = 0, ii = endss.length; i < ii; ++i) {\n      var ends = endss[i];\n      offset = this.drawRings_(flatCoordinates, offset, ends, stride);\n    }\n    if (this.fillState_) {\n      context.fill();\n    }\n    if (this.strokeState_) {\n      context.stroke();\n    }\n  }\n  if (this.text_ !== '') {\n    var flatInteriorPoints = geometry.getFlatInteriorPoints();\n    this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2);\n  }\n};\n\n\n/**\n * @param {ol.CanvasFillState} fillState Fill state.\n * @private\n */\nol.render.canvas.Immediate.prototype.setContextFillState_ = function(fillState) {\n  var context = this.context_;\n  var contextFillState = this.contextFillState_;\n  if (!contextFillState) {\n    context.fillStyle = fillState.fillStyle;\n    this.contextFillState_ = {\n      fillStyle: fillState.fillStyle\n    };\n  } else {\n    if (contextFillState.fillStyle != fillState.fillStyle) {\n      contextFillState.fillStyle = context.fillStyle = fillState.fillStyle;\n    }\n  }\n};\n\n\n/**\n * @param {ol.CanvasStrokeState} strokeState Stroke state.\n * @private\n */\nol.render.canvas.Immediate.prototype.setContextStrokeState_ = function(strokeState) {\n  var context = this.context_;\n  var contextStrokeState = this.contextStrokeState_;\n  if (!contextStrokeState) {\n    context.lineCap = strokeState.lineCap;\n    if (ol.has.CANVAS_LINE_DASH) {\n      context.setLineDash(strokeState.lineDash);\n    }\n    context.lineJoin = strokeState.lineJoin;\n    context.lineWidth = strokeState.lineWidth;\n    context.miterLimit = strokeState.miterLimit;\n    context.strokeStyle = strokeState.strokeStyle;\n    this.contextStrokeState_ = {\n      lineCap: strokeState.lineCap,\n      lineDash: strokeState.lineDash,\n      lineJoin: strokeState.lineJoin,\n      lineWidth: strokeState.lineWidth,\n      miterLimit: strokeState.miterLimit,\n      strokeStyle: strokeState.strokeStyle\n    };\n  } else {\n    if (contextStrokeState.lineCap != strokeState.lineCap) {\n      contextStrokeState.lineCap = context.lineCap = strokeState.lineCap;\n    }\n    if (ol.has.CANVAS_LINE_DASH) {\n      if (!ol.array.equals(\n          contextStrokeState.lineDash, strokeState.lineDash)) {\n        context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash);\n      }\n    }\n    if (contextStrokeState.lineJoin != strokeState.lineJoin) {\n      contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin;\n    }\n    if (contextStrokeState.lineWidth != strokeState.lineWidth) {\n      contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth;\n    }\n    if (contextStrokeState.miterLimit != strokeState.miterLimit) {\n      contextStrokeState.miterLimit = context.miterLimit =\n          strokeState.miterLimit;\n    }\n    if (contextStrokeState.strokeStyle != strokeState.strokeStyle) {\n      contextStrokeState.strokeStyle = context.strokeStyle =\n          strokeState.strokeStyle;\n    }\n  }\n};\n\n\n/**\n * @param {ol.CanvasTextState} textState Text state.\n * @private\n */\nol.render.canvas.Immediate.prototype.setContextTextState_ = function(textState) {\n  var context = this.context_;\n  var contextTextState = this.contextTextState_;\n  if (!contextTextState) {\n    context.font = textState.font;\n    context.textAlign = textState.textAlign;\n    context.textBaseline = textState.textBaseline;\n    this.contextTextState_ = {\n      font: textState.font,\n      textAlign: textState.textAlign,\n      textBaseline: textState.textBaseline\n    };\n  } else {\n    if (contextTextState.font != textState.font) {\n      contextTextState.font = context.font = textState.font;\n    }\n    if (contextTextState.textAlign != textState.textAlign) {\n      contextTextState.textAlign = context.textAlign = textState.textAlign;\n    }\n    if (contextTextState.textBaseline != textState.textBaseline) {\n      contextTextState.textBaseline = context.textBaseline =\n          textState.textBaseline;\n    }\n  }\n};\n\n\n/**\n * Set the fill and stroke style for subsequent draw operations.  To clear\n * either fill or stroke styles, pass null for the appropriate parameter.\n *\n * @param {ol.style.Fill} fillStyle Fill style.\n * @param {ol.style.Stroke} strokeStyle Stroke style.\n */\nol.render.canvas.Immediate.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {\n  if (!fillStyle) {\n    this.fillState_ = null;\n  } else {\n    var fillStyleColor = fillStyle.getColor();\n    this.fillState_ = {\n      fillStyle: ol.colorlike.asColorLike(fillStyleColor ?\n          fillStyleColor : ol.render.canvas.defaultFillStyle)\n    };\n  }\n  if (!strokeStyle) {\n    this.strokeState_ = null;\n  } else {\n    var strokeStyleColor = strokeStyle.getColor();\n    var strokeStyleLineCap = strokeStyle.getLineCap();\n    var strokeStyleLineDash = strokeStyle.getLineDash();\n    var strokeStyleLineJoin = strokeStyle.getLineJoin();\n    var strokeStyleWidth = strokeStyle.getWidth();\n    var strokeStyleMiterLimit = strokeStyle.getMiterLimit();\n    this.strokeState_ = {\n      lineCap: strokeStyleLineCap !== undefined ?\n          strokeStyleLineCap : ol.render.canvas.defaultLineCap,\n      lineDash: strokeStyleLineDash ?\n          strokeStyleLineDash : ol.render.canvas.defaultLineDash,\n      lineJoin: strokeStyleLineJoin !== undefined ?\n          strokeStyleLineJoin : ol.render.canvas.defaultLineJoin,\n      lineWidth: this.pixelRatio_ * (strokeStyleWidth !== undefined ?\n          strokeStyleWidth : ol.render.canvas.defaultLineWidth),\n      miterLimit: strokeStyleMiterLimit !== undefined ?\n          strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit,\n      strokeStyle: ol.colorlike.asColorLike(strokeStyleColor ?\n          strokeStyleColor : ol.render.canvas.defaultStrokeStyle)\n    };\n  }\n};\n\n\n/**\n * Set the image style for subsequent draw operations.  Pass null to remove\n * the image style.\n *\n * @param {ol.style.Image} imageStyle Image style.\n */\nol.render.canvas.Immediate.prototype.setImageStyle = function(imageStyle) {\n  if (!imageStyle) {\n    this.image_ = null;\n  } else {\n    var imageAnchor = imageStyle.getAnchor();\n    // FIXME pixel ratio\n    var imageImage = imageStyle.getImage(1);\n    var imageOrigin = imageStyle.getOrigin();\n    var imageSize = imageStyle.getSize();\n    ol.DEBUG && console.assert(imageImage, 'imageImage must be truthy');\n    this.imageAnchorX_ = imageAnchor[0];\n    this.imageAnchorY_ = imageAnchor[1];\n    this.imageHeight_ = imageSize[1];\n    this.image_ = imageImage;\n    this.imageOpacity_ = imageStyle.getOpacity();\n    this.imageOriginX_ = imageOrigin[0];\n    this.imageOriginY_ = imageOrigin[1];\n    this.imageRotateWithView_ = imageStyle.getRotateWithView();\n    this.imageRotation_ = imageStyle.getRotation();\n    this.imageScale_ = imageStyle.getScale();\n    this.imageSnapToPixel_ = imageStyle.getSnapToPixel();\n    this.imageWidth_ = imageSize[0];\n  }\n};\n\n\n/**\n * Set the text style for subsequent draw operations.  Pass null to\n * remove the text style.\n *\n * @param {ol.style.Text} textStyle Text style.\n */\nol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) {\n  if (!textStyle) {\n    this.text_ = '';\n  } else {\n    var textFillStyle = textStyle.getFill();\n    if (!textFillStyle) {\n      this.textFillState_ = null;\n    } else {\n      var textFillStyleColor = textFillStyle.getColor();\n      this.textFillState_ = {\n        fillStyle: ol.colorlike.asColorLike(textFillStyleColor ?\n            textFillStyleColor : ol.render.canvas.defaultFillStyle)\n      };\n    }\n    var textStrokeStyle = textStyle.getStroke();\n    if (!textStrokeStyle) {\n      this.textStrokeState_ = null;\n    } else {\n      var textStrokeStyleColor = textStrokeStyle.getColor();\n      var textStrokeStyleLineCap = textStrokeStyle.getLineCap();\n      var textStrokeStyleLineDash = textStrokeStyle.getLineDash();\n      var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();\n      var textStrokeStyleWidth = textStrokeStyle.getWidth();\n      var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();\n      this.textStrokeState_ = {\n        lineCap: textStrokeStyleLineCap !== undefined ?\n            textStrokeStyleLineCap : ol.render.canvas.defaultLineCap,\n        lineDash: textStrokeStyleLineDash ?\n            textStrokeStyleLineDash : ol.render.canvas.defaultLineDash,\n        lineJoin: textStrokeStyleLineJoin !== undefined ?\n            textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin,\n        lineWidth: textStrokeStyleWidth !== undefined ?\n            textStrokeStyleWidth : ol.render.canvas.defaultLineWidth,\n        miterLimit: textStrokeStyleMiterLimit !== undefined ?\n            textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit,\n        strokeStyle: ol.colorlike.asColorLike(textStrokeStyleColor ?\n            textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle)\n      };\n    }\n    var textFont = textStyle.getFont();\n    var textOffsetX = textStyle.getOffsetX();\n    var textOffsetY = textStyle.getOffsetY();\n    var textRotateWithView = textStyle.getRotateWithView();\n    var textRotation = textStyle.getRotation();\n    var textScale = textStyle.getScale();\n    var textText = textStyle.getText();\n    var textTextAlign = textStyle.getTextAlign();\n    var textTextBaseline = textStyle.getTextBaseline();\n    this.textState_ = {\n      font: textFont !== undefined ?\n          textFont : ol.render.canvas.defaultFont,\n      textAlign: textTextAlign !== undefined ?\n          textTextAlign : ol.render.canvas.defaultTextAlign,\n      textBaseline: textTextBaseline !== undefined ?\n          textTextBaseline : ol.render.canvas.defaultTextBaseline\n    };\n    this.text_ = textText !== undefined ? textText : '';\n    this.textOffsetX_ =\n        textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0;\n    this.textOffsetY_ =\n        textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0;\n    this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;\n    this.textRotation_ = textRotation !== undefined ? textRotation : 0;\n    this.textScale_ = this.pixelRatio_ * (textScale !== undefined ?\n        textScale : 1);\n  }\n};\n\ngoog.provide('ol.renderer.Layer');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.Observable');\ngoog.require('ol.Tile');\ngoog.require('ol.asserts');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.functions');\ngoog.require('ol.source.State');\n\n\n/**\n * @constructor\n * @extends {ol.Observable}\n * @param {ol.layer.Layer} layer Layer.\n * @struct\n */\nol.renderer.Layer = function(layer) {\n\n  ol.Observable.call(this);\n\n  /**\n   * @private\n   * @type {ol.layer.Layer}\n   */\n  this.layer_ = layer;\n\n\n};\nol.inherits(ol.renderer.Layer, ol.Observable);\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {olx.FrameState} frameState Frame state.\n * @param {number} hitTolerance Hit tolerance in pixels.\n * @param {function(this: S, (ol.Feature|ol.render.Feature), ol.layer.Layer): T}\n *     callback Feature callback.\n * @param {S} thisArg Value to use as `this` when executing `callback`.\n * @return {T|undefined} Callback result.\n * @template S,T\n */\nol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction;\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {olx.FrameState} frameState Frame state.\n * @return {boolean} Is there a feature at the given coordinate?\n */\nol.renderer.Layer.prototype.hasFeatureAtCoordinate = ol.functions.FALSE;\n\n\n/**\n * Create a function that adds loaded tiles to the tile lookup.\n * @param {ol.source.Tile} source Tile source.\n * @param {ol.proj.Projection} projection Projection of the tiles.\n * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded\n *     tiles by zoom level.\n * @return {function(number, ol.TileRange):boolean} A function that can be\n *     called with a zoom level and a tile range to add loaded tiles to the\n *     lookup.\n * @protected\n */\nol.renderer.Layer.prototype.createLoadedTileFinder = function(source, projection, tiles) {\n  return (\n      /**\n       * @param {number} zoom Zoom level.\n       * @param {ol.TileRange} tileRange Tile range.\n       * @return {boolean} The tile range is fully loaded.\n       */\n      function(zoom, tileRange) {\n        function callback(tile) {\n          if (!tiles[zoom]) {\n            tiles[zoom] = {};\n          }\n          tiles[zoom][tile.tileCoord.toString()] = tile;\n        }\n        return source.forEachLoadedTile(projection, zoom, tileRange, callback);\n      });\n};\n\n\n/**\n * @return {ol.layer.Layer} Layer.\n */\nol.renderer.Layer.prototype.getLayer = function() {\n  return this.layer_;\n};\n\n\n/**\n * Handle changes in image state.\n * @param {ol.events.Event} event Image change event.\n * @private\n */\nol.renderer.Layer.prototype.handleImageChange_ = function(event) {\n  var image = /** @type {ol.Image} */ (event.target);\n  if (image.getState() === ol.Image.State.LOADED) {\n    this.renderIfReadyAndVisible();\n  }\n};\n\n\n/**\n * Load the image if not already loaded, and register the image change\n * listener if needed.\n * @param {ol.ImageBase} image Image.\n * @return {boolean} `true` if the image is already loaded, `false`\n *     otherwise.\n * @protected\n */\nol.renderer.Layer.prototype.loadImage = function(image) {\n  var imageState = image.getState();\n  if (imageState != ol.Image.State.LOADED &&\n      imageState != ol.Image.State.ERROR) {\n    // the image is either \"idle\" or \"loading\", register the change\n    // listener (a noop if the listener was already registered)\n    ol.DEBUG && console.assert(imageState == ol.Image.State.IDLE ||\n        imageState == ol.Image.State.LOADING,\n        'imageState is \"idle\" or \"loading\"');\n    ol.events.listen(image, ol.events.EventType.CHANGE,\n        this.handleImageChange_, this);\n  }\n  if (imageState == ol.Image.State.IDLE) {\n    image.load();\n    imageState = image.getState();\n    ol.DEBUG && console.assert(imageState == ol.Image.State.LOADING ||\n        imageState == ol.Image.State.LOADED,\n        'imageState is \"loading\" or \"loaded\"');\n  }\n  return imageState == ol.Image.State.LOADED;\n};\n\n\n/**\n * @protected\n */\nol.renderer.Layer.prototype.renderIfReadyAndVisible = function() {\n  var layer = this.getLayer();\n  if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) {\n    this.changed();\n  }\n};\n\n\n/**\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.source.Tile} tileSource Tile source.\n * @protected\n */\nol.renderer.Layer.prototype.scheduleExpireCache = function(frameState, tileSource) {\n  if (tileSource.canExpireCache()) {\n    /**\n     * @param {ol.source.Tile} tileSource Tile source.\n     * @param {ol.Map} map Map.\n     * @param {olx.FrameState} frameState Frame state.\n     */\n    var postRenderFunction = function(tileSource, map, frameState) {\n      var tileSourceKey = ol.getUid(tileSource).toString();\n      tileSource.expireCache(frameState.viewState.projection,\n                             frameState.usedTiles[tileSourceKey]);\n    }.bind(null, tileSource);\n\n    frameState.postRenderFunctions.push(\n      /** @type {ol.PostRenderFunction} */ (postRenderFunction)\n    );\n  }\n};\n\n\n/**\n * @param {Object.<string, ol.Attribution>} attributionsSet Attributions\n *     set (target).\n * @param {Array.<ol.Attribution>} attributions Attributions (source).\n * @protected\n */\nol.renderer.Layer.prototype.updateAttributions = function(attributionsSet, attributions) {\n  if (attributions) {\n    var attribution, i, ii;\n    for (i = 0, ii = attributions.length; i < ii; ++i) {\n      attribution = attributions[i];\n      attributionsSet[ol.getUid(attribution).toString()] = attribution;\n    }\n  }\n};\n\n\n/**\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.source.Source} source Source.\n * @protected\n */\nol.renderer.Layer.prototype.updateLogos = function(frameState, source) {\n  var logo = source.getLogo();\n  if (logo !== undefined) {\n    if (typeof logo === 'string') {\n      frameState.logos[logo] = '';\n    } else if (logo) {\n      ol.asserts.assert(typeof logo.href == 'string', 44); // `logo.href` should be a string.\n      ol.asserts.assert(typeof logo.src == 'string', 45); // `logo.src` should be a string.\n      frameState.logos[logo.src] = logo.href;\n    }\n  }\n};\n\n\n/**\n * @param {Object.<string, Object.<string, ol.TileRange>>} usedTiles Used tiles.\n * @param {ol.source.Tile} tileSource Tile source.\n * @param {number} z Z.\n * @param {ol.TileRange} tileRange Tile range.\n * @protected\n */\nol.renderer.Layer.prototype.updateUsedTiles = function(usedTiles, tileSource, z, tileRange) {\n  // FIXME should we use tilesToDrawByZ instead?\n  var tileSourceKey = ol.getUid(tileSource).toString();\n  var zKey = z.toString();\n  if (tileSourceKey in usedTiles) {\n    if (zKey in usedTiles[tileSourceKey]) {\n      usedTiles[tileSourceKey][zKey].extend(tileRange);\n    } else {\n      usedTiles[tileSourceKey][zKey] = tileRange;\n    }\n  } else {\n    usedTiles[tileSourceKey] = {};\n    usedTiles[tileSourceKey][zKey] = tileRange;\n  }\n};\n\n\n/**\n * Manage tile pyramid.\n * This function performs a number of functions related to the tiles at the\n * current zoom and lower zoom levels:\n * - registers idle tiles in frameState.wantedTiles so that they are not\n *   discarded by the tile queue\n * - enqueues missing tiles\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.source.Tile} tileSource Tile source.\n * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @param {ol.Extent} extent Extent.\n * @param {number} currentZ Current Z.\n * @param {number} preload Load low resolution tiles up to 'preload' levels.\n * @param {function(this: T, ol.Tile)=} opt_tileCallback Tile callback.\n * @param {T=} opt_this Object to use as `this` in `opt_tileCallback`.\n * @protected\n * @template T\n */\nol.renderer.Layer.prototype.manageTilePyramid = function(\n    frameState, tileSource, tileGrid, pixelRatio, projection, extent,\n    currentZ, preload, opt_tileCallback, opt_this) {\n  var tileSourceKey = ol.getUid(tileSource).toString();\n  if (!(tileSourceKey in frameState.wantedTiles)) {\n    frameState.wantedTiles[tileSourceKey] = {};\n  }\n  var wantedTiles = frameState.wantedTiles[tileSourceKey];\n  var tileQueue = frameState.tileQueue;\n  var minZoom = tileGrid.getMinZoom();\n  var tile, tileRange, tileResolution, x, y, z;\n  for (z = currentZ; z >= minZoom; --z) {\n    tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange);\n    tileResolution = tileGrid.getResolution(z);\n    for (x = tileRange.minX; x <= tileRange.maxX; ++x) {\n      for (y = tileRange.minY; y <= tileRange.maxY; ++y) {\n        if (currentZ - z <= preload) {\n          tile = tileSource.getTile(z, x, y, pixelRatio, projection);\n          if (tile.getState() == ol.Tile.State.IDLE) {\n            wantedTiles[tile.getKey()] = true;\n            if (!tileQueue.isKeyQueued(tile.getKey())) {\n              tileQueue.enqueue([tile, tileSourceKey,\n                tileGrid.getTileCoordCenter(tile.tileCoord), tileResolution]);\n            }\n          }\n          if (opt_tileCallback !== undefined) {\n            opt_tileCallback.call(opt_this, tile);\n          }\n        } else {\n          tileSource.useTile(z, x, y, projection);\n        }\n      }\n    }\n  }\n};\n\ngoog.provide('ol.renderer.canvas.Layer');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.functions');\ngoog.require('ol.render.Event');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.Immediate');\ngoog.require('ol.renderer.Layer');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.Layer}\n * @param {ol.layer.Layer} layer Layer.\n */\nol.renderer.canvas.Layer = function(layer) {\n\n  ol.renderer.Layer.call(this, layer);\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.renderedResolution;\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.transform_ = ol.transform.create();\n\n};\nol.inherits(ol.renderer.canvas.Layer, ol.renderer.Layer);\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.Extent} extent Clip extent.\n * @protected\n */\nol.renderer.canvas.Layer.prototype.clip = function(context, frameState, extent) {\n  var pixelRatio = frameState.pixelRatio;\n  var width = frameState.size[0] * pixelRatio;\n  var height = frameState.size[1] * pixelRatio;\n  var rotation = frameState.viewState.rotation;\n  var topLeft = ol.extent.getTopLeft(/** @type {ol.Extent} */ (extent));\n  var topRight = ol.extent.getTopRight(/** @type {ol.Extent} */ (extent));\n  var bottomRight = ol.extent.getBottomRight(/** @type {ol.Extent} */ (extent));\n  var bottomLeft = ol.extent.getBottomLeft(/** @type {ol.Extent} */ (extent));\n\n  ol.transform.apply(frameState.coordinateToPixelTransform, topLeft);\n  ol.transform.apply(frameState.coordinateToPixelTransform, topRight);\n  ol.transform.apply(frameState.coordinateToPixelTransform, bottomRight);\n  ol.transform.apply(frameState.coordinateToPixelTransform, bottomLeft);\n\n  context.save();\n  ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);\n  context.beginPath();\n  context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio);\n  context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio);\n  context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio);\n  context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio);\n  context.clip();\n  ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);\n};\n\n\n/**\n * @param {ol.render.Event.Type} type Event type.\n * @param {CanvasRenderingContext2D} context Context.\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.Transform=} opt_transform Transform.\n * @private\n */\nol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState, opt_transform) {\n  var layer = this.getLayer();\n  if (layer.hasListener(type)) {\n    var width = frameState.size[0] * frameState.pixelRatio;\n    var height = frameState.size[1] * frameState.pixelRatio;\n    var rotation = frameState.viewState.rotation;\n    ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);\n    var transform = opt_transform !== undefined ?\n        opt_transform : this.getTransform(frameState, 0);\n    var render = new ol.render.canvas.Immediate(\n        context, frameState.pixelRatio, frameState.extent, transform,\n        frameState.viewState.rotation);\n    var composeEvent = new ol.render.Event(type, render, frameState,\n        context, null);\n    layer.dispatchEvent(composeEvent);\n    ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);\n  }\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {olx.FrameState} frameState FrameState.\n * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer\n *     callback.\n * @param {S} thisArg Value to use as `this` when executing `callback`.\n * @return {T|undefined} Callback result.\n * @template S,T,U\n */\nol.renderer.canvas.Layer.prototype.forEachLayerAtCoordinate = function(coordinate, frameState, callback, thisArg) {\n  var hasFeature = this.forEachFeatureAtCoordinate(\n      coordinate, frameState, 0, ol.functions.TRUE, this);\n\n  if (hasFeature) {\n    return callback.call(thisArg, this.getLayer(), null);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.LayerState} layerState Layer state.\n * @param {ol.Transform=} opt_transform Transform.\n * @protected\n */\nol.renderer.canvas.Layer.prototype.postCompose = function(context, frameState, layerState, opt_transform) {\n  this.dispatchComposeEvent_(ol.render.Event.Type.POSTCOMPOSE, context,\n      frameState, opt_transform);\n};\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.Transform=} opt_transform Transform.\n * @protected\n */\nol.renderer.canvas.Layer.prototype.preCompose = function(context, frameState, opt_transform) {\n  this.dispatchComposeEvent_(ol.render.Event.Type.PRECOMPOSE, context,\n      frameState, opt_transform);\n};\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.Transform=} opt_transform Transform.\n * @protected\n */\nol.renderer.canvas.Layer.prototype.dispatchRenderEvent = function(context, frameState, opt_transform) {\n  this.dispatchComposeEvent_(ol.render.Event.Type.RENDER, context,\n      frameState, opt_transform);\n};\n\n\n/**\n * @param {olx.FrameState} frameState Frame state.\n * @param {number} offsetX Offset on the x-axis in view coordinates.\n * @protected\n * @return {!ol.Transform} Transform.\n */\nol.renderer.canvas.Layer.prototype.getTransform = function(frameState, offsetX) {\n  var viewState = frameState.viewState;\n  var pixelRatio = frameState.pixelRatio;\n  var dx1 = pixelRatio * frameState.size[0] / 2;\n  var dy1 = pixelRatio * frameState.size[1] / 2;\n  var sx = pixelRatio / viewState.resolution;\n  var sy = -sx;\n  var angle = -viewState.rotation;\n  var dx2 = -viewState.center[0] + offsetX;\n  var dy2 = -viewState.center[1];\n  return ol.transform.compose(this.transform_, dx1, dy1, sx, sy, angle, dx2, dy2);\n};\n\n\n/**\n * @abstract\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.LayerState} layerState Layer state.\n * @param {CanvasRenderingContext2D} context Context.\n */\nol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerState, context) {};\n\n/**\n * @abstract\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.LayerState} layerState Layer state.\n * @return {boolean} whether composeFrame should be called.\n */\nol.renderer.canvas.Layer.prototype.prepareFrame = function(frameState, layerState) {};\n\ngoog.provide('ol.renderer.canvas.IntermediateCanvas');\n\ngoog.require('ol');\ngoog.require('ol.coordinate');\ngoog.require('ol.dom');\ngoog.require('ol.renderer.canvas.Layer');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.canvas.Layer}\n * @param {ol.layer.Layer} layer Layer.\n */\nol.renderer.canvas.IntermediateCanvas = function(layer) {\n\n  ol.renderer.canvas.Layer.call(this, layer);\n\n  /**\n   * @protected\n   * @type {ol.Transform}\n   */\n  this.coordinateToCanvasPixelTransform = ol.transform.create();\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.hitCanvasContext_ = null;\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.renderedResolution;\n\n};\nol.inherits(ol.renderer.canvas.IntermediateCanvas, ol.renderer.canvas.Layer);\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.IntermediateCanvas.prototype.composeFrame = function(frameState, layerState, context) {\n\n  this.preCompose(context, frameState);\n\n  var image = this.getImage();\n  if (image) {\n\n    // clipped rendering if layer extent is set\n    var extent = layerState.extent;\n    var clipped = extent !== undefined;\n    if (clipped) {\n      this.clip(context, frameState, /** @type {ol.Extent} */ (extent));\n    }\n\n    var imageTransform = this.getImageTransform();\n    // for performance reasons, context.save / context.restore is not used\n    // to save and restore the transformation matrix and the opacity.\n    // see http://jsperf.com/context-save-restore-versus-variable\n    var alpha = context.globalAlpha;\n    context.globalAlpha = layerState.opacity;\n\n    // for performance reasons, context.setTransform is only used\n    // when the view is rotated. see http://jsperf.com/canvas-transform\n    var dx = imageTransform[4];\n    var dy = imageTransform[5];\n    var dw = image.width * imageTransform[0];\n    var dh = image.height * imageTransform[3];\n    context.drawImage(image, 0, 0, +image.width, +image.height,\n        Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));\n    context.globalAlpha = alpha;\n\n    if (clipped) {\n      context.restore();\n    }\n  }\n\n  this.postCompose(context, frameState, layerState);\n};\n\n\n/**\n * @abstract\n * @return {HTMLCanvasElement|HTMLVideoElement|Image} Canvas.\n */\nol.renderer.canvas.IntermediateCanvas.prototype.getImage = function() {};\n\n\n/**\n * @abstract\n * @return {!ol.Transform} Image transform.\n */\nol.renderer.canvas.IntermediateCanvas.prototype.getImageTransform = function() {};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.IntermediateCanvas.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {\n  var layer = this.getLayer();\n  var source = layer.getSource();\n  var resolution = frameState.viewState.resolution;\n  var rotation = frameState.viewState.rotation;\n  var skippedFeatureUids = frameState.skippedFeatureUids;\n  return source.forEachFeatureAtCoordinate(\n      coordinate, resolution, rotation, hitTolerance, skippedFeatureUids,\n      /**\n       * @param {ol.Feature|ol.render.Feature} feature Feature.\n       * @return {?} Callback result.\n       */\n      function(feature) {\n        return callback.call(thisArg, feature, layer);\n      });\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.IntermediateCanvas.prototype.forEachLayerAtCoordinate = function(coordinate, frameState, callback, thisArg) {\n  if (!this.getImage()) {\n    return undefined;\n  }\n\n  if (this.getLayer().getSource().forEachFeatureAtCoordinate !== ol.nullFunction) {\n    // for ImageVector sources use the original hit-detection logic,\n    // so that for example also transparent polygons are detected\n    return ol.renderer.canvas.Layer.prototype.forEachLayerAtCoordinate.apply(this, arguments);\n  } else {\n    var pixel = ol.transform.apply(this.coordinateToCanvasPixelTransform, coordinate.slice());\n    ol.coordinate.scale(pixel, frameState.viewState.resolution / this.renderedResolution);\n\n    if (!this.hitCanvasContext_) {\n      this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);\n    }\n\n    this.hitCanvasContext_.clearRect(0, 0, 1, 1);\n    this.hitCanvasContext_.drawImage(this.getImage(), pixel[0], pixel[1], 1, 1, 0, 0, 1, 1);\n\n    var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data;\n    if (imageData[3] > 0) {\n      return callback.call(thisArg, this.getLayer(),  imageData);\n    } else {\n      return undefined;\n    }\n  }\n};\n\ngoog.provide('ol.renderer.canvas.ImageLayer');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.extent');\ngoog.require('ol.proj');\ngoog.require('ol.renderer.canvas.IntermediateCanvas');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.canvas.IntermediateCanvas}\n * @param {ol.layer.Image} imageLayer Single image layer.\n */\nol.renderer.canvas.ImageLayer = function(imageLayer) {\n\n  ol.renderer.canvas.IntermediateCanvas.call(this, imageLayer);\n\n  /**\n   * @private\n   * @type {?ol.ImageBase}\n   */\n  this.image_ = null;\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.imageTransform_ = ol.transform.create();\n\n};\nol.inherits(ol.renderer.canvas.ImageLayer, ol.renderer.canvas.IntermediateCanvas);\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.ImageLayer.prototype.getImage = function() {\n  return !this.image_ ? null : this.image_.getImage();\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.ImageLayer.prototype.getImageTransform = function() {\n  return this.imageTransform_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, layerState) {\n\n  var pixelRatio = frameState.pixelRatio;\n  var size = frameState.size;\n  var viewState = frameState.viewState;\n  var viewCenter = viewState.center;\n  var viewResolution = viewState.resolution;\n\n  var image;\n  var imageLayer = /** @type {ol.layer.Image} */ (this.getLayer());\n  var imageSource = imageLayer.getSource();\n\n  var hints = frameState.viewHints;\n\n  var renderedExtent = frameState.extent;\n  if (layerState.extent !== undefined) {\n    renderedExtent = ol.extent.getIntersection(\n        renderedExtent, layerState.extent);\n  }\n\n  if (!hints[ol.View.Hint.ANIMATING] && !hints[ol.View.Hint.INTERACTING] &&\n      !ol.extent.isEmpty(renderedExtent)) {\n    var projection = viewState.projection;\n    if (!ol.ENABLE_RASTER_REPROJECTION) {\n      var sourceProjection = imageSource.getProjection();\n      if (sourceProjection) {\n        ol.DEBUG && console.assert(ol.proj.equivalent(projection, sourceProjection),\n            'projection and sourceProjection are equivalent');\n        projection = sourceProjection;\n      }\n    }\n    image = imageSource.getImage(\n        renderedExtent, viewResolution, pixelRatio, projection);\n    if (image) {\n      var loaded = this.loadImage(image);\n      if (loaded) {\n        this.image_ = image;\n        this.renderedResolution = viewResolution;\n      }\n    }\n  }\n\n  if (this.image_) {\n    image = this.image_;\n    var imageExtent = image.getExtent();\n    var imageResolution = image.getResolution();\n    var imagePixelRatio = image.getPixelRatio();\n    var scale = pixelRatio * imageResolution /\n        (viewResolution * imagePixelRatio);\n    var transform = ol.transform.compose(this.imageTransform_,\n        pixelRatio * size[0] / 2, pixelRatio * size[1] / 2,\n        scale, scale,\n        0,\n        imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution,\n        imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution);\n    ol.transform.compose(this.coordinateToCanvasPixelTransform,\n        pixelRatio * size[0] / 2 - transform[4], pixelRatio * size[1] / 2 - transform[5],\n        pixelRatio / viewResolution, -pixelRatio / viewResolution,\n        0,\n        -viewCenter[0], -viewCenter[1]);\n\n    this.updateAttributions(frameState.attributions, image.getAttributions());\n    this.updateLogos(frameState, imageSource);\n  }\n\n  return !!this.image_;\n};\n\n// FIXME find correct globalCompositeOperation\n\ngoog.provide('ol.renderer.canvas.TileLayer');\n\ngoog.require('ol');\ngoog.require('ol.transform');\ngoog.require('ol.TileRange');\ngoog.require('ol.Tile');\ngoog.require('ol.array');\ngoog.require('ol.dom');\ngoog.require('ol.extent');\ngoog.require('ol.renderer.canvas.IntermediateCanvas');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.canvas.IntermediateCanvas}\n * @param {ol.layer.Tile|ol.layer.VectorTile} tileLayer Tile layer.\n */\nol.renderer.canvas.TileLayer = function(tileLayer) {\n\n  ol.renderer.canvas.IntermediateCanvas.call(this, tileLayer);\n\n  /**\n   * @protected\n   * @type {CanvasRenderingContext2D}\n   */\n  this.context = ol.dom.createCanvasContext2D();\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.renderedExtent_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_;\n\n  /**\n   * @protected\n   * @type {!Array.<ol.Tile>}\n   */\n  this.renderedTiles = [];\n\n  /**\n   * @protected\n   * @type {ol.Extent}\n   */\n  this.tmpExtent = ol.extent.createEmpty();\n\n  /**\n   * @private\n   * @type {ol.TileCoord}\n   */\n  this.tmpTileCoord_ = [0, 0, 0];\n\n  /**\n   * @private\n   * @type {ol.TileRange}\n   */\n  this.tmpTileRange_ = new ol.TileRange(0, 0, 0, 0);\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.imageTransform_ = ol.transform.create();\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.zDirection = 0;\n\n};\nol.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.IntermediateCanvas);\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layerState) {\n\n  var pixelRatio = frameState.pixelRatio;\n  var size = frameState.size;\n  var viewState = frameState.viewState;\n  var projection = viewState.projection;\n  var viewResolution = viewState.resolution;\n  var viewCenter = viewState.center;\n\n  var tileLayer = this.getLayer();\n  var tileSource = /** @type {ol.source.Tile} */ (tileLayer.getSource());\n  var sourceRevision = tileSource.getRevision();\n  var tileGrid = tileSource.getTileGridForProjection(projection);\n  var z = tileGrid.getZForResolution(viewResolution, this.zDirection);\n  var tileResolution = tileGrid.getResolution(z);\n  var extent = frameState.extent;\n\n  if (layerState.extent !== undefined) {\n    extent = ol.extent.getIntersection(extent, layerState.extent);\n  }\n  if (ol.extent.isEmpty(extent)) {\n    // Return false to prevent the rendering of the layer.\n    return false;\n  }\n\n  var tileRange = tileGrid.getTileRangeForExtentAndResolution(\n      extent, tileResolution);\n  var imageExtent = tileGrid.getTileRangeExtent(z, tileRange);\n\n  var tilePixelRatio = tileSource.getTilePixelRatio(pixelRatio);\n\n  /**\n   * @type {Object.<number, Object.<string, ol.Tile>>}\n   */\n  var tilesToDrawByZ = {};\n  tilesToDrawByZ[z] = {};\n\n  var findLoadedTiles = this.createLoadedTileFinder(\n      tileSource, projection, tilesToDrawByZ);\n\n  var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();\n  var tmpExtent = this.tmpExtent;\n  var tmpTileRange = this.tmpTileRange_;\n  var newTiles = false;\n  var tile, x, y;\n  for (x = tileRange.minX; x <= tileRange.maxX; ++x) {\n    for (y = tileRange.minY; y <= tileRange.maxY; ++y) {\n      tile = tileSource.getTile(z, x, y, pixelRatio, projection);\n      var tileState = tile.getState();\n      var drawable = tileState == ol.Tile.State.LOADED ||\n          tileState == ol.Tile.State.EMPTY ||\n          tileState == ol.Tile.State.ERROR && !useInterimTilesOnError;\n      if (!drawable) {\n        tile = tile.getInterimTile();\n      } else {\n        if (tileState == ol.Tile.State.LOADED) {\n          tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;\n          if (!newTiles && this.renderedTiles.indexOf(tile) == -1) {\n            newTiles = true;\n          }\n        }\n        continue;\n      }\n\n      var fullyLoaded = tileGrid.forEachTileCoordParentTileRange(\n          tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);\n      if (!fullyLoaded) {\n        var childTileRange = tileGrid.getTileCoordChildTileRange(\n            tile.tileCoord, tmpTileRange, tmpExtent);\n        if (childTileRange) {\n          findLoadedTiles(z + 1, childTileRange);\n        }\n      }\n\n    }\n  }\n\n  var hints = frameState.viewHints;\n  if (!(this.renderedResolution && Date.now() - frameState.time > 16 &&\n      (hints[ol.View.Hint.ANIMATING] || hints[ol.View.Hint.INTERACTING])) &&\n      (newTiles || !(this.renderedExtent_ &&\n      ol.extent.equals(this.renderedExtent_, imageExtent)) ||\n      this.renderedRevision_ != sourceRevision)) {\n\n    var tilePixelSize = tileSource.getTilePixelSize(z, pixelRatio, projection);\n    var width = tileRange.getWidth() * tilePixelSize[0];\n    var height = tileRange.getHeight() * tilePixelSize[0];\n    var context = this.context;\n    var canvas = context.canvas;\n    var opaque = tileSource.getOpaque(projection);\n    if (canvas.width != width || canvas.height != height) {\n      canvas.width = width;\n      canvas.height = height;\n    } else {\n      context.clearRect(0, 0, width, height);\n    }\n\n    this.renderedTiles.length = 0;\n    /** @type {Array.<number>} */\n    var zs = Object.keys(tilesToDrawByZ).map(Number);\n    zs.sort(ol.array.numberSafeCompareFunction);\n    var currentResolution, currentScale, currentTilePixelSize, currentZ, i, ii;\n    var tileExtent, tileGutter, tilesToDraw, w, h;\n    for (i = 0, ii = zs.length; i < ii; ++i) {\n      currentZ = zs[i];\n      currentTilePixelSize = tileSource.getTilePixelSize(currentZ, pixelRatio, projection);\n      currentResolution = tileGrid.getResolution(currentZ);\n      currentScale = currentResolution / tileResolution;\n      tileGutter = tilePixelRatio * tileSource.getGutter(projection);\n      tilesToDraw = tilesToDrawByZ[currentZ];\n      for (var tileCoordKey in tilesToDraw) {\n        tile = tilesToDraw[tileCoordKey];\n        tileExtent = tileGrid.getTileCoordExtent(tile.getTileCoord(), tmpExtent);\n        x = (tileExtent[0] - imageExtent[0]) / tileResolution * tilePixelRatio;\n        y = (imageExtent[3] - tileExtent[3]) / tileResolution * tilePixelRatio;\n        w = currentTilePixelSize[0] * currentScale;\n        h = currentTilePixelSize[1] * currentScale;\n        if (!opaque) {\n          context.clearRect(x, y, w, h);\n        }\n        this.drawTileImage(tile, frameState, layerState, x, y, w, h, tileGutter);\n        this.renderedTiles.push(tile);\n      }\n    }\n\n    this.renderedRevision_ = sourceRevision;\n    this.renderedResolution = tileResolution;\n    this.renderedExtent_ = imageExtent;\n  }\n\n  var scale = pixelRatio / tilePixelRatio * this.renderedResolution / viewResolution;\n  var transform = ol.transform.compose(this.imageTransform_,\n      pixelRatio * size[0] / 2, pixelRatio * size[1] / 2,\n      scale, scale,\n      0,\n      tilePixelRatio * (this.renderedExtent_[0] - viewCenter[0]) / this.renderedResolution,\n      tilePixelRatio * (viewCenter[1] - this.renderedExtent_[3]) / this.renderedResolution);\n  ol.transform.compose(this.coordinateToCanvasPixelTransform,\n      pixelRatio * size[0] / 2 - transform[4], pixelRatio * size[1] / 2 - transform[5],\n      pixelRatio / viewResolution, -pixelRatio / viewResolution,\n      0,\n      -viewCenter[0], -viewCenter[1]);\n\n\n  this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);\n  this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,\n      projection, extent, z, tileLayer.getPreload());\n  this.scheduleExpireCache(frameState, tileSource);\n  this.updateLogos(frameState, tileSource);\n\n  return this.renderedTiles.length > 0;\n};\n\n\n/**\n * @param {ol.Tile} tile Tile.\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.LayerState} layerState Layer state.\n * @param {number} x Left of the tile.\n * @param {number} y Top of the tile.\n * @param {number} w Width of the tile.\n * @param {number} h Height of the tile.\n * @param {number} gutter Tile gutter.\n */\nol.renderer.canvas.TileLayer.prototype.drawTileImage = function(tile, frameState, layerState, x, y, w, h, gutter) {\n  var image = tile.getImage();\n  if (image) {\n    this.context.drawImage(image, gutter, gutter,\n        image.width - 2 * gutter, image.height - 2 * gutter, x, y, w, h);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.TileLayer.prototype.getImage = function() {\n  return this.context.canvas;\n};\n\n\n/**\n * @function\n * @return {ol.layer.Tile|ol.layer.VectorTile}\n */\nol.renderer.canvas.TileLayer.prototype.getLayer;\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.TileLayer.prototype.getImageTransform = function() {\n  return this.imageTransform_;\n};\n\ngoog.provide('ol.render.ReplayGroup');\n\n\n/**\n * Base class for replay groups.\n * @constructor\n */\nol.render.ReplayGroup = function() {};\n\n\n/**\n * @abstract\n * @param {number|undefined} zIndex Z index.\n * @param {ol.render.ReplayType} replayType Replay type.\n * @return {ol.render.VectorContext} Replay.\n */\nol.render.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {};\n\n\n/**\n * @abstract\n * @return {boolean} Is empty.\n */\nol.render.ReplayGroup.prototype.isEmpty = function() {};\n\ngoog.provide('ol.render.canvas.Instruction');\n\n/**\n * @enum {number}\n */\nol.render.canvas.Instruction = {\n  BEGIN_GEOMETRY: 0,\n  BEGIN_PATH: 1,\n  CIRCLE: 2,\n  CLOSE_PATH: 3,\n  DRAW_IMAGE: 4,\n  DRAW_TEXT: 5,\n  END_GEOMETRY: 6,\n  FILL: 7,\n  MOVE_TO_LINE_TO: 8,\n  SET_FILL_STYLE: 9,\n  SET_STROKE_STYLE: 10,\n  SET_TEXT_STYLE: 11,\n  STROKE: 12\n};\n\ngoog.provide('ol.render.canvas.Replay');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.colorlike');\ngoog.require('ol.extent');\ngoog.require('ol.extent.Relationship');\ngoog.require('ol.geom.flat.transform');\ngoog.require('ol.has');\ngoog.require('ol.obj');\ngoog.require('ol.render.VectorContext');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.Instruction');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.render.VectorContext}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Maximum extent.\n * @param {number} resolution Resolution.\n * @param {boolean} overlaps The replay can have overlapping geometries.\n * @struct\n */\nol.render.canvas.Replay = function(tolerance, maxExtent, resolution, overlaps) {\n  ol.render.VectorContext.call(this);\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.tolerance = tolerance;\n\n  /**\n   * @protected\n   * @const\n   * @type {ol.Extent}\n   */\n  this.maxExtent = maxExtent;\n\n  /**\n   * @protected\n   * @type {boolean}\n   */\n  this.overlaps = overlaps;\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.maxLineWidth = 0;\n\n  /**\n   * @protected\n   * @const\n   * @type {number}\n   */\n  this.resolution = resolution;\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.fillOrigin_;\n\n  /**\n   * @private\n   * @type {Array.<*>}\n   */\n  this.beginGeometryInstruction1_ = null;\n\n  /**\n   * @private\n   * @type {Array.<*>}\n   */\n  this.beginGeometryInstruction2_ = null;\n\n  /**\n   * @protected\n   * @type {Array.<*>}\n   */\n  this.instructions = [];\n\n  /**\n   * @protected\n   * @type {Array.<number>}\n   */\n  this.coordinates = [];\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.renderedTransform_ = ol.transform.create();\n\n  /**\n   * @protected\n   * @type {Array.<*>}\n   */\n  this.hitDetectionInstructions = [];\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.pixelCoordinates_ = [];\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.tmpLocalTransform_ = ol.transform.create();\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.resetTransform_ = ol.transform.create();\n};\nol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {boolean} closed Last input coordinate equals first.\n * @param {boolean} skipFirst Skip first coordinate.\n * @protected\n * @return {number} My end.\n */\nol.render.canvas.Replay.prototype.appendFlatCoordinates = function(flatCoordinates, offset, end, stride, closed, skipFirst) {\n\n  var myEnd = this.coordinates.length;\n  var extent = this.getBufferedMaxExtent();\n  if (skipFirst) {\n    offset += stride;\n  }\n  var lastCoord = [flatCoordinates[offset], flatCoordinates[offset + 1]];\n  var nextCoord = [NaN, NaN];\n  var skipped = true;\n\n  var i, lastRel, nextRel;\n  for (i = offset + stride; i < end; i += stride) {\n    nextCoord[0] = flatCoordinates[i];\n    nextCoord[1] = flatCoordinates[i + 1];\n    nextRel = ol.extent.coordinateRelationship(extent, nextCoord);\n    if (nextRel !== lastRel) {\n      if (skipped) {\n        this.coordinates[myEnd++] = lastCoord[0];\n        this.coordinates[myEnd++] = lastCoord[1];\n      }\n      this.coordinates[myEnd++] = nextCoord[0];\n      this.coordinates[myEnd++] = nextCoord[1];\n      skipped = false;\n    } else if (nextRel === ol.extent.Relationship.INTERSECTING) {\n      this.coordinates[myEnd++] = nextCoord[0];\n      this.coordinates[myEnd++] = nextCoord[1];\n      skipped = false;\n    } else {\n      skipped = true;\n    }\n    lastCoord[0] = nextCoord[0];\n    lastCoord[1] = nextCoord[1];\n    lastRel = nextRel;\n  }\n\n  // Last coordinate equals first or only one point to append:\n  if ((closed && skipped) || i === offset + stride) {\n    this.coordinates[myEnd++] = lastCoord[0];\n    this.coordinates[myEnd++] = lastCoord[1];\n  }\n  return myEnd;\n};\n\n\n/**\n * @protected\n * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) {\n  this.beginGeometryInstruction1_ =\n      [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0];\n  this.instructions.push(this.beginGeometryInstruction1_);\n  this.beginGeometryInstruction2_ =\n      [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0];\n  this.hitDetectionInstructions.push(this.beginGeometryInstruction2_);\n};\n\n\n/**\n * @private\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} rotation Rotation.\n */\nol.render.canvas.Replay.prototype.fill_ = function(context, rotation) {\n  if (this.fillOrigin_) {\n    var origin = ol.transform.apply(this.renderedTransform_, this.fillOrigin_.slice());\n    context.translate(origin[0], origin[1]);\n    context.rotate(rotation);\n  }\n  context.fill();\n  if (this.fillOrigin_) {\n    context.setTransform.apply(context, this.resetTransform_);\n  }\n};\n\n\n/**\n * @private\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Transform} transform Transform.\n * @param {number} viewRotation View rotation.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *     to skip.\n * @param {Array.<*>} instructions Instructions array.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined}\n *     featureCallback Feature callback.\n * @param {ol.Extent=} opt_hitExtent Only check features that intersect this\n *     extent.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.canvas.Replay.prototype.replay_ = function(\n    context, pixelRatio, transform, viewRotation, skippedFeaturesHash,\n    instructions, featureCallback, opt_hitExtent) {\n  /** @type {Array.<number>} */\n  var pixelCoordinates;\n  if (ol.array.equals(transform, this.renderedTransform_)) {\n    pixelCoordinates = this.pixelCoordinates_;\n  } else {\n    pixelCoordinates = ol.geom.flat.transform.transform2D(\n        this.coordinates, 0, this.coordinates.length, 2,\n        transform, this.pixelCoordinates_);\n    ol.transform.setFromArray(this.renderedTransform_, transform);\n    ol.DEBUG && console.assert(pixelCoordinates === this.pixelCoordinates_,\n        'pixelCoordinates should be the same as this.pixelCoordinates_');\n  }\n  var skipFeatures = !ol.obj.isEmpty(skippedFeaturesHash);\n  var i = 0; // instruction index\n  var ii = instructions.length; // end of instructions\n  var d = 0; // data index\n  var dd; // end of per-instruction data\n  var localTransform = this.tmpLocalTransform_;\n  var resetTransform = this.resetTransform_;\n  var prevX, prevY, roundX, roundY;\n  var pendingFill = 0;\n  var pendingStroke = 0;\n  // When the batch size gets too big, performance decreases. 200 is a good\n  // balance between batch size and number of fill/stroke instructions.\n  var batchSize =\n      this.instructions != instructions || this.overlaps ? 0 : 200;\n  while (i < ii) {\n    var instruction = instructions[i];\n    var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);\n    var feature, fill, stroke, text, x, y;\n    switch (type) {\n      case ol.render.canvas.Instruction.BEGIN_GEOMETRY:\n        feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]);\n        if ((skipFeatures &&\n            skippedFeaturesHash[ol.getUid(feature).toString()]) ||\n            !feature.getGeometry()) {\n          i = /** @type {number} */ (instruction[2]);\n        } else if (opt_hitExtent !== undefined && !ol.extent.intersects(\n            opt_hitExtent, feature.getGeometry().getExtent())) {\n          i = /** @type {number} */ (instruction[2]) + 1;\n        } else {\n          ++i;\n        }\n        break;\n      case ol.render.canvas.Instruction.BEGIN_PATH:\n        if (pendingFill > batchSize) {\n          this.fill_(context, viewRotation);\n          pendingFill = 0;\n        }\n        if (pendingStroke > batchSize) {\n          context.stroke();\n          pendingStroke = 0;\n        }\n        if (!pendingFill && !pendingStroke) {\n          context.beginPath();\n        }\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.CIRCLE:\n        ol.DEBUG && console.assert(typeof instruction[1] === 'number',\n            'second instruction should be a number');\n        d = /** @type {number} */ (instruction[1]);\n        var x1 = pixelCoordinates[d];\n        var y1 = pixelCoordinates[d + 1];\n        var x2 = pixelCoordinates[d + 2];\n        var y2 = pixelCoordinates[d + 3];\n        var dx = x2 - x1;\n        var dy = y2 - y1;\n        var r = Math.sqrt(dx * dx + dy * dy);\n        context.moveTo(x1 + r, y1);\n        context.arc(x1, y1, r, 0, 2 * Math.PI, true);\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.CLOSE_PATH:\n        context.closePath();\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.DRAW_IMAGE:\n        ol.DEBUG && console.assert(typeof instruction[1] === 'number',\n            'second instruction should be a number');\n        d = /** @type {number} */ (instruction[1]);\n        ol.DEBUG && console.assert(typeof instruction[2] === 'number',\n            'third instruction should be a number');\n        dd = /** @type {number} */ (instruction[2]);\n        var image =  /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */\n            (instruction[3]);\n        // Remaining arguments in DRAW_IMAGE are in alphabetical order\n        var anchorX = /** @type {number} */ (instruction[4]) * pixelRatio;\n        var anchorY = /** @type {number} */ (instruction[5]) * pixelRatio;\n        var height = /** @type {number} */ (instruction[6]);\n        var opacity = /** @type {number} */ (instruction[7]);\n        var originX = /** @type {number} */ (instruction[8]);\n        var originY = /** @type {number} */ (instruction[9]);\n        var rotateWithView = /** @type {boolean} */ (instruction[10]);\n        var rotation = /** @type {number} */ (instruction[11]);\n        var scale = /** @type {number} */ (instruction[12]);\n        var snapToPixel = /** @type {boolean} */ (instruction[13]);\n        var width = /** @type {number} */ (instruction[14]);\n        if (rotateWithView) {\n          rotation += viewRotation;\n        }\n        for (; d < dd; d += 2) {\n          x = pixelCoordinates[d] - anchorX;\n          y = pixelCoordinates[d + 1] - anchorY;\n          if (snapToPixel) {\n            x = Math.round(x);\n            y = Math.round(y);\n          }\n          if (scale != 1 || rotation !== 0) {\n            var centerX = x + anchorX;\n            var centerY = y + anchorY;\n            ol.transform.compose(localTransform,\n                centerX, centerY, scale, scale, rotation, -centerX, -centerY);\n            context.setTransform.apply(context, localTransform);\n          }\n          var alpha = context.globalAlpha;\n          if (opacity != 1) {\n            context.globalAlpha = alpha * opacity;\n          }\n\n          var w = (width + originX > image.width) ? image.width - originX : width;\n          var h = (height + originY > image.height) ? image.height - originY : height;\n\n          context.drawImage(image, originX, originY, w, h,\n              x, y, w * pixelRatio, h * pixelRatio);\n\n          if (opacity != 1) {\n            context.globalAlpha = alpha;\n          }\n          if (scale != 1 || rotation !== 0) {\n            context.setTransform.apply(context, resetTransform);\n          }\n        }\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.DRAW_TEXT:\n        ol.DEBUG && console.assert(typeof instruction[1] === 'number',\n            '2nd instruction should be a number');\n        d = /** @type {number} */ (instruction[1]);\n        ol.DEBUG && console.assert(typeof instruction[2] === 'number',\n            '3rd instruction should be a number');\n        dd = /** @type {number} */ (instruction[2]);\n        ol.DEBUG && console.assert(typeof instruction[3] === 'string',\n            '4th instruction should be a string');\n        text = /** @type {string} */ (instruction[3]);\n        ol.DEBUG && console.assert(typeof instruction[4] === 'number',\n            '5th instruction should be a number');\n        var offsetX = /** @type {number} */ (instruction[4]) * pixelRatio;\n        ol.DEBUG && console.assert(typeof instruction[5] === 'number',\n            '6th instruction should be a number');\n        var offsetY = /** @type {number} */ (instruction[5]) * pixelRatio;\n        ol.DEBUG && console.assert(typeof instruction[6] === 'number',\n            '7th instruction should be a number');\n        rotation = /** @type {number} */ (instruction[6]);\n        ol.DEBUG && console.assert(typeof instruction[7] === 'number',\n            '8th instruction should be a number');\n        scale = /** @type {number} */ (instruction[7]) * pixelRatio;\n        ol.DEBUG && console.assert(typeof instruction[8] === 'boolean',\n            '9th instruction should be a boolean');\n        fill = /** @type {boolean} */ (instruction[8]);\n        ol.DEBUG && console.assert(typeof instruction[9] === 'boolean',\n            '10th instruction should be a boolean');\n        stroke = /** @type {boolean} */ (instruction[9]);\n        rotateWithView = /** @type {boolean} */ (instruction[10]);\n        if (rotateWithView) {\n          rotation += viewRotation;\n        }\n        for (; d < dd; d += 2) {\n          x = pixelCoordinates[d] + offsetX;\n          y = pixelCoordinates[d + 1] + offsetY;\n          if (scale != 1 || rotation !== 0) {\n            ol.transform.compose(localTransform, x, y, scale, scale, rotation, -x, -y);\n            context.setTransform.apply(context, localTransform);\n          }\n\n          // Support multiple lines separated by \\n\n          var lines = text.split('\\n');\n          var numLines = lines.length;\n          var fontSize, lineY;\n          if (numLines > 1) {\n            // Estimate line height using width of capital M, and add padding\n            fontSize = Math.round(context.measureText('M').width * 1.5);\n            lineY = y - (((numLines - 1) / 2) * fontSize);\n          } else {\n            // No need to calculate line height/offset for a single line\n            fontSize = 0;\n            lineY = y;\n          }\n\n          for (var lineIndex = 0; lineIndex < numLines; lineIndex++) {\n            var line = lines[lineIndex];\n            if (stroke) {\n              context.strokeText(line, x, lineY);\n            }\n            if (fill) {\n              context.fillText(line, x, lineY);\n            }\n\n            // Move next line down by fontSize px\n            lineY = lineY + fontSize;\n          }\n\n          if (scale != 1 || rotation !== 0) {\n            context.setTransform.apply(context, resetTransform);\n          }\n        }\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.END_GEOMETRY:\n        if (featureCallback !== undefined) {\n          feature =\n              /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]);\n          var result = featureCallback(feature);\n          if (result) {\n            return result;\n          }\n        }\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.FILL:\n        if (batchSize) {\n          pendingFill++;\n        } else {\n          this.fill_(context, viewRotation);\n        }\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.MOVE_TO_LINE_TO:\n        ol.DEBUG && console.assert(typeof instruction[1] === 'number',\n            '2nd instruction should be a number');\n        d = /** @type {number} */ (instruction[1]);\n        ol.DEBUG && console.assert(typeof instruction[2] === 'number',\n            '3rd instruction should be a number');\n        dd = /** @type {number} */ (instruction[2]);\n        x = pixelCoordinates[d];\n        y = pixelCoordinates[d + 1];\n        roundX = (x + 0.5) | 0;\n        roundY = (y + 0.5) | 0;\n        if (roundX !== prevX || roundY !== prevY) {\n          context.moveTo(x, y);\n          prevX = roundX;\n          prevY = roundY;\n        }\n        for (d += 2; d < dd; d += 2) {\n          x = pixelCoordinates[d];\n          y = pixelCoordinates[d + 1];\n          roundX = (x + 0.5) | 0;\n          roundY = (y + 0.5) | 0;\n          if (d == dd - 2 || roundX !== prevX || roundY !== prevY) {\n            context.lineTo(x, y);\n            prevX = roundX;\n            prevY = roundY;\n          }\n        }\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.SET_FILL_STYLE:\n        ol.DEBUG && console.assert(\n            ol.colorlike.isColorLike(instruction[1]),\n            '2nd instruction should be a string, ' +\n            'CanvasPattern, or CanvasGradient');\n        this.fillOrigin_ = instruction[2];\n\n        if (pendingFill) {\n          this.fill_(context, viewRotation);\n          pendingFill = 0;\n        }\n\n        context.fillStyle = /** @type {ol.ColorLike} */ (instruction[1]);\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.SET_STROKE_STYLE:\n        ol.DEBUG && console.assert(ol.colorlike.isColorLike(instruction[1]),\n            '2nd instruction should be a string, CanvasPattern, or CanvasGradient');\n        ol.DEBUG && console.assert(typeof instruction[2] === 'number',\n            '3rd instruction should be a number');\n        ol.DEBUG && console.assert(typeof instruction[3] === 'string',\n            '4rd instruction should be a string');\n        ol.DEBUG && console.assert(typeof instruction[4] === 'string',\n            '5th instruction should be a string');\n        ol.DEBUG && console.assert(typeof instruction[5] === 'number',\n            '6th instruction should be a number');\n        ol.DEBUG && console.assert(instruction[6],\n            '7th instruction should not be null');\n        ol.DEBUG && console.assert(typeof instruction[8] === 'number',\n            '9th instruction should be a number');\n        var usePixelRatio = instruction[7] !== undefined ?\n            instruction[7] : true;\n        var renderedPixelRatio = instruction[8];\n\n        var lineWidth = /** @type {number} */ (instruction[2]);\n        if (pendingStroke) {\n          context.stroke();\n          pendingStroke = 0;\n        }\n        context.strokeStyle = /** @type {ol.ColorLike} */ (instruction[1]);\n        context.lineWidth = usePixelRatio ? lineWidth * pixelRatio : lineWidth;\n        context.lineCap = /** @type {string} */ (instruction[3]);\n        context.lineJoin = /** @type {string} */ (instruction[4]);\n        context.miterLimit = /** @type {number} */ (instruction[5]);\n        if (ol.has.CANVAS_LINE_DASH) {\n          var lineDash = /** @type {Array.<number>} */ (instruction[6]);\n          if (usePixelRatio && pixelRatio !== renderedPixelRatio) {\n            lineDash = lineDash.map(function(dash) {\n              return dash * pixelRatio / renderedPixelRatio;\n            });\n            instruction[6] = lineDash;\n            instruction[8] = pixelRatio;\n          }\n          context.setLineDash(lineDash);\n        }\n        prevX = NaN;\n        prevY = NaN;\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.SET_TEXT_STYLE:\n        ol.DEBUG && console.assert(typeof instruction[1] === 'string',\n            '2nd instruction should be a string');\n        ol.DEBUG && console.assert(typeof instruction[2] === 'string',\n            '3rd instruction should be a string');\n        ol.DEBUG && console.assert(typeof instruction[3] === 'string',\n            '4th instruction should be a string');\n        context.font = /** @type {string} */ (instruction[1]);\n        context.textAlign = /** @type {string} */ (instruction[2]);\n        context.textBaseline = /** @type {string} */ (instruction[3]);\n        ++i;\n        break;\n      case ol.render.canvas.Instruction.STROKE:\n        if (batchSize) {\n          pendingStroke++;\n        } else {\n          context.stroke();\n        }\n        ++i;\n        break;\n      default:\n        ol.DEBUG && console.assert(false, 'Unknown canvas render instruction');\n        ++i; // consume the instruction anyway, to avoid an infinite loop\n        break;\n    }\n  }\n  if (pendingFill) {\n    this.fill_(context, viewRotation);\n  }\n  if (pendingStroke) {\n    context.stroke();\n  }\n  // assert that all instructions were consumed\n  ol.DEBUG && console.assert(i == instructions.length,\n      'all instructions should be consumed');\n  return undefined;\n};\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Transform} transform Transform.\n * @param {number} viewRotation View rotation.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *     to skip.\n */\nol.render.canvas.Replay.prototype.replay = function(\n    context, pixelRatio, transform, viewRotation, skippedFeaturesHash) {\n  var instructions = this.instructions;\n  this.replay_(context, pixelRatio, transform, viewRotation,\n      skippedFeaturesHash, instructions, undefined, undefined);\n};\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {ol.Transform} transform Transform.\n * @param {number} viewRotation View rotation.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *     to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T=} opt_featureCallback\n *     Feature callback.\n * @param {ol.Extent=} opt_hitExtent Only check features that intersect this\n *     extent.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.canvas.Replay.prototype.replayHitDetection = function(\n    context, transform, viewRotation, skippedFeaturesHash,\n    opt_featureCallback, opt_hitExtent) {\n  var instructions = this.hitDetectionInstructions;\n  return this.replay_(context, 1, transform, viewRotation,\n      skippedFeaturesHash, instructions, opt_featureCallback, opt_hitExtent);\n};\n\n\n/**\n * Reverse the hit detection instructions.\n */\nol.render.canvas.Replay.prototype.reverseHitDetectionInstructions = function() {\n  var hitDetectionInstructions = this.hitDetectionInstructions;\n  // step 1 - reverse array\n  hitDetectionInstructions.reverse();\n  // step 2 - reverse instructions within geometry blocks\n  var i;\n  var n = hitDetectionInstructions.length;\n  var instruction;\n  var type;\n  var begin = -1;\n  for (i = 0; i < n; ++i) {\n    instruction = hitDetectionInstructions[i];\n    type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);\n    if (type == ol.render.canvas.Instruction.END_GEOMETRY) {\n      ol.DEBUG && console.assert(begin == -1, 'begin should be -1');\n      begin = i;\n    } else if (type == ol.render.canvas.Instruction.BEGIN_GEOMETRY) {\n      instruction[2] = i;\n      ol.DEBUG && console.assert(begin >= 0,\n          'begin should be larger than or equal to 0');\n      ol.array.reverseSubArray(this.hitDetectionInstructions, begin, i);\n      begin = -1;\n    }\n  }\n};\n\n\n/**\n * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.canvas.Replay.prototype.endGeometry = function(geometry, feature) {\n  ol.DEBUG && console.assert(this.beginGeometryInstruction1_,\n      'this.beginGeometryInstruction1_ should not be null');\n  this.beginGeometryInstruction1_[2] = this.instructions.length;\n  this.beginGeometryInstruction1_ = null;\n  ol.DEBUG && console.assert(this.beginGeometryInstruction2_,\n      'this.beginGeometryInstruction2_ should not be null');\n  this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length;\n  this.beginGeometryInstruction2_ = null;\n  var endGeometryInstruction =\n      [ol.render.canvas.Instruction.END_GEOMETRY, feature];\n  this.instructions.push(endGeometryInstruction);\n  this.hitDetectionInstructions.push(endGeometryInstruction);\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nol.render.canvas.Replay.prototype.finish = ol.nullFunction;\n\n\n/**\n * Get the buffered rendering extent.  Rendering will be clipped to the extent\n * provided to the constructor.  To account for symbolizers that may intersect\n * this extent, we calculate a buffered extent (e.g. based on stroke width).\n * @return {ol.Extent} The buffered rendering extent.\n * @protected\n */\nol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() {\n  return this.maxExtent;\n};\n\ngoog.provide('ol.render.canvas.ImageReplay');\n\ngoog.require('ol');\ngoog.require('ol.render.canvas.Instruction');\ngoog.require('ol.render.canvas.Replay');\n\n\n/**\n * @constructor\n * @extends {ol.render.canvas.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Maximum extent.\n * @param {number} resolution Resolution.\n * @param {boolean} overlaps The replay can have overlapping geometries.\n * @struct\n */\nol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution, overlaps) {\n  ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement|HTMLVideoElement|Image}\n   */\n  this.hitDetectionImage_ = null;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement|HTMLVideoElement|Image}\n   */\n  this.image_ = null;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.anchorX_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.anchorY_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.height_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.opacity_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.originX_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.originY_ = undefined;\n\n  /**\n   * @private\n   * @type {boolean|undefined}\n   */\n  this.rotateWithView_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.rotation_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.scale_ = undefined;\n\n  /**\n   * @private\n   * @type {boolean|undefined}\n   */\n  this.snapToPixel_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.width_ = undefined;\n\n};\nol.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay);\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @private\n * @return {number} My end.\n */\nol.render.canvas.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) {\n  return this.appendFlatCoordinates(\n      flatCoordinates, offset, end, stride, false, false);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) {\n  if (!this.image_) {\n    return;\n  }\n  ol.DEBUG && console.assert(this.anchorX_ !== undefined,\n      'this.anchorX_ should be defined');\n  ol.DEBUG && console.assert(this.anchorY_ !== undefined,\n      'this.anchorY_ should be defined');\n  ol.DEBUG && console.assert(this.height_ !== undefined,\n      'this.height_ should be defined');\n  ol.DEBUG && console.assert(this.opacity_ !== undefined,\n      'this.opacity_ should be defined');\n  ol.DEBUG && console.assert(this.originX_ !== undefined,\n      'this.originX_ should be defined');\n  ol.DEBUG && console.assert(this.originY_ !== undefined,\n      'this.originY_ should be defined');\n  ol.DEBUG && console.assert(this.rotateWithView_ !== undefined,\n      'this.rotateWithView_ should be defined');\n  ol.DEBUG && console.assert(this.rotation_ !== undefined,\n      'this.rotation_ should be defined');\n  ol.DEBUG && console.assert(this.scale_ !== undefined,\n      'this.scale_ should be defined');\n  ol.DEBUG && console.assert(this.width_ !== undefined,\n      'this.width_ should be defined');\n  this.beginGeometry(pointGeometry, feature);\n  var flatCoordinates = pointGeometry.getFlatCoordinates();\n  var stride = pointGeometry.getStride();\n  var myBegin = this.coordinates.length;\n  var myEnd = this.drawCoordinates_(\n      flatCoordinates, 0, flatCoordinates.length, stride);\n  this.instructions.push([\n    ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,\n    // Remaining arguments to DRAW_IMAGE are in alphabetical order\n    this.anchorX_, this.anchorY_, this.height_, this.opacity_,\n    this.originX_, this.originY_, this.rotateWithView_, this.rotation_,\n    this.scale_, this.snapToPixel_, this.width_\n  ]);\n  this.hitDetectionInstructions.push([\n    ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,\n    this.hitDetectionImage_,\n    // Remaining arguments to DRAW_IMAGE are in alphabetical order\n    this.anchorX_, this.anchorY_, this.height_, this.opacity_,\n    this.originX_, this.originY_, this.rotateWithView_, this.rotation_,\n    this.scale_, this.snapToPixel_, this.width_\n  ]);\n  this.endGeometry(pointGeometry, feature);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) {\n  if (!this.image_) {\n    return;\n  }\n  ol.DEBUG && console.assert(this.anchorX_ !== undefined,\n      'this.anchorX_ should be defined');\n  ol.DEBUG && console.assert(this.anchorY_ !== undefined,\n      'this.anchorY_ should be defined');\n  ol.DEBUG && console.assert(this.height_ !== undefined,\n      'this.height_ should be defined');\n  ol.DEBUG && console.assert(this.opacity_ !== undefined,\n      'this.opacity_ should be defined');\n  ol.DEBUG && console.assert(this.originX_ !== undefined,\n      'this.originX_ should be defined');\n  ol.DEBUG && console.assert(this.originY_ !== undefined,\n      'this.originY_ should be defined');\n  ol.DEBUG && console.assert(this.rotateWithView_ !== undefined,\n      'this.rotateWithView_ should be defined');\n  ol.DEBUG && console.assert(this.rotation_ !== undefined,\n      'this.rotation_ should be defined');\n  ol.DEBUG && console.assert(this.scale_ !== undefined,\n      'this.scale_ should be defined');\n  ol.DEBUG && console.assert(this.width_ !== undefined,\n      'this.width_ should be defined');\n  this.beginGeometry(multiPointGeometry, feature);\n  var flatCoordinates = multiPointGeometry.getFlatCoordinates();\n  var stride = multiPointGeometry.getStride();\n  var myBegin = this.coordinates.length;\n  var myEnd = this.drawCoordinates_(\n      flatCoordinates, 0, flatCoordinates.length, stride);\n  this.instructions.push([\n    ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,\n    // Remaining arguments to DRAW_IMAGE are in alphabetical order\n    this.anchorX_, this.anchorY_, this.height_, this.opacity_,\n    this.originX_, this.originY_, this.rotateWithView_, this.rotation_,\n    this.scale_, this.snapToPixel_, this.width_\n  ]);\n  this.hitDetectionInstructions.push([\n    ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,\n    this.hitDetectionImage_,\n    // Remaining arguments to DRAW_IMAGE are in alphabetical order\n    this.anchorX_, this.anchorY_, this.height_, this.opacity_,\n    this.originX_, this.originY_, this.rotateWithView_, this.rotation_,\n    this.scale_, this.snapToPixel_, this.width_\n  ]);\n  this.endGeometry(multiPointGeometry, feature);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.ImageReplay.prototype.finish = function() {\n  this.reverseHitDetectionInstructions();\n  // FIXME this doesn't really protect us against further calls to draw*Geometry\n  this.anchorX_ = undefined;\n  this.anchorY_ = undefined;\n  this.hitDetectionImage_ = null;\n  this.image_ = null;\n  this.height_ = undefined;\n  this.scale_ = undefined;\n  this.opacity_ = undefined;\n  this.originX_ = undefined;\n  this.originY_ = undefined;\n  this.rotateWithView_ = undefined;\n  this.rotation_ = undefined;\n  this.snapToPixel_ = undefined;\n  this.width_ = undefined;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) {\n  ol.DEBUG && console.assert(imageStyle, 'imageStyle should not be null');\n  var anchor = imageStyle.getAnchor();\n  ol.DEBUG && console.assert(anchor, 'anchor should not be null');\n  var size = imageStyle.getSize();\n  ol.DEBUG && console.assert(size, 'size should not be null');\n  var hitDetectionImage = imageStyle.getHitDetectionImage(1);\n  ol.DEBUG && console.assert(hitDetectionImage,\n      'hitDetectionImage should not be null');\n  var image = imageStyle.getImage(1);\n  ol.DEBUG && console.assert(image, 'image should not be null');\n  var origin = imageStyle.getOrigin();\n  ol.DEBUG && console.assert(origin, 'origin should not be null');\n  this.anchorX_ = anchor[0];\n  this.anchorY_ = anchor[1];\n  this.hitDetectionImage_ = hitDetectionImage;\n  this.image_ = image;\n  this.height_ = size[1];\n  this.opacity_ = imageStyle.getOpacity();\n  this.originX_ = origin[0];\n  this.originY_ = origin[1];\n  this.rotateWithView_ = imageStyle.getRotateWithView();\n  this.rotation_ = imageStyle.getRotation();\n  this.scale_ = imageStyle.getScale();\n  this.snapToPixel_ = imageStyle.getSnapToPixel();\n  this.width_ = size[0];\n};\n\ngoog.provide('ol.render.canvas.LineStringReplay');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.colorlike');\ngoog.require('ol.extent');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.Instruction');\ngoog.require('ol.render.canvas.Replay');\n\n\n/**\n * @constructor\n * @extends {ol.render.canvas.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Maximum extent.\n * @param {number} resolution Resolution.\n * @param {boolean} overlaps The replay can have overlapping geometries.\n * @struct\n */\nol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution, overlaps) {\n\n  ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.bufferedMaxExtent_ = null;\n\n  /**\n   * @private\n   * @type {{currentStrokeStyle: (ol.ColorLike|undefined),\n   *         currentLineCap: (string|undefined),\n   *         currentLineDash: Array.<number>,\n   *         currentLineJoin: (string|undefined),\n   *         currentLineWidth: (number|undefined),\n   *         currentMiterLimit: (number|undefined),\n   *         lastStroke: number,\n   *         strokeStyle: (ol.ColorLike|undefined),\n   *         lineCap: (string|undefined),\n   *         lineDash: Array.<number>,\n   *         lineJoin: (string|undefined),\n   *         lineWidth: (number|undefined),\n   *         miterLimit: (number|undefined)}|null}\n   */\n  this.state_ = {\n    currentStrokeStyle: undefined,\n    currentLineCap: undefined,\n    currentLineDash: null,\n    currentLineJoin: undefined,\n    currentLineWidth: undefined,\n    currentMiterLimit: undefined,\n    lastStroke: 0,\n    strokeStyle: undefined,\n    lineCap: undefined,\n    lineDash: null,\n    lineJoin: undefined,\n    lineWidth: undefined,\n    miterLimit: undefined\n  };\n\n};\nol.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay);\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @private\n * @return {number} end.\n */\nol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = function(flatCoordinates, offset, end, stride) {\n  var myBegin = this.coordinates.length;\n  var myEnd = this.appendFlatCoordinates(\n      flatCoordinates, offset, end, stride, false, false);\n  var moveToLineToInstruction =\n      [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd];\n  this.instructions.push(moveToLineToInstruction);\n  this.hitDetectionInstructions.push(moveToLineToInstruction);\n  return end;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() {\n  if (!this.bufferedMaxExtent_) {\n    this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);\n    if (this.maxLineWidth > 0) {\n      var width = this.resolution * (this.maxLineWidth + 1) / 2;\n      ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);\n    }\n  }\n  return this.bufferedMaxExtent_;\n};\n\n\n/**\n * @private\n */\nol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() {\n  var state = this.state_;\n  var strokeStyle = state.strokeStyle;\n  var lineCap = state.lineCap;\n  var lineDash = state.lineDash;\n  var lineJoin = state.lineJoin;\n  var lineWidth = state.lineWidth;\n  var miterLimit = state.miterLimit;\n  ol.DEBUG && console.assert(strokeStyle !== undefined,\n      'strokeStyle should be defined');\n  ol.DEBUG && console.assert(lineCap !== undefined, 'lineCap should be defined');\n  ol.DEBUG && console.assert(lineDash, 'lineDash should not be null');\n  ol.DEBUG && console.assert(lineJoin !== undefined, 'lineJoin should be defined');\n  ol.DEBUG && console.assert(lineWidth !== undefined, 'lineWidth should be defined');\n  ol.DEBUG && console.assert(miterLimit !== undefined, 'miterLimit should be defined');\n  if (state.currentStrokeStyle != strokeStyle ||\n      state.currentLineCap != lineCap ||\n      !ol.array.equals(state.currentLineDash, lineDash) ||\n      state.currentLineJoin != lineJoin ||\n      state.currentLineWidth != lineWidth ||\n      state.currentMiterLimit != miterLimit) {\n    if (state.lastStroke != this.coordinates.length) {\n      this.instructions.push([ol.render.canvas.Instruction.STROKE]);\n      state.lastStroke = this.coordinates.length;\n    }\n    this.instructions.push([\n      ol.render.canvas.Instruction.SET_STROKE_STYLE,\n      strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash, true, 1\n    ], [\n      ol.render.canvas.Instruction.BEGIN_PATH\n    ]);\n    state.currentStrokeStyle = strokeStyle;\n    state.currentLineCap = lineCap;\n    state.currentLineDash = lineDash;\n    state.currentLineJoin = lineJoin;\n    state.currentLineWidth = lineWidth;\n    state.currentMiterLimit = miterLimit;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) {\n  var state = this.state_;\n  ol.DEBUG && console.assert(state, 'state should not be null');\n  var strokeStyle = state.strokeStyle;\n  var lineWidth = state.lineWidth;\n  if (strokeStyle === undefined || lineWidth === undefined) {\n    return;\n  }\n  this.setStrokeStyle_();\n  this.beginGeometry(lineStringGeometry, feature);\n  this.hitDetectionInstructions.push([\n    ol.render.canvas.Instruction.SET_STROKE_STYLE,\n    state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,\n    state.miterLimit, state.lineDash, true, 1\n  ], [\n    ol.render.canvas.Instruction.BEGIN_PATH\n  ]);\n  var flatCoordinates = lineStringGeometry.getFlatCoordinates();\n  var stride = lineStringGeometry.getStride();\n  this.drawFlatCoordinates_(flatCoordinates, 0, flatCoordinates.length, stride);\n  this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]);\n  this.endGeometry(lineStringGeometry, feature);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {\n  var state = this.state_;\n  ol.DEBUG && console.assert(state, 'state should not be null');\n  var strokeStyle = state.strokeStyle;\n  var lineWidth = state.lineWidth;\n  if (strokeStyle === undefined || lineWidth === undefined) {\n    return;\n  }\n  this.setStrokeStyle_();\n  this.beginGeometry(multiLineStringGeometry, feature);\n  this.hitDetectionInstructions.push([\n    ol.render.canvas.Instruction.SET_STROKE_STYLE,\n    state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,\n    state.miterLimit, state.lineDash, true, 1\n  ], [\n    ol.render.canvas.Instruction.BEGIN_PATH\n  ]);\n  var ends = multiLineStringGeometry.getEnds();\n  var flatCoordinates = multiLineStringGeometry.getFlatCoordinates();\n  var stride = multiLineStringGeometry.getStride();\n  var offset = 0;\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    offset = this.drawFlatCoordinates_(\n        flatCoordinates, offset, ends[i], stride);\n  }\n  this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]);\n  this.endGeometry(multiLineStringGeometry, feature);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.LineStringReplay.prototype.finish = function() {\n  var state = this.state_;\n  ol.DEBUG && console.assert(state, 'state should not be null');\n  if (state.lastStroke != this.coordinates.length) {\n    this.instructions.push([ol.render.canvas.Instruction.STROKE]);\n  }\n  this.reverseHitDetectionInstructions();\n  this.state_ = null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {\n  ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');\n  ol.DEBUG && console.assert(!fillStyle, 'fillStyle should be null');\n  ol.DEBUG && console.assert(strokeStyle, 'strokeStyle should not be null');\n  var strokeStyleColor = strokeStyle.getColor();\n  this.state_.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?\n      strokeStyleColor : ol.render.canvas.defaultStrokeStyle);\n  var strokeStyleLineCap = strokeStyle.getLineCap();\n  this.state_.lineCap = strokeStyleLineCap !== undefined ?\n      strokeStyleLineCap : ol.render.canvas.defaultLineCap;\n  var strokeStyleLineDash = strokeStyle.getLineDash();\n  this.state_.lineDash = strokeStyleLineDash ?\n      strokeStyleLineDash : ol.render.canvas.defaultLineDash;\n  var strokeStyleLineJoin = strokeStyle.getLineJoin();\n  this.state_.lineJoin = strokeStyleLineJoin !== undefined ?\n      strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;\n  var strokeStyleWidth = strokeStyle.getWidth();\n  this.state_.lineWidth = strokeStyleWidth !== undefined ?\n      strokeStyleWidth : ol.render.canvas.defaultLineWidth;\n  var strokeStyleMiterLimit = strokeStyle.getMiterLimit();\n  this.state_.miterLimit = strokeStyleMiterLimit !== undefined ?\n      strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;\n\n  if (this.state_.lineWidth > this.maxLineWidth) {\n    this.maxLineWidth = this.state_.lineWidth;\n    // invalidate the buffered max extent cache\n    this.bufferedMaxExtent_ = null;\n  }\n};\n\ngoog.provide('ol.render.canvas.PolygonReplay');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.color');\ngoog.require('ol.colorlike');\ngoog.require('ol.extent');\ngoog.require('ol.geom.flat.simplify');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.Instruction');\ngoog.require('ol.render.canvas.Replay');\n\n\n/**\n * @constructor\n * @extends {ol.render.canvas.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Maximum extent.\n * @param {number} resolution Resolution.\n * @param {boolean} overlaps The replay can have overlapping geometries.\n * @struct\n */\nol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution, overlaps) {\n\n  ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.bufferedMaxExtent_ = null;\n\n  /**\n   * @private\n   * @type {{currentFillStyle: (ol.ColorLike|undefined),\n   *         currentStrokeStyle: (ol.ColorLike|undefined),\n   *         currentLineCap: (string|undefined),\n   *         currentLineDash: Array.<number>,\n   *         currentLineJoin: (string|undefined),\n   *         currentLineWidth: (number|undefined),\n   *         currentMiterLimit: (number|undefined),\n   *         fillStyle: (ol.ColorLike|undefined),\n   *         strokeStyle: (ol.ColorLike|undefined),\n   *         lineCap: (string|undefined),\n   *         lineDash: Array.<number>,\n   *         lineJoin: (string|undefined),\n   *         lineWidth: (number|undefined),\n   *         miterLimit: (number|undefined)}|null}\n   */\n  this.state_ = {\n    currentFillStyle: undefined,\n    currentStrokeStyle: undefined,\n    currentLineCap: undefined,\n    currentLineDash: null,\n    currentLineJoin: undefined,\n    currentLineWidth: undefined,\n    currentMiterLimit: undefined,\n    fillStyle: undefined,\n    strokeStyle: undefined,\n    lineCap: undefined,\n    lineDash: null,\n    lineJoin: undefined,\n    lineWidth: undefined,\n    miterLimit: undefined\n  };\n\n};\nol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay);\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @private\n * @return {number} End.\n */\nol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) {\n  var state = this.state_;\n  var fill = state.fillStyle !== undefined;\n  var stroke = state.strokeStyle != undefined;\n  var numEnds = ends.length;\n  var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];\n  this.instructions.push(beginPathInstruction);\n  this.hitDetectionInstructions.push(beginPathInstruction);\n  for (var i = 0; i < numEnds; ++i) {\n    var end = ends[i];\n    var myBegin = this.coordinates.length;\n    var myEnd = this.appendFlatCoordinates(\n        flatCoordinates, offset, end, stride, true, !stroke);\n    var moveToLineToInstruction =\n        [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd];\n    this.instructions.push(moveToLineToInstruction);\n    this.hitDetectionInstructions.push(moveToLineToInstruction);\n    if (stroke) {\n      // Performance optimization: only call closePath() when we have a stroke.\n      // Otherwise the ring is closed already (see appendFlatCoordinates above).\n      var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH];\n      this.instructions.push(closePathInstruction);\n      this.hitDetectionInstructions.push(closePathInstruction);\n    }\n    offset = end;\n  }\n  var fillInstruction = [ol.render.canvas.Instruction.FILL];\n  this.hitDetectionInstructions.push(fillInstruction);\n  if (fill) {\n    this.instructions.push(fillInstruction);\n  }\n  if (stroke) {\n    ol.DEBUG && console.assert(state.lineWidth !== undefined,\n        'state.lineWidth should be defined');\n    var strokeInstruction = [ol.render.canvas.Instruction.STROKE];\n    this.instructions.push(strokeInstruction);\n    this.hitDetectionInstructions.push(strokeInstruction);\n  }\n  return offset;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, feature) {\n  var state = this.state_;\n  ol.DEBUG && console.assert(state, 'state should not be null');\n  var fillStyle = state.fillStyle;\n  var strokeStyle = state.strokeStyle;\n  if (fillStyle === undefined && strokeStyle === undefined) {\n    return;\n  }\n  if (strokeStyle !== undefined) {\n    ol.DEBUG && console.assert(state.lineWidth !== undefined,\n        'state.lineWidth should be defined');\n  }\n  this.setFillStrokeStyles_(circleGeometry);\n  this.beginGeometry(circleGeometry, feature);\n  // always fill the circle for hit detection\n  this.hitDetectionInstructions.push([\n    ol.render.canvas.Instruction.SET_FILL_STYLE,\n    ol.color.asString(ol.render.canvas.defaultFillStyle)\n  ]);\n  if (state.strokeStyle !== undefined) {\n    this.hitDetectionInstructions.push([\n      ol.render.canvas.Instruction.SET_STROKE_STYLE,\n      state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,\n      state.miterLimit, state.lineDash, true, 1\n    ]);\n  }\n  var flatCoordinates = circleGeometry.getFlatCoordinates();\n  var stride = circleGeometry.getStride();\n  var myBegin = this.coordinates.length;\n  this.appendFlatCoordinates(\n      flatCoordinates, 0, flatCoordinates.length, stride, false, false);\n  var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];\n  var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin];\n  this.instructions.push(beginPathInstruction, circleInstruction);\n  this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction);\n  var fillInstruction = [ol.render.canvas.Instruction.FILL];\n  this.hitDetectionInstructions.push(fillInstruction);\n  if (state.fillStyle !== undefined) {\n    this.instructions.push(fillInstruction);\n  }\n  if (state.strokeStyle !== undefined) {\n    ol.DEBUG && console.assert(state.lineWidth !== undefined,\n        'state.lineWidth should be defined');\n    var strokeInstruction = [ol.render.canvas.Instruction.STROKE];\n    this.instructions.push(strokeInstruction);\n    this.hitDetectionInstructions.push(strokeInstruction);\n  }\n  this.endGeometry(circleGeometry, feature);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {\n  var state = this.state_;\n  ol.DEBUG && console.assert(state, 'state should not be null');\n  var strokeStyle = state.strokeStyle;\n  ol.DEBUG && console.assert(state.fillStyle !== undefined || strokeStyle !== undefined,\n      'fillStyle or strokeStyle should be defined');\n  if (strokeStyle !== undefined) {\n    ol.DEBUG && console.assert(state.lineWidth !== undefined,\n        'state.lineWidth should be defined');\n  }\n  this.setFillStrokeStyles_(polygonGeometry);\n  this.beginGeometry(polygonGeometry, feature);\n  // always fill the polygon for hit detection\n  this.hitDetectionInstructions.push([\n    ol.render.canvas.Instruction.SET_FILL_STYLE,\n    ol.color.asString(ol.render.canvas.defaultFillStyle)]\n                                    );\n  if (state.strokeStyle !== undefined) {\n    this.hitDetectionInstructions.push([\n      ol.render.canvas.Instruction.SET_STROKE_STYLE,\n      state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,\n      state.miterLimit, state.lineDash, true, 1\n    ]);\n  }\n  var ends = polygonGeometry.getEnds();\n  var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates();\n  var stride = polygonGeometry.getStride();\n  this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride);\n  this.endGeometry(polygonGeometry, feature);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {\n  var state = this.state_;\n  ol.DEBUG && console.assert(state, 'state should not be null');\n  var fillStyle = state.fillStyle;\n  var strokeStyle = state.strokeStyle;\n  if (fillStyle === undefined && strokeStyle === undefined) {\n    return;\n  }\n  if (strokeStyle !== undefined) {\n    ol.DEBUG && console.assert(state.lineWidth !== undefined,\n        'state.lineWidth should be defined');\n  }\n  this.setFillStrokeStyles_(multiPolygonGeometry);\n  this.beginGeometry(multiPolygonGeometry, feature);\n  // always fill the multi-polygon for hit detection\n  this.hitDetectionInstructions.push([\n    ol.render.canvas.Instruction.SET_FILL_STYLE,\n    ol.color.asString(ol.render.canvas.defaultFillStyle)\n  ]);\n  if (state.strokeStyle !== undefined) {\n    this.hitDetectionInstructions.push([\n      ol.render.canvas.Instruction.SET_STROKE_STYLE,\n      state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,\n      state.miterLimit, state.lineDash, true, 1\n    ]);\n  }\n  var endss = multiPolygonGeometry.getEndss();\n  var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates();\n  var stride = multiPolygonGeometry.getStride();\n  var offset = 0;\n  var i, ii;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    offset = this.drawFlatCoordinatess_(\n        flatCoordinates, offset, endss[i], stride);\n  }\n  this.endGeometry(multiPolygonGeometry, feature);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.PolygonReplay.prototype.finish = function() {\n  ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');\n  this.reverseHitDetectionInstructions();\n  this.state_ = null;\n  // We want to preserve topology when drawing polygons.  Polygons are\n  // simplified using quantization and point elimination. However, we might\n  // have received a mix of quantized and non-quantized geometries, so ensure\n  // that all are quantized by quantizing all coordinates in the batch.\n  var tolerance = this.tolerance;\n  if (tolerance !== 0) {\n    var coordinates = this.coordinates;\n    var i, ii;\n    for (i = 0, ii = coordinates.length; i < ii; ++i) {\n      coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance);\n    }\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() {\n  if (!this.bufferedMaxExtent_) {\n    this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);\n    if (this.maxLineWidth > 0) {\n      var width = this.resolution * (this.maxLineWidth + 1) / 2;\n      ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);\n    }\n  }\n  return this.bufferedMaxExtent_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {\n  ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');\n  ol.DEBUG && console.assert(fillStyle || strokeStyle,\n      'fillStyle or strokeStyle should not be null');\n  var state = this.state_;\n  if (fillStyle) {\n    var fillStyleColor = fillStyle.getColor();\n    state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?\n        fillStyleColor : ol.render.canvas.defaultFillStyle);\n  } else {\n    state.fillStyle = undefined;\n  }\n  if (strokeStyle) {\n    var strokeStyleColor = strokeStyle.getColor();\n    state.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?\n        strokeStyleColor : ol.render.canvas.defaultStrokeStyle);\n    var strokeStyleLineCap = strokeStyle.getLineCap();\n    state.lineCap = strokeStyleLineCap !== undefined ?\n        strokeStyleLineCap : ol.render.canvas.defaultLineCap;\n    var strokeStyleLineDash = strokeStyle.getLineDash();\n    state.lineDash = strokeStyleLineDash ?\n        strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;\n    var strokeStyleLineJoin = strokeStyle.getLineJoin();\n    state.lineJoin = strokeStyleLineJoin !== undefined ?\n        strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;\n    var strokeStyleWidth = strokeStyle.getWidth();\n    state.lineWidth = strokeStyleWidth !== undefined ?\n        strokeStyleWidth : ol.render.canvas.defaultLineWidth;\n    var strokeStyleMiterLimit = strokeStyle.getMiterLimit();\n    state.miterLimit = strokeStyleMiterLimit !== undefined ?\n        strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;\n\n    if (state.lineWidth > this.maxLineWidth) {\n      this.maxLineWidth = state.lineWidth;\n      // invalidate the buffered max extent cache\n      this.bufferedMaxExtent_ = null;\n    }\n  } else {\n    state.strokeStyle = undefined;\n    state.lineCap = undefined;\n    state.lineDash = null;\n    state.lineJoin = undefined;\n    state.lineWidth = undefined;\n    state.miterLimit = undefined;\n  }\n};\n\n\n/**\n * @private\n * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.\n */\nol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function(geometry) {\n  var state = this.state_;\n  var fillStyle = state.fillStyle;\n  var strokeStyle = state.strokeStyle;\n  var lineCap = state.lineCap;\n  var lineDash = state.lineDash;\n  var lineJoin = state.lineJoin;\n  var lineWidth = state.lineWidth;\n  var miterLimit = state.miterLimit;\n  if (fillStyle !== undefined && (typeof fillStyle !== 'string' || state.currentFillStyle != fillStyle)) {\n    var fillInstruction = [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle];\n    if (typeof fillStyle !== 'string') {\n      var fillExtent = geometry.getExtent();\n      fillInstruction.push([fillExtent[0], fillExtent[3]]);\n    }\n    this.instructions.push(fillInstruction);\n    state.currentFillStyle = state.fillStyle;\n  }\n  if (strokeStyle !== undefined) {\n    ol.DEBUG && console.assert(lineCap !== undefined, 'lineCap should be defined');\n    ol.DEBUG && console.assert(lineDash, 'lineDash should not be null');\n    ol.DEBUG && console.assert(lineJoin !== undefined, 'lineJoin should be defined');\n    ol.DEBUG && console.assert(lineWidth !== undefined, 'lineWidth should be defined');\n    ol.DEBUG && console.assert(miterLimit !== undefined,\n        'miterLimit should be defined');\n    if (state.currentStrokeStyle != strokeStyle ||\n        state.currentLineCap != lineCap ||\n        !ol.array.equals(state.currentLineDash, lineDash) ||\n        state.currentLineJoin != lineJoin ||\n        state.currentLineWidth != lineWidth ||\n        state.currentMiterLimit != miterLimit) {\n      this.instructions.push([\n        ol.render.canvas.Instruction.SET_STROKE_STYLE,\n        strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash, true, 1\n      ]);\n      state.currentStrokeStyle = strokeStyle;\n      state.currentLineCap = lineCap;\n      state.currentLineDash = lineDash;\n      state.currentLineJoin = lineJoin;\n      state.currentLineWidth = lineWidth;\n      state.currentMiterLimit = miterLimit;\n    }\n  }\n};\n\ngoog.provide('ol.render.canvas.TextReplay');\n\ngoog.require('ol');\ngoog.require('ol.colorlike');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.Instruction');\ngoog.require('ol.render.canvas.Replay');\n\n\n/**\n * @constructor\n * @extends {ol.render.canvas.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Maximum extent.\n * @param {number} resolution Resolution.\n * @param {boolean} overlaps The replay can have overlapping geometries.\n * @struct\n */\nol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, overlaps) {\n\n  ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);\n\n  /**\n   * @private\n   * @type {?ol.CanvasFillState}\n   */\n  this.replayFillState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasStrokeState}\n   */\n  this.replayStrokeState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasTextState}\n   */\n  this.replayTextState_ = null;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.text_ = '';\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textOffsetX_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textOffsetY_ = 0;\n\n  /**\n   * @private\n   * @type {boolean|undefined}\n   */\n  this.textRotateWithView_ = undefined;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textRotation_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textScale_ = 0;\n\n  /**\n   * @private\n   * @type {?ol.CanvasFillState}\n   */\n  this.textFillState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasStrokeState}\n   */\n  this.textStrokeState_ = null;\n\n  /**\n   * @private\n   * @type {?ol.CanvasTextState}\n   */\n  this.textState_ = null;\n\n};\nol.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay);\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) {\n  if (this.text_ === '' || !this.textState_ ||\n      (!this.textFillState_ && !this.textStrokeState_)) {\n    return;\n  }\n  if (this.textFillState_) {\n    this.setReplayFillState_(this.textFillState_);\n  }\n  if (this.textStrokeState_) {\n    this.setReplayStrokeState_(this.textStrokeState_);\n  }\n  this.setReplayTextState_(this.textState_);\n  this.beginGeometry(geometry, feature);\n  var myBegin = this.coordinates.length;\n  var myEnd =\n      this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false, false);\n  var fill = !!this.textFillState_;\n  var stroke = !!this.textStrokeState_;\n  var drawTextInstruction = [\n    ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_,\n    this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_,\n    fill, stroke, this.textRotateWithView_];\n  this.instructions.push(drawTextInstruction);\n  this.hitDetectionInstructions.push(drawTextInstruction);\n  this.endGeometry(geometry, feature);\n};\n\n\n/**\n * @param {ol.CanvasFillState} fillState Fill state.\n * @private\n */\nol.render.canvas.TextReplay.prototype.setReplayFillState_ = function(fillState) {\n  var replayFillState = this.replayFillState_;\n  if (replayFillState &&\n      replayFillState.fillStyle == fillState.fillStyle) {\n    return;\n  }\n  var setFillStyleInstruction =\n      [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle];\n  this.instructions.push(setFillStyleInstruction);\n  this.hitDetectionInstructions.push(setFillStyleInstruction);\n  if (!replayFillState) {\n    this.replayFillState_ = {\n      fillStyle: fillState.fillStyle\n    };\n  } else {\n    replayFillState.fillStyle = fillState.fillStyle;\n  }\n};\n\n\n/**\n * @param {ol.CanvasStrokeState} strokeState Stroke state.\n * @private\n */\nol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = function(strokeState) {\n  var replayStrokeState = this.replayStrokeState_;\n  if (replayStrokeState &&\n      replayStrokeState.lineCap == strokeState.lineCap &&\n      replayStrokeState.lineDash == strokeState.lineDash &&\n      replayStrokeState.lineJoin == strokeState.lineJoin &&\n      replayStrokeState.lineWidth == strokeState.lineWidth &&\n      replayStrokeState.miterLimit == strokeState.miterLimit &&\n      replayStrokeState.strokeStyle == strokeState.strokeStyle) {\n    return;\n  }\n  var setStrokeStyleInstruction = [\n    ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle,\n    strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin,\n    strokeState.miterLimit, strokeState.lineDash, false, 1\n  ];\n  this.instructions.push(setStrokeStyleInstruction);\n  this.hitDetectionInstructions.push(setStrokeStyleInstruction);\n  if (!replayStrokeState) {\n    this.replayStrokeState_ = {\n      lineCap: strokeState.lineCap,\n      lineDash: strokeState.lineDash,\n      lineJoin: strokeState.lineJoin,\n      lineWidth: strokeState.lineWidth,\n      miterLimit: strokeState.miterLimit,\n      strokeStyle: strokeState.strokeStyle\n    };\n  } else {\n    replayStrokeState.lineCap = strokeState.lineCap;\n    replayStrokeState.lineDash = strokeState.lineDash;\n    replayStrokeState.lineJoin = strokeState.lineJoin;\n    replayStrokeState.lineWidth = strokeState.lineWidth;\n    replayStrokeState.miterLimit = strokeState.miterLimit;\n    replayStrokeState.strokeStyle = strokeState.strokeStyle;\n  }\n};\n\n\n/**\n * @param {ol.CanvasTextState} textState Text state.\n * @private\n */\nol.render.canvas.TextReplay.prototype.setReplayTextState_ = function(textState) {\n  var replayTextState = this.replayTextState_;\n  if (replayTextState &&\n      replayTextState.font == textState.font &&\n      replayTextState.textAlign == textState.textAlign &&\n      replayTextState.textBaseline == textState.textBaseline) {\n    return;\n  }\n  var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE,\n    textState.font, textState.textAlign, textState.textBaseline];\n  this.instructions.push(setTextStyleInstruction);\n  this.hitDetectionInstructions.push(setTextStyleInstruction);\n  if (!replayTextState) {\n    this.replayTextState_ = {\n      font: textState.font,\n      textAlign: textState.textAlign,\n      textBaseline: textState.textBaseline\n    };\n  } else {\n    replayTextState.font = textState.font;\n    replayTextState.textAlign = textState.textAlign;\n    replayTextState.textBaseline = textState.textBaseline;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {\n  if (!textStyle) {\n    this.text_ = '';\n  } else {\n    var textFillStyle = textStyle.getFill();\n    if (!textFillStyle) {\n      this.textFillState_ = null;\n    } else {\n      var textFillStyleColor = textFillStyle.getColor();\n      var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ?\n          textFillStyleColor : ol.render.canvas.defaultFillStyle);\n      if (!this.textFillState_) {\n        this.textFillState_ = {\n          fillStyle: fillStyle\n        };\n      } else {\n        var textFillState = this.textFillState_;\n        textFillState.fillStyle = fillStyle;\n      }\n    }\n    var textStrokeStyle = textStyle.getStroke();\n    if (!textStrokeStyle) {\n      this.textStrokeState_ = null;\n    } else {\n      var textStrokeStyleColor = textStrokeStyle.getColor();\n      var textStrokeStyleLineCap = textStrokeStyle.getLineCap();\n      var textStrokeStyleLineDash = textStrokeStyle.getLineDash();\n      var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();\n      var textStrokeStyleWidth = textStrokeStyle.getWidth();\n      var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();\n      var lineCap = textStrokeStyleLineCap !== undefined ?\n          textStrokeStyleLineCap : ol.render.canvas.defaultLineCap;\n      var lineDash = textStrokeStyleLineDash ?\n          textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;\n      var lineJoin = textStrokeStyleLineJoin !== undefined ?\n          textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin;\n      var lineWidth = textStrokeStyleWidth !== undefined ?\n          textStrokeStyleWidth : ol.render.canvas.defaultLineWidth;\n      var miterLimit = textStrokeStyleMiterLimit !== undefined ?\n          textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;\n      var strokeStyle = ol.colorlike.asColorLike(textStrokeStyleColor ?\n          textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle);\n      if (!this.textStrokeState_) {\n        this.textStrokeState_ = {\n          lineCap: lineCap,\n          lineDash: lineDash,\n          lineJoin: lineJoin,\n          lineWidth: lineWidth,\n          miterLimit: miterLimit,\n          strokeStyle: strokeStyle\n        };\n      } else {\n        var textStrokeState = this.textStrokeState_;\n        textStrokeState.lineCap = lineCap;\n        textStrokeState.lineDash = lineDash;\n        textStrokeState.lineJoin = lineJoin;\n        textStrokeState.lineWidth = lineWidth;\n        textStrokeState.miterLimit = miterLimit;\n        textStrokeState.strokeStyle = strokeStyle;\n      }\n    }\n    var textFont = textStyle.getFont();\n    var textOffsetX = textStyle.getOffsetX();\n    var textOffsetY = textStyle.getOffsetY();\n    var textRotateWithView = textStyle.getRotateWithView();\n    var textRotation = textStyle.getRotation();\n    var textScale = textStyle.getScale();\n    var textText = textStyle.getText();\n    var textTextAlign = textStyle.getTextAlign();\n    var textTextBaseline = textStyle.getTextBaseline();\n    var font = textFont !== undefined ?\n        textFont : ol.render.canvas.defaultFont;\n    var textAlign = textTextAlign !== undefined ?\n        textTextAlign : ol.render.canvas.defaultTextAlign;\n    var textBaseline = textTextBaseline !== undefined ?\n        textTextBaseline : ol.render.canvas.defaultTextBaseline;\n    if (!this.textState_) {\n      this.textState_ = {\n        font: font,\n        textAlign: textAlign,\n        textBaseline: textBaseline\n      };\n    } else {\n      var textState = this.textState_;\n      textState.font = font;\n      textState.textAlign = textAlign;\n      textState.textBaseline = textBaseline;\n    }\n    this.text_ = textText !== undefined ? textText : '';\n    this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0;\n    this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0;\n    this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;\n    this.textRotation_ = textRotation !== undefined ? textRotation : 0;\n    this.textScale_ = textScale !== undefined ? textScale : 1;\n  }\n};\n\ngoog.provide('ol.render.ReplayType');\n\n\n/**\n * @enum {string}\n */\nol.render.ReplayType = {\n  CIRCLE: 'Circle',\n  IMAGE: 'Image',\n  LINE_STRING: 'LineString',\n  POLYGON: 'Polygon',\n  TEXT: 'Text'\n};\n\ngoog.provide('ol.render.replay');\n\ngoog.require('ol.render.ReplayType');\n\n\n/**\n * @const\n * @type {Array.<ol.render.ReplayType>}\n */\nol.render.replay.ORDER = [\n  ol.render.ReplayType.POLYGON,\n  ol.render.ReplayType.CIRCLE,\n  ol.render.ReplayType.LINE_STRING,\n  ol.render.ReplayType.IMAGE,\n  ol.render.ReplayType.TEXT\n];\n\ngoog.provide('ol.render.canvas.ReplayGroup');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.dom');\ngoog.require('ol.extent');\ngoog.require('ol.geom.flat.transform');\ngoog.require('ol.obj');\ngoog.require('ol.render.ReplayGroup');\ngoog.require('ol.render.canvas.ImageReplay');\ngoog.require('ol.render.canvas.LineStringReplay');\ngoog.require('ol.render.canvas.PolygonReplay');\ngoog.require('ol.render.canvas.TextReplay');\ngoog.require('ol.render.replay');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.render.ReplayGroup}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @param {number} resolution Resolution.\n * @param {boolean} overlaps The replay group can have overlapping geometries.\n * @param {number=} opt_renderBuffer Optional rendering buffer.\n * @struct\n */\nol.render.canvas.ReplayGroup = function(\n    tolerance, maxExtent, resolution, overlaps, opt_renderBuffer) {\n  ol.render.ReplayGroup.call(this);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.tolerance_ = tolerance;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.maxExtent_ = maxExtent;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.overlaps_ = overlaps;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.resolution_ = resolution;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.renderBuffer_ = opt_renderBuffer;\n\n  /**\n   * @private\n   * @type {!Object.<string,\n   *        Object.<ol.render.ReplayType, ol.render.canvas.Replay>>}\n   */\n  this.replaysByZIndex_ = {};\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1);\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.hitDetectionTransform_ = ol.transform.create();\n};\nol.inherits(ol.render.canvas.ReplayGroup, ol.render.ReplayGroup);\n\n\n/**\n * This cache is used for storing calculated pixel circles for increasing performance.\n * It is a static property to allow each Replaygroup to access it.\n * @type {Object.<number, Array.<Array.<(boolean|undefined)>>>}\n * @private\n */\nol.render.canvas.ReplayGroup.circleArrayCache_ = {\n  0: [[true]]\n};\n\n\n/**\n * This method fills a row in the array from the given coordinate to the\n * middle with `true`.\n * @param {Array.<Array.<(boolean|undefined)>>} array The array that will be altered.\n * @param {number} x X coordinate.\n * @param {number} y Y coordinate.\n * @private\n */\nol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_ = function(array, x, y) {\n  var i;\n  var radius = Math.floor(array.length / 2);\n  if (x >= radius) {\n    for (i = radius; i < x; i++) {\n      array[i][y] = true;\n    }\n  } else if (x < radius) {\n    for (i = x + 1; i < radius; i++) {\n      array[i][y] = true;\n    }\n  }\n};\n\n\n/**\n * This methods creates a circle inside a fitting array. Points inside the\n * circle are marked by true, points on the outside are undefined.\n * It uses the midpoint circle algorithm.\n * A cache is used to increase performance.\n * @param {number} radius Radius.\n * @returns {Array.<Array.<(boolean|undefined)>>} An array with marked circle points.\n * @private\n */\nol.render.canvas.ReplayGroup.getCircleArray_ = function(radius) {\n  if (ol.render.canvas.ReplayGroup.circleArrayCache_[radius] !== undefined) {\n    return ol.render.canvas.ReplayGroup.circleArrayCache_[radius];\n  }\n\n  var arraySize = radius * 2 + 1;\n  var arr = new Array(arraySize);\n  for (var i = 0; i < arraySize; i++) {\n    arr[i] = new Array(arraySize);\n  }\n\n  var x = radius;\n  var y = 0;\n  var error = 0;\n\n  while (x >= y) {\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + x, radius + y);\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + y, radius + x);\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - y, radius + x);\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - x, radius + y);\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - x, radius - y);\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - y, radius - x);\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + y, radius - x);\n    ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + x, radius - y);\n\n    y++;\n    error += 1 + 2 * y;\n    if (2 * (error - x) + 1 > 0) {\n      x -= 1;\n      error += 1 - 2 * x;\n    }\n  }\n\n  ol.render.canvas.ReplayGroup.circleArrayCache_[radius] = arr;\n  return arr;\n};\n\n/**\n * FIXME empty description for jsdoc\n */\nol.render.canvas.ReplayGroup.prototype.finish = function() {\n  var zKey;\n  for (zKey in this.replaysByZIndex_) {\n    var replays = this.replaysByZIndex_[zKey];\n    var replayKey;\n    for (replayKey in replays) {\n      replays[replayKey].finish();\n    }\n  }\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {number} hitTolerance Hit tolerance in pixels.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *     to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature\n *     callback.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(\n    coordinate, resolution, rotation, hitTolerance, skippedFeaturesHash, callback) {\n\n  hitTolerance = Math.round(hitTolerance);\n  var contextSize = hitTolerance * 2 + 1;\n  var transform = ol.transform.compose(this.hitDetectionTransform_,\n      hitTolerance + 0.5, hitTolerance + 0.5,\n      1 / resolution, -1 / resolution,\n      -rotation,\n      -coordinate[0], -coordinate[1]);\n  var context = this.hitDetectionContext_;\n\n  if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {\n    context.canvas.width = contextSize;\n    context.canvas.height = contextSize;\n  } else {\n    context.clearRect(0, 0, contextSize, contextSize);\n  }\n\n  /**\n   * @type {ol.Extent}\n   */\n  var hitExtent;\n  if (this.renderBuffer_ !== undefined) {\n    hitExtent = ol.extent.createEmpty();\n    ol.extent.extendCoordinate(hitExtent, coordinate);\n    ol.extent.buffer(hitExtent, resolution * (this.renderBuffer_ + hitTolerance), hitExtent);\n  }\n\n  var mask = ol.render.canvas.ReplayGroup.getCircleArray_(hitTolerance);\n\n  return this.replayHitDetection_(context, transform, rotation,\n      skippedFeaturesHash,\n      /**\n       * @param {ol.Feature|ol.render.Feature} feature Feature.\n       * @return {?} Callback result.\n       */\n      function(feature) {\n        var imageData = context.getImageData(0, 0, contextSize, contextSize).data;\n        for (var i = 0; i < contextSize; i++) {\n          for (var j = 0; j < contextSize; j++) {\n            if (mask[i][j]) {\n              if (imageData[(j * contextSize + i) * 4 + 3] > 0) {\n                var result = callback(feature);\n                if (result) {\n                  return result;\n                } else {\n                  context.clearRect(0, 0, contextSize, contextSize);\n                  return undefined;\n                }\n              }\n            }\n          }\n        }\n      }, hitExtent);\n};\n\n\n/**\n * @param {ol.Transform} transform Transform.\n * @return {Array.<number>} Clip coordinates.\n */\nol.render.canvas.ReplayGroup.prototype.getClipCoords = function(transform) {\n  var maxExtent = this.maxExtent_;\n  var minX = maxExtent[0];\n  var minY = maxExtent[1];\n  var maxX = maxExtent[2];\n  var maxY = maxExtent[3];\n  var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY];\n  ol.geom.flat.transform.transform2D(\n      flatClipCoords, 0, 8, 2, transform, flatClipCoords);\n  return flatClipCoords;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {\n  var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';\n  var replays = this.replaysByZIndex_[zIndexKey];\n  if (replays === undefined) {\n    replays = {};\n    this.replaysByZIndex_[zIndexKey] = replays;\n  }\n  var replay = replays[replayType];\n  if (replay === undefined) {\n    var Constructor = ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];\n    ol.DEBUG && console.assert(Constructor !== undefined,\n        replayType +\n        ' constructor missing from ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_');\n    replay = new Constructor(this.tolerance_, this.maxExtent_,\n        this.resolution_, this.overlaps_);\n    replays[replayType] = replay;\n  }\n  return replay;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.canvas.ReplayGroup.prototype.isEmpty = function() {\n  return ol.obj.isEmpty(this.replaysByZIndex_);\n};\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Transform} transform Transform.\n * @param {number} viewRotation View rotation.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *     to skip.\n * @param {Array.<ol.render.ReplayType>=} opt_replayTypes Ordered replay types\n *     to replay. Default is {@link ol.render.replay.ORDER}\n */\nol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio,\n    transform, viewRotation, skippedFeaturesHash, opt_replayTypes) {\n\n  /** @type {Array.<number>} */\n  var zs = Object.keys(this.replaysByZIndex_).map(Number);\n  zs.sort(ol.array.numberSafeCompareFunction);\n\n  // setup clipping so that the parts of over-simplified geometries are not\n  // visible outside the current extent when panning\n  var flatClipCoords = this.getClipCoords(transform);\n  context.save();\n  context.beginPath();\n  context.moveTo(flatClipCoords[0], flatClipCoords[1]);\n  context.lineTo(flatClipCoords[2], flatClipCoords[3]);\n  context.lineTo(flatClipCoords[4], flatClipCoords[5]);\n  context.lineTo(flatClipCoords[6], flatClipCoords[7]);\n  context.clip();\n\n  var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.replay.ORDER;\n  var i, ii, j, jj, replays, replay;\n  for (i = 0, ii = zs.length; i < ii; ++i) {\n    replays = this.replaysByZIndex_[zs[i].toString()];\n    for (j = 0, jj = replayTypes.length; j < jj; ++j) {\n      replay = replays[replayTypes[j]];\n      if (replay !== undefined) {\n        replay.replay(context, pixelRatio, transform, viewRotation,\n            skippedFeaturesHash);\n      }\n    }\n  }\n\n  context.restore();\n};\n\n\n/**\n * @private\n * @param {CanvasRenderingContext2D} context Context.\n * @param {ol.Transform} transform Transform.\n * @param {number} viewRotation View rotation.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *     to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback\n *     Feature callback.\n * @param {ol.Extent=} opt_hitExtent Only check features that intersect this\n *     extent.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(\n    context, transform, viewRotation, skippedFeaturesHash,\n    featureCallback, opt_hitExtent) {\n  /** @type {Array.<number>} */\n  var zs = Object.keys(this.replaysByZIndex_).map(Number);\n  zs.sort(function(a, b) {\n    return b - a;\n  });\n\n  var i, ii, j, replays, replay, result;\n  for (i = 0, ii = zs.length; i < ii; ++i) {\n    replays = this.replaysByZIndex_[zs[i].toString()];\n    for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {\n      replay = replays[ol.render.replay.ORDER[j]];\n      if (replay !== undefined) {\n        result = replay.replayHitDetection(context, transform, viewRotation,\n            skippedFeaturesHash, featureCallback, opt_hitExtent);\n        if (result) {\n          return result;\n        }\n      }\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @const\n * @private\n * @type {Object.<ol.render.ReplayType,\n *                function(new: ol.render.canvas.Replay, number, ol.Extent,\n *                number, boolean)>}\n */\nol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_ = {\n  'Circle': ol.render.canvas.PolygonReplay,\n  'Image': ol.render.canvas.ImageReplay,\n  'LineString': ol.render.canvas.LineStringReplay,\n  'Polygon': ol.render.canvas.PolygonReplay,\n  'Text': ol.render.canvas.TextReplay\n};\n\ngoog.provide('ol.renderer.vector');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.render.ReplayType');\n\n\n/**\n * @param {ol.Feature|ol.render.Feature} feature1 Feature 1.\n * @param {ol.Feature|ol.render.Feature} feature2 Feature 2.\n * @return {number} Order.\n */\nol.renderer.vector.defaultOrder = function(feature1, feature2) {\n  return ol.getUid(feature1) - ol.getUid(feature2);\n};\n\n\n/**\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @return {number} Squared pixel tolerance.\n */\nol.renderer.vector.getSquaredTolerance = function(resolution, pixelRatio) {\n  var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio);\n  return tolerance * tolerance;\n};\n\n\n/**\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @return {number} Pixel tolerance.\n */\nol.renderer.vector.getTolerance = function(resolution, pixelRatio) {\n  return ol.SIMPLIFY_TOLERANCE * resolution / pixelRatio;\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.Circle} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderCircleGeometry_ = function(replayGroup, geometry, style, feature) {\n  var fillStyle = style.getFill();\n  var strokeStyle = style.getStroke();\n  if (fillStyle || strokeStyle) {\n    var circleReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.CIRCLE);\n    circleReplay.setFillStrokeStyle(fillStyle, strokeStyle);\n    circleReplay.drawCircle(geometry, feature);\n  }\n  var textStyle = style.getText();\n  if (textStyle) {\n    var textReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.TEXT);\n    textReplay.setTextStyle(textStyle);\n    textReplay.drawText(geometry.getCenter(), 0, 2, 2, geometry, feature);\n  }\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @param {ol.style.Style} style Style.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {function(this: T, ol.events.Event)} listener Listener function.\n * @param {T} thisArg Value to use as `this` when executing `listener`.\n * @return {boolean} `true` if style is loading.\n * @template T\n */\nol.renderer.vector.renderFeature = function(\n    replayGroup, feature, style, squaredTolerance, listener, thisArg) {\n  var loading = false;\n  var imageStyle, imageState;\n  imageStyle = style.getImage();\n  if (imageStyle) {\n    imageState = imageStyle.getImageState();\n    if (imageState == ol.Image.State.LOADED ||\n        imageState == ol.Image.State.ERROR) {\n      imageStyle.unlistenImageChange(listener, thisArg);\n    } else {\n      if (imageState == ol.Image.State.IDLE) {\n        imageStyle.load();\n      }\n      imageState = imageStyle.getImageState();\n      ol.DEBUG && console.assert(imageState == ol.Image.State.LOADING,\n          'imageState should be LOADING');\n      imageStyle.listenImageChange(listener, thisArg);\n      loading = true;\n    }\n  }\n  ol.renderer.vector.renderFeature_(replayGroup, feature, style,\n      squaredTolerance);\n  return loading;\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @param {ol.style.Style} style Style.\n * @param {number} squaredTolerance Squared tolerance.\n * @private\n */\nol.renderer.vector.renderFeature_ = function(\n    replayGroup, feature, style, squaredTolerance) {\n  var geometry = style.getGeometryFunction()(feature);\n  if (!geometry) {\n    return;\n  }\n  var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);\n  var geometryRenderer =\n      ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()];\n  geometryRenderer(replayGroup, simplifiedGeometry, style, feature);\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.GeometryCollection} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderGeometryCollectionGeometry_ = function(replayGroup, geometry, style, feature) {\n  var geometries = geometry.getGeometriesArray();\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    var geometryRenderer =\n        ol.renderer.vector.GEOMETRY_RENDERERS_[geometries[i].getType()];\n    geometryRenderer(replayGroup, geometries[i], style, feature);\n  }\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.LineString|ol.render.Feature} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderLineStringGeometry_ = function(replayGroup, geometry, style, feature) {\n  var strokeStyle = style.getStroke();\n  if (strokeStyle) {\n    var lineStringReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.LINE_STRING);\n    lineStringReplay.setFillStrokeStyle(null, strokeStyle);\n    lineStringReplay.drawLineString(geometry, feature);\n  }\n  var textStyle = style.getText();\n  if (textStyle) {\n    var textReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.TEXT);\n    textReplay.setTextStyle(textStyle);\n    textReplay.drawText(geometry.getFlatMidpoint(), 0, 2, 2, geometry, feature);\n  }\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.MultiLineString|ol.render.Feature} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderMultiLineStringGeometry_ = function(replayGroup, geometry, style, feature) {\n  var strokeStyle = style.getStroke();\n  if (strokeStyle) {\n    var lineStringReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.LINE_STRING);\n    lineStringReplay.setFillStrokeStyle(null, strokeStyle);\n    lineStringReplay.drawMultiLineString(geometry, feature);\n  }\n  var textStyle = style.getText();\n  if (textStyle) {\n    var textReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.TEXT);\n    textReplay.setTextStyle(textStyle);\n    var flatMidpointCoordinates = geometry.getFlatMidpoints();\n    textReplay.drawText(flatMidpointCoordinates, 0,\n        flatMidpointCoordinates.length, 2, geometry, feature);\n  }\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.MultiPolygon} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderMultiPolygonGeometry_ = function(replayGroup, geometry, style, feature) {\n  var fillStyle = style.getFill();\n  var strokeStyle = style.getStroke();\n  if (strokeStyle || fillStyle) {\n    var polygonReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.POLYGON);\n    polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);\n    polygonReplay.drawMultiPolygon(geometry, feature);\n  }\n  var textStyle = style.getText();\n  if (textStyle) {\n    var textReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.TEXT);\n    textReplay.setTextStyle(textStyle);\n    var flatInteriorPointCoordinates = geometry.getFlatInteriorPoints();\n    textReplay.drawText(flatInteriorPointCoordinates, 0,\n        flatInteriorPointCoordinates.length, 2, geometry, feature);\n  }\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.Point|ol.render.Feature} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderPointGeometry_ = function(replayGroup, geometry, style, feature) {\n  var imageStyle = style.getImage();\n  if (imageStyle) {\n    if (imageStyle.getImageState() != ol.Image.State.LOADED) {\n      return;\n    }\n    var imageReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.IMAGE);\n    imageReplay.setImageStyle(imageStyle);\n    imageReplay.drawPoint(geometry, feature);\n  }\n  var textStyle = style.getText();\n  if (textStyle) {\n    var textReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.TEXT);\n    textReplay.setTextStyle(textStyle);\n    textReplay.drawText(geometry.getFlatCoordinates(), 0, 2, 2, geometry,\n        feature);\n  }\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.MultiPoint|ol.render.Feature} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderMultiPointGeometry_ = function(replayGroup, geometry, style, feature) {\n  var imageStyle = style.getImage();\n  if (imageStyle) {\n    if (imageStyle.getImageState() != ol.Image.State.LOADED) {\n      return;\n    }\n    var imageReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.IMAGE);\n    imageReplay.setImageStyle(imageStyle);\n    imageReplay.drawMultiPoint(geometry, feature);\n  }\n  var textStyle = style.getText();\n  if (textStyle) {\n    var textReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.TEXT);\n    textReplay.setTextStyle(textStyle);\n    var flatCoordinates = geometry.getFlatCoordinates();\n    textReplay.drawText(flatCoordinates, 0, flatCoordinates.length,\n        geometry.getStride(), geometry, feature);\n  }\n};\n\n\n/**\n * @param {ol.render.ReplayGroup} replayGroup Replay group.\n * @param {ol.geom.Polygon|ol.render.Feature} geometry Geometry.\n * @param {ol.style.Style} style Style.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @private\n */\nol.renderer.vector.renderPolygonGeometry_ = function(replayGroup, geometry, style, feature) {\n  var fillStyle = style.getFill();\n  var strokeStyle = style.getStroke();\n  if (fillStyle || strokeStyle) {\n    var polygonReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.POLYGON);\n    polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);\n    polygonReplay.drawPolygon(geometry, feature);\n  }\n  var textStyle = style.getText();\n  if (textStyle) {\n    var textReplay = replayGroup.getReplay(\n        style.getZIndex(), ol.render.ReplayType.TEXT);\n    textReplay.setTextStyle(textStyle);\n    textReplay.drawText(\n        geometry.getFlatInteriorPoint(), 0, 2, 2, geometry, feature);\n  }\n};\n\n\n/**\n * @const\n * @private\n * @type {Object.<ol.geom.GeometryType,\n *                function(ol.render.ReplayGroup, ol.geom.Geometry,\n *                         ol.style.Style, Object)>}\n */\nol.renderer.vector.GEOMETRY_RENDERERS_ = {\n  'Point': ol.renderer.vector.renderPointGeometry_,\n  'LineString': ol.renderer.vector.renderLineStringGeometry_,\n  'Polygon': ol.renderer.vector.renderPolygonGeometry_,\n  'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_,\n  'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_,\n  'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_,\n  'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_,\n  'Circle': ol.renderer.vector.renderCircleGeometry_\n};\n\ngoog.provide('ol.renderer.canvas.VectorLayer');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.dom');\ngoog.require('ol.extent');\ngoog.require('ol.render.Event');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.ReplayGroup');\ngoog.require('ol.renderer.canvas.Layer');\ngoog.require('ol.renderer.vector');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.canvas.Layer}\n * @param {ol.layer.Vector} vectorLayer Vector layer.\n */\nol.renderer.canvas.VectorLayer = function(vectorLayer) {\n\n  ol.renderer.canvas.Layer.call(this, vectorLayer);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.dirty_ = false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedResolution_ = NaN;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.renderedExtent_ = ol.extent.createEmpty();\n\n  /**\n   * @private\n   * @type {function(ol.Feature, ol.Feature): number|null}\n   */\n  this.renderedRenderOrder_ = null;\n\n  /**\n   * @private\n   * @type {ol.render.canvas.ReplayGroup}\n   */\n  this.replayGroup_ = null;\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.context_ = ol.dom.createCanvasContext2D();\n\n};\nol.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, layerState, context) {\n\n  var extent = frameState.extent;\n  var pixelRatio = frameState.pixelRatio;\n  var skippedFeatureUids = layerState.managed ?\n      frameState.skippedFeatureUids : {};\n  var viewState = frameState.viewState;\n  var projection = viewState.projection;\n  var rotation = viewState.rotation;\n  var projectionExtent = projection.getExtent();\n  var vectorSource = /** @type {ol.source.Vector} */ (this.getLayer().getSource());\n\n  var transform = this.getTransform(frameState, 0);\n\n  this.preCompose(context, frameState, transform);\n\n  // clipped rendering if layer extent is set\n  var clipExtent = layerState.extent;\n  var clipped = clipExtent !== undefined;\n  if (clipped) {\n    this.clip(context, frameState,  /** @type {ol.Extent} */ (clipExtent));\n  }\n  var replayGroup = this.replayGroup_;\n  if (replayGroup && !replayGroup.isEmpty()) {\n    var layer = this.getLayer();\n    var drawOffsetX = 0;\n    var drawOffsetY = 0;\n    var replayContext;\n    if (layer.hasListener(ol.render.Event.Type.RENDER)) {\n      var drawWidth = context.canvas.width;\n      var drawHeight = context.canvas.height;\n      if (rotation) {\n        var drawSize = Math.round(Math.sqrt(drawWidth * drawWidth + drawHeight * drawHeight));\n        drawOffsetX = (drawSize - drawWidth) / 2;\n        drawOffsetY = (drawSize - drawHeight) / 2;\n        drawWidth = drawHeight = drawSize;\n      }\n      // resize and clear\n      this.context_.canvas.width = drawWidth;\n      this.context_.canvas.height = drawHeight;\n      replayContext = this.context_;\n    } else {\n      replayContext = context;\n    }\n    // for performance reasons, context.save / context.restore is not used\n    // to save and restore the transformation matrix and the opacity.\n    // see http://jsperf.com/context-save-restore-versus-variable\n    var alpha = replayContext.globalAlpha;\n    replayContext.globalAlpha = layerState.opacity;\n    if (replayContext != context) {\n      replayContext.translate(drawOffsetX, drawOffsetY);\n    }\n\n    var width = frameState.size[0] * pixelRatio;\n    var height = frameState.size[1] * pixelRatio;\n    ol.render.canvas.rotateAtOffset(replayContext, -rotation,\n        width / 2, height / 2);\n    replayGroup.replay(replayContext, pixelRatio, transform, rotation,\n        skippedFeatureUids);\n    if (vectorSource.getWrapX() && projection.canWrapX() &&\n        !ol.extent.containsExtent(projectionExtent, extent)) {\n      var startX = extent[0];\n      var worldWidth = ol.extent.getWidth(projectionExtent);\n      var world = 0;\n      var offsetX;\n      while (startX < projectionExtent[0]) {\n        --world;\n        offsetX = worldWidth * world;\n        transform = this.getTransform(frameState, offsetX);\n        replayGroup.replay(replayContext, pixelRatio, transform, rotation,\n            skippedFeatureUids);\n        startX += worldWidth;\n      }\n      world = 0;\n      startX = extent[2];\n      while (startX > projectionExtent[2]) {\n        ++world;\n        offsetX = worldWidth * world;\n        transform = this.getTransform(frameState, offsetX);\n        replayGroup.replay(replayContext, pixelRatio, transform, rotation,\n            skippedFeatureUids);\n        startX -= worldWidth;\n      }\n      // restore original transform for render and compose events\n      transform = this.getTransform(frameState, 0);\n    }\n    ol.render.canvas.rotateAtOffset(replayContext, rotation,\n        width / 2, height / 2);\n\n    if (replayContext != context) {\n      this.dispatchRenderEvent(replayContext, frameState, transform);\n      context.drawImage(replayContext.canvas, -drawOffsetX, -drawOffsetY);\n      replayContext.translate(-drawOffsetX, -drawOffsetY);\n    }\n    replayContext.globalAlpha = alpha;\n  }\n\n  if (clipped) {\n    context.restore();\n  }\n  this.postCompose(context, frameState, layerState, transform);\n\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {\n  if (!this.replayGroup_) {\n    return undefined;\n  } else {\n    var resolution = frameState.viewState.resolution;\n    var rotation = frameState.viewState.rotation;\n    var layer = this.getLayer();\n    /** @type {Object.<string, boolean>} */\n    var features = {};\n    return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,\n        rotation, hitTolerance, {},\n        /**\n         * @param {ol.Feature|ol.render.Feature} feature Feature.\n         * @return {?} Callback result.\n         */\n        function(feature) {\n          var key = ol.getUid(feature).toString();\n          if (!(key in features)) {\n            features[key] = true;\n            return callback.call(thisArg, feature, layer);\n          }\n        });\n  }\n};\n\n\n/**\n * Handle changes in image style state.\n * @param {ol.events.Event} event Image style change event.\n * @private\n */\nol.renderer.canvas.VectorLayer.prototype.handleStyleImageChange_ = function(event) {\n  this.renderIfReadyAndVisible();\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, layerState) {\n\n  var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());\n  var vectorSource = vectorLayer.getSource();\n\n  this.updateAttributions(\n      frameState.attributions, vectorSource.getAttributions());\n  this.updateLogos(frameState, vectorSource);\n\n  var animating = frameState.viewHints[ol.View.Hint.ANIMATING];\n  var interacting = frameState.viewHints[ol.View.Hint.INTERACTING];\n  var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();\n  var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();\n\n  if (!this.dirty_ && (!updateWhileAnimating && animating) ||\n      (!updateWhileInteracting && interacting)) {\n    return true;\n  }\n\n  var frameStateExtent = frameState.extent;\n  var viewState = frameState.viewState;\n  var projection = viewState.projection;\n  var resolution = viewState.resolution;\n  var pixelRatio = frameState.pixelRatio;\n  var vectorLayerRevision = vectorLayer.getRevision();\n  var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();\n  var vectorLayerRenderOrder = vectorLayer.getRenderOrder();\n\n  if (vectorLayerRenderOrder === undefined) {\n    vectorLayerRenderOrder = ol.renderer.vector.defaultOrder;\n  }\n\n  var extent = ol.extent.buffer(frameStateExtent,\n      vectorLayerRenderBuffer * resolution);\n  var projectionExtent = viewState.projection.getExtent();\n\n  if (vectorSource.getWrapX() && viewState.projection.canWrapX() &&\n      !ol.extent.containsExtent(projectionExtent, frameState.extent)) {\n    // For the replay group, we need an extent that intersects the real world\n    // (-180° to +180°). To support geometries in a coordinate range from -540°\n    // to +540°, we add at least 1 world width on each side of the projection\n    // extent. If the viewport is wider than the world, we need to add half of\n    // the viewport width to make sure we cover the whole viewport.\n    var worldWidth = ol.extent.getWidth(projectionExtent);\n    var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth);\n    extent[0] = projectionExtent[0] - buffer;\n    extent[2] = projectionExtent[2] + buffer;\n  }\n\n  if (!this.dirty_ &&\n      this.renderedResolution_ == resolution &&\n      this.renderedRevision_ == vectorLayerRevision &&\n      this.renderedRenderOrder_ == vectorLayerRenderOrder &&\n      ol.extent.containsExtent(this.renderedExtent_, extent)) {\n    return true;\n  }\n\n  this.replayGroup_ = null;\n\n  this.dirty_ = false;\n\n  var replayGroup =\n      new ol.render.canvas.ReplayGroup(\n          ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,\n          resolution, vectorSource.getOverlaps(), vectorLayer.getRenderBuffer());\n  vectorSource.loadFeatures(extent, resolution, projection);\n  /**\n   * @param {ol.Feature} feature Feature.\n   * @this {ol.renderer.canvas.VectorLayer}\n   */\n  var renderFeature = function(feature) {\n    var styles;\n    var styleFunction = feature.getStyleFunction();\n    if (styleFunction) {\n      styles = styleFunction.call(feature, resolution);\n    } else {\n      styleFunction = vectorLayer.getStyleFunction();\n      if (styleFunction) {\n        styles = styleFunction(feature, resolution);\n      }\n    }\n    if (styles) {\n      var dirty = this.renderFeature(\n          feature, resolution, pixelRatio, styles, replayGroup);\n      this.dirty_ = this.dirty_ || dirty;\n    }\n  };\n  if (vectorLayerRenderOrder) {\n    /** @type {Array.<ol.Feature>} */\n    var features = [];\n    vectorSource.forEachFeatureInExtent(extent,\n        /**\n         * @param {ol.Feature} feature Feature.\n         */\n        function(feature) {\n          features.push(feature);\n        }, this);\n    features.sort(vectorLayerRenderOrder);\n    features.forEach(renderFeature, this);\n  } else {\n    vectorSource.forEachFeatureInExtent(extent, renderFeature, this);\n  }\n  replayGroup.finish();\n\n  this.renderedResolution_ = resolution;\n  this.renderedRevision_ = vectorLayerRevision;\n  this.renderedRenderOrder_ = vectorLayerRenderOrder;\n  this.renderedExtent_ = extent;\n  this.replayGroup_ = replayGroup;\n\n  return true;\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of\n *     styles.\n * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.\n * @return {boolean} `true` if an image is loading.\n */\nol.renderer.canvas.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {\n  if (!styles) {\n    return false;\n  }\n  var loading = false;\n  if (Array.isArray(styles)) {\n    for (var i = 0, ii = styles.length; i < ii; ++i) {\n      loading = ol.renderer.vector.renderFeature(\n          replayGroup, feature, styles[i],\n          ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),\n          this.handleStyleImageChange_, this) || loading;\n    }\n  } else {\n    loading = ol.renderer.vector.renderFeature(\n        replayGroup, feature, styles,\n        ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),\n        this.handleStyleImageChange_, this) || loading;\n  }\n  return loading;\n};\n\ngoog.provide('ol.renderer.canvas.VectorTileLayer');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Units');\ngoog.require('ol.layer.VectorTile');\ngoog.require('ol.render.ReplayType');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.ReplayGroup');\ngoog.require('ol.render.replay');\ngoog.require('ol.renderer.canvas.TileLayer');\ngoog.require('ol.renderer.vector');\ngoog.require('ol.size');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.canvas.TileLayer}\n * @param {ol.layer.VectorTile} layer VectorTile layer.\n */\nol.renderer.canvas.VectorTileLayer = function(layer) {\n\n  ol.renderer.canvas.TileLayer.call(this, layer);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.dirty_ = false;\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.tmpTransform_ = ol.transform.create();\n\n  // Use lower resolution for pure vector rendering. Closest resolution otherwise.\n  this.zDirection =\n      layer.getRenderMode() == ol.layer.VectorTile.RenderType.VECTOR ? 1 : 0;\n\n};\nol.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.TileLayer);\n\n\n/**\n * @const\n * @type {!Object.<string, Array.<ol.render.ReplayType>>}\n */\nol.renderer.canvas.VectorTileLayer.IMAGE_REPLAYS = {\n  'image': ol.render.replay.ORDER,\n  'hybrid': [ol.render.ReplayType.POLYGON, ol.render.ReplayType.LINE_STRING]\n};\n\n\n/**\n * @const\n * @type {!Object.<string, Array.<ol.render.ReplayType>>}\n */\nol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS = {\n  'hybrid': [ol.render.ReplayType.IMAGE, ol.render.ReplayType.TEXT],\n  'vector': ol.render.replay.ORDER\n};\n\n\n/**\n * @param {ol.VectorTile} tile Tile.\n * @param {olx.FrameState} frameState Frame state.\n * @private\n */\nol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,\n    frameState) {\n  var layer = this.getLayer();\n  var pixelRatio = frameState.pixelRatio;\n  var projection = frameState.viewState.projection;\n  var revision = layer.getRevision();\n  var renderOrder = layer.getRenderOrder() || null;\n\n  var replayState = tile.getReplayState();\n  if (!replayState.dirty && replayState.renderedRevision == revision &&\n      replayState.renderedRenderOrder == renderOrder) {\n    return;\n  }\n\n  replayState.replayGroup = null;\n  replayState.dirty = false;\n\n  var source = /** @type {ol.source.VectorTile} */ (layer.getSource());\n  var tileGrid = source.getTileGrid();\n  var tileCoord = tile.tileCoord;\n  var tileProjection = tile.getProjection();\n  var resolution = tileGrid.getResolution(tileCoord[0]);\n  var extent, reproject, tileResolution;\n  if (tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS) {\n    var tilePixelRatio = tileResolution = source.getTilePixelRatio();\n    var tileSize = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]));\n    extent = [0, 0, tileSize[0] * tilePixelRatio, tileSize[1] * tilePixelRatio];\n  } else {\n    tileResolution = resolution;\n    extent = tileGrid.getTileCoordExtent(tileCoord);\n    if (!ol.proj.equivalent(projection, tileProjection)) {\n      reproject = true;\n      tile.setProjection(projection);\n    }\n  }\n  replayState.dirty = false;\n  var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,\n      tileResolution, source.getOverlaps(), layer.getRenderBuffer());\n  var squaredTolerance = ol.renderer.vector.getSquaredTolerance(\n      tileResolution, pixelRatio);\n\n  /**\n   * @param {ol.Feature|ol.render.Feature} feature Feature.\n   * @this {ol.renderer.canvas.VectorTileLayer}\n   */\n  function renderFeature(feature) {\n    var styles;\n    var styleFunction = feature.getStyleFunction();\n    if (styleFunction) {\n      styles = styleFunction.call(/** @type {ol.Feature} */ (feature), resolution);\n    } else {\n      styleFunction = layer.getStyleFunction();\n      if (styleFunction) {\n        styles = styleFunction(feature, resolution);\n      }\n    }\n    if (styles) {\n      if (!Array.isArray(styles)) {\n        styles = [styles];\n      }\n      var dirty = this.renderFeature(feature, squaredTolerance, styles,\n          replayGroup);\n      this.dirty_ = this.dirty_ || dirty;\n      replayState.dirty = replayState.dirty || dirty;\n    }\n  }\n\n  var features = tile.getFeatures();\n  if (renderOrder && renderOrder !== replayState.renderedRenderOrder) {\n    features.sort(renderOrder);\n  }\n  var feature;\n  for (var i = 0, ii = features.length; i < ii; ++i) {\n    feature = features[i];\n    if (reproject) {\n      feature.getGeometry().transform(tileProjection, projection);\n    }\n    renderFeature.call(this, feature);\n  }\n\n  replayGroup.finish();\n\n  replayState.renderedRevision = revision;\n  replayState.renderedRenderOrder = renderOrder;\n  replayState.replayGroup = replayGroup;\n  replayState.resolution = NaN;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.VectorTileLayer.prototype.drawTileImage = function(\n    tile, frameState, layerState, x, y, w, h, gutter) {\n  var vectorTile = /** @type {ol.VectorTile} */ (tile);\n  this.createReplayGroup_(vectorTile, frameState);\n  var layer = this.getLayer();\n  if (layer.getRenderMode() != ol.layer.VectorTile.RenderType.VECTOR) {\n    this.renderTileImage_(vectorTile, frameState, layerState);\n  }\n  ol.renderer.canvas.TileLayer.prototype.drawTileImage.apply(this, arguments);\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {\n  var resolution = frameState.viewState.resolution;\n  var rotation = frameState.viewState.rotation;\n  hitTolerance = hitTolerance == undefined ? 0 : hitTolerance;\n  var layer = this.getLayer();\n  /** @type {Object.<string, boolean>} */\n  var features = {};\n\n  /** @type {Array.<ol.VectorTile>} */\n  var replayables = this.renderedTiles;\n\n  var source = /** @type {ol.source.VectorTile} */ (layer.getSource());\n  var tileGrid = source.getTileGrid();\n  var found, tileSpaceCoordinate;\n  var i, ii, origin, replayGroup;\n  var tile, tileCoord, tileExtent, tilePixelRatio, tileResolution;\n  for (i = 0, ii = replayables.length; i < ii; ++i) {\n    tile = replayables[i];\n    tileCoord = tile.tileCoord;\n    tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord, this.tmpExtent);\n    if (!ol.extent.containsCoordinate(ol.extent.buffer(tileExtent, hitTolerance * resolution), coordinate)) {\n      continue;\n    }\n    if (tile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) {\n      origin = ol.extent.getTopLeft(tileExtent);\n      tilePixelRatio = source.getTilePixelRatio();\n      tileResolution = tileGrid.getResolution(tileCoord[0]) / tilePixelRatio;\n      tileSpaceCoordinate = [\n        (coordinate[0] - origin[0]) / tileResolution,\n        (origin[1] - coordinate[1]) / tileResolution\n      ];\n      resolution = tilePixelRatio;\n    } else {\n      tileSpaceCoordinate = coordinate;\n    }\n    replayGroup = tile.getReplayState().replayGroup;\n    found = found || replayGroup.forEachFeatureAtCoordinate(\n        tileSpaceCoordinate, resolution, rotation, hitTolerance, {},\n        /**\n         * @param {ol.Feature|ol.render.Feature} feature Feature.\n         * @return {?} Callback result.\n         */\n        function(feature) {\n          var key = ol.getUid(feature).toString();\n          if (!(key in features)) {\n            features[key] = true;\n            return callback.call(thisArg, feature, layer);\n          }\n        });\n  }\n  return found;\n};\n\n\n/**\n * @param {ol.Tile} tile Tile.\n * @param {olx.FrameState} frameState Frame state.\n * @return {ol.Transform} transform Transform.\n * @private\n */\nol.renderer.canvas.VectorTileLayer.prototype.getReplayTransform_ = function(tile, frameState) {\n  if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {\n    var layer = this.getLayer();\n    var source = /** @type {ol.source.VectorTile} */ (layer.getSource());\n    var tileGrid = source.getTileGrid();\n    var tileCoord = tile.tileCoord;\n    var tileResolution =\n        tileGrid.getResolution(tileCoord[0]) / source.getTilePixelRatio();\n    var viewState = frameState.viewState;\n    var pixelRatio = frameState.pixelRatio;\n    var renderResolution = viewState.resolution / pixelRatio;\n    var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);\n    var center = viewState.center;\n    var origin = ol.extent.getTopLeft(tileExtent);\n    var size = frameState.size;\n    var offsetX = Math.round(pixelRatio * size[0] / 2);\n    var offsetY = Math.round(pixelRatio * size[1] / 2);\n    return ol.transform.compose(this.tmpTransform_,\n        offsetX, offsetY,\n        tileResolution / renderResolution, tileResolution / renderResolution,\n        viewState.rotation,\n        (origin[0] - center[0]) / tileResolution,\n        (center[1] - origin[1]) / tileResolution);\n  } else {\n    return this.getTransform(frameState, 0);\n  }\n};\n\n\n/**\n * Handle changes in image style state.\n * @param {ol.events.Event} event Image style change event.\n * @private\n */\nol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(event) {\n  this.renderIfReadyAndVisible();\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, frameState, layerState) {\n  var renderMode = this.getLayer().getRenderMode();\n  var replays = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];\n  if (replays) {\n    var pixelRatio = frameState.pixelRatio;\n    var rotation = frameState.viewState.rotation;\n    var size = frameState.size;\n    var offsetX = Math.round(pixelRatio * size[0] / 2);\n    var offsetY = Math.round(pixelRatio * size[1] / 2);\n    var tiles = this.renderedTiles;\n    var clips = [];\n    var zs = [];\n    for (var i = tiles.length - 1; i >= 0; --i) {\n      var tile = /** @type {ol.VectorTile} */ (tiles[i]);\n      // Create a clip mask for regions in this low resolution tile that are\n      // already filled by a higher resolution tile\n      var transform = this.getReplayTransform_(tile, frameState);\n      var currentClip = tile.getReplayState().replayGroup.getClipCoords(transform);\n      var currentZ = tile.tileCoord[0];\n      context.save();\n      context.globalAlpha = layerState.opacity;\n      ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);\n      for (var j = 0, jj = clips.length; j < jj; ++j) {\n        var clip = clips[j];\n        if (currentZ < zs[j]) {\n          context.beginPath();\n          // counter-clockwise (outer ring) for current tile\n          context.moveTo(currentClip[0], currentClip[1]);\n          context.lineTo(currentClip[2], currentClip[3]);\n          context.lineTo(currentClip[4], currentClip[5]);\n          context.lineTo(currentClip[6], currentClip[7]);\n          // clockwise (inner ring) for higher resolution tile\n          context.moveTo(clip[6], clip[7]);\n          context.lineTo(clip[4], clip[5]);\n          context.lineTo(clip[2], clip[3]);\n          context.lineTo(clip[0], clip[1]);\n          context.clip();\n        }\n      }\n      var replayGroup = tile.getReplayState().replayGroup;\n      replayGroup.replay(context, pixelRatio, transform, rotation, {}, replays);\n      context.restore();\n      clips.push(currentClip);\n      zs.push(currentZ);\n    }\n  }\n  ol.renderer.canvas.TileLayer.prototype.postCompose.apply(this, arguments);\n};\n\n\n/**\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of\n *     styles.\n * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.\n * @return {boolean} `true` if an image is loading.\n */\nol.renderer.canvas.VectorTileLayer.prototype.renderFeature = function(feature, squaredTolerance, styles, replayGroup) {\n  if (!styles) {\n    return false;\n  }\n  var loading = false;\n  if (Array.isArray(styles)) {\n    for (var i = 0, ii = styles.length; i < ii; ++i) {\n      loading = ol.renderer.vector.renderFeature(\n          replayGroup, feature, styles[i], squaredTolerance,\n          this.handleStyleImageChange_, this) || loading;\n    }\n  } else {\n    loading = ol.renderer.vector.renderFeature(\n        replayGroup, feature, styles, squaredTolerance,\n        this.handleStyleImageChange_, this) || loading;\n  }\n  return loading;\n};\n\n\n/**\n * @param {ol.VectorTile} tile Tile.\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.LayerState} layerState Layer state.\n * @private\n */\nol.renderer.canvas.VectorTileLayer.prototype.renderTileImage_ = function(\n    tile, frameState, layerState) {\n  var layer = this.getLayer();\n  var replayState = tile.getReplayState();\n  var revision = layer.getRevision();\n  var replays = ol.renderer.canvas.VectorTileLayer.IMAGE_REPLAYS[layer.getRenderMode()];\n  if (replays && replayState.renderedTileRevision !== revision) {\n    replayState.renderedTileRevision = revision;\n    var tileCoord = tile.tileCoord;\n    var z = tile.tileCoord[0];\n    var pixelRatio = frameState.pixelRatio;\n    var source = layer.getSource();\n    var tileGrid = source.getTileGrid();\n    var tilePixelRatio = source.getTilePixelRatio();\n    var transform = ol.transform.reset(this.tmpTransform_);\n    if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {\n      var renderPixelRatio = pixelRatio / tilePixelRatio;\n      ol.transform.scale(transform, renderPixelRatio, renderPixelRatio);\n    } else {\n      var resolution = tileGrid.getResolution(z);\n      var pixelScale = pixelRatio / resolution;\n      var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);\n      ol.transform.scale(transform, pixelScale, -pixelScale);\n      ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);\n    }\n\n    var context = tile.getContext();\n    var size = source.getTilePixelSize(z, pixelRatio, frameState.viewState.projection);\n    context.canvas.width = size[0];\n    context.canvas.height = size[1];\n    replayState.replayGroup.replay(context, pixelRatio, transform, 0, {}, replays);\n  }\n};\n\n// FIXME offset panning\n\ngoog.provide('ol.renderer.canvas.Map');\n\ngoog.require('ol.transform');\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.css');\ngoog.require('ol.dom');\ngoog.require('ol.layer.Image');\ngoog.require('ol.layer.Layer');\ngoog.require('ol.layer.Tile');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.layer.VectorTile');\ngoog.require('ol.render.Event');\ngoog.require('ol.render.canvas');\ngoog.require('ol.render.canvas.Immediate');\ngoog.require('ol.renderer.Map');\ngoog.require('ol.renderer.Type');\ngoog.require('ol.renderer.canvas.ImageLayer');\ngoog.require('ol.renderer.canvas.TileLayer');\ngoog.require('ol.renderer.canvas.VectorLayer');\ngoog.require('ol.renderer.canvas.VectorTileLayer');\ngoog.require('ol.source.State');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.Map}\n * @param {Element} container Container.\n * @param {ol.Map} map Map.\n */\nol.renderer.canvas.Map = function(container, map) {\n\n  ol.renderer.Map.call(this, container, map);\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.context_ = ol.dom.createCanvasContext2D();\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = this.context_.canvas;\n\n  this.canvas_.style.width = '100%';\n  this.canvas_.style.height = '100%';\n  this.canvas_.className = ol.css.CLASS_UNSELECTABLE;\n  container.insertBefore(this.canvas_, container.childNodes[0] || null);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.renderedVisible_ = true;\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.transform_ = ol.transform.create();\n\n};\nol.inherits(ol.renderer.canvas.Map, ol.renderer.Map);\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) {\n  if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) {\n    return new ol.renderer.canvas.ImageLayer(layer);\n  } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) {\n    return new ol.renderer.canvas.TileLayer(layer);\n  } else if (ol.ENABLE_VECTOR_TILE && layer instanceof ol.layer.VectorTile) {\n    return new ol.renderer.canvas.VectorTileLayer(layer);\n  } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) {\n    return new ol.renderer.canvas.VectorLayer(layer);\n  } else {\n    ol.DEBUG && console.assert(false, 'unexpected layer configuration');\n    return null;\n  }\n};\n\n\n/**\n * @param {ol.render.Event.Type} type Event type.\n * @param {olx.FrameState} frameState Frame state.\n * @private\n */\nol.renderer.canvas.Map.prototype.dispatchComposeEvent_ = function(type, frameState) {\n  var map = this.getMap();\n  var context = this.context_;\n  if (map.hasListener(type)) {\n    var extent = frameState.extent;\n    var pixelRatio = frameState.pixelRatio;\n    var viewState = frameState.viewState;\n    var rotation = viewState.rotation;\n\n    var transform = this.getTransform(frameState);\n\n    var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,\n        extent, transform, rotation);\n    var composeEvent = new ol.render.Event(type, vectorContext,\n        frameState, context, null);\n    map.dispatchEvent(composeEvent);\n  }\n};\n\n\n/**\n * @param {olx.FrameState} frameState Frame state.\n * @protected\n * @return {!ol.Transform} Transform.\n */\nol.renderer.canvas.Map.prototype.getTransform = function(frameState) {\n  var viewState = frameState.viewState;\n  var dx1 = this.canvas_.width / 2;\n  var dy1 = this.canvas_.height / 2;\n  var sx = frameState.pixelRatio / viewState.resolution;\n  var sy = -sx;\n  var angle = -viewState.rotation;\n  var dx2 = -viewState.center[0];\n  var dy2 = -viewState.center[1];\n  return ol.transform.compose(this.transform_, dx1, dy1, sx, sy, angle, dx2, dy2);\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.Map.prototype.getType = function() {\n  return ol.renderer.Type.CANVAS;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {\n\n  if (!frameState) {\n    if (this.renderedVisible_) {\n      this.canvas_.style.display = 'none';\n      this.renderedVisible_ = false;\n    }\n    return;\n  }\n\n  var context = this.context_;\n  var pixelRatio = frameState.pixelRatio;\n  var width = Math.round(frameState.size[0] * pixelRatio);\n  var height = Math.round(frameState.size[1] * pixelRatio);\n  if (this.canvas_.width != width || this.canvas_.height != height) {\n    this.canvas_.width = width;\n    this.canvas_.height = height;\n  } else {\n    context.clearRect(0, 0, width, height);\n  }\n\n  var rotation = frameState.viewState.rotation;\n\n  this.calculateMatrices2D(frameState);\n\n  this.dispatchComposeEvent_(ol.render.Event.Type.PRECOMPOSE, frameState);\n\n  var layerStatesArray = frameState.layerStatesArray;\n  ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);\n\n  ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);\n\n  var viewResolution = frameState.viewState.resolution;\n  var i, ii, layer, layerRenderer, layerState;\n  for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {\n    layerState = layerStatesArray[i];\n    layer = layerState.layer;\n    layerRenderer = /** @type {ol.renderer.canvas.Layer} */ (this.getLayerRenderer(layer));\n    if (!ol.layer.Layer.visibleAtResolution(layerState, viewResolution) ||\n        layerState.sourceState != ol.source.State.READY) {\n      continue;\n    }\n    if (layerRenderer.prepareFrame(frameState, layerState)) {\n      layerRenderer.composeFrame(frameState, layerState, context);\n    }\n  }\n\n  ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);\n\n  this.dispatchComposeEvent_(\n      ol.render.Event.Type.POSTCOMPOSE, frameState);\n\n  if (!this.renderedVisible_) {\n    this.canvas_.style.display = '';\n    this.renderedVisible_ = true;\n  }\n\n  this.scheduleRemoveUnusedLayerRenderers(frameState);\n  this.scheduleExpireIconCache(frameState);\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.canvas.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,\n        layerFilter, thisArg2) {\n  var result;\n  var viewState = frameState.viewState;\n  var viewResolution = viewState.resolution;\n\n  var layerStates = frameState.layerStatesArray;\n  var numLayers = layerStates.length;\n\n  var coordinate = ol.transform.apply(\n      frameState.pixelToCoordinateTransform, pixel.slice());\n\n  var i;\n  for (i = numLayers - 1; i >= 0; --i) {\n    var layerState = layerStates[i];\n    var layer = layerState.layer;\n    if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&\n        layerFilter.call(thisArg2, layer)) {\n      var layerRenderer = /** @type {ol.renderer.canvas.Layer} */ (this.getLayerRenderer(layer));\n      result = layerRenderer.forEachLayerAtCoordinate(\n          coordinate, frameState, callback, thisArg);\n      if (result) {\n        return result;\n      }\n    }\n  }\n  return undefined;\n};\n\ngoog.provide('ol.render.webgl');\n\n/**\n * @const\n * @type {ol.Color}\n */\nol.render.webgl.defaultFillStyle = [0.0, 0.0, 0.0, 1.0];\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.defaultLineCap = 'round';\n\n\n/**\n * @const\n * @type {Array.<number>}\n */\nol.render.webgl.defaultLineDash = [];\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.defaultLineJoin = 'round';\n\n\n/**\n * @const\n * @type {number}\n */\nol.render.webgl.defaultMiterLimit = 10;\n\n/**\n * @const\n * @type {ol.Color}\n */\nol.render.webgl.defaultStrokeStyle = [0.0, 0.0, 0.0, 1.0];\n\n/**\n * @const\n * @type {number}\n */\nol.render.webgl.defaultLineWidth = 1;\n\n/**\n * @enum {number}\n */\nol.render.webgl.lineStringInstruction = {\n  ROUND: 2,\n  BEGIN_LINE: 3,\n  END_LINE: 5,\n  BEGIN_LINE_CAP: 7,\n  END_LINE_CAP : 11,\n  BEVEL_FIRST: 13,\n  BEVEL_SECOND: 17,\n  MITER_BOTTOM: 19,\n  MITER_TOP: 23\n};\n\n/**\n * Calculates the orientation of a triangle based on the determinant method.\n * @param {number} x1 First X coordinate.\n * @param {number} y1 First Y coordinate.\n * @param {number} x2 Second X coordinate.\n * @param {number} y2 Second Y coordinate.\n * @param {number} x3 Third X coordinate.\n * @param {number} y3 Third Y coordinate.\n * @return {boolean|undefined} Triangle is clockwise.\n */\nol.render.webgl.triangleIsCounterClockwise = function(x1, y1, x2, y2, x3, y3) {\n  var area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);\n  return (area <= ol.render.webgl.EPSILON && area >= -ol.render.webgl.EPSILON) ?\n      undefined : area > 0;\n};\n\n/**\n * @const\n * @type {number}\n */\nol.render.webgl.EPSILON = Number.EPSILON || 2.220446049250313e-16;\n\ngoog.provide('ol.webgl.Shader');\n\ngoog.require('ol.functions');\ngoog.require('ol.webgl');\n\n\n/**\n * @constructor\n * @param {string} source Source.\n * @struct\n */\nol.webgl.Shader = function(source) {\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.source_ = source;\n\n};\n\n\n/**\n * @abstract\n * @return {number} Type.\n */\nol.webgl.Shader.prototype.getType = function() {};\n\n\n/**\n * @return {string} Source.\n */\nol.webgl.Shader.prototype.getSource = function() {\n  return this.source_;\n};\n\n\n/**\n * @return {boolean} Is animated?\n */\nol.webgl.Shader.prototype.isAnimated = ol.functions.FALSE;\n\ngoog.provide('ol.webgl.Fragment');\n\ngoog.require('ol');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Shader');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Shader}\n * @param {string} source Source.\n * @struct\n */\nol.webgl.Fragment = function(source) {\n  ol.webgl.Shader.call(this, source);\n};\nol.inherits(ol.webgl.Fragment, ol.webgl.Shader);\n\n\n/**\n * @inheritDoc\n */\nol.webgl.Fragment.prototype.getType = function() {\n  return ol.webgl.FRAGMENT_SHADER;\n};\n\ngoog.provide('ol.webgl.Vertex');\n\ngoog.require('ol');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Shader');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Shader}\n * @param {string} source Source.\n * @struct\n */\nol.webgl.Vertex = function(source) {\n  ol.webgl.Shader.call(this, source);\n};\nol.inherits(ol.webgl.Vertex, ol.webgl.Shader);\n\n\n/**\n * @inheritDoc\n */\nol.webgl.Vertex.prototype.getType = function() {\n  return ol.webgl.VERTEX_SHADER;\n};\n\n// This file is automatically generated, do not edit\ngoog.provide('ol.render.webgl.circlereplay.defaultshader');\n\ngoog.require('ol');\ngoog.require('ol.webgl.Fragment');\ngoog.require('ol.webgl.Vertex');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Fragment}\n * @struct\n */\nol.render.webgl.circlereplay.defaultshader.Fragment = function() {\n  ol.webgl.Fragment.call(this, ol.render.webgl.circlereplay.defaultshader.Fragment.SOURCE);\n};\nol.inherits(ol.render.webgl.circlereplay.defaultshader.Fragment, ol.webgl.Fragment);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.circlereplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\\nvarying vec2 v_center;\\nvarying vec2 v_offset;\\nvarying float v_halfWidth;\\nvarying float v_pixelRatio;\\n\\n\\n\\nuniform float u_opacity;\\nuniform vec4 u_fillColor;\\nuniform vec4 u_strokeColor;\\nuniform vec2 u_size;\\n\\nvoid main(void) {\\n  vec2 windowCenter = vec2((v_center.x + 1.0) / 2.0 * u_size.x * v_pixelRatio,\\n      (v_center.y + 1.0) / 2.0 * u_size.y * v_pixelRatio);\\n  vec2 windowOffset = vec2((v_offset.x + 1.0) / 2.0 * u_size.x * v_pixelRatio,\\n      (v_offset.y + 1.0) / 2.0 * u_size.y * v_pixelRatio);\\n  float radius = length(windowCenter - windowOffset);\\n  float dist = length(windowCenter - gl_FragCoord.xy);\\n  if (dist > radius + v_halfWidth) {\\n    if (u_strokeColor.a == 0.0) {\\n      gl_FragColor = u_fillColor;\\n    } else {\\n      gl_FragColor = u_strokeColor;\\n    }\\n    gl_FragColor.a = gl_FragColor.a - (dist - (radius + v_halfWidth));\\n  } else if (u_fillColor.a == 0.0) {\\n    // Hooray, no fill, just stroke. We can use real antialiasing.\\n    gl_FragColor = u_strokeColor;\\n    if (dist < radius - v_halfWidth) {\\n      gl_FragColor.a = gl_FragColor.a - (radius - v_halfWidth - dist);\\n    }\\n  } else {\\n    gl_FragColor = u_fillColor;\\n    float strokeDist = radius - v_halfWidth;\\n    float antialias = 2.0 * v_pixelRatio;\\n    if (dist > strokeDist) {\\n      gl_FragColor = u_strokeColor;\\n    } else if (dist >= strokeDist - antialias) {\\n      float step = smoothstep(strokeDist - antialias, strokeDist, dist);\\n      gl_FragColor = mix(u_fillColor, u_strokeColor, step);\\n    }\\n  }\\n  gl_FragColor.a = gl_FragColor.a * u_opacity;\\n  if (gl_FragColor.a <= 0.0) {\\n    discard;\\n  }\\n}\\n';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.circlereplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;varying vec2 b;varying float c;varying float d;uniform float m;uniform vec4 n;uniform vec4 o;uniform vec2 p;void main(void){vec2 windowCenter=vec2((a.x+1.0)/2.0*p.x*d,(a.y+1.0)/2.0*p.y*d);vec2 windowOffset=vec2((b.x+1.0)/2.0*p.x*d,(b.y+1.0)/2.0*p.y*d);float radius=length(windowCenter-windowOffset);float dist=length(windowCenter-gl_FragCoord.xy);if(dist>radius+c){if(o.a==0.0){gl_FragColor=n;}else{gl_FragColor=o;}gl_FragColor.a=gl_FragColor.a-(dist-(radius+c));}else if(n.a==0.0){gl_FragColor=o;if(dist<radius-c){gl_FragColor.a=gl_FragColor.a-(radius-c-dist);}} else{gl_FragColor=n;float strokeDist=radius-c;float antialias=2.0*d;if(dist>strokeDist){gl_FragColor=o;}else if(dist>=strokeDist-antialias){float step=smoothstep(strokeDist-antialias,strokeDist,dist);gl_FragColor=mix(n,o,step);}} gl_FragColor.a=gl_FragColor.a*m;if(gl_FragColor.a<=0.0){discard;}}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.circlereplay.defaultshader.Fragment.SOURCE = ol.DEBUG ?\n    ol.render.webgl.circlereplay.defaultshader.Fragment.DEBUG_SOURCE :\n    ol.render.webgl.circlereplay.defaultshader.Fragment.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.circlereplay.defaultshader.fragment = new ol.render.webgl.circlereplay.defaultshader.Fragment();\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Vertex}\n * @struct\n */\nol.render.webgl.circlereplay.defaultshader.Vertex = function() {\n  ol.webgl.Vertex.call(this, ol.render.webgl.circlereplay.defaultshader.Vertex.SOURCE);\n};\nol.inherits(ol.render.webgl.circlereplay.defaultshader.Vertex, ol.webgl.Vertex);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.circlereplay.defaultshader.Vertex.DEBUG_SOURCE = 'varying vec2 v_center;\\nvarying vec2 v_offset;\\nvarying float v_halfWidth;\\nvarying float v_pixelRatio;\\n\\n\\nattribute vec2 a_position;\\nattribute float a_instruction;\\nattribute float a_radius;\\n\\nuniform mat4 u_projectionMatrix;\\nuniform mat4 u_offsetScaleMatrix;\\nuniform mat4 u_offsetRotateMatrix;\\nuniform float u_lineWidth;\\nuniform float u_pixelRatio;\\n\\nvoid main(void) {\\n  mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\\n  v_center = vec4(u_projectionMatrix * vec4(a_position, 0.0, 1.0)).xy;\\n  v_pixelRatio = u_pixelRatio;\\n  float lineWidth = u_lineWidth * u_pixelRatio;\\n  v_halfWidth = lineWidth / 2.0;\\n  if (lineWidth == 0.0) {\\n    lineWidth = 2.0 * u_pixelRatio;\\n  }\\n  vec2 offset;\\n  // Radius with anitaliasing (roughly).\\n  float radius = a_radius + 3.0 * u_pixelRatio;\\n  // Until we get gl_VertexID in WebGL, we store an instruction.\\n  if (a_instruction == 0.0) {\\n    // Offsetting the edges of the triangle by lineWidth / 2 is necessary, however\\n    // we should also leave some space for the antialiasing, thus we offset by lineWidth.\\n    offset = vec2(-1.0, 1.0);\\n  } else if (a_instruction == 1.0) {\\n    offset = vec2(-1.0, -1.0);\\n  } else if (a_instruction == 2.0) {\\n    offset = vec2(1.0, -1.0);\\n  } else {\\n    offset = vec2(1.0, 1.0);\\n  }\\n\\n  gl_Position = u_projectionMatrix * vec4(a_position + offset * radius, 0.0, 1.0) +\\n      offsetMatrix * vec4(offset * lineWidth, 0.0, 0.0);\\n  v_offset = vec4(u_projectionMatrix * vec4(a_position.x + a_radius, a_position.y,\\n      0.0, 1.0)).xy;\\n\\n  if (distance(v_center, v_offset) > 20000.0) {\\n    gl_Position = vec4(v_center, 0.0, 1.0);\\n  }\\n}\\n\\n\\n';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;varying vec2 b;varying float c;varying float d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;void main(void){mat4 offsetMatrix=i*j;a=vec4(h*vec4(e,0.0,1.0)).xy;d=l;float lineWidth=k*l;c=lineWidth/2.0;if(lineWidth==0.0){lineWidth=2.0*l;}vec2 offset;float radius=g+3.0*l;if(f==0.0){offset=vec2(-1.0,1.0);}else if(f==1.0){offset=vec2(-1.0,-1.0);}else if(f==2.0){offset=vec2(1.0,-1.0);}else{offset=vec2(1.0,1.0);}gl_Position=h*vec4(e+offset*radius,0.0,1.0)+offsetMatrix*vec4(offset*lineWidth,0.0,0.0);b=vec4(h*vec4(e.x+g,e.y,0.0,1.0)).xy;if(distance(a,b)>20000.0){gl_Position=vec4(a,0.0,1.0);}}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.circlereplay.defaultshader.Vertex.SOURCE = ol.DEBUG ?\n    ol.render.webgl.circlereplay.defaultshader.Vertex.DEBUG_SOURCE :\n    ol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.circlereplay.defaultshader.vertex = new ol.render.webgl.circlereplay.defaultshader.Vertex();\n\n\n/**\n * @constructor\n * @param {WebGLRenderingContext} gl GL.\n * @param {WebGLProgram} program Program.\n * @struct\n */\nol.render.webgl.circlereplay.defaultshader.Locations = function(gl, program) {\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_fillColor = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_fillColor' : 'n');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_lineWidth = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_lineWidth' : 'k');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetRotateMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetRotateMatrix' : 'j');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetScaleMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetScaleMatrix' : 'i');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_opacity = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_opacity' : 'm');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_pixelRatio = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_pixelRatio' : 'l');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_projectionMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_projectionMatrix' : 'h');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_size = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_size' : 'p');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_strokeColor = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_strokeColor' : 'o');\n\n  /**\n   * @type {number}\n   */\n  this.a_instruction = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_instruction' : 'f');\n\n  /**\n   * @type {number}\n   */\n  this.a_position = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_position' : 'e');\n\n  /**\n   * @type {number}\n   */\n  this.a_radius = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_radius' : 'g');\n};\n\ngoog.provide('ol.vec.Mat4');\n\n\n/**\n * @return {Array.<number>} 4x4 matrix representing a 3D identity transform.\n */\nol.vec.Mat4.create = function() {\n  return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];\n};\n\n\n/**\n * @param {Array.<number>} mat4 Flattened 4x4 matrix receiving the result.\n * @param {ol.Transform} transform Transformation matrix.\n * @return {Array.<number>} 2D transformation matrix as flattened 4x4 matrix.\n */\nol.vec.Mat4.fromTransform = function(mat4, transform) {\n  mat4[0] = transform[0];\n  mat4[1] = transform[1];\n  mat4[4] = transform[2];\n  mat4[5] = transform[3];\n  mat4[12] = transform[4];\n  mat4[13] = transform[5];\n  return mat4;\n};\n\ngoog.provide('ol.render.webgl.Replay');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.render.VectorContext');\ngoog.require('ol.transform');\ngoog.require('ol.vec.Mat4');\ngoog.require('ol.webgl');\n\n/**\n * @constructor\n * @extends {ol.render.VectorContext}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @struct\n */\nol.render.webgl.Replay = function(tolerance, maxExtent) {\n  ol.render.VectorContext.call(this);\n\n  /**\n   * @protected\n   * @type {number}\n   */\n  this.tolerance = tolerance;\n\n  /**\n   * @protected\n   * @const\n   * @type {ol.Extent}\n   */\n  this.maxExtent = maxExtent;\n\n  /**\n   * The origin of the coordinate system for the point coordinates sent to\n   * the GPU. To eliminate jitter caused by precision problems in the GPU\n   * we use the \"Rendering Relative to Eye\" technique described in the \"3D\n   * Engine Design for Virtual Globes\" book.\n   * @protected\n   * @type {ol.Coordinate}\n   */\n  this.origin = ol.extent.getCenter(maxExtent);\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.projectionMatrix_ = ol.transform.create();\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.offsetRotateMatrix_ = ol.transform.create();\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.offsetScaleMatrix_ = ol.transform.create();\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.tmpMat4_ = ol.vec.Mat4.create();\n\n  /**\n   * @protected\n   * @type {Array.<number>}\n   */\n  this.indices = [];\n\n  /**\n   * @protected\n   * @type {?ol.webgl.Buffer}\n   */\n  this.indicesBuffer = null;\n\n  /**\n   * Start index per feature (the index).\n   * @protected\n   * @type {Array.<number>}\n   */\n  this.startIndices = [];\n\n  /**\n   * Start index per feature (the feature).\n   * @protected\n   * @type {Array.<ol.Feature|ol.render.Feature>}\n   */\n  this.startIndicesFeature = [];\n\n  /**\n   * @protected\n   * @type {Array.<number>}\n   */\n  this.vertices = [];\n\n  /**\n   * @protected\n   * @type {?ol.webgl.Buffer}\n   */\n  this.verticesBuffer = null;\n\n  /**\n   * Optional parameter for PolygonReplay instances.\n   * @protected\n   * @type {ol.render.webgl.LineStringReplay|undefined}\n   */\n  this.lineStringReplay = undefined;\n\n};\nol.inherits(ol.render.webgl.Replay, ol.render.VectorContext);\n\n\n/**\n * @abstract\n * @param {ol.webgl.Context} context WebGL context.\n * @return {function()} Delete resources function.\n */\nol.render.webgl.Replay.prototype.getDeleteResourcesFunction = function(context) {};\n\n\n/**\n * @abstract\n * @param {ol.webgl.Context} context Context.\n */\nol.render.webgl.Replay.prototype.finish = function(context) {};\n\n\n/**\n * @abstract\n * @protected\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @return {ol.render.webgl.circlereplay.defaultshader.Locations|\n            ol.render.webgl.imagereplay.defaultshader.Locations|\n            ol.render.webgl.linestringreplay.defaultshader.Locations|\n            ol.render.webgl.polygonreplay.defaultshader.Locations} Locations.\n */\nol.render.webgl.Replay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {};\n\n\n/**\n * @abstract\n * @protected\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.render.webgl.circlereplay.defaultshader.Locations|\n           ol.render.webgl.imagereplay.defaultshader.Locations|\n           ol.render.webgl.linestringreplay.defaultshader.Locations|\n           ol.render.webgl.polygonreplay.defaultshader.Locations} locations Locations.\n */\nol.render.webgl.Replay.prototype.shutDownProgram = function(gl, locations) {};\n\n\n/**\n * @abstract\n * @protected\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {boolean} hitDetection Hit detection mode.\n */\nol.render.webgl.Replay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {};\n\n\n/**\n * @abstract\n * @protected\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.\n * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting\n *  this extent are checked.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.webgl.Replay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash, featureCallback, opt_hitExtent) {};\n\n\n/**\n * @protected\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.\n * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.\n * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting\n *  this extent are checked.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.webgl.Replay.prototype.drawHitDetectionReplay = function(gl, context, skippedFeaturesHash,\n    featureCallback, oneByOne, opt_hitExtent) {\n  if (!oneByOne) {\n    // draw all hit-detection features in \"once\" (by texture group)\n    return this.drawHitDetectionReplayAll(gl, context,\n        skippedFeaturesHash, featureCallback);\n  } else {\n    // draw hit-detection features one by one\n    return this.drawHitDetectionReplayOneByOne(gl, context,\n        skippedFeaturesHash, featureCallback, opt_hitExtent);\n  }\n};\n\n\n/**\n * @protected\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.webgl.Replay.prototype.drawHitDetectionReplayAll = function(gl, context, skippedFeaturesHash,\n    featureCallback) {\n  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n  this.drawReplay(gl, context, skippedFeaturesHash, true);\n\n  var result = featureCallback(null);\n  if (result) {\n    return result;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} opacity Global opacity.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.\n * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.\n * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting\n *  this extent are checked.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.webgl.Replay.prototype.replay = function(context,\n    center, resolution, rotation, size, pixelRatio,\n    opacity, skippedFeaturesHash,\n    featureCallback, oneByOne, opt_hitExtent) {\n  var gl = context.getGL();\n  var tmpStencil, tmpStencilFunc, tmpStencilMaskVal, tmpStencilRef, tmpStencilMask,\n      tmpStencilOpFail, tmpStencilOpPass, tmpStencilOpZFail;\n\n  if (this.lineStringReplay) {\n    tmpStencil = gl.isEnabled(gl.STENCIL_TEST);\n    tmpStencilFunc = gl.getParameter(gl.STENCIL_FUNC);\n    tmpStencilMaskVal = gl.getParameter(gl.STENCIL_VALUE_MASK);\n    tmpStencilRef = gl.getParameter(gl.STENCIL_REF);\n    tmpStencilMask = gl.getParameter(gl.STENCIL_WRITEMASK);\n    tmpStencilOpFail = gl.getParameter(gl.STENCIL_FAIL);\n    tmpStencilOpPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS);\n    tmpStencilOpZFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL);\n\n    gl.enable(gl.STENCIL_TEST);\n    gl.clear(gl.STENCIL_BUFFER_BIT);\n    gl.stencilMask(255);\n    gl.stencilFunc(gl.ALWAYS, 1, 255);\n    gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);\n\n    this.lineStringReplay.replay(context,\n        center, resolution, rotation, size, pixelRatio,\n        opacity, skippedFeaturesHash,\n        featureCallback, oneByOne, opt_hitExtent);\n\n    gl.stencilMask(0);\n    gl.stencilFunc(gl.NOTEQUAL, 1, 255);\n  }\n\n  // bind the vertices buffer\n  ol.DEBUG && console.assert(this.verticesBuffer,\n      'verticesBuffer must not be null');\n  context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.verticesBuffer);\n\n  // bind the indices buffer\n  ol.DEBUG && console.assert(this.indicesBuffer,\n      'indicesBuffer must not be null');\n  context.bindBuffer(ol.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);\n\n  var locations = this.setUpProgram(gl, context, size, pixelRatio);\n\n  // set the \"uniform\" values\n  var projectionMatrix = ol.transform.reset(this.projectionMatrix_);\n  ol.transform.scale(projectionMatrix, 2 / (resolution * size[0]), 2 / (resolution * size[1]));\n  ol.transform.rotate(projectionMatrix, -rotation);\n  ol.transform.translate(projectionMatrix, -(center[0] - this.origin[0]), -(center[1] - this.origin[1]));\n\n  var offsetScaleMatrix = ol.transform.reset(this.offsetScaleMatrix_);\n  ol.transform.scale(offsetScaleMatrix, 2 / size[0], 2 / size[1]);\n\n  var offsetRotateMatrix = ol.transform.reset(this.offsetRotateMatrix_);\n  if (rotation !== 0) {\n    ol.transform.rotate(offsetRotateMatrix, -rotation);\n  }\n\n  gl.uniformMatrix4fv(locations.u_projectionMatrix, false,\n      ol.vec.Mat4.fromTransform(this.tmpMat4_, projectionMatrix));\n  gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false,\n      ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetScaleMatrix));\n  gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false,\n      ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetRotateMatrix));\n  gl.uniform1f(locations.u_opacity, opacity);\n\n  // draw!\n  var result;\n  if (featureCallback === undefined) {\n    this.drawReplay(gl, context, skippedFeaturesHash, false);\n  } else {\n    // draw feature by feature for the hit-detection\n    result = this.drawHitDetectionReplay(gl, context, skippedFeaturesHash,\n        featureCallback, oneByOne, opt_hitExtent);\n  }\n\n  // disable the vertex attrib arrays\n  this.shutDownProgram(gl, locations);\n\n  if (this.lineStringReplay) {\n    if (!tmpStencil) {\n      gl.disable(gl.STENCIL_TEST);\n    }\n    gl.clear(gl.STENCIL_BUFFER_BIT);\n    gl.stencilFunc(/** @type {number} */ (tmpStencilFunc),\n        /** @type {number} */ (tmpStencilRef), /** @type {number} */ (tmpStencilMaskVal));\n    gl.stencilMask(/** @type {number} */ (tmpStencilMask));\n    gl.stencilOp(/** @type {number} */ (tmpStencilOpFail),\n        /** @type {number} */ (tmpStencilOpZFail), /** @type {number} */ (tmpStencilOpPass));\n  }\n\n  return result;\n};\n\n/**\n * @protected\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {number} start Start index.\n * @param {number} end End index.\n */\nol.render.webgl.Replay.prototype.drawElements = function(\n    gl, context, start, end) {\n  var elementType = context.hasOESElementIndexUint ?\n      ol.webgl.UNSIGNED_INT : ol.webgl.UNSIGNED_SHORT;\n  var elementSize = context.hasOESElementIndexUint ? 4 : 2;\n\n  var numItems = end - start;\n  var offsetInBytes = start * elementSize;\n  gl.drawElements(ol.webgl.TRIANGLES, numItems, elementType, offsetInBytes);\n};\n\ngoog.provide('ol.webgl.Buffer');\n\ngoog.require('ol');\ngoog.require('ol.webgl');\n\n\n/**\n * @constructor\n * @param {Array.<number>=} opt_arr Array.\n * @param {number=} opt_usage Usage.\n * @struct\n */\nol.webgl.Buffer = function(opt_arr, opt_usage) {\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.arr_ = opt_arr !== undefined ? opt_arr : [];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.usage_ = opt_usage !== undefined ?\n      opt_usage : ol.webgl.Buffer.Usage.STATIC_DRAW;\n\n};\n\n\n/**\n * @return {Array.<number>} Array.\n */\nol.webgl.Buffer.prototype.getArray = function() {\n  return this.arr_;\n};\n\n\n/**\n * @return {number} Usage.\n */\nol.webgl.Buffer.prototype.getUsage = function() {\n  return this.usage_;\n};\n\n\n/**\n * @enum {number}\n */\nol.webgl.Buffer.Usage = {\n  STATIC_DRAW: ol.webgl.STATIC_DRAW,\n  STREAM_DRAW: ol.webgl.STREAM_DRAW,\n  DYNAMIC_DRAW: ol.webgl.DYNAMIC_DRAW\n};\n\ngoog.provide('ol.render.webgl.CircleReplay');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.color');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.geom.flat.transform');\ngoog.require('ol.render.webgl.circlereplay.defaultshader');\ngoog.require('ol.render.webgl.Replay');\ngoog.require('ol.render.webgl');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Buffer');\n\n\n/**\n * @constructor\n * @extends {ol.render.webgl.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @struct\n */\nol.render.webgl.CircleReplay = function(tolerance, maxExtent) {\n  ol.render.webgl.Replay.call(this, tolerance, maxExtent);\n\n  /**\n   * @private\n   * @type {ol.render.webgl.circlereplay.defaultshader.Locations}\n   */\n  this.defaultLocations_ = null;\n\n  /**\n   * @private\n   * @type {Array.<Array.<Array.<number>|number>>}\n   */\n  this.styles_ = [];\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.styleIndices_ = [];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.radius_ = 0;\n\n  /**\n   * @private\n   * @type {{fillColor: (Array.<number>|null),\n   *         strokeColor: (Array.<number>|null),\n   *         lineDash: Array.<number>,\n   *         lineWidth: (number|undefined),\n   *         changed: boolean}|null}\n   */\n  this.state_ = {\n    fillColor: null,\n    strokeColor: null,\n    lineDash: null,\n    lineWidth: undefined,\n    changed: false\n  };\n\n};\nol.inherits(ol.render.webgl.CircleReplay, ol.render.webgl.Replay);\n\n\n/**\n * @private\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n */\nol.render.webgl.CircleReplay.prototype.drawCoordinates_ = function(\n    flatCoordinates, offset, end, stride) {\n  var numVertices = this.vertices.length;\n  var numIndices = this.indices.length;\n  var n = numVertices / 4;\n  var i, ii;\n  for (i = offset, ii = end; i < ii; i += stride) {\n    this.vertices[numVertices++] = flatCoordinates[i];\n    this.vertices[numVertices++] = flatCoordinates[i + 1];\n    this.vertices[numVertices++] = 0;\n    this.vertices[numVertices++] = this.radius_;\n\n    this.vertices[numVertices++] = flatCoordinates[i];\n    this.vertices[numVertices++] = flatCoordinates[i + 1];\n    this.vertices[numVertices++] = 1;\n    this.vertices[numVertices++] = this.radius_;\n\n    this.vertices[numVertices++] = flatCoordinates[i];\n    this.vertices[numVertices++] = flatCoordinates[i + 1];\n    this.vertices[numVertices++] = 2;\n    this.vertices[numVertices++] = this.radius_;\n\n    this.vertices[numVertices++] = flatCoordinates[i];\n    this.vertices[numVertices++] = flatCoordinates[i + 1];\n    this.vertices[numVertices++] = 3;\n    this.vertices[numVertices++] = this.radius_;\n\n    this.indices[numIndices++] = n;\n    this.indices[numIndices++] = n + 1;\n    this.indices[numIndices++] = n + 2;\n\n    this.indices[numIndices++] = n + 2;\n    this.indices[numIndices++] = n + 3;\n    this.indices[numIndices++] = n;\n\n    n += 4;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.CircleReplay.prototype.drawCircle = function(circleGeometry, feature) {\n  var radius = circleGeometry.getRadius();\n  var stride = circleGeometry.getStride();\n  if (radius) {\n    this.startIndices.push(this.indices.length);\n    this.startIndicesFeature.push(feature);\n    if (this.state_.changed) {\n      this.styleIndices_.push(this.indices.length);\n      this.state_.changed = false;\n    }\n\n    this.radius_ = radius;\n    var flatCoordinates = circleGeometry.getFlatCoordinates();\n    flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, 2,\n        stride, -this.origin[0], -this.origin[1]);\n    this.drawCoordinates_(flatCoordinates, 0, 2, stride);\n  } else {\n    if (this.state_.changed) {\n      this.styles_.pop();\n      if (this.styles_.length) {\n        var lastState = this.styles_[this.styles_.length - 1];\n        this.state_.fillColor =  /** @type {Array.<number>} */ (lastState[0]);\n        this.state_.strokeColor = /** @type {Array.<number>} */ (lastState[1]);\n        this.state_.lineWidth = /** @type {number} */ (lastState[2]);\n        this.state_.changed = false;\n      }\n    }\n  }\n};\n\n\n/**\n * @inheritDoc\n **/\nol.render.webgl.CircleReplay.prototype.finish = function(context) {\n  // create, bind, and populate the vertices buffer\n  this.verticesBuffer = new ol.webgl.Buffer(this.vertices);\n\n  // create, bind, and populate the indices buffer\n  this.indicesBuffer = new ol.webgl.Buffer(this.indices);\n\n  this.startIndices.push(this.indices.length);\n\n  //Clean up, if there is nothing to draw\n  if (this.styleIndices_.length === 0 && this.styles_.length > 0) {\n    this.styles_ = [];\n  }\n\n  this.vertices = null;\n  this.indices = null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.CircleReplay.prototype.getDeleteResourcesFunction = function(context) {\n  // We only delete our stuff here. The shaders and the program may\n  // be used by other CircleReplay instances (for other layers). And\n  // they will be deleted when disposing of the ol.webgl.Context\n  // object.\n  ol.DEBUG && console.assert(this.verticesBuffer,\n      'verticesBuffer must not be null');\n  ol.DEBUG && console.assert(this.indicesBuffer,\n      'indicesBuffer must not be null');\n  var verticesBuffer = this.verticesBuffer;\n  var indicesBuffer = this.indicesBuffer;\n  return function() {\n    context.deleteBuffer(verticesBuffer);\n    context.deleteBuffer(indicesBuffer);\n  };\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.CircleReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {\n  // get the program\n  var fragmentShader, vertexShader;\n  fragmentShader = ol.render.webgl.circlereplay.defaultshader.fragment;\n  vertexShader = ol.render.webgl.circlereplay.defaultshader.vertex;\n  var program = context.getProgram(fragmentShader, vertexShader);\n\n  // get the locations\n  var locations;\n  if (!this.defaultLocations_) {\n    locations =\n        new ol.render.webgl.circlereplay.defaultshader.Locations(gl, program);\n    this.defaultLocations_ = locations;\n  } else {\n    locations = this.defaultLocations_;\n  }\n\n  context.useProgram(program);\n\n  // enable the vertex attrib arrays\n  gl.enableVertexAttribArray(locations.a_position);\n  gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,\n      false, 16, 0);\n\n  gl.enableVertexAttribArray(locations.a_instruction);\n  gl.vertexAttribPointer(locations.a_instruction, 1, ol.webgl.FLOAT,\n      false, 16, 8);\n\n  gl.enableVertexAttribArray(locations.a_radius);\n  gl.vertexAttribPointer(locations.a_radius, 1, ol.webgl.FLOAT,\n      false, 16, 12);\n\n  // Enable renderer specific uniforms.\n  gl.uniform2fv(locations.u_size, size);\n  gl.uniform1f(locations.u_pixelRatio, pixelRatio);\n\n  return locations;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.CircleReplay.prototype.shutDownProgram = function(gl, locations) {\n  gl.disableVertexAttribArray(locations.a_position);\n  gl.disableVertexAttribArray(locations.a_instruction);\n  gl.disableVertexAttribArray(locations.a_radius);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.CircleReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {\n  if (!ol.obj.isEmpty(skippedFeaturesHash)) {\n    this.drawReplaySkipping_(gl, context, skippedFeaturesHash);\n  } else {\n    ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,\n        'number of styles and styleIndices match');\n\n    //Draw by style groups to minimize drawElements() calls.\n    var i, start, end, nextStyle;\n    end = this.startIndices[this.startIndices.length - 1];\n    for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n      start = this.styleIndices_[i];\n      nextStyle = this.styles_[i];\n      this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));\n      this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),\n          /** @type {number} */ (nextStyle[2]));\n      this.drawElements(gl, context, start, end);\n      end = start;\n    }\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.CircleReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,\n    featureCallback, opt_hitExtent) {\n  ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,\n      'number of styles and styleIndices match');\n  ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,\n      'number of startIndices and startIndicesFeature match');\n\n  var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex;\n  featureIndex = this.startIndices.length - 2;\n  end = this.startIndices[featureIndex + 1];\n  for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n    nextStyle = this.styles_[i];\n    this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));\n    this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),\n        /** @type {number} */ (nextStyle[2]));\n    groupStart = this.styleIndices_[i];\n\n    while (featureIndex >= 0 &&\n        this.startIndices[featureIndex] >= groupStart) {\n      start = this.startIndices[featureIndex];\n      feature = this.startIndicesFeature[featureIndex];\n      featureUid = ol.getUid(feature).toString();\n\n      if (skippedFeaturesHash[featureUid] === undefined &&\n          feature.getGeometry() &&\n          (opt_hitExtent === undefined || ol.extent.intersects(\n              /** @type {Array<number>} */ (opt_hitExtent),\n              feature.getGeometry().getExtent()))) {\n        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        this.drawElements(gl, context, start, end);\n\n        var result = featureCallback(feature);\n\n        if (result) {\n          return result;\n        }\n\n      }\n      featureIndex--;\n      end = start;\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object} skippedFeaturesHash Ids of features to skip.\n */\nol.render.webgl.CircleReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) {\n  ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,\n      'number of startIndices and startIndicesFeature match');\n\n  var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart;\n  featureIndex = this.startIndices.length - 2;\n  end = start = this.startIndices[featureIndex + 1];\n  for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n    nextStyle = this.styles_[i];\n    this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));\n    this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),\n        /** @type {number} */ (nextStyle[2]));\n    groupStart = this.styleIndices_[i];\n\n    while (featureIndex >= 0 &&\n        this.startIndices[featureIndex] >= groupStart) {\n      featureStart = this.startIndices[featureIndex];\n      feature = this.startIndicesFeature[featureIndex];\n      featureUid = ol.getUid(feature).toString();\n\n      if (skippedFeaturesHash[featureUid]) {\n        if (start !== end) {\n          this.drawElements(gl, context, start, end);\n        }\n        end = featureStart;\n      }\n      featureIndex--;\n      start = featureStart;\n    }\n    if (start !== end) {\n      this.drawElements(gl, context, start, end);\n    }\n    start = end = groupStart;\n  }\n};\n\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {Array.<number>} color Color.\n */\nol.render.webgl.CircleReplay.prototype.setFillStyle_ = function(gl, color) {\n  gl.uniform4fv(this.defaultLocations_.u_fillColor, color);\n};\n\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {Array.<number>} color Color.\n * @param {number} lineWidth Line width.\n */\nol.render.webgl.CircleReplay.prototype.setStrokeStyle_ = function(gl, color, lineWidth) {\n  gl.uniform4fv(this.defaultLocations_.u_strokeColor, color);\n  gl.uniform1f(this.defaultLocations_.u_lineWidth, lineWidth);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.CircleReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {\n  ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');\n  var strokeStyleColor, strokeStyleWidth;\n  if (strokeStyle) {\n    var strokeStyleLineDash = strokeStyle.getLineDash();\n    this.state_.lineDash = strokeStyleLineDash ?\n        strokeStyleLineDash : ol.render.webgl.defaultLineDash;\n    strokeStyleColor = strokeStyle.getColor();\n    if (!(strokeStyleColor instanceof CanvasGradient) &&\n        !(strokeStyleColor instanceof CanvasPattern)) {\n      strokeStyleColor = ol.color.asArray(strokeStyleColor).map(function(c, i) {\n        return i != 3 ? c / 255 : c;\n      }) || ol.render.webgl.defaultStrokeStyle;\n    } else {\n      strokeStyleColor = ol.render.webgl.defaultStrokeStyle;\n    }\n    strokeStyleWidth = strokeStyle.getWidth();\n    strokeStyleWidth = strokeStyleWidth !== undefined ?\n        strokeStyleWidth : ol.render.webgl.defaultLineWidth;\n  } else {\n    strokeStyleColor = [0, 0, 0, 0];\n    strokeStyleWidth = 0;\n  }\n  var fillStyleColor = fillStyle ? fillStyle.getColor() : [0, 0, 0, 0];\n  if (!(fillStyleColor instanceof CanvasGradient) &&\n      !(fillStyleColor instanceof CanvasPattern)) {\n    fillStyleColor = ol.color.asArray(fillStyleColor).map(function(c, i) {\n      return i != 3 ? c / 255 : c;\n    }) || ol.render.webgl.defaultFillStyle;\n  } else {\n    fillStyleColor = ol.render.webgl.defaultFillStyle;\n  }\n  if (!this.state_.strokeColor || !ol.array.equals(this.state_.strokeColor, strokeStyleColor) ||\n      !this.state_.fillColor || !ol.array.equals(this.state_.fillColor, fillStyleColor) ||\n      this.state_.lineWidth !== strokeStyleWidth) {\n    this.state_.changed = true;\n    this.state_.fillColor = fillStyleColor;\n    this.state_.strokeColor = strokeStyleColor;\n    this.state_.lineWidth = strokeStyleWidth;\n    this.styles_.push([fillStyleColor, strokeStyleColor, strokeStyleWidth]);\n  }\n};\n\n// This file is automatically generated, do not edit\ngoog.provide('ol.render.webgl.imagereplay.defaultshader');\n\ngoog.require('ol');\ngoog.require('ol.webgl.Fragment');\ngoog.require('ol.webgl.Vertex');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Fragment}\n * @struct\n */\nol.render.webgl.imagereplay.defaultshader.Fragment = function() {\n  ol.webgl.Fragment.call(this, ol.render.webgl.imagereplay.defaultshader.Fragment.SOURCE);\n};\nol.inherits(ol.render.webgl.imagereplay.defaultshader.Fragment, ol.webgl.Fragment);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.imagereplay.defaultshader.Fragment.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';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.imagereplay.defaultshader.Fragment.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;}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.imagereplay.defaultshader.Fragment.SOURCE = ol.DEBUG ?\n    ol.render.webgl.imagereplay.defaultshader.Fragment.DEBUG_SOURCE :\n    ol.render.webgl.imagereplay.defaultshader.Fragment.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.imagereplay.defaultshader.fragment = new ol.render.webgl.imagereplay.defaultshader.Fragment();\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Vertex}\n * @struct\n */\nol.render.webgl.imagereplay.defaultshader.Vertex = function() {\n  ol.webgl.Vertex.call(this, ol.render.webgl.imagereplay.defaultshader.Vertex.SOURCE);\n};\nol.inherits(ol.render.webgl.imagereplay.defaultshader.Vertex, ol.webgl.Vertex);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.imagereplay.defaultshader.Vertex.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, 0.0);\\n  gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;\\n  v_texCoord = a_texCoord;\\n  v_opacity = a_opacity;\\n}\\n\\n\\n';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.imagereplay.defaultshader.Vertex.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,0.0);gl_Position=h*vec4(c,0.0,1.0)+offsets;a=d;b=f;}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.imagereplay.defaultshader.Vertex.SOURCE = ol.DEBUG ?\n    ol.render.webgl.imagereplay.defaultshader.Vertex.DEBUG_SOURCE :\n    ol.render.webgl.imagereplay.defaultshader.Vertex.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.imagereplay.defaultshader.vertex = new ol.render.webgl.imagereplay.defaultshader.Vertex();\n\n\n/**\n * @constructor\n * @param {WebGLRenderingContext} gl GL.\n * @param {WebGLProgram} program Program.\n * @struct\n */\nol.render.webgl.imagereplay.defaultshader.Locations = function(gl, program) {\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_image = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_image' : 'l');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetRotateMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetRotateMatrix' : 'j');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetScaleMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetScaleMatrix' : 'i');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_opacity = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_opacity' : 'k');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_projectionMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_projectionMatrix' : 'h');\n\n  /**\n   * @type {number}\n   */\n  this.a_offsets = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_offsets' : 'e');\n\n  /**\n   * @type {number}\n   */\n  this.a_opacity = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_opacity' : 'f');\n\n  /**\n   * @type {number}\n   */\n  this.a_position = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_position' : 'c');\n\n  /**\n   * @type {number}\n   */\n  this.a_rotateWithView = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_rotateWithView' : 'g');\n\n  /**\n   * @type {number}\n   */\n  this.a_texCoord = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_texCoord' : 'd');\n};\n\ngoog.provide('ol.webgl.ContextEventType');\n\n\n/**\n * @enum {string}\n */\nol.webgl.ContextEventType = {\n  LOST: 'webglcontextlost',\n  RESTORED: 'webglcontextrestored'\n};\n\ngoog.provide('ol.webgl.Context');\n\ngoog.require('ol');\ngoog.require('ol.Disposable');\ngoog.require('ol.array');\ngoog.require('ol.events');\ngoog.require('ol.obj');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.ContextEventType');\n\n\n/**\n * @classdesc\n * A WebGL context for accessing low-level WebGL capabilities.\n *\n * @constructor\n * @extends {ol.Disposable}\n * @param {HTMLCanvasElement} canvas Canvas.\n * @param {WebGLRenderingContext} gl GL.\n */\nol.webgl.Context = function(canvas, gl) {\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = canvas;\n\n  /**\n   * @private\n   * @type {WebGLRenderingContext}\n   */\n  this.gl_ = gl;\n\n  /**\n   * @private\n   * @type {Object.<string, ol.WebglBufferCacheEntry>}\n   */\n  this.bufferCache_ = {};\n\n  /**\n   * @private\n   * @type {Object.<string, WebGLShader>}\n   */\n  this.shaderCache_ = {};\n\n  /**\n   * @private\n   * @type {Object.<string, WebGLProgram>}\n   */\n  this.programCache_ = {};\n\n  /**\n   * @private\n   * @type {WebGLProgram}\n   */\n  this.currentProgram_ = null;\n\n  /**\n   * @private\n   * @type {WebGLFramebuffer}\n   */\n  this.hitDetectionFramebuffer_ = null;\n\n  /**\n   * @private\n   * @type {WebGLTexture}\n   */\n  this.hitDetectionTexture_ = null;\n\n  /**\n   * @private\n   * @type {WebGLRenderbuffer}\n   */\n  this.hitDetectionRenderbuffer_ = null;\n\n  /**\n   * @type {boolean}\n   */\n  this.hasOESElementIndexUint = ol.array.includes(\n      ol.WEBGL_EXTENSIONS, 'OES_element_index_uint');\n\n  // use the OES_element_index_uint extension if available\n  if (this.hasOESElementIndexUint) {\n    var ext = gl.getExtension('OES_element_index_uint');\n    ol.DEBUG && console.assert(ext,\n        'Failed to get extension \"OES_element_index_uint\"');\n  }\n\n  ol.events.listen(this.canvas_, ol.webgl.ContextEventType.LOST,\n      this.handleWebGLContextLost, this);\n  ol.events.listen(this.canvas_, ol.webgl.ContextEventType.RESTORED,\n      this.handleWebGLContextRestored, this);\n\n};\nol.inherits(ol.webgl.Context, ol.Disposable);\n\n\n/**\n * Just bind the buffer if it's in the cache. Otherwise create\n * the WebGL buffer, bind it, populate it, and add an entry to\n * the cache.\n * @param {number} target Target.\n * @param {ol.webgl.Buffer} buf Buffer.\n */\nol.webgl.Context.prototype.bindBuffer = function(target, buf) {\n  var gl = this.getGL();\n  var arr = buf.getArray();\n  var bufferKey = String(ol.getUid(buf));\n  if (bufferKey in this.bufferCache_) {\n    var bufferCacheEntry = this.bufferCache_[bufferKey];\n    gl.bindBuffer(target, bufferCacheEntry.buffer);\n  } else {\n    var buffer = gl.createBuffer();\n    gl.bindBuffer(target, buffer);\n    ol.DEBUG && console.assert(target == ol.webgl.ARRAY_BUFFER ||\n        target == ol.webgl.ELEMENT_ARRAY_BUFFER,\n        'target is supposed to be an ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER');\n    var /** @type {ArrayBufferView} */ arrayBuffer;\n    if (target == ol.webgl.ARRAY_BUFFER) {\n      arrayBuffer = new Float32Array(arr);\n    } else if (target == ol.webgl.ELEMENT_ARRAY_BUFFER) {\n      arrayBuffer = this.hasOESElementIndexUint ?\n          new Uint32Array(arr) : new Uint16Array(arr);\n    }\n    gl.bufferData(target, arrayBuffer, buf.getUsage());\n    this.bufferCache_[bufferKey] = {\n      buf: buf,\n      buffer: buffer\n    };\n  }\n};\n\n\n/**\n * @param {ol.webgl.Buffer} buf Buffer.\n */\nol.webgl.Context.prototype.deleteBuffer = function(buf) {\n  var gl = this.getGL();\n  var bufferKey = String(ol.getUid(buf));\n  ol.DEBUG && console.assert(bufferKey in this.bufferCache_,\n      'attempted to delete uncached buffer');\n  var bufferCacheEntry = this.bufferCache_[bufferKey];\n  if (!gl.isContextLost()) {\n    gl.deleteBuffer(bufferCacheEntry.buffer);\n  }\n  delete this.bufferCache_[bufferKey];\n};\n\n\n/**\n * @inheritDoc\n */\nol.webgl.Context.prototype.disposeInternal = function() {\n  ol.events.unlistenAll(this.canvas_);\n  var gl = this.getGL();\n  if (!gl.isContextLost()) {\n    var key;\n    for (key in this.bufferCache_) {\n      gl.deleteBuffer(this.bufferCache_[key].buffer);\n    }\n    for (key in this.programCache_) {\n      gl.deleteProgram(this.programCache_[key]);\n    }\n    for (key in this.shaderCache_) {\n      gl.deleteShader(this.shaderCache_[key]);\n    }\n    // delete objects for hit-detection\n    gl.deleteFramebuffer(this.hitDetectionFramebuffer_);\n    gl.deleteRenderbuffer(this.hitDetectionRenderbuffer_);\n    gl.deleteTexture(this.hitDetectionTexture_);\n  }\n};\n\n\n/**\n * @return {HTMLCanvasElement} Canvas.\n */\nol.webgl.Context.prototype.getCanvas = function() {\n  return this.canvas_;\n};\n\n\n/**\n * Get the WebGL rendering context\n * @return {WebGLRenderingContext} The rendering context.\n * @api\n */\nol.webgl.Context.prototype.getGL = function() {\n  return this.gl_;\n};\n\n\n/**\n * Get the frame buffer for hit detection.\n * @return {WebGLFramebuffer} The hit detection frame buffer.\n */\nol.webgl.Context.prototype.getHitDetectionFramebuffer = function() {\n  if (!this.hitDetectionFramebuffer_) {\n    this.initHitDetectionFramebuffer_();\n  }\n  return this.hitDetectionFramebuffer_;\n};\n\n\n/**\n * Get shader from the cache if it's in the cache. Otherwise, create\n * the WebGL shader, compile it, and add entry to cache.\n * @param {ol.webgl.Shader} shaderObject Shader object.\n * @return {WebGLShader} Shader.\n */\nol.webgl.Context.prototype.getShader = function(shaderObject) {\n  var shaderKey = String(ol.getUid(shaderObject));\n  if (shaderKey in this.shaderCache_) {\n    return this.shaderCache_[shaderKey];\n  } else {\n    var gl = this.getGL();\n    var shader = gl.createShader(shaderObject.getType());\n    gl.shaderSource(shader, shaderObject.getSource());\n    gl.compileShader(shader);\n    ol.DEBUG && console.assert(\n        gl.getShaderParameter(shader, ol.webgl.COMPILE_STATUS) ||\n        gl.isContextLost(),\n        gl.getShaderInfoLog(shader) || 'illegal state, shader not compiled or context lost');\n    this.shaderCache_[shaderKey] = shader;\n    return shader;\n  }\n};\n\n\n/**\n * Get the program from the cache if it's in the cache. Otherwise create\n * the WebGL program, attach the shaders to it, and add an entry to the\n * cache.\n * @param {ol.webgl.Fragment} fragmentShaderObject Fragment shader.\n * @param {ol.webgl.Vertex} vertexShaderObject Vertex shader.\n * @return {WebGLProgram} Program.\n */\nol.webgl.Context.prototype.getProgram = function(\n    fragmentShaderObject, vertexShaderObject) {\n  var programKey =\n      ol.getUid(fragmentShaderObject) + '/' + ol.getUid(vertexShaderObject);\n  if (programKey in this.programCache_) {\n    return this.programCache_[programKey];\n  } else {\n    var gl = this.getGL();\n    var program = gl.createProgram();\n    gl.attachShader(program, this.getShader(fragmentShaderObject));\n    gl.attachShader(program, this.getShader(vertexShaderObject));\n    gl.linkProgram(program);\n    ol.DEBUG && console.assert(\n        gl.getProgramParameter(program, ol.webgl.LINK_STATUS) ||\n        gl.isContextLost(),\n        gl.getProgramInfoLog(program) || 'illegal state, shader not linked or context lost');\n    this.programCache_[programKey] = program;\n    return program;\n  }\n};\n\n\n/**\n * FIXME empy description for jsdoc\n */\nol.webgl.Context.prototype.handleWebGLContextLost = function() {\n  ol.obj.clear(this.bufferCache_);\n  ol.obj.clear(this.shaderCache_);\n  ol.obj.clear(this.programCache_);\n  this.currentProgram_ = null;\n  this.hitDetectionFramebuffer_ = null;\n  this.hitDetectionTexture_ = null;\n  this.hitDetectionRenderbuffer_ = null;\n};\n\n\n/**\n * FIXME empy description for jsdoc\n */\nol.webgl.Context.prototype.handleWebGLContextRestored = function() {\n};\n\n\n/**\n * Creates a 1x1 pixel framebuffer for the hit-detection.\n * @private\n */\nol.webgl.Context.prototype.initHitDetectionFramebuffer_ = function() {\n  var gl = this.gl_;\n  var framebuffer = gl.createFramebuffer();\n  gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n\n  var texture = ol.webgl.Context.createEmptyTexture(gl, 1, 1);\n  var renderbuffer = gl.createRenderbuffer();\n  gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);\n  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1);\n  gl.framebufferTexture2D(\n      gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,\n      gl.RENDERBUFFER, renderbuffer);\n\n  gl.bindTexture(gl.TEXTURE_2D, null);\n  gl.bindRenderbuffer(gl.RENDERBUFFER, null);\n  gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n  this.hitDetectionFramebuffer_ = framebuffer;\n  this.hitDetectionTexture_ = texture;\n  this.hitDetectionRenderbuffer_ = renderbuffer;\n};\n\n\n/**\n * Use a program.  If the program is already in use, this will return `false`.\n * @param {WebGLProgram} program Program.\n * @return {boolean} Changed.\n * @api\n */\nol.webgl.Context.prototype.useProgram = function(program) {\n  if (program == this.currentProgram_) {\n    return false;\n  } else {\n    var gl = this.getGL();\n    gl.useProgram(program);\n    this.currentProgram_ = program;\n    return true;\n  }\n};\n\n\n/**\n * @param {WebGLRenderingContext} gl WebGL rendering context.\n * @param {number=} opt_wrapS wrapS.\n * @param {number=} opt_wrapT wrapT.\n * @return {WebGLTexture} The texture.\n * @private\n */\nol.webgl.Context.createTexture_ = function(gl, opt_wrapS, opt_wrapT) {\n  var texture = gl.createTexture();\n  gl.bindTexture(gl.TEXTURE_2D, texture);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\n  if (opt_wrapS !== undefined) {\n    gl.texParameteri(\n        ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_S, opt_wrapS);\n  }\n  if (opt_wrapT !== undefined) {\n    gl.texParameteri(\n        ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_T, opt_wrapT);\n  }\n\n  return texture;\n};\n\n\n/**\n * @param {WebGLRenderingContext} gl WebGL rendering context.\n * @param {number} width Width.\n * @param {number} height Height.\n * @param {number=} opt_wrapS wrapS.\n * @param {number=} opt_wrapT wrapT.\n * @return {WebGLTexture} The texture.\n */\nol.webgl.Context.createEmptyTexture = function(\n    gl, width, height, opt_wrapS, opt_wrapT) {\n  var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);\n  gl.texImage2D(\n      gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE,\n      null);\n\n  return texture;\n};\n\n\n/**\n * @param {WebGLRenderingContext} gl WebGL rendering context.\n * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image.\n * @param {number=} opt_wrapS wrapS.\n * @param {number=} opt_wrapT wrapT.\n * @return {WebGLTexture} The texture.\n */\nol.webgl.Context.createTexture = function(gl, image, opt_wrapS, opt_wrapT) {\n  var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);\n  gl.texImage2D(\n      gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);\n\n  return texture;\n};\n\ngoog.provide('ol.render.webgl.ImageReplay');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.render.webgl.imagereplay.defaultshader');\ngoog.require('ol.render.webgl.Replay');\ngoog.require('ol.render.webgl');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Buffer');\ngoog.require('ol.webgl.Context');\n\n\n/**\n * @constructor\n * @extends {ol.render.webgl.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @struct\n */\nol.render.webgl.ImageReplay = function(tolerance, maxExtent) {\n  ol.render.webgl.Replay.call(this, tolerance, maxExtent);\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.anchorX_ = undefined;\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.anchorY_ = undefined;\n\n  /**\n   * @type {Array.<number>}\n   * @private\n   */\n  this.groupIndices_ = [];\n\n  /**\n   * @type {Array.<number>}\n   * @private\n   */\n  this.hitDetectionGroupIndices_ = [];\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.height_ = undefined;\n\n  /**\n   * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>}\n   * @private\n   */\n  this.images_ = [];\n\n  /**\n   * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>}\n   * @private\n   */\n  this.hitDetectionImages_ = [];\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.imageHeight_ = undefined;\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.imageWidth_ = undefined;\n\n  /**\n   * @private\n   * @type {ol.render.webgl.imagereplay.defaultshader.Locations}\n   */\n  this.defaultLocations_ = null;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.opacity_ = undefined;\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.originX_ = undefined;\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.originY_ = undefined;\n\n  /**\n   * @private\n   * @type {boolean|undefined}\n   */\n  this.rotateWithView_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.rotation_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.scale_ = undefined;\n\n  /**\n   * @type {Array.<WebGLTexture>}\n   * @private\n   */\n  this.textures_ = [];\n\n  /**\n   * @type {Array.<WebGLTexture>}\n   * @private\n   */\n  this.hitDetectionTextures_ = [];\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.width_ = undefined;\n};\nol.inherits(ol.render.webgl.ImageReplay, ol.render.webgl.Replay);\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.getDeleteResourcesFunction = function(context) {\n  // We only delete our stuff here. The shaders and the program may\n  // be used by other ImageReplay instances (for other layers). And\n  // they will be deleted when disposing of the ol.webgl.Context\n  // object.\n  ol.DEBUG && console.assert(this.verticesBuffer,\n      'verticesBuffer must not be null');\n  ol.DEBUG && console.assert(this.indicesBuffer,\n      'indicesBuffer must not be null');\n  var verticesBuffer = this.verticesBuffer;\n  var indicesBuffer = this.indicesBuffer;\n  var textures = this.textures_;\n  var hitDetectionTextures = this.hitDetectionTextures_;\n  var gl = context.getGL();\n  return function() {\n    if (!gl.isContextLost()) {\n      var i, ii;\n      for (i = 0, ii = textures.length; i < ii; ++i) {\n        gl.deleteTexture(textures[i]);\n      }\n      for (i = 0, ii = hitDetectionTextures.length; i < ii; ++i) {\n        gl.deleteTexture(hitDetectionTextures[i]);\n      }\n    }\n    context.deleteBuffer(verticesBuffer);\n    context.deleteBuffer(indicesBuffer);\n  };\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} My end.\n * @private\n */\nol.render.webgl.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) {\n  ol.DEBUG && console.assert(this.anchorX_ !== undefined, 'anchorX is defined');\n  ol.DEBUG && console.assert(this.anchorY_ !== undefined, 'anchorY is defined');\n  ol.DEBUG && console.assert(this.height_ !== undefined, 'height is defined');\n  ol.DEBUG && console.assert(this.imageHeight_ !== undefined,\n      'imageHeight is defined');\n  ol.DEBUG && console.assert(this.imageWidth_ !== undefined, 'imageWidth is defined');\n  ol.DEBUG && console.assert(this.opacity_ !== undefined, 'opacity is defined');\n  ol.DEBUG && console.assert(this.originX_ !== undefined, 'originX is defined');\n  ol.DEBUG && console.assert(this.originY_ !== undefined, 'originY is defined');\n  ol.DEBUG && console.assert(this.rotateWithView_ !== undefined,\n      'rotateWithView is defined');\n  ol.DEBUG && console.assert(this.rotation_ !== undefined, 'rotation is defined');\n  ol.DEBUG && console.assert(this.scale_ !== undefined, 'scale is defined');\n  ol.DEBUG && console.assert(this.width_ !== undefined, 'width is defined');\n  var anchorX = /** @type {number} */ (this.anchorX_);\n  var anchorY = /** @type {number} */ (this.anchorY_);\n  var height = /** @type {number} */ (this.height_);\n  var imageHeight = /** @type {number} */ (this.imageHeight_);\n  var imageWidth = /** @type {number} */ (this.imageWidth_);\n  var opacity = /** @type {number} */ (this.opacity_);\n  var originX = /** @type {number} */ (this.originX_);\n  var originY = /** @type {number} */ (this.originY_);\n  var rotateWithView = this.rotateWithView_ ? 1.0 : 0.0;\n  // this.rotation_ is anti-clockwise, but rotation is clockwise\n  var rotation = /** @type {number} */ (-this.rotation_);\n  var scale = /** @type {number} */ (this.scale_);\n  var width = /** @type {number} */ (this.width_);\n  var cos = Math.cos(rotation);\n  var sin = Math.sin(rotation);\n  var numIndices = this.indices.length;\n  var numVertices = this.vertices.length;\n  var i, n, offsetX, offsetY, x, y;\n  for (i = offset; i < end; i += stride) {\n    x = flatCoordinates[i] - this.origin[0];\n    y = flatCoordinates[i + 1] - this.origin[1];\n\n    // There are 4 vertices per [x, y] point, one for each corner of the\n    // rectangle we're going to draw. We'd use 1 vertex per [x, y] point if\n    // WebGL supported Geometry Shaders (which can emit new vertices), but that\n    // is not currently the case.\n    //\n    // And each vertex includes 8 values: the x and y coordinates, the x and\n    // y offsets used to calculate the position of the corner, the u and\n    // v texture coordinates for the corner, the opacity, and whether the\n    // the image should be rotated with the view (rotateWithView).\n\n    n = numVertices / 8;\n\n    // bottom-left corner\n    offsetX = -scale * anchorX;\n    offsetY = -scale * (height - anchorY);\n    this.vertices[numVertices++] = x;\n    this.vertices[numVertices++] = y;\n    this.vertices[numVertices++] = offsetX * cos - offsetY * sin;\n    this.vertices[numVertices++] = offsetX * sin + offsetY * cos;\n    this.vertices[numVertices++] = originX / imageWidth;\n    this.vertices[numVertices++] = (originY + height) / imageHeight;\n    this.vertices[numVertices++] = opacity;\n    this.vertices[numVertices++] = rotateWithView;\n\n    // bottom-right corner\n    offsetX = scale * (width - anchorX);\n    offsetY = -scale * (height - anchorY);\n    this.vertices[numVertices++] = x;\n    this.vertices[numVertices++] = y;\n    this.vertices[numVertices++] = offsetX * cos - offsetY * sin;\n    this.vertices[numVertices++] = offsetX * sin + offsetY * cos;\n    this.vertices[numVertices++] = (originX + width) / imageWidth;\n    this.vertices[numVertices++] = (originY + height) / imageHeight;\n    this.vertices[numVertices++] = opacity;\n    this.vertices[numVertices++] = rotateWithView;\n\n    // top-right corner\n    offsetX = scale * (width - anchorX);\n    offsetY = scale * anchorY;\n    this.vertices[numVertices++] = x;\n    this.vertices[numVertices++] = y;\n    this.vertices[numVertices++] = offsetX * cos - offsetY * sin;\n    this.vertices[numVertices++] = offsetX * sin + offsetY * cos;\n    this.vertices[numVertices++] = (originX + width) / imageWidth;\n    this.vertices[numVertices++] = originY / imageHeight;\n    this.vertices[numVertices++] = opacity;\n    this.vertices[numVertices++] = rotateWithView;\n\n    // top-left corner\n    offsetX = -scale * anchorX;\n    offsetY = scale * anchorY;\n    this.vertices[numVertices++] = x;\n    this.vertices[numVertices++] = y;\n    this.vertices[numVertices++] = offsetX * cos - offsetY * sin;\n    this.vertices[numVertices++] = offsetX * sin + offsetY * cos;\n    this.vertices[numVertices++] = originX / imageWidth;\n    this.vertices[numVertices++] = originY / imageHeight;\n    this.vertices[numVertices++] = opacity;\n    this.vertices[numVertices++] = rotateWithView;\n\n    this.indices[numIndices++] = n;\n    this.indices[numIndices++] = n + 1;\n    this.indices[numIndices++] = n + 2;\n    this.indices[numIndices++] = n;\n    this.indices[numIndices++] = n + 2;\n    this.indices[numIndices++] = n + 3;\n  }\n\n  return numVertices;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) {\n  this.startIndices.push(this.indices.length);\n  this.startIndicesFeature.push(feature);\n  var flatCoordinates = multiPointGeometry.getFlatCoordinates();\n  var stride = multiPointGeometry.getStride();\n  this.drawCoordinates_(\n      flatCoordinates, 0, flatCoordinates.length, stride);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) {\n  this.startIndices.push(this.indices.length);\n  this.startIndicesFeature.push(feature);\n  var flatCoordinates = pointGeometry.getFlatCoordinates();\n  var stride = pointGeometry.getStride();\n  this.drawCoordinates_(\n      flatCoordinates, 0, flatCoordinates.length, stride);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.finish = function(context) {\n  var gl = context.getGL();\n\n  this.groupIndices_.push(this.indices.length);\n  ol.DEBUG && console.assert(this.images_.length === this.groupIndices_.length,\n      'number of images and groupIndices match');\n  this.hitDetectionGroupIndices_.push(this.indices.length);\n  ol.DEBUG && console.assert(this.hitDetectionImages_.length ===\n      this.hitDetectionGroupIndices_.length,\n      'number of hitDetectionImages and hitDetectionGroupIndices match');\n\n  // create, bind, and populate the vertices buffer\n  this.verticesBuffer = new ol.webgl.Buffer(this.vertices);\n\n  var indices = this.indices;\n  var bits = context.hasOESElementIndexUint ? 32 : 16;\n  ol.DEBUG && console.assert(indices[indices.length - 1] < Math.pow(2, bits),\n      'Too large element index detected [%s] (OES_element_index_uint \"%s\")',\n      indices[indices.length - 1], context.hasOESElementIndexUint);\n\n  // create, bind, and populate the indices buffer\n  this.indicesBuffer = new ol.webgl.Buffer(indices);\n\n  // create textures\n  /** @type {Object.<string, WebGLTexture>} */\n  var texturePerImage = {};\n\n  this.createTextures_(this.textures_, this.images_, texturePerImage, gl);\n  ol.DEBUG && console.assert(this.textures_.length === this.groupIndices_.length,\n      'number of textures and groupIndices match');\n\n  this.createTextures_(this.hitDetectionTextures_, this.hitDetectionImages_,\n      texturePerImage, gl);\n  ol.DEBUG && console.assert(this.hitDetectionTextures_.length ===\n      this.hitDetectionGroupIndices_.length,\n      'number of hitDetectionTextures and hitDetectionGroupIndices match');\n\n  this.anchorX_ = undefined;\n  this.anchorY_ = undefined;\n  this.height_ = undefined;\n  this.images_ = null;\n  this.hitDetectionImages_ = null;\n  this.imageHeight_ = undefined;\n  this.imageWidth_ = undefined;\n  this.indices = null;\n  this.opacity_ = undefined;\n  this.originX_ = undefined;\n  this.originY_ = undefined;\n  this.rotateWithView_ = undefined;\n  this.rotation_ = undefined;\n  this.scale_ = undefined;\n  this.vertices = null;\n  this.width_ = undefined;\n};\n\n\n/**\n * @private\n * @param {Array.<WebGLTexture>} textures Textures.\n * @param {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} images\n *    Images.\n * @param {Object.<string, WebGLTexture>} texturePerImage Texture cache.\n * @param {WebGLRenderingContext} gl Gl.\n */\nol.render.webgl.ImageReplay.prototype.createTextures_ = function(textures, images, texturePerImage, gl) {\n  ol.DEBUG && console.assert(textures.length === 0,\n      'upon creation, textures is empty');\n\n  var texture, image, uid, i;\n  var ii = images.length;\n  for (i = 0; i < ii; ++i) {\n    image = images[i];\n\n    uid = ol.getUid(image).toString();\n    if (uid in texturePerImage) {\n      texture = texturePerImage[uid];\n    } else {\n      texture = ol.webgl.Context.createTexture(\n          gl, image, ol.webgl.CLAMP_TO_EDGE, ol.webgl.CLAMP_TO_EDGE);\n      texturePerImage[uid] = texture;\n    }\n    textures[i] = texture;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {\n  // get the program\n  var fragmentShader = ol.render.webgl.imagereplay.defaultshader.fragment;\n  var vertexShader = ol.render.webgl.imagereplay.defaultshader.vertex;\n  var program = context.getProgram(fragmentShader, vertexShader);\n\n  // get the locations\n  var locations;\n  if (!this.defaultLocations_) {\n    locations =\n        new ol.render.webgl.imagereplay.defaultshader.Locations(gl, program);\n    this.defaultLocations_ = locations;\n  } else {\n    locations = this.defaultLocations_;\n  }\n\n  // use the program (FIXME: use the return value)\n  context.useProgram(program);\n\n  // enable the vertex attrib arrays\n  gl.enableVertexAttribArray(locations.a_position);\n  gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,\n      false, 32, 0);\n\n  gl.enableVertexAttribArray(locations.a_offsets);\n  gl.vertexAttribPointer(locations.a_offsets, 2, ol.webgl.FLOAT,\n      false, 32, 8);\n\n  gl.enableVertexAttribArray(locations.a_texCoord);\n  gl.vertexAttribPointer(locations.a_texCoord, 2, ol.webgl.FLOAT,\n      false, 32, 16);\n\n  gl.enableVertexAttribArray(locations.a_opacity);\n  gl.vertexAttribPointer(locations.a_opacity, 1, ol.webgl.FLOAT,\n      false, 32, 24);\n\n  gl.enableVertexAttribArray(locations.a_rotateWithView);\n  gl.vertexAttribPointer(locations.a_rotateWithView, 1, ol.webgl.FLOAT,\n      false, 32, 28);\n\n  return locations;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.shutDownProgram = function(gl, locations) {\n  gl.disableVertexAttribArray(locations.a_position);\n  gl.disableVertexAttribArray(locations.a_offsets);\n  gl.disableVertexAttribArray(locations.a_texCoord);\n  gl.disableVertexAttribArray(locations.a_opacity);\n  gl.disableVertexAttribArray(locations.a_rotateWithView);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {\n  var textures = hitDetection ? this.hitDetectionTextures_ : this.textures_;\n  var groupIndices = hitDetection ? this.hitDetectionGroupIndices_ : this.groupIndices_;\n  ol.DEBUG && console.assert(textures.length === groupIndices.length,\n      'number of textures and groupIndeces match');\n\n  if (!ol.obj.isEmpty(skippedFeaturesHash)) {\n    this.drawReplaySkipping_(\n        gl, context, skippedFeaturesHash, textures, groupIndices);\n  } else {\n    var i, ii, start;\n    for (i = 0, ii = textures.length, start = 0; i < ii; ++i) {\n      gl.bindTexture(ol.webgl.TEXTURE_2D, textures[i]);\n      var end = groupIndices[i];\n      this.drawElements(gl, context, start, end);\n      start = end;\n    }\n  }\n};\n\n\n/**\n * Draw the replay while paying attention to skipped features.\n *\n * This functions creates groups of features that can be drawn to together,\n * so that the number of `drawElements` calls is minimized.\n *\n * For example given the following texture groups:\n *\n *    Group 1: A B C\n *    Group 2: D [E] F G\n *\n * If feature E should be skipped, the following `drawElements` calls will be\n * made:\n *\n *    drawElements with feature A, B and C\n *    drawElements with feature D\n *    drawElements with feature F and G\n *\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {Array.<WebGLTexture>} textures Textures.\n * @param {Array.<number>} groupIndices Texture group indices.\n */\nol.render.webgl.ImageReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash, textures,\n    groupIndices) {\n  var featureIndex = 0;\n\n  var i, ii;\n  for (i = 0, ii = textures.length; i < ii; ++i) {\n    gl.bindTexture(ol.webgl.TEXTURE_2D, textures[i]);\n    var groupStart = (i > 0) ? groupIndices[i - 1] : 0;\n    var groupEnd = groupIndices[i];\n\n    var start = groupStart;\n    var end = groupStart;\n    while (featureIndex < this.startIndices.length &&\n        this.startIndices[featureIndex] <= groupEnd) {\n      var feature = this.startIndicesFeature[featureIndex];\n\n      var featureUid = ol.getUid(feature).toString();\n      if (skippedFeaturesHash[featureUid] !== undefined) {\n        // feature should be skipped\n        if (start !== end) {\n          // draw the features so far\n          this.drawElements(gl, context, start, end);\n        }\n        // continue with the next feature\n        start = (featureIndex === this.startIndices.length - 1) ?\n            groupEnd : this.startIndices[featureIndex + 1];\n        end = start;\n      } else {\n        // the feature is not skipped, augment the end index\n        end = (featureIndex === this.startIndices.length - 1) ?\n            groupEnd : this.startIndices[featureIndex + 1];\n      }\n      featureIndex++;\n    }\n\n    if (start !== end) {\n      // draw the remaining features (in case there was no skipped feature\n      // in this texture group, all features of a group are drawn together)\n      this.drawElements(gl, context, start, end);\n    }\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,\n    featureCallback, opt_hitExtent) {\n  ol.DEBUG && console.assert(this.hitDetectionTextures_.length ===\n      this.hitDetectionGroupIndices_.length,\n      'number of hitDetectionTextures and hitDetectionGroupIndices match');\n\n  var i, groupStart, start, end, feature, featureUid;\n  var featureIndex = this.startIndices.length - 1;\n  for (i = this.hitDetectionTextures_.length - 1; i >= 0; --i) {\n    gl.bindTexture(ol.webgl.TEXTURE_2D, this.hitDetectionTextures_[i]);\n    groupStart = (i > 0) ? this.hitDetectionGroupIndices_[i - 1] : 0;\n    end = this.hitDetectionGroupIndices_[i];\n\n    // draw all features for this texture group\n    while (featureIndex >= 0 &&\n        this.startIndices[featureIndex] >= groupStart) {\n      start = this.startIndices[featureIndex];\n      feature = this.startIndicesFeature[featureIndex];\n      featureUid = ol.getUid(feature).toString();\n\n      if (skippedFeaturesHash[featureUid] === undefined &&\n          feature.getGeometry() &&\n          (opt_hitExtent === undefined || ol.extent.intersects(\n              /** @type {Array<number>} */ (opt_hitExtent),\n              feature.getGeometry().getExtent()))) {\n        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        this.drawElements(gl, context, start, end);\n\n        var result = featureCallback(feature);\n        if (result) {\n          return result;\n        }\n      }\n\n      end = start;\n      featureIndex--;\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ImageReplay.prototype.setImageStyle = function(imageStyle) {\n  var anchor = imageStyle.getAnchor();\n  var image = imageStyle.getImage(1);\n  var imageSize = imageStyle.getImageSize();\n  var hitDetectionImage = imageStyle.getHitDetectionImage(1);\n  var hitDetectionImageSize = imageStyle.getHitDetectionImageSize();\n  var opacity = imageStyle.getOpacity();\n  var origin = imageStyle.getOrigin();\n  var rotateWithView = imageStyle.getRotateWithView();\n  var rotation = imageStyle.getRotation();\n  var size = imageStyle.getSize();\n  var scale = imageStyle.getScale();\n  ol.DEBUG && console.assert(anchor, 'imageStyle anchor is not null');\n  ol.DEBUG && console.assert(image, 'imageStyle image is not null');\n  ol.DEBUG && console.assert(imageSize,\n      'imageStyle imageSize is not null');\n  ol.DEBUG && console.assert(hitDetectionImage,\n      'imageStyle hitDetectionImage is not null');\n  ol.DEBUG && console.assert(hitDetectionImageSize,\n      'imageStyle hitDetectionImageSize is not null');\n  ol.DEBUG && console.assert(opacity !== undefined, 'imageStyle opacity is defined');\n  ol.DEBUG && console.assert(origin, 'imageStyle origin is not null');\n  ol.DEBUG && console.assert(rotateWithView !== undefined,\n      'imageStyle rotateWithView is defined');\n  ol.DEBUG && console.assert(rotation !== undefined, 'imageStyle rotation is defined');\n  ol.DEBUG && console.assert(size, 'imageStyle size is not null');\n  ol.DEBUG && console.assert(scale !== undefined, 'imageStyle scale is defined');\n\n  var currentImage;\n  if (this.images_.length === 0) {\n    this.images_.push(image);\n  } else {\n    currentImage = this.images_[this.images_.length - 1];\n    if (ol.getUid(currentImage) != ol.getUid(image)) {\n      this.groupIndices_.push(this.indices.length);\n      ol.DEBUG && console.assert(this.groupIndices_.length === this.images_.length,\n          'number of groupIndices and images match');\n      this.images_.push(image);\n    }\n  }\n\n  if (this.hitDetectionImages_.length === 0) {\n    this.hitDetectionImages_.push(hitDetectionImage);\n  } else {\n    currentImage =\n        this.hitDetectionImages_[this.hitDetectionImages_.length - 1];\n    if (ol.getUid(currentImage) != ol.getUid(hitDetectionImage)) {\n      this.hitDetectionGroupIndices_.push(this.indices.length);\n      ol.DEBUG && console.assert(this.hitDetectionGroupIndices_.length ===\n          this.hitDetectionImages_.length,\n          'number of hitDetectionGroupIndices and hitDetectionImages match');\n      this.hitDetectionImages_.push(hitDetectionImage);\n    }\n  }\n\n  this.anchorX_ = anchor[0];\n  this.anchorY_ = anchor[1];\n  this.height_ = size[1];\n  this.imageHeight_ = imageSize[1];\n  this.imageWidth_ = imageSize[0];\n  this.opacity_ = opacity;\n  this.originX_ = origin[0];\n  this.originY_ = origin[1];\n  this.rotation_ = rotation;\n  this.rotateWithView_ = rotateWithView;\n  this.scale_ = scale;\n  this.width_ = size[0];\n};\n\ngoog.provide('ol.geom.flat.topology');\n\ngoog.require('ol.geom.flat.area');\n\n/**\n * Check if the linestring is a boundary.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {boolean} The linestring is a boundary.\n */\nol.geom.flat.topology.lineStringIsClosed = function(flatCoordinates, offset, end, stride) {\n  var lastCoord = end - stride;\n  if (flatCoordinates[offset] === flatCoordinates[lastCoord] &&\n      flatCoordinates[offset + 1] === flatCoordinates[lastCoord + 1] && (end - offset) / stride > 3) {\n    return !!ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride);\n  }\n  return false;\n};\n\n// This file is automatically generated, do not edit\ngoog.provide('ol.render.webgl.linestringreplay.defaultshader');\n\ngoog.require('ol');\ngoog.require('ol.webgl.Fragment');\ngoog.require('ol.webgl.Vertex');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Fragment}\n * @struct\n */\nol.render.webgl.linestringreplay.defaultshader.Fragment = function() {\n  ol.webgl.Fragment.call(this, ol.render.webgl.linestringreplay.defaultshader.Fragment.SOURCE);\n};\nol.inherits(ol.render.webgl.linestringreplay.defaultshader.Fragment, ol.webgl.Fragment);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.linestringreplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\\nvarying float v_round;\\nvarying vec2 v_roundVertex;\\nvarying float v_halfWidth;\\n\\n\\n\\nuniform float u_opacity;\\nuniform vec4 u_color;\\nuniform vec2 u_size;\\nuniform float u_pixelRatio;\\n\\nvoid main(void) {\\n  if (v_round > 0.0) {\\n    vec2 windowCoords = vec2((v_roundVertex.x + 1.0) / 2.0 * u_size.x * u_pixelRatio,\\n        (v_roundVertex.y + 1.0) / 2.0 * u_size.y * u_pixelRatio);\\n    if (length(windowCoords - gl_FragCoord.xy) > v_halfWidth * u_pixelRatio) {\\n      discard;\\n    }\\n  }\\n  gl_FragColor = u_color;\\n  float alpha = u_color.a * u_opacity;\\n  if (alpha == 0.0) {\\n    discard;\\n  }\\n  gl_FragColor.a = alpha;\\n}\\n';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.linestringreplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying float a;varying vec2 b;varying float c;uniform float m;uniform vec4 n;uniform vec2 o;uniform float p;void main(void){if(a>0.0){vec2 windowCoords=vec2((b.x+1.0)/2.0*o.x*p,(b.y+1.0)/2.0*o.y*p);if(length(windowCoords-gl_FragCoord.xy)>c*p){discard;}} gl_FragColor=n;float alpha=n.a*m;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.linestringreplay.defaultshader.Fragment.SOURCE = ol.DEBUG ?\n    ol.render.webgl.linestringreplay.defaultshader.Fragment.DEBUG_SOURCE :\n    ol.render.webgl.linestringreplay.defaultshader.Fragment.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.linestringreplay.defaultshader.fragment = new ol.render.webgl.linestringreplay.defaultshader.Fragment();\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Vertex}\n * @struct\n */\nol.render.webgl.linestringreplay.defaultshader.Vertex = function() {\n  ol.webgl.Vertex.call(this, ol.render.webgl.linestringreplay.defaultshader.Vertex.SOURCE);\n};\nol.inherits(ol.render.webgl.linestringreplay.defaultshader.Vertex, ol.webgl.Vertex);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.linestringreplay.defaultshader.Vertex.DEBUG_SOURCE = 'varying float v_round;\\nvarying vec2 v_roundVertex;\\nvarying float v_halfWidth;\\n\\n\\nattribute vec2 a_lastPos;\\nattribute vec2 a_position;\\nattribute vec2 a_nextPos;\\nattribute float a_direction;\\n\\nuniform mat4 u_projectionMatrix;\\nuniform mat4 u_offsetScaleMatrix;\\nuniform mat4 u_offsetRotateMatrix;\\nuniform float u_lineWidth;\\nuniform float u_miterLimit;\\n\\nbool nearlyEquals(in float value, in float ref) {\\n  float epsilon = 0.000000000001;\\n  return value >= ref - epsilon && value <= ref + epsilon;\\n}\\n\\nvoid alongNormal(out vec2 offset, in vec2 nextP, in float turnDir, in float direction) {\\n  vec2 dirVect = nextP - a_position;\\n  vec2 normal = normalize(vec2(-turnDir * dirVect.y, turnDir * dirVect.x));\\n  offset = u_lineWidth / 2.0 * normal * direction;\\n}\\n\\nvoid miterUp(out vec2 offset, out float round, in bool isRound, in float direction) {\\n  float halfWidth = u_lineWidth / 2.0;\\n  vec2 tangent = normalize(normalize(a_nextPos - a_position) + normalize(a_position - a_lastPos));\\n  vec2 normal = vec2(-tangent.y, tangent.x);\\n  vec2 dirVect = a_nextPos - a_position;\\n  vec2 tmpNormal = normalize(vec2(-dirVect.y, dirVect.x));\\n  float miterLength = abs(halfWidth / dot(normal, tmpNormal));\\n  offset = normal * direction * miterLength;\\n  round = 0.0;\\n  if (isRound) {\\n    round = 1.0;\\n  } else if (miterLength > u_miterLimit + u_lineWidth) {\\n    offset = halfWidth * tmpNormal * direction;\\n  }\\n}\\n\\nbool miterDown(out vec2 offset, in vec4 projPos, in mat4 offsetMatrix, in float direction) {\\n  bool degenerate = false;\\n  vec2 tangent = normalize(normalize(a_nextPos - a_position) + normalize(a_position - a_lastPos));\\n  vec2 normal = vec2(-tangent.y, tangent.x);\\n  vec2 dirVect = a_lastPos - a_position;\\n  vec2 tmpNormal = normalize(vec2(-dirVect.y, dirVect.x));\\n  vec2 longOffset, shortOffset, longVertex;\\n  vec4 shortProjVertex;\\n  float halfWidth = u_lineWidth / 2.0;\\n  if (length(a_nextPos - a_position) > length(a_lastPos - a_position)) {\\n    longOffset = tmpNormal * direction * halfWidth;\\n    shortOffset = normalize(vec2(dirVect.y, -dirVect.x)) * direction * halfWidth;\\n    longVertex = a_nextPos;\\n    shortProjVertex = u_projectionMatrix * vec4(a_lastPos, 0.0, 1.0);\\n  } else {\\n    shortOffset = tmpNormal * direction * halfWidth;\\n    longOffset = normalize(vec2(dirVect.y, -dirVect.x)) * direction * halfWidth;\\n    longVertex = a_lastPos;\\n    shortProjVertex = u_projectionMatrix * vec4(a_nextPos, 0.0, 1.0);\\n  }\\n  //Intersection algorithm based on theory by Paul Bourke (http://paulbourke.net/geometry/pointlineplane/).\\n  vec4 p1 = u_projectionMatrix * vec4(longVertex, 0.0, 1.0) + offsetMatrix * vec4(longOffset, 0.0, 0.0);\\n  vec4 p2 = projPos + offsetMatrix * vec4(longOffset, 0.0, 0.0);\\n  vec4 p3 = shortProjVertex + offsetMatrix * vec4(-shortOffset, 0.0, 0.0);\\n  vec4 p4 = shortProjVertex + offsetMatrix * vec4(shortOffset, 0.0, 0.0);\\n  float denom = (p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y);\\n  float firstU = ((p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x)) / denom;\\n  float secondU = ((p2.x - p1.x) * (p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x)) / denom;\\n  float epsilon = 0.000000000001;\\n  if (firstU > epsilon && firstU < 1.0 - epsilon && secondU > epsilon && secondU < 1.0 - epsilon) {\\n    shortProjVertex.x = p1.x + firstU * (p2.x - p1.x);\\n    shortProjVertex.y = p1.y + firstU * (p2.y - p1.y);\\n    offset = shortProjVertex.xy;\\n    degenerate = true;\\n  } else {\\n    float miterLength = abs(halfWidth / dot(normal, tmpNormal));\\n    offset = normal * direction * miterLength;\\n  }\\n  return degenerate;\\n}\\n\\nvoid squareCap(out vec2 offset, out float round, in bool isRound, in vec2 nextP,\\n    in float turnDir, in float direction) {\\n  round = 0.0;\\n  vec2 dirVect = a_position - nextP;\\n  vec2 firstNormal = normalize(dirVect);\\n  vec2 secondNormal = vec2(turnDir * firstNormal.y * direction, -turnDir * firstNormal.x * direction);\\n  vec2 hypotenuse = normalize(firstNormal - secondNormal);\\n  vec2 normal = vec2(turnDir * hypotenuse.y * direction, -turnDir * hypotenuse.x * direction);\\n  float length = sqrt(v_halfWidth * v_halfWidth * 2.0);\\n  offset = normal * length;\\n  if (isRound) {\\n    round = 1.0;\\n  }\\n}\\n\\nvoid main(void) {\\n  bool degenerate = false;\\n  float direction = float(sign(a_direction));\\n  mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\\n  vec2 offset;\\n  vec4 projPos = u_projectionMatrix * vec4(a_position, 0.0, 1.0);\\n  bool round = nearlyEquals(mod(a_direction, 2.0), 0.0);\\n\\n  v_round = 0.0;\\n  v_halfWidth = u_lineWidth / 2.0;\\n  v_roundVertex = projPos.xy;\\n\\n  if (nearlyEquals(mod(a_direction, 3.0), 0.0) || nearlyEquals(mod(a_direction, 17.0), 0.0)) {\\n    alongNormal(offset, a_nextPos, 1.0, direction);\\n  } else if (nearlyEquals(mod(a_direction, 5.0), 0.0) || nearlyEquals(mod(a_direction, 13.0), 0.0)) {\\n    alongNormal(offset, a_lastPos, -1.0, direction);\\n  } else if (nearlyEquals(mod(a_direction, 23.0), 0.0)) {\\n    miterUp(offset, v_round, round, direction);\\n  } else if (nearlyEquals(mod(a_direction, 19.0), 0.0)) {\\n    degenerate = miterDown(offset, projPos, offsetMatrix, direction);\\n  } else if (nearlyEquals(mod(a_direction, 7.0), 0.0)) {\\n    squareCap(offset, v_round, round, a_nextPos, 1.0, direction);\\n  } else if (nearlyEquals(mod(a_direction, 11.0), 0.0)) {\\n    squareCap(offset, v_round, round, a_lastPos, -1.0, direction);\\n  }\\n  if (!degenerate) {\\n    vec4 offsets = offsetMatrix * vec4(offset, 0.0, 0.0);\\n    gl_Position = projPos + offsets;\\n  } else {\\n    gl_Position = vec4(offset, 0.0, 1.0);\\n  }\\n}\\n\\n\\n';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.linestringreplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying float a;varying vec2 b;varying float c;attribute vec2 d;attribute vec2 e;attribute vec2 f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;bool nearlyEquals(in float value,in float ref){float epsilon=0.000000000001;return value>=ref-epsilon&&value<=ref+epsilon;}void alongNormal(out vec2 offset,in vec2 nextP,in float turnDir,in float direction){vec2 dirVect=nextP-e;vec2 normal=normalize(vec2(-turnDir*dirVect.y,turnDir*dirVect.x));offset=k/2.0*normal*direction;}void miterUp(out vec2 offset,out float round,in bool isRound,in float direction){float halfWidth=k/2.0;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=f-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;round=0.0;if(isRound){round=1.0;}else if(miterLength>l+k){offset=halfWidth*tmpNormal*direction;}} bool miterDown(out vec2 offset,in vec4 projPos,in mat4 offsetMatrix,in float direction){bool degenerate=false;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=d-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));vec2 longOffset,shortOffset,longVertex;vec4 shortProjVertex;float halfWidth=k/2.0;if(length(f-e)>length(d-e)){longOffset=tmpNormal*direction*halfWidth;shortOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=f;shortProjVertex=h*vec4(d,0.0,1.0);}else{shortOffset=tmpNormal*direction*halfWidth;longOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=d;shortProjVertex=h*vec4(f,0.0,1.0);}vec4 p1=h*vec4(longVertex,0.0,1.0)+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p2=projPos+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p3=shortProjVertex+offsetMatrix*vec4(-shortOffset,0.0,0.0);vec4 p4=shortProjVertex+offsetMatrix*vec4(shortOffset,0.0,0.0);float denom=(p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y);float firstU=((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x))/denom;float secondU=((p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x))/denom;float epsilon=0.000000000001;if(firstU>epsilon&&firstU<1.0-epsilon&&secondU>epsilon&&secondU<1.0-epsilon){shortProjVertex.x=p1.x+firstU*(p2.x-p1.x);shortProjVertex.y=p1.y+firstU*(p2.y-p1.y);offset=shortProjVertex.xy;degenerate=true;}else{float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;}return degenerate;}void squareCap(out vec2 offset,out float round,in bool isRound,in vec2 nextP,in float turnDir,in float direction){round=0.0;vec2 dirVect=e-nextP;vec2 firstNormal=normalize(dirVect);vec2 secondNormal=vec2(turnDir*firstNormal.y*direction,-turnDir*firstNormal.x*direction);vec2 hypotenuse=normalize(firstNormal-secondNormal);vec2 normal=vec2(turnDir*hypotenuse.y*direction,-turnDir*hypotenuse.x*direction);float length=sqrt(c*c*2.0);offset=normal*length;if(isRound){round=1.0;}} void main(void){bool degenerate=false;float direction=float(sign(g));mat4 offsetMatrix=i*j;vec2 offset;vec4 projPos=h*vec4(e,0.0,1.0);bool round=nearlyEquals(mod(g,2.0),0.0);a=0.0;c=k/2.0;b=projPos.xy;if(nearlyEquals(mod(g,3.0),0.0)||nearlyEquals(mod(g,17.0),0.0)){alongNormal(offset,f,1.0,direction);}else if(nearlyEquals(mod(g,5.0),0.0)||nearlyEquals(mod(g,13.0),0.0)){alongNormal(offset,d,-1.0,direction);}else if(nearlyEquals(mod(g,23.0),0.0)){miterUp(offset,a,round,direction);}else if(nearlyEquals(mod(g,19.0),0.0)){degenerate=miterDown(offset,projPos,offsetMatrix,direction);}else if(nearlyEquals(mod(g,7.0),0.0)){squareCap(offset,a,round,f,1.0,direction);}else if(nearlyEquals(mod(g,11.0),0.0)){squareCap(offset,a,round,d,-1.0,direction);}if(!degenerate){vec4 offsets=offsetMatrix*vec4(offset,0.0,0.0);gl_Position=projPos+offsets;}else{gl_Position=vec4(offset,0.0,1.0);}}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.linestringreplay.defaultshader.Vertex.SOURCE = ol.DEBUG ?\n    ol.render.webgl.linestringreplay.defaultshader.Vertex.DEBUG_SOURCE :\n    ol.render.webgl.linestringreplay.defaultshader.Vertex.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.linestringreplay.defaultshader.vertex = new ol.render.webgl.linestringreplay.defaultshader.Vertex();\n\n\n/**\n * @constructor\n * @param {WebGLRenderingContext} gl GL.\n * @param {WebGLProgram} program Program.\n * @struct\n */\nol.render.webgl.linestringreplay.defaultshader.Locations = function(gl, program) {\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_color = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_color' : 'n');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_lineWidth = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_lineWidth' : 'k');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_miterLimit = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_miterLimit' : 'l');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetRotateMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetRotateMatrix' : 'j');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetScaleMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetScaleMatrix' : 'i');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_opacity = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_opacity' : 'm');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_pixelRatio = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_pixelRatio' : 'p');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_projectionMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_projectionMatrix' : 'h');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_size = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_size' : 'o');\n\n  /**\n   * @type {number}\n   */\n  this.a_direction = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_direction' : 'g');\n\n  /**\n   * @type {number}\n   */\n  this.a_lastPos = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_lastPos' : 'd');\n\n  /**\n   * @type {number}\n   */\n  this.a_nextPos = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_nextPos' : 'f');\n\n  /**\n   * @type {number}\n   */\n  this.a_position = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_position' : 'e');\n};\n\ngoog.provide('ol.render.webgl.LineStringReplay');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.color');\ngoog.require('ol.extent');\ngoog.require('ol.geom.flat.orient');\ngoog.require('ol.geom.flat.transform');\ngoog.require('ol.geom.flat.topology');\ngoog.require('ol.obj');\ngoog.require('ol.render.webgl');\ngoog.require('ol.render.webgl.Replay');\ngoog.require('ol.render.webgl.linestringreplay.defaultshader');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Buffer');\n\n\n/**\n * @constructor\n * @extends {ol.render.webgl.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @struct\n */\nol.render.webgl.LineStringReplay = function(tolerance, maxExtent) {\n  ol.render.webgl.Replay.call(this, tolerance, maxExtent);\n\n  /**\n   * @private\n   * @type {ol.render.webgl.linestringreplay.defaultshader.Locations}\n   */\n  this.defaultLocations_ = null;\n\n  /**\n   * @private\n   * @type {Array.<Array.<?>>}\n   */\n  this.styles_ = [];\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.styleIndices_ = [];\n\n  /**\n   * @private\n   * @type {{strokeColor: (Array.<number>|null),\n   *         lineCap: (string|undefined),\n   *         lineDash: Array.<number>,\n   *         lineJoin: (string|undefined),\n   *         lineWidth: (number|undefined),\n   *         miterLimit: (number|undefined),\n   *         changed: boolean}|null}\n   */\n  this.state_ = {\n    strokeColor: null,\n    lineCap: undefined,\n    lineDash: null,\n    lineJoin: undefined,\n    lineWidth: undefined,\n    miterLimit: undefined,\n    changed: false\n  };\n\n};\nol.inherits(ol.render.webgl.LineStringReplay, ol.render.webgl.Replay);\n\n\n/**\n * Draw one segment.\n * @private\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n */\nol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) {\n\n  var i, ii;\n  var numVertices = this.vertices.length;\n  var numIndices = this.indices.length;\n  //To save a vertex, the direction of a point is a product of the sign (1 or -1), a prime from\n  //ol.render.webgl.lineStringInstruction, and a rounding factor (1 or 2). If the product is even,\n  //we round it. If it is odd, we don't.\n  var lineJoin = this.state_.lineJoin === 'bevel' ? 0 :\n      this.state_.lineJoin === 'miter' ? 1 : 2;\n  var lineCap = this.state_.lineCap === 'butt' ? 0 :\n      this.state_.lineCap === 'square' ? 1 : 2;\n  var closed = ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, offset, end, stride);\n  var startCoords, sign, n;\n  var lastIndex = numIndices;\n  var lastSign = 1;\n  //We need the adjacent vertices to define normals in joins. p0 = last, p1 = current, p2 = next.\n  var p0, p1, p2;\n\n  for (i = offset, ii = end; i < ii; i += stride) {\n\n    n = numVertices / 7;\n\n    p0 = p1;\n    p1 = p2 || [flatCoordinates[i], flatCoordinates[i + 1]];\n    //First vertex.\n    if (i === offset) {\n      p2 = [flatCoordinates[i + stride], flatCoordinates[i + stride + 1]];\n      if (end - offset === stride * 2 && ol.array.equals(p1, p2)) {\n        break;\n      }\n      if (closed) {\n        //A closed line! Complete the circle.\n        p0 = [flatCoordinates[end - stride * 2],\n          flatCoordinates[end - stride * 2 + 1]];\n\n        startCoords = p2;\n      } else {\n        //Add the first two/four vertices.\n\n        if (lineCap) {\n          numVertices = this.addVertices_([0, 0], p1, p2,\n              lastSign * ol.render.webgl.lineStringInstruction.BEGIN_LINE_CAP * lineCap, numVertices);\n\n          numVertices = this.addVertices_([0, 0], p1, p2,\n              -lastSign * ol.render.webgl.lineStringInstruction.BEGIN_LINE_CAP * lineCap, numVertices);\n\n          this.indices[numIndices++] = n + 2;\n          this.indices[numIndices++] = n;\n          this.indices[numIndices++] = n + 1;\n\n          this.indices[numIndices++] = n + 1;\n          this.indices[numIndices++] = n + 3;\n          this.indices[numIndices++] = n + 2;\n\n        }\n\n        numVertices = this.addVertices_([0, 0], p1, p2,\n            lastSign * ol.render.webgl.lineStringInstruction.BEGIN_LINE * (lineCap || 1), numVertices);\n\n        numVertices = this.addVertices_([0, 0], p1, p2,\n            -lastSign * ol.render.webgl.lineStringInstruction.BEGIN_LINE * (lineCap || 1), numVertices);\n\n        lastIndex = numVertices / 7 - 1;\n\n        continue;\n      }\n    } else if (i === end - stride) {\n      //Last vertex.\n      if (closed) {\n        //Same as the first vertex.\n        p2 = startCoords;\n        break;\n      } else {\n        //For the compiler not to complain. This will never be [0, 0].\n        ol.DEBUG && console.assert(p0, 'p0 should be defined');\n        p0 = p0 || [0, 0];\n\n        numVertices = this.addVertices_(p0, p1, [0, 0],\n            lastSign * ol.render.webgl.lineStringInstruction.END_LINE * (lineCap || 1), numVertices);\n\n        numVertices = this.addVertices_(p0, p1, [0, 0],\n            -lastSign * ol.render.webgl.lineStringInstruction.END_LINE * (lineCap || 1), numVertices);\n\n        this.indices[numIndices++] = n;\n        this.indices[numIndices++] = lastIndex - 1;\n        this.indices[numIndices++] = lastIndex;\n\n        this.indices[numIndices++] = lastIndex;\n        this.indices[numIndices++] = n + 1;\n        this.indices[numIndices++] = n;\n\n        if (lineCap) {\n          numVertices = this.addVertices_(p0, p1, [0, 0],\n              lastSign * ol.render.webgl.lineStringInstruction.END_LINE_CAP * lineCap, numVertices);\n\n          numVertices = this.addVertices_(p0, p1, [0, 0],\n              -lastSign * ol.render.webgl.lineStringInstruction.END_LINE_CAP * lineCap, numVertices);\n\n          this.indices[numIndices++] = n + 2;\n          this.indices[numIndices++] = n;\n          this.indices[numIndices++] = n + 1;\n\n          this.indices[numIndices++] = n + 1;\n          this.indices[numIndices++] = n + 3;\n          this.indices[numIndices++] = n + 2;\n\n        }\n\n        break;\n      }\n    } else {\n      p2 = [flatCoordinates[i + stride], flatCoordinates[i + stride + 1]];\n    }\n\n    // We group CW and straight lines, thus the not so inituitive CCW checking function.\n    sign = ol.render.webgl.triangleIsCounterClockwise(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1])\n        ? -1 : 1;\n\n    numVertices = this.addVertices_(p0, p1, p2,\n        sign * ol.render.webgl.lineStringInstruction.BEVEL_FIRST * (lineJoin || 1), numVertices);\n\n    numVertices = this.addVertices_(p0, p1, p2,\n        sign * ol.render.webgl.lineStringInstruction.BEVEL_SECOND * (lineJoin || 1), numVertices);\n\n    numVertices = this.addVertices_(p0, p1, p2,\n        -sign * ol.render.webgl.lineStringInstruction.MITER_BOTTOM * (lineJoin || 1), numVertices);\n\n    if (i > offset) {\n      this.indices[numIndices++] = n;\n      this.indices[numIndices++] = lastIndex - 1;\n      this.indices[numIndices++] = lastIndex;\n\n      this.indices[numIndices++] = n + 2;\n      this.indices[numIndices++] = n;\n      this.indices[numIndices++] = lastSign * sign > 0 ? lastIndex : lastIndex - 1;\n    }\n\n    this.indices[numIndices++] = n;\n    this.indices[numIndices++] = n + 2;\n    this.indices[numIndices++] = n + 1;\n\n    lastIndex = n + 2;\n    lastSign = sign;\n\n    //Add miter\n    if (lineJoin) {\n      numVertices = this.addVertices_(p0, p1, p2,\n          sign * ol.render.webgl.lineStringInstruction.MITER_TOP * lineJoin, numVertices);\n\n      this.indices[numIndices++] = n + 1;\n      this.indices[numIndices++] = n + 3;\n      this.indices[numIndices++] = n;\n    }\n  }\n\n  if (closed) {\n    //Link the last triangle/rhombus to the first one.\n    //n will never be numVertices / 7 here. However, the compiler complains otherwise.\n    ol.DEBUG && console.assert(n, 'n should be defined');\n    n = n || numVertices / 7;\n    sign = ol.geom.flat.orient.linearRingIsClockwise([p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]], 0, 6, 2)\n        ? 1 : -1;\n\n    numVertices = this.addVertices_(p0, p1, p2,\n        sign * ol.render.webgl.lineStringInstruction.BEVEL_FIRST * (lineJoin || 1), numVertices);\n\n    numVertices = this.addVertices_(p0, p1, p2,\n        -sign * ol.render.webgl.lineStringInstruction.MITER_BOTTOM * (lineJoin || 1), numVertices);\n\n    this.indices[numIndices++] = n;\n    this.indices[numIndices++] = lastIndex - 1;\n    this.indices[numIndices++] = lastIndex;\n\n    this.indices[numIndices++] = n + 1;\n    this.indices[numIndices++] = n;\n    this.indices[numIndices++] = lastSign * sign > 0 ? lastIndex : lastIndex - 1;\n  }\n};\n\n/**\n * @param {Array.<number>} p0 Last coordinates.\n * @param {Array.<number>} p1 Current coordinates.\n * @param {Array.<number>} p2 Next coordinates.\n * @param {number} product Sign, instruction, and rounding product.\n * @param {number} numVertices Vertex counter.\n * @return {number} Vertex counter.\n * @private\n */\nol.render.webgl.LineStringReplay.prototype.addVertices_ = function(p0, p1, p2, product, numVertices) {\n  this.vertices[numVertices++] = p0[0];\n  this.vertices[numVertices++] = p0[1];\n  this.vertices[numVertices++] = p1[0];\n  this.vertices[numVertices++] = p1[1];\n  this.vertices[numVertices++] = p2[0];\n  this.vertices[numVertices++] = p2[1];\n  this.vertices[numVertices++] = product;\n\n  return numVertices;\n};\n\n/**\n * Check if the linestring can be drawn (i. e. valid).\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {boolean} The linestring can be drawn.\n * @private\n */\nol.render.webgl.LineStringReplay.prototype.isValid_ = function(flatCoordinates, offset, end, stride) {\n  var range = end - offset;\n  if (range < stride * 2) {\n    return false;\n  } else if (range === stride * 2) {\n    var firstP = [flatCoordinates[offset], flatCoordinates[offset + 1]];\n    var lastP = [flatCoordinates[offset + stride], flatCoordinates[offset + stride + 1]];\n    return !ol.array.equals(firstP, lastP);\n  }\n\n  return true;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) {\n  var flatCoordinates = lineStringGeometry.getFlatCoordinates();\n  var stride = lineStringGeometry.getStride();\n  if (this.isValid_(flatCoordinates, 0, flatCoordinates.length, stride)) {\n    flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,\n        stride, -this.origin[0], -this.origin[1]);\n    if (this.state_.changed) {\n      this.styleIndices_.push(this.indices.length);\n      this.state_.changed = false;\n    }\n    this.startIndices.push(this.indices.length);\n    this.startIndicesFeature.push(feature);\n    this.drawCoordinates_(\n        flatCoordinates, 0, flatCoordinates.length, stride);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {\n  var indexCount = this.indices.length;\n  var lineStringGeometries = multiLineStringGeometry.getLineStrings();\n  var i, ii;\n  for (i = 0, ii = lineStringGeometries.length; i < ii; ++i) {\n    var flatCoordinates = lineStringGeometries[i].getFlatCoordinates();\n    var stride = lineStringGeometries[i].getStride();\n    if (this.isValid_(flatCoordinates, 0, flatCoordinates.length, stride)) {\n      flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,\n          stride, -this.origin[0], -this.origin[1]);\n      this.drawCoordinates_(\n          flatCoordinates, 0, flatCoordinates.length, stride);\n    }\n  }\n  if (this.indices.length > indexCount) {\n    this.startIndices.push(indexCount);\n    this.startIndicesFeature.push(feature);\n    if (this.state_.changed) {\n      this.styleIndices_.push(indexCount);\n      this.state_.changed = false;\n    }\n  }\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {Array.<Array.<number>>} holeFlatCoordinates Hole flat coordinates.\n * @param {number} stride Stride.\n */\nol.render.webgl.LineStringReplay.prototype.drawPolygonCoordinates = function(\n    flatCoordinates, holeFlatCoordinates, stride) {\n  if (!ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, 0,\n      flatCoordinates.length, stride)) {\n    flatCoordinates.push(flatCoordinates[0]);\n    flatCoordinates.push(flatCoordinates[1]);\n  }\n  this.drawCoordinates_(flatCoordinates, 0, flatCoordinates.length, stride);\n  if (holeFlatCoordinates.length) {\n    var i, ii;\n    for (i = 0, ii = holeFlatCoordinates.length; i < ii; ++i) {\n      if (!ol.geom.flat.topology.lineStringIsClosed(holeFlatCoordinates[i], 0,\n          holeFlatCoordinates[i].length, stride)) {\n        holeFlatCoordinates[i].push(holeFlatCoordinates[i][0]);\n        holeFlatCoordinates[i].push(holeFlatCoordinates[i][1]);\n      }\n      this.drawCoordinates_(holeFlatCoordinates[i], 0,\n          holeFlatCoordinates[i].length, stride);\n    }\n  }\n};\n\n\n/**\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @param {number=} opt_index Index count.\n */\nol.render.webgl.LineStringReplay.prototype.setPolygonStyle = function(feature, opt_index) {\n  var index = opt_index === undefined ? this.indices.length : opt_index;\n  this.startIndices.push(index);\n  this.startIndicesFeature.push(feature);\n  if (this.state_.changed) {\n    this.styleIndices_.push(index);\n    this.state_.changed = false;\n  }\n};\n\n\n/**\n * @return {number} Current index.\n */\nol.render.webgl.LineStringReplay.prototype.getCurrentIndex = function() {\n  return this.indices.length;\n};\n\n\n/**\n * @inheritDoc\n **/\nol.render.webgl.LineStringReplay.prototype.finish = function(context) {\n  // create, bind, and populate the vertices buffer\n  this.verticesBuffer = new ol.webgl.Buffer(this.vertices);\n\n  // create, bind, and populate the indices buffer\n  this.indicesBuffer = new ol.webgl.Buffer(this.indices);\n\n  this.startIndices.push(this.indices.length);\n\n  //Clean up, if there is nothing to draw\n  if (this.styleIndices_.length === 0 && this.styles_.length > 0) {\n    this.styles_ = [];\n  }\n\n  this.vertices = null;\n  this.indices = null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.getDeleteResourcesFunction = function(context) {\n  // We only delete our stuff here. The shaders and the program may\n  // be used by other LineStringReplay instances (for other layers). And\n  // they will be deleted when disposing of the ol.webgl.Context\n  // object.\n  ol.DEBUG && console.assert(this.verticesBuffer, 'verticesBuffer must not be null');\n  var verticesBuffer = this.verticesBuffer;\n  var indicesBuffer = this.indicesBuffer;\n  return function() {\n    context.deleteBuffer(verticesBuffer);\n    context.deleteBuffer(indicesBuffer);\n  };\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {\n  // get the program\n  var fragmentShader, vertexShader;\n  fragmentShader = ol.render.webgl.linestringreplay.defaultshader.fragment;\n  vertexShader = ol.render.webgl.linestringreplay.defaultshader.vertex;\n  var program = context.getProgram(fragmentShader, vertexShader);\n\n  // get the locations\n  var locations;\n  if (!this.defaultLocations_) {\n    locations =\n        new ol.render.webgl.linestringreplay.defaultshader.Locations(gl, program);\n    this.defaultLocations_ = locations;\n  } else {\n    locations = this.defaultLocations_;\n  }\n\n  context.useProgram(program);\n\n  // enable the vertex attrib arrays\n  gl.enableVertexAttribArray(locations.a_lastPos);\n  gl.vertexAttribPointer(locations.a_lastPos, 2, ol.webgl.FLOAT,\n      false, 28, 0);\n\n  gl.enableVertexAttribArray(locations.a_position);\n  gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,\n      false, 28, 8);\n\n  gl.enableVertexAttribArray(locations.a_nextPos);\n  gl.vertexAttribPointer(locations.a_nextPos, 2, ol.webgl.FLOAT,\n      false, 28, 16);\n\n  gl.enableVertexAttribArray(locations.a_direction);\n  gl.vertexAttribPointer(locations.a_direction, 1, ol.webgl.FLOAT,\n      false, 28, 24);\n\n  // Enable renderer specific uniforms.\n  gl.uniform2fv(locations.u_size, size);\n  gl.uniform1f(locations.u_pixelRatio, pixelRatio);\n\n  return locations;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.shutDownProgram = function(gl, locations) {\n  gl.disableVertexAttribArray(locations.a_lastPos);\n  gl.disableVertexAttribArray(locations.a_position);\n  gl.disableVertexAttribArray(locations.a_nextPos);\n  gl.disableVertexAttribArray(locations.a_direction);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {\n  //Save GL parameters.\n  var tmpDepthFunc = /** @type {number} */ (gl.getParameter(gl.DEPTH_FUNC));\n  var tmpDepthMask = /** @type {boolean} */ (gl.getParameter(gl.DEPTH_WRITEMASK));\n\n  if (!hitDetection) {\n    gl.enable(gl.DEPTH_TEST);\n    gl.depthMask(true);\n    gl.depthFunc(gl.NOTEQUAL);\n  }\n\n  if (!ol.obj.isEmpty(skippedFeaturesHash)) {\n    this.drawReplaySkipping_(gl, context, skippedFeaturesHash);\n  } else {\n    ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,\n        'number of styles and styleIndices match');\n\n    //Draw by style groups to minimize drawElements() calls.\n    var i, start, end, nextStyle;\n    end = this.startIndices[this.startIndices.length - 1];\n    for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n      start = this.styleIndices_[i];\n      nextStyle = this.styles_[i];\n      this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]);\n      this.drawElements(gl, context, start, end);\n      gl.clear(gl.DEPTH_BUFFER_BIT);\n      end = start;\n    }\n  }\n  if (!hitDetection) {\n    gl.disable(gl.DEPTH_TEST);\n    gl.clear(gl.DEPTH_BUFFER_BIT);\n    //Restore GL parameters.\n    gl.depthMask(tmpDepthMask);\n    gl.depthFunc(tmpDepthFunc);\n  }\n};\n\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object} skippedFeaturesHash Ids of features to skip.\n */\nol.render.webgl.LineStringReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) {\n  ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,\n      'number of startIndices and startIndicesFeature match');\n\n  var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart;\n  featureIndex = this.startIndices.length - 2;\n  end = start = this.startIndices[featureIndex + 1];\n  for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n    nextStyle = this.styles_[i];\n    this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]);\n    groupStart = this.styleIndices_[i];\n\n    while (featureIndex >= 0 &&\n        this.startIndices[featureIndex] >= groupStart) {\n      featureStart = this.startIndices[featureIndex];\n      feature = this.startIndicesFeature[featureIndex];\n      featureUid = ol.getUid(feature).toString();\n\n      if (skippedFeaturesHash[featureUid]) {\n        if (start !== end) {\n          this.drawElements(gl, context, start, end);\n          gl.clear(gl.DEPTH_BUFFER_BIT);\n        }\n        end = featureStart;\n      }\n      featureIndex--;\n      start = featureStart;\n    }\n    if (start !== end) {\n      this.drawElements(gl, context, start, end);\n      gl.clear(gl.DEPTH_BUFFER_BIT);\n    }\n    start = end = groupStart;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,\n    featureCallback, opt_hitExtent) {\n  ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,\n      'number of styles and styleIndices match');\n  ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,\n      'number of startIndices and startIndicesFeature match');\n\n  var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex;\n  featureIndex = this.startIndices.length - 2;\n  end = this.startIndices[featureIndex + 1];\n  for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n    nextStyle = this.styles_[i];\n    this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]);\n    groupStart = this.styleIndices_[i];\n\n    while (featureIndex >= 0 &&\n        this.startIndices[featureIndex] >= groupStart) {\n      start = this.startIndices[featureIndex];\n      feature = this.startIndicesFeature[featureIndex];\n      featureUid = ol.getUid(feature).toString();\n\n      if (skippedFeaturesHash[featureUid] === undefined &&\n          feature.getGeometry() &&\n          (opt_hitExtent === undefined || ol.extent.intersects(\n              /** @type {Array<number>} */ (opt_hitExtent),\n              feature.getGeometry().getExtent()))) {\n        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        this.drawElements(gl, context, start, end);\n\n        var result = featureCallback(feature);\n\n        if (result) {\n          return result;\n        }\n\n      }\n      featureIndex--;\n      end = start;\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {Array.<number>} color Color.\n * @param {number} lineWidth Line width.\n * @param {number} miterLimit Miter limit.\n */\nol.render.webgl.LineStringReplay.prototype.setStrokeStyle_ = function(gl, color, lineWidth, miterLimit) {\n  gl.uniform4fv(this.defaultLocations_.u_color, color);\n  gl.uniform1f(this.defaultLocations_.u_lineWidth, lineWidth);\n  gl.uniform1f(this.defaultLocations_.u_miterLimit, miterLimit);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {\n  ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');\n  var strokeStyleLineCap = strokeStyle.getLineCap();\n  this.state_.lineCap = strokeStyleLineCap !== undefined ?\n      strokeStyleLineCap : ol.render.webgl.defaultLineCap;\n  var strokeStyleLineDash = strokeStyle.getLineDash();\n  this.state_.lineDash = strokeStyleLineDash ?\n      strokeStyleLineDash : ol.render.webgl.defaultLineDash;\n  var strokeStyleLineJoin = strokeStyle.getLineJoin();\n  this.state_.lineJoin = strokeStyleLineJoin !== undefined ?\n      strokeStyleLineJoin : ol.render.webgl.defaultLineJoin;\n  var strokeStyleColor = strokeStyle.getColor();\n  if (!(strokeStyleColor instanceof CanvasGradient) &&\n      !(strokeStyleColor instanceof CanvasPattern)) {\n    strokeStyleColor = ol.color.asArray(strokeStyleColor).map(function(c, i) {\n      return i != 3 ? c / 255 : c;\n    }) || ol.render.webgl.defaultStrokeStyle;\n  } else {\n    strokeStyleColor = ol.render.webgl.defaultStrokeStyle;\n  }\n  var strokeStyleWidth = strokeStyle.getWidth();\n  strokeStyleWidth = strokeStyleWidth !== undefined ?\n      strokeStyleWidth : ol.render.webgl.defaultLineWidth;\n  var strokeStyleMiterLimit = strokeStyle.getMiterLimit();\n  strokeStyleMiterLimit = strokeStyleMiterLimit !== undefined ?\n      strokeStyleMiterLimit : ol.render.webgl.defaultMiterLimit;\n  if (!this.state_.strokeColor || !ol.array.equals(this.state_.strokeColor, strokeStyleColor) ||\n      this.state_.lineWidth !== strokeStyleWidth || this.state_.miterLimit !== strokeStyleMiterLimit) {\n    this.state_.changed = true;\n    this.state_.strokeColor = strokeStyleColor;\n    this.state_.lineWidth = strokeStyleWidth;\n    this.state_.miterLimit = strokeStyleMiterLimit;\n    this.styles_.push([strokeStyleColor, strokeStyleWidth, strokeStyleMiterLimit]);\n  }\n};\n\n// This file is automatically generated, do not edit\ngoog.provide('ol.render.webgl.polygonreplay.defaultshader');\n\ngoog.require('ol');\ngoog.require('ol.webgl.Fragment');\ngoog.require('ol.webgl.Vertex');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Fragment}\n * @struct\n */\nol.render.webgl.polygonreplay.defaultshader.Fragment = function() {\n  ol.webgl.Fragment.call(this, ol.render.webgl.polygonreplay.defaultshader.Fragment.SOURCE);\n};\nol.inherits(ol.render.webgl.polygonreplay.defaultshader.Fragment, ol.webgl.Fragment);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.polygonreplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\\n\\n\\n\\nuniform vec4 u_color;\\nuniform float u_opacity;\\n\\nvoid main(void) {\\n  gl_FragColor = u_color;\\n  float alpha = u_color.a * u_opacity;\\n  if (alpha == 0.0) {\\n    discard;\\n  }\\n  gl_FragColor.a = alpha;\\n}\\n';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.polygonreplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;uniform vec4 e;uniform float f;void main(void){gl_FragColor=e;float alpha=e.a*f;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.polygonreplay.defaultshader.Fragment.SOURCE = ol.DEBUG ?\n    ol.render.webgl.polygonreplay.defaultshader.Fragment.DEBUG_SOURCE :\n    ol.render.webgl.polygonreplay.defaultshader.Fragment.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.polygonreplay.defaultshader.fragment = new ol.render.webgl.polygonreplay.defaultshader.Fragment();\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Vertex}\n * @struct\n */\nol.render.webgl.polygonreplay.defaultshader.Vertex = function() {\n  ol.webgl.Vertex.call(this, ol.render.webgl.polygonreplay.defaultshader.Vertex.SOURCE);\n};\nol.inherits(ol.render.webgl.polygonreplay.defaultshader.Vertex, ol.webgl.Vertex);\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.polygonreplay.defaultshader.Vertex.DEBUG_SOURCE = '\\n\\nattribute vec2 a_position;\\n\\nuniform mat4 u_projectionMatrix;\\nuniform mat4 u_offsetScaleMatrix;\\nuniform mat4 u_offsetRotateMatrix;\\n\\nvoid main(void) {\\n  gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0);\\n}\\n\\n\\n';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.polygonreplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'attribute vec2 a;uniform mat4 b;uniform mat4 c;uniform mat4 d;void main(void){gl_Position=b*vec4(a,0.0,1.0);}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.render.webgl.polygonreplay.defaultshader.Vertex.SOURCE = ol.DEBUG ?\n    ol.render.webgl.polygonreplay.defaultshader.Vertex.DEBUG_SOURCE :\n    ol.render.webgl.polygonreplay.defaultshader.Vertex.OPTIMIZED_SOURCE;\n\n\nol.render.webgl.polygonreplay.defaultshader.vertex = new ol.render.webgl.polygonreplay.defaultshader.Vertex();\n\n\n/**\n * @constructor\n * @param {WebGLRenderingContext} gl GL.\n * @param {WebGLProgram} program Program.\n * @struct\n */\nol.render.webgl.polygonreplay.defaultshader.Locations = function(gl, program) {\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_color = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_color' : 'e');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetRotateMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetRotateMatrix' : 'd');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_offsetScaleMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_offsetScaleMatrix' : 'c');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_opacity = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_opacity' : 'f');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_projectionMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_projectionMatrix' : 'b');\n\n  /**\n   * @type {number}\n   */\n  this.a_position = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_position' : 'a');\n};\n\ngoog.provide('ol.structs.LinkedList');\n\n/**\n * Creates an empty linked list structure.\n *\n * @constructor\n * @struct\n * @param {boolean=} opt_circular The last item is connected to the first one,\n * and the first item to the last one. Default is true.\n */\nol.structs.LinkedList = function(opt_circular) {\n\n  /**\n   * @private\n   * @type {ol.LinkedListItem|undefined}\n   */\n  this.first_ = undefined;\n\n  /**\n   * @private\n   * @type {ol.LinkedListItem|undefined}\n   */\n  this.last_ = undefined;\n\n  /**\n   * @private\n   * @type {ol.LinkedListItem|undefined}\n   */\n  this.head_ = undefined;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.circular_ = opt_circular === undefined ? true : opt_circular;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.length_ = 0;\n};\n\n/**\n * Inserts an item into the linked list right after the current one.\n *\n * @param {?} data Item data.\n */\nol.structs.LinkedList.prototype.insertItem = function(data) {\n\n  /** @type {ol.LinkedListItem} */\n  var item = {\n    prev: undefined,\n    next: undefined,\n    data: data\n  };\n\n  var head = this.head_;\n\n  //Initialize the list.\n  if (!head) {\n    this.first_ = item;\n    this.last_ = item;\n    if (this.circular_) {\n      item.next = item;\n      item.prev = item;\n    }\n  } else {\n    //Link the new item to the adjacent ones.\n    var next = head.next;\n    item.prev = head;\n    item.next = next;\n    head.next = item;\n    if (next) {\n      next.prev = item;\n    }\n\n    if (head === this.last_) {\n      this.last_ = item;\n    }\n  }\n  this.head_ = item;\n  this.length_++;\n};\n\n/**\n * Removes the current item from the list. Sets the cursor to the next item,\n * if possible.\n */\nol.structs.LinkedList.prototype.removeItem = function() {\n  var head = this.head_;\n  if (head) {\n    var next = head.next;\n    var prev = head.prev;\n    if (next) {\n      next.prev = prev;\n    }\n    if (prev) {\n      prev.next = next;\n    }\n    this.head_ = next || prev;\n\n    if (this.first_ === this.last_) {\n      this.head_ = undefined;\n      this.first_ = undefined;\n      this.last_ = undefined;\n    } else if (this.first_ === head) {\n      this.first_ = this.head_;\n    } else if (this.last_ === head) {\n      this.last_ = prev ? this.head_.prev : this.head_;\n    }\n    this.length_--;\n  }\n};\n\n/**\n * Sets the cursor to the first item, and returns the associated data.\n *\n * @return {?} Item data.\n */\nol.structs.LinkedList.prototype.firstItem = function() {\n  this.head_ = this.first_;\n  if (this.head_) {\n    return this.head_.data;\n  }\n  return undefined;\n};\n\n/**\n* Sets the cursor to the last item, and returns the associated data.\n*\n* @return {?} Item data.\n*/\nol.structs.LinkedList.prototype.lastItem = function() {\n  this.head_ = this.last_;\n  if (this.head_) {\n    return this.head_.data;\n  }\n  return undefined;\n};\n\n/**\n * Sets the cursor to the next item, and returns the associated data.\n *\n * @return {?} Item data.\n */\nol.structs.LinkedList.prototype.nextItem = function() {\n  if (this.head_ && this.head_.next) {\n    this.head_ = this.head_.next;\n    return this.head_.data;\n  }\n  return undefined;\n};\n\n/**\n * Returns the next item's data without moving the cursor.\n *\n * @return {?} Item data.\n */\nol.structs.LinkedList.prototype.getNextItem = function() {\n  if (this.head_ && this.head_.next) {\n    return this.head_.next.data;\n  }\n  return undefined;\n};\n\n/**\n * Sets the cursor to the previous item, and returns the associated data.\n *\n * @return {?} Item data.\n */\nol.structs.LinkedList.prototype.prevItem = function() {\n  if (this.head_ && this.head_.prev) {\n    this.head_ = this.head_.prev;\n    return this.head_.data;\n  }\n  return undefined;\n};\n\n/**\n * Returns the previous item's data without moving the cursor.\n *\n * @return {?} Item data.\n */\nol.structs.LinkedList.prototype.getPrevItem = function() {\n  if (this.head_ && this.head_.prev) {\n    return this.head_.prev.data;\n  }\n  return undefined;\n};\n\n/**\n * Returns the current item's data.\n *\n * @return {?} Item data.\n */\nol.structs.LinkedList.prototype.getCurrItem = function() {\n  if (this.head_) {\n    return this.head_.data;\n  }\n  return undefined;\n};\n\n/**\n * Sets the first item of the list. This only works for circular lists, and sets\n * the last item accordingly.\n */\nol.structs.LinkedList.prototype.setFirstItem = function() {\n  if (this.circular_ && this.head_) {\n    this.first_ = this.head_;\n    this.last_ = this.head_.prev;\n  }\n};\n\n/**\n * Concatenates two lists.\n * @param {ol.structs.LinkedList} list List to merge into the current list.\n */\nol.structs.LinkedList.prototype.concat = function(list) {\n  if (list.head_) {\n    if (this.head_) {\n      var end = this.head_.next;\n      this.head_.next = list.first_;\n      list.first_.prev = this.head_;\n      end.prev = list.last_;\n      list.last_.next = end;\n      this.length_ += list.length_;\n    } else {\n      this.head_ = list.head_;\n      this.first_ = list.first_;\n      this.last_ = list.last_;\n      this.length_ = list.length_;\n    }\n    list.head_ = undefined;\n    list.first_ = undefined;\n    list.last_ = undefined;\n    list.length_ = 0;\n  }\n};\n\n/**\n * Returns the current length of the list.\n *\n * @return {number} Length.\n */\nol.structs.LinkedList.prototype.getLength = function() {\n  return this.length_;\n};\n\ngoog.provide('ol.ext.rbush');\n/** @typedef {function(*)} */\nol.ext.rbush;\n(function() {\nvar exports = {};\nvar module = {exports: exports};\nvar define;\n/**\n * @fileoverview\n * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}\n */\n(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){\n'use strict';\n\nmodule.exports = partialSort;\n\n// Floyd-Rivest selection algorithm:\n// Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];\n// The k-th element will have the (k - left + 1)th smallest value in [left, right]\n\nfunction partialSort(arr, k, left, right, compare) {\n    left = left || 0;\n    right = right || (arr.length - 1);\n    compare = compare || defaultCompare;\n\n    while (right > left) {\n        if (right - left > 600) {\n            var n = right - left + 1;\n            var m = k - left + 1;\n            var z = Math.log(n);\n            var s = 0.5 * Math.exp(2 * z / 3);\n            var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);\n            var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));\n            var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));\n            partialSort(arr, k, newLeft, newRight, compare);\n        }\n\n        var t = arr[k];\n        var i = left;\n        var j = right;\n\n        swap(arr, left, k);\n        if (compare(arr[right], t) > 0) swap(arr, left, right);\n\n        while (i < j) {\n            swap(arr, i, j);\n            i++;\n            j--;\n            while (compare(arr[i], t) < 0) i++;\n            while (compare(arr[j], t) > 0) j--;\n        }\n\n        if (compare(arr[left], t) === 0) swap(arr, left, j);\n        else {\n            j++;\n            swap(arr, j, right);\n        }\n\n        if (j <= k) left = j + 1;\n        if (k <= j) right = j - 1;\n    }\n}\n\nfunction swap(arr, i, j) {\n    var tmp = arr[i];\n    arr[i] = arr[j];\n    arr[j] = tmp;\n}\n\nfunction defaultCompare(a, b) {\n    return a < b ? -1 : a > b ? 1 : 0;\n}\n\n},{}],2:[function(_dereq_,module,exports){\n'use strict';\n\nmodule.exports = rbush;\n\nvar quickselect = _dereq_('quickselect');\n\nfunction rbush(maxEntries, format) {\n    if (!(this instanceof rbush)) return new rbush(maxEntries, format);\n\n    // max entries in a node is 9 by default; min node fill is 40% for best performance\n    this._maxEntries = Math.max(4, maxEntries || 9);\n    this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));\n\n    if (format) {\n        this._initFormat(format);\n    }\n\n    this.clear();\n}\n\nrbush.prototype = {\n\n    all: function () {\n        return this._all(this.data, []);\n    },\n\n    search: function (bbox) {\n\n        var node = this.data,\n            result = [],\n            toBBox = this.toBBox;\n\n        if (!intersects(bbox, node)) return result;\n\n        var nodesToSearch = [],\n            i, len, child, childBBox;\n\n        while (node) {\n            for (i = 0, len = node.children.length; i < len; i++) {\n\n                child = node.children[i];\n                childBBox = node.leaf ? toBBox(child) : child;\n\n                if (intersects(bbox, childBBox)) {\n                    if (node.leaf) result.push(child);\n                    else if (contains(bbox, childBBox)) this._all(child, result);\n                    else nodesToSearch.push(child);\n                }\n            }\n            node = nodesToSearch.pop();\n        }\n\n        return result;\n    },\n\n    collides: function (bbox) {\n\n        var node = this.data,\n            toBBox = this.toBBox;\n\n        if (!intersects(bbox, node)) return false;\n\n        var nodesToSearch = [],\n            i, len, child, childBBox;\n\n        while (node) {\n            for (i = 0, len = node.children.length; i < len; i++) {\n\n                child = node.children[i];\n                childBBox = node.leaf ? toBBox(child) : child;\n\n                if (intersects(bbox, childBBox)) {\n                    if (node.leaf || contains(bbox, childBBox)) return true;\n                    nodesToSearch.push(child);\n                }\n            }\n            node = nodesToSearch.pop();\n        }\n\n        return false;\n    },\n\n    load: function (data) {\n        if (!(data && data.length)) return this;\n\n        if (data.length < this._minEntries) {\n            for (var i = 0, len = data.length; i < len; i++) {\n                this.insert(data[i]);\n            }\n            return this;\n        }\n\n        // recursively build the tree with the given data from stratch using OMT algorithm\n        var node = this._build(data.slice(), 0, data.length - 1, 0);\n\n        if (!this.data.children.length) {\n            // save as is if tree is empty\n            this.data = node;\n\n        } else if (this.data.height === node.height) {\n            // split root if trees have the same height\n            this._splitRoot(this.data, node);\n\n        } else {\n            if (this.data.height < node.height) {\n                // swap trees if inserted one is bigger\n                var tmpNode = this.data;\n                this.data = node;\n                node = tmpNode;\n            }\n\n            // insert the small tree into the large tree at appropriate level\n            this._insert(node, this.data.height - node.height - 1, true);\n        }\n\n        return this;\n    },\n\n    insert: function (item) {\n        if (item) this._insert(item, this.data.height - 1);\n        return this;\n    },\n\n    clear: function () {\n        this.data = createNode([]);\n        return this;\n    },\n\n    remove: function (item, equalsFn) {\n        if (!item) return this;\n\n        var node = this.data,\n            bbox = this.toBBox(item),\n            path = [],\n            indexes = [],\n            i, parent, index, goingUp;\n\n        // depth-first iterative tree traversal\n        while (node || path.length) {\n\n            if (!node) { // go up\n                node = path.pop();\n                parent = path[path.length - 1];\n                i = indexes.pop();\n                goingUp = true;\n            }\n\n            if (node.leaf) { // check current node\n                index = findItem(item, node.children, equalsFn);\n\n                if (index !== -1) {\n                    // item found, remove the item and condense tree upwards\n                    node.children.splice(index, 1);\n                    path.push(node);\n                    this._condense(path);\n                    return this;\n                }\n            }\n\n            if (!goingUp && !node.leaf && contains(node, bbox)) { // go down\n                path.push(node);\n                indexes.push(i);\n                i = 0;\n                parent = node;\n                node = node.children[0];\n\n            } else if (parent) { // go right\n                i++;\n                node = parent.children[i];\n                goingUp = false;\n\n            } else node = null; // nothing found\n        }\n\n        return this;\n    },\n\n    toBBox: function (item) { return item; },\n\n    compareMinX: compareNodeMinX,\n    compareMinY: compareNodeMinY,\n\n    toJSON: function () { return this.data; },\n\n    fromJSON: function (data) {\n        this.data = data;\n        return this;\n    },\n\n    _all: function (node, result) {\n        var nodesToSearch = [];\n        while (node) {\n            if (node.leaf) result.push.apply(result, node.children);\n            else nodesToSearch.push.apply(nodesToSearch, node.children);\n\n            node = nodesToSearch.pop();\n        }\n        return result;\n    },\n\n    _build: function (items, left, right, height) {\n\n        var N = right - left + 1,\n            M = this._maxEntries,\n            node;\n\n        if (N <= M) {\n            // reached leaf level; return leaf\n            node = createNode(items.slice(left, right + 1));\n            calcBBox(node, this.toBBox);\n            return node;\n        }\n\n        if (!height) {\n            // target height of the bulk-loaded tree\n            height = Math.ceil(Math.log(N) / Math.log(M));\n\n            // target number of root entries to maximize storage utilization\n            M = Math.ceil(N / Math.pow(M, height - 1));\n        }\n\n        node = createNode([]);\n        node.leaf = false;\n        node.height = height;\n\n        // split the items into M mostly square tiles\n\n        var N2 = Math.ceil(N / M),\n            N1 = N2 * Math.ceil(Math.sqrt(M)),\n            i, j, right2, right3;\n\n        multiSelect(items, left, right, N1, this.compareMinX);\n\n        for (i = left; i <= right; i += N1) {\n\n            right2 = Math.min(i + N1 - 1, right);\n\n            multiSelect(items, i, right2, N2, this.compareMinY);\n\n            for (j = i; j <= right2; j += N2) {\n\n                right3 = Math.min(j + N2 - 1, right2);\n\n                // pack each entry recursively\n                node.children.push(this._build(items, j, right3, height - 1));\n            }\n        }\n\n        calcBBox(node, this.toBBox);\n\n        return node;\n    },\n\n    _chooseSubtree: function (bbox, node, level, path) {\n\n        var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;\n\n        while (true) {\n            path.push(node);\n\n            if (node.leaf || path.length - 1 === level) break;\n\n            minArea = minEnlargement = Infinity;\n\n            for (i = 0, len = node.children.length; i < len; i++) {\n                child = node.children[i];\n                area = bboxArea(child);\n                enlargement = enlargedArea(bbox, child) - area;\n\n                // choose entry with the least area enlargement\n                if (enlargement < minEnlargement) {\n                    minEnlargement = enlargement;\n                    minArea = area < minArea ? area : minArea;\n                    targetNode = child;\n\n                } else if (enlargement === minEnlargement) {\n                    // otherwise choose one with the smallest area\n                    if (area < minArea) {\n                        minArea = area;\n                        targetNode = child;\n                    }\n                }\n            }\n\n            node = targetNode || node.children[0];\n        }\n\n        return node;\n    },\n\n    _insert: function (item, level, isNode) {\n\n        var toBBox = this.toBBox,\n            bbox = isNode ? item : toBBox(item),\n            insertPath = [];\n\n        // find the best node for accommodating the item, saving all nodes along the path too\n        var node = this._chooseSubtree(bbox, this.data, level, insertPath);\n\n        // put the item into the node\n        node.children.push(item);\n        extend(node, bbox);\n\n        // split on node overflow; propagate upwards if necessary\n        while (level >= 0) {\n            if (insertPath[level].children.length > this._maxEntries) {\n                this._split(insertPath, level);\n                level--;\n            } else break;\n        }\n\n        // adjust bboxes along the insertion path\n        this._adjustParentBBoxes(bbox, insertPath, level);\n    },\n\n    // split overflowed node into two\n    _split: function (insertPath, level) {\n\n        var node = insertPath[level],\n            M = node.children.length,\n            m = this._minEntries;\n\n        this._chooseSplitAxis(node, m, M);\n\n        var splitIndex = this._chooseSplitIndex(node, m, M);\n\n        var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));\n        newNode.height = node.height;\n        newNode.leaf = node.leaf;\n\n        calcBBox(node, this.toBBox);\n        calcBBox(newNode, this.toBBox);\n\n        if (level) insertPath[level - 1].children.push(newNode);\n        else this._splitRoot(node, newNode);\n    },\n\n    _splitRoot: function (node, newNode) {\n        // split root node\n        this.data = createNode([node, newNode]);\n        this.data.height = node.height + 1;\n        this.data.leaf = false;\n        calcBBox(this.data, this.toBBox);\n    },\n\n    _chooseSplitIndex: function (node, m, M) {\n\n        var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;\n\n        minOverlap = minArea = Infinity;\n\n        for (i = m; i <= M - m; i++) {\n            bbox1 = distBBox(node, 0, i, this.toBBox);\n            bbox2 = distBBox(node, i, M, this.toBBox);\n\n            overlap = intersectionArea(bbox1, bbox2);\n            area = bboxArea(bbox1) + bboxArea(bbox2);\n\n            // choose distribution with minimum overlap\n            if (overlap < minOverlap) {\n                minOverlap = overlap;\n                index = i;\n\n                minArea = area < minArea ? area : minArea;\n\n            } else if (overlap === minOverlap) {\n                // otherwise choose distribution with minimum area\n                if (area < minArea) {\n                    minArea = area;\n                    index = i;\n                }\n            }\n        }\n\n        return index;\n    },\n\n    // sorts node children by the best axis for split\n    _chooseSplitAxis: function (node, m, M) {\n\n        var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,\n            compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,\n            xMargin = this._allDistMargin(node, m, M, compareMinX),\n            yMargin = this._allDistMargin(node, m, M, compareMinY);\n\n        // if total distributions margin value is minimal for x, sort by minX,\n        // otherwise it's already sorted by minY\n        if (xMargin < yMargin) node.children.sort(compareMinX);\n    },\n\n    // total margin of all possible split distributions where each node is at least m full\n    _allDistMargin: function (node, m, M, compare) {\n\n        node.children.sort(compare);\n\n        var toBBox = this.toBBox,\n            leftBBox = distBBox(node, 0, m, toBBox),\n            rightBBox = distBBox(node, M - m, M, toBBox),\n            margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),\n            i, child;\n\n        for (i = m; i < M - m; i++) {\n            child = node.children[i];\n            extend(leftBBox, node.leaf ? toBBox(child) : child);\n            margin += bboxMargin(leftBBox);\n        }\n\n        for (i = M - m - 1; i >= m; i--) {\n            child = node.children[i];\n            extend(rightBBox, node.leaf ? toBBox(child) : child);\n            margin += bboxMargin(rightBBox);\n        }\n\n        return margin;\n    },\n\n    _adjustParentBBoxes: function (bbox, path, level) {\n        // adjust bboxes along the given tree path\n        for (var i = level; i >= 0; i--) {\n            extend(path[i], bbox);\n        }\n    },\n\n    _condense: function (path) {\n        // go through the path, removing empty nodes and updating bboxes\n        for (var i = path.length - 1, siblings; i >= 0; i--) {\n            if (path[i].children.length === 0) {\n                if (i > 0) {\n                    siblings = path[i - 1].children;\n                    siblings.splice(siblings.indexOf(path[i]), 1);\n\n                } else this.clear();\n\n            } else calcBBox(path[i], this.toBBox);\n        }\n    },\n\n    _initFormat: function (format) {\n        // data format (minX, minY, maxX, maxY accessors)\n\n        // uses eval-type function compilation instead of just accepting a toBBox function\n        // because the algorithms are very sensitive to sorting functions performance,\n        // so they should be dead simple and without inner calls\n\n        var compareArr = ['return a', ' - b', ';'];\n\n        this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));\n        this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));\n\n        this.toBBox = new Function('a',\n            'return {minX: a' + format[0] +\n            ', minY: a' + format[1] +\n            ', maxX: a' + format[2] +\n            ', maxY: a' + format[3] + '};');\n    }\n};\n\nfunction findItem(item, items, equalsFn) {\n    if (!equalsFn) return items.indexOf(item);\n\n    for (var i = 0; i < items.length; i++) {\n        if (equalsFn(item, items[i])) return i;\n    }\n    return -1;\n}\n\n// calculate node's bbox from bboxes of its children\nfunction calcBBox(node, toBBox) {\n    distBBox(node, 0, node.children.length, toBBox, node);\n}\n\n// min bounding rectangle of node children from k to p-1\nfunction distBBox(node, k, p, toBBox, destNode) {\n    if (!destNode) destNode = createNode(null);\n    destNode.minX = Infinity;\n    destNode.minY = Infinity;\n    destNode.maxX = -Infinity;\n    destNode.maxY = -Infinity;\n\n    for (var i = k, child; i < p; i++) {\n        child = node.children[i];\n        extend(destNode, node.leaf ? toBBox(child) : child);\n    }\n\n    return destNode;\n}\n\nfunction extend(a, b) {\n    a.minX = Math.min(a.minX, b.minX);\n    a.minY = Math.min(a.minY, b.minY);\n    a.maxX = Math.max(a.maxX, b.maxX);\n    a.maxY = Math.max(a.maxY, b.maxY);\n    return a;\n}\n\nfunction compareNodeMinX(a, b) { return a.minX - b.minX; }\nfunction compareNodeMinY(a, b) { return a.minY - b.minY; }\n\nfunction bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }\nfunction bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }\n\nfunction enlargedArea(a, b) {\n    return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *\n           (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));\n}\n\nfunction intersectionArea(a, b) {\n    var minX = Math.max(a.minX, b.minX),\n        minY = Math.max(a.minY, b.minY),\n        maxX = Math.min(a.maxX, b.maxX),\n        maxY = Math.min(a.maxY, b.maxY);\n\n    return Math.max(0, maxX - minX) *\n           Math.max(0, maxY - minY);\n}\n\nfunction contains(a, b) {\n    return a.minX <= b.minX &&\n           a.minY <= b.minY &&\n           b.maxX <= a.maxX &&\n           b.maxY <= a.maxY;\n}\n\nfunction intersects(a, b) {\n    return b.minX <= a.maxX &&\n           b.minY <= a.maxY &&\n           b.maxX >= a.minX &&\n           b.maxY >= a.minY;\n}\n\nfunction createNode(children) {\n    return {\n        children: children,\n        height: 1,\n        leaf: true,\n        minX: Infinity,\n        minY: Infinity,\n        maxX: -Infinity,\n        maxY: -Infinity\n    };\n}\n\n// sort an array so that items come in groups of n unsorted items, with groups sorted between each other;\n// combines selection algorithm with binary divide & conquer approach\n\nfunction multiSelect(arr, left, right, n, compare) {\n    var stack = [left, right],\n        mid;\n\n    while (stack.length) {\n        right = stack.pop();\n        left = stack.pop();\n\n        if (right - left <= n) continue;\n\n        mid = left + Math.ceil((right - left) / n / 2) * n;\n        quickselect(arr, mid, left, right, compare);\n\n        stack.push(left, mid, mid, right);\n    }\n}\n\n},{\"quickselect\":1}]},{},[2])(2)\n});\nol.ext.rbush = module.exports;\n})();\n\ngoog.provide('ol.structs.RBush');\n\ngoog.require('ol');\ngoog.require('ol.ext.rbush');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\n\n\n/**\n * Wrapper around the RBush by Vladimir Agafonkin.\n *\n * @constructor\n * @param {number=} opt_maxEntries Max entries.\n * @see https://github.com/mourner/rbush\n * @struct\n * @template T\n */\nol.structs.RBush = function(opt_maxEntries) {\n\n  /**\n   * @private\n   */\n  this.rbush_ = ol.ext.rbush(opt_maxEntries);\n\n  /**\n   * A mapping between the objects added to this rbush wrapper\n   * and the objects that are actually added to the internal rbush.\n   * @private\n   * @type {Object.<number, ol.RBushEntry>}\n   */\n  this.items_ = {};\n\n  if (ol.DEBUG) {\n    /**\n     * @private\n     * @type {number}\n     */\n    this.readers_ = 0;\n  }\n};\n\n\n/**\n * Insert a value into the RBush.\n * @param {ol.Extent} extent Extent.\n * @param {T} value Value.\n */\nol.structs.RBush.prototype.insert = function(extent, value) {\n  if (ol.DEBUG && this.readers_) {\n    throw new Error('Can not insert value while reading');\n  }\n  /** @type {ol.RBushEntry} */\n  var item = {\n    minX: extent[0],\n    minY: extent[1],\n    maxX: extent[2],\n    maxY: extent[3],\n    value: value\n  };\n\n  this.rbush_.insert(item);\n  // remember the object that was added to the internal rbush\n  ol.DEBUG && console.assert(!(ol.getUid(value) in this.items_),\n      'uid (%s) of value (%s) already exists', ol.getUid(value), value);\n  this.items_[ol.getUid(value)] = item;\n};\n\n\n/**\n * Bulk-insert values into the RBush.\n * @param {Array.<ol.Extent>} extents Extents.\n * @param {Array.<T>} values Values.\n */\nol.structs.RBush.prototype.load = function(extents, values) {\n  if (ol.DEBUG && this.readers_) {\n    throw new Error('Can not insert values while reading');\n  }\n  ol.DEBUG && console.assert(extents.length === values.length,\n      'extens and values must have same length (%s === %s)',\n      extents.length, values.length);\n\n  var items = new Array(values.length);\n  for (var i = 0, l = values.length; i < l; i++) {\n    var extent = extents[i];\n    var value = values[i];\n\n    /** @type {ol.RBushEntry} */\n    var item = {\n      minX: extent[0],\n      minY: extent[1],\n      maxX: extent[2],\n      maxY: extent[3],\n      value: value\n    };\n    items[i] = item;\n    ol.DEBUG && console.assert(!(ol.getUid(value) in this.items_),\n        'uid (%s) of value (%s) already exists', ol.getUid(value), value);\n    this.items_[ol.getUid(value)] = item;\n  }\n  this.rbush_.load(items);\n};\n\n\n/**\n * Remove a value from the RBush.\n * @param {T} value Value.\n * @return {boolean} Removed.\n */\nol.structs.RBush.prototype.remove = function(value) {\n  if (ol.DEBUG && this.readers_) {\n    throw new Error('Can not remove value while reading');\n  }\n  var uid = ol.getUid(value);\n  ol.DEBUG && console.assert(uid in this.items_,\n      'uid (%s) of value (%s) does not exist', uid, value);\n\n  // get the object in which the value was wrapped when adding to the\n  // internal rbush. then use that object to do the removal.\n  var item = this.items_[uid];\n  delete this.items_[uid];\n  return this.rbush_.remove(item) !== null;\n};\n\n\n/**\n * Update the extent of a value in the RBush.\n * @param {ol.Extent} extent Extent.\n * @param {T} value Value.\n */\nol.structs.RBush.prototype.update = function(extent, value) {\n  ol.DEBUG && console.assert(ol.getUid(value) in this.items_,\n      'uid (%s) of value (%s) does not exist', ol.getUid(value), value);\n\n  var item = this.items_[ol.getUid(value)];\n  var bbox = [item.minX, item.minY, item.maxX, item.maxY];\n  if (!ol.extent.equals(bbox, extent)) {\n    if (ol.DEBUG && this.readers_) {\n      throw new Error('Can not update extent while reading');\n    }\n    this.remove(value);\n    this.insert(extent, value);\n  }\n};\n\n\n/**\n * Return all values in the RBush.\n * @return {Array.<T>} All.\n */\nol.structs.RBush.prototype.getAll = function() {\n  var items = this.rbush_.all();\n  return items.map(function(item) {\n    return item.value;\n  });\n};\n\n\n/**\n * Return all values in the given extent.\n * @param {ol.Extent} extent Extent.\n * @return {Array.<T>} All in extent.\n */\nol.structs.RBush.prototype.getInExtent = function(extent) {\n  /** @type {ol.RBushEntry} */\n  var bbox = {\n    minX: extent[0],\n    minY: extent[1],\n    maxX: extent[2],\n    maxY: extent[3]\n  };\n  var items = this.rbush_.search(bbox);\n  return items.map(function(item) {\n    return item.value;\n  });\n};\n\n\n/**\n * Calls a callback function with each value in the tree.\n * If the callback returns a truthy value, this value is returned without\n * checking the rest of the tree.\n * @param {function(this: S, T): *} callback Callback.\n * @param {S=} opt_this The object to use as `this` in `callback`.\n * @return {*} Callback return value.\n * @template S\n */\nol.structs.RBush.prototype.forEach = function(callback, opt_this) {\n  if (ol.DEBUG) {\n    ++this.readers_;\n    try {\n      return this.forEach_(this.getAll(), callback, opt_this);\n    } finally {\n      --this.readers_;\n    }\n  } else {\n    return this.forEach_(this.getAll(), callback, opt_this);\n  }\n};\n\n\n/**\n * Calls a callback function with each value in the provided extent.\n * @param {ol.Extent} extent Extent.\n * @param {function(this: S, T): *} callback Callback.\n * @param {S=} opt_this The object to use as `this` in `callback`.\n * @return {*} Callback return value.\n * @template S\n */\nol.structs.RBush.prototype.forEachInExtent = function(extent, callback, opt_this) {\n  if (ol.DEBUG) {\n    ++this.readers_;\n    try {\n      return this.forEach_(this.getInExtent(extent), callback, opt_this);\n    } finally {\n      --this.readers_;\n    }\n  } else {\n    return this.forEach_(this.getInExtent(extent), callback, opt_this);\n  }\n};\n\n\n/**\n * @param {Array.<T>} values Values.\n * @param {function(this: S, T): *} callback Callback.\n * @param {S=} opt_this The object to use as `this` in `callback`.\n * @private\n * @return {*} Callback return value.\n * @template S\n */\nol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) {\n  var result;\n  for (var i = 0, l = values.length; i < l; i++) {\n    result = callback.call(opt_this, values[i]);\n    if (result) {\n      return result;\n    }\n  }\n  return result;\n};\n\n\n/**\n * @return {boolean} Is empty.\n */\nol.structs.RBush.prototype.isEmpty = function() {\n  return ol.obj.isEmpty(this.items_);\n};\n\n\n/**\n * Remove all values from the RBush.\n */\nol.structs.RBush.prototype.clear = function() {\n  this.rbush_.clear();\n  this.items_ = {};\n};\n\n\n/**\n * @param {ol.Extent=} opt_extent Extent.\n * @return {!ol.Extent} Extent.\n */\nol.structs.RBush.prototype.getExtent = function(opt_extent) {\n  // FIXME add getExtent() to rbush\n  var data = this.rbush_.data;\n  return [data.minX, data.minY, data.maxX, data.maxY];\n};\n\ngoog.provide('ol.render.webgl.PolygonReplay');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.color');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.geom.flat.contains');\ngoog.require('ol.geom.flat.orient');\ngoog.require('ol.geom.flat.transform');\ngoog.require('ol.render.webgl.polygonreplay.defaultshader');\ngoog.require('ol.render.webgl.LineStringReplay');\ngoog.require('ol.render.webgl.Replay');\ngoog.require('ol.render.webgl');\ngoog.require('ol.style.Stroke');\ngoog.require('ol.structs.LinkedList');\ngoog.require('ol.structs.RBush');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Buffer');\n\n\n/**\n * @constructor\n * @extends {ol.render.webgl.Replay}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @struct\n */\nol.render.webgl.PolygonReplay = function(tolerance, maxExtent) {\n  ol.render.webgl.Replay.call(this, tolerance, maxExtent);\n\n  this.lineStringReplay = new ol.render.webgl.LineStringReplay(\n      tolerance, maxExtent);\n\n  /**\n   * @private\n   * @type {ol.render.webgl.polygonreplay.defaultshader.Locations}\n   */\n  this.defaultLocations_ = null;\n\n  /**\n   * @private\n   * @type {Array.<Array.<number>>}\n   */\n  this.styles_ = [];\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.styleIndices_ = [];\n\n  /**\n   * @private\n   * @type {{fillColor: (Array.<number>|null),\n   *         changed: boolean}|null}\n   */\n  this.state_ = {\n    fillColor: null,\n    changed: false\n  };\n\n};\nol.inherits(ol.render.webgl.PolygonReplay, ol.render.webgl.Replay);\n\n\n/**\n * Draw one polygon.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {Array.<Array.<number>>} holeFlatCoordinates Hole flat coordinates.\n * @param {number} stride Stride.\n * @private\n */\nol.render.webgl.PolygonReplay.prototype.drawCoordinates_ = function(\n    flatCoordinates, holeFlatCoordinates, stride) {\n  // Triangulate the polygon\n  var outerRing = new ol.structs.LinkedList();\n  var rtree = new ol.structs.RBush();\n  // Initialize the outer ring\n  var maxX = this.processFlatCoordinates_(flatCoordinates, stride, outerRing, rtree, true);\n\n  // Eliminate holes, if there are any\n  if (holeFlatCoordinates.length) {\n    var i, ii;\n    var holeLists = [];\n    for (i = 0, ii = holeFlatCoordinates.length; i < ii; ++i) {\n      var holeList = {\n        list: new ol.structs.LinkedList(),\n        maxX: undefined\n      };\n      holeLists.push(holeList);\n      holeList.maxX = this.processFlatCoordinates_(holeFlatCoordinates[i],\n          stride, holeList.list, rtree, false);\n    }\n    holeLists.sort(function(a, b) {\n      return b.maxX - a.maxX;\n    });\n    for (i = 0; i < holeLists.length; ++i) {\n      this.bridgeHole_(holeLists[i].list, holeLists[i].maxX, outerRing, maxX, rtree);\n    }\n  }\n  this.classifyPoints_(outerRing, rtree, false);\n  this.triangulate_(outerRing, rtree);\n};\n\n\n/**\n * Inserts flat coordinates in a linked list and adds them to the vertex buffer.\n * @private\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} stride Stride.\n * @param {ol.structs.LinkedList} list Linked list.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n * @param {boolean} clockwise Coordinate order should be clockwise.\n * @return {number} Maximum X value.\n */\nol.render.webgl.PolygonReplay.prototype.processFlatCoordinates_ = function(\n    flatCoordinates, stride, list, rtree, clockwise) {\n  var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(flatCoordinates,\n      0, flatCoordinates.length, stride);\n  var i, ii, maxX;\n  var n = this.vertices.length / 2;\n  /** @type {ol.WebglPolygonVertex} */\n  var start;\n  /** @type {ol.WebglPolygonVertex} */\n  var p0;\n  /** @type {ol.WebglPolygonVertex} */\n  var p1;\n  var extents = [];\n  var segments = [];\n  if (clockwise === isClockwise) {\n    start = this.createPoint_(flatCoordinates[0], flatCoordinates[1], n++);\n    p0 = start;\n    maxX = flatCoordinates[0];\n    for (i = stride, ii = flatCoordinates.length; i < ii; i += stride) {\n      p1 = this.createPoint_(flatCoordinates[i], flatCoordinates[i + 1], n++);\n      segments.push(this.insertItem_(p0, p1, list));\n      extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),\n        Math.max(p0.y, p1.y)]);\n      maxX = flatCoordinates[i] > maxX ? flatCoordinates[i] : maxX;\n      p0 = p1;\n    }\n    segments.push(this.insertItem_(p1, start, list));\n    extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),\n      Math.max(p0.y, p1.y)]);\n  } else {\n    var end = flatCoordinates.length - stride;\n    start = this.createPoint_(flatCoordinates[end], flatCoordinates[end + 1], n++);\n    p0 = start;\n    maxX = flatCoordinates[end];\n    for (i = end - stride, ii = 0; i >= ii; i -= stride) {\n      p1 = this.createPoint_(flatCoordinates[i], flatCoordinates[i + 1], n++);\n      segments.push(this.insertItem_(p0, p1, list));\n      extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),\n        Math.max(p0.y, p1.y)]);\n      maxX = flatCoordinates[i] > maxX ? flatCoordinates[i] : maxX;\n      p0 = p1;\n    }\n    segments.push(this.insertItem_(p1, start, list));\n    extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),\n      Math.max(p0.y, p1.y)]);\n  }\n  rtree.load(extents, segments);\n\n  return maxX;\n};\n\n\n/**\n * Classifies the points of a polygon list as convex, reflex. Removes collinear vertices.\n * @private\n * @param {ol.structs.LinkedList} list Polygon ring.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n * @param {boolean} ccw The orientation of the polygon is counter-clockwise.\n * @return {boolean} There were reclassified points.\n */\nol.render.webgl.PolygonReplay.prototype.classifyPoints_ = function(list, rtree, ccw) {\n  var start = list.firstItem();\n  var s0 = start;\n  var s1 = list.nextItem();\n  var pointsReclassified = false;\n  do {\n    var reflex = ccw ? ol.render.webgl.triangleIsCounterClockwise(s1.p1.x,\n        s1.p1.y, s0.p1.x, s0.p1.y, s0.p0.x, s0.p0.y) :\n        ol.render.webgl.triangleIsCounterClockwise(s0.p0.x, s0.p0.y, s0.p1.x,\n        s0.p1.y, s1.p1.x, s1.p1.y);\n    if (reflex === undefined) {\n      this.removeItem_(s0, s1, list, rtree);\n      pointsReclassified = true;\n      if (s1 === start) {\n        start = list.getNextItem();\n      }\n      s1 = s0;\n      list.prevItem();\n    } else if (s0.p1.reflex !== reflex) {\n      s0.p1.reflex = reflex;\n      pointsReclassified = true;\n    }\n    s0 = s1;\n    s1 = list.nextItem();\n  } while (s0 !== start);\n  return pointsReclassified;\n};\n\n\n/**\n * @private\n * @param {ol.structs.LinkedList} hole Linked list of the hole.\n * @param {number} holeMaxX Maximum X value of the hole.\n * @param {ol.structs.LinkedList} list Linked list of the polygon.\n * @param {number} listMaxX Maximum X value of the polygon.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n */\nol.render.webgl.PolygonReplay.prototype.bridgeHole_ = function(hole, holeMaxX,\n    list, listMaxX, rtree) {\n  this.classifyPoints_(hole, rtree, true);\n  var seg = hole.firstItem();\n  while (seg.p1.x !== holeMaxX) {\n    seg = hole.nextItem();\n  }\n\n  var p1 = seg.p1;\n  /** @type {ol.WebglPolygonVertex} */\n  var p2 = {x: listMaxX, y: p1.y, i: -1};\n  var minDist = Infinity;\n  var i, ii, bestPoint;\n  /** @type {ol.WebglPolygonVertex} */\n  var p5;\n\n  var intersectingSegments = this.getIntersections_({p0: p1, p1: p2}, rtree, true);\n  for (i = 0, ii = intersectingSegments.length; i < ii; ++i) {\n    var currSeg = intersectingSegments[i];\n    if (currSeg.p0.reflex === undefined) {\n      var intersection = this.calculateIntersection_(p1, p2, currSeg.p0,\n          currSeg.p1, true);\n      var dist = Math.abs(p1.x - intersection[0]);\n      if (dist < minDist) {\n        minDist = dist;\n        p5 = {x: intersection[0], y: intersection[1], i: -1};\n        seg = currSeg;\n      }\n    }\n  }\n  if (minDist === Infinity) {\n    return;\n  }\n  bestPoint = seg.p1;\n\n  if (minDist > 0) {\n    var pointsInTriangle = this.getPointsInTriangle_(p1, p5, seg.p1, rtree);\n    if (pointsInTriangle.length) {\n      var theta = Infinity;\n      for (i = 0, ii = pointsInTriangle.length; i < ii; ++i) {\n        var currPoint = pointsInTriangle[i];\n        var currTheta = Math.atan2(p1.y - currPoint.y, p2.x - currPoint.x);\n        if (currTheta < theta || (currTheta === theta && currPoint.x < bestPoint.x)) {\n          theta = currTheta;\n          bestPoint = currPoint;\n        }\n      }\n    }\n  }\n\n  seg = list.firstItem();\n  while (seg.p1 !== bestPoint) {\n    seg = list.nextItem();\n  }\n\n  //We clone the bridge points as they can have different convexity.\n  var p0Bridge = {x: p1.x, y: p1.y, i: p1.i, reflex: undefined};\n  var p1Bridge = {x: seg.p1.x, y: seg.p1.y, i: seg.p1.i, reflex: undefined};\n\n  hole.getNextItem().p0 = p0Bridge;\n  this.insertItem_(p1, seg.p1, hole, rtree);\n  this.insertItem_(p1Bridge, p0Bridge, hole, rtree);\n  seg.p1 = p1Bridge;\n  hole.setFirstItem();\n  list.concat(hole);\n};\n\n\n/**\n * @private\n * @param {ol.structs.LinkedList} list Linked list of the polygon.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n */\nol.render.webgl.PolygonReplay.prototype.triangulate_ = function(list, rtree) {\n  var ccw = false;\n  var simple = this.isSimple_(list, rtree);\n\n  // Start clipping ears\n  while (list.getLength() > 3) {\n    if (simple) {\n      if (!this.clipEars_(list, rtree, simple, ccw)) {\n        if (!this.classifyPoints_(list, rtree, ccw)) {\n          // Due to the behavior of OL's PIP algorithm, the ear clipping cannot\n          // introduce touching segments. However, the original data may have some.\n          if (!this.resolveLocalSelfIntersections_(list, rtree, true)) {\n            // Something went wrong.\n            ol.DEBUG && console.assert(false, 'Unexpected simple polygon geometry');\n            break;\n          }\n        }\n      }\n    } else {\n      if (!this.clipEars_(list, rtree, simple, ccw)) {\n        // We ran out of ears, try to reclassify.\n        if (!this.classifyPoints_(list, rtree, ccw)) {\n          // We have a bad polygon, try to resolve local self-intersections.\n          if (!this.resolveLocalSelfIntersections_(list, rtree)) {\n            simple = this.isSimple_(list, rtree);\n            if (!simple) {\n              // We have a really bad polygon, try more time consuming methods.\n              this.splitPolygon_(list, rtree);\n              break;\n            } else {\n              ccw = !this.isClockwise_(list);\n              this.classifyPoints_(list, rtree, ccw);\n            }\n          }\n        }\n      }\n    }\n  }\n  if (list.getLength() === 3) {\n    var numIndices = this.indices.length;\n    this.indices[numIndices++] = list.getPrevItem().p0.i;\n    this.indices[numIndices++] = list.getCurrItem().p0.i;\n    this.indices[numIndices++] = list.getNextItem().p0.i;\n  }\n};\n\n\n/**\n * @private\n * @param {ol.structs.LinkedList} list Linked list of the polygon.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n * @param {boolean} simple The polygon is simple.\n * @param {boolean} ccw Orientation of the polygon is counter-clockwise.\n * @return {boolean} There were processed ears.\n */\nol.render.webgl.PolygonReplay.prototype.clipEars_ = function(list, rtree, simple, ccw) {\n  var numIndices = this.indices.length;\n  var start = list.firstItem();\n  var s0 = list.getPrevItem();\n  var s1 = start;\n  var s2 = list.nextItem();\n  var s3 = list.getNextItem();\n  var p0, p1, p2;\n  var processedEars = false;\n  do {\n    p0 = s1.p0;\n    p1 = s1.p1;\n    p2 = s2.p1;\n    if (p1.reflex === false) {\n      // We might have a valid ear\n      var diagonalIsInside = ccw ? this.diagonalIsInside_(s3.p1, p2, p1, p0,\n          s0.p0) : this.diagonalIsInside_(s0.p0, p0, p1, p2, s3.p1);\n      if ((simple || this.getIntersections_({p0: p0, p1: p2}, rtree).length === 0) &&\n          diagonalIsInside && this.getPointsInTriangle_(p0, p1, p2, rtree, true).length === 0) {\n        //The diagonal is completely inside the polygon\n        if (simple || p0.reflex === false || p2.reflex === false ||\n            ol.geom.flat.orient.linearRingIsClockwise([s0.p0.x, s0.p0.y, p0.x,\n              p0.y, p1.x, p1.y, p2.x, p2.y, s3.p1.x, s3.p1.y], 0, 10, 2) === !ccw) {\n          //The diagonal is persumably valid, we have an ear\n          this.indices[numIndices++] = p0.i;\n          this.indices[numIndices++] = p1.i;\n          this.indices[numIndices++] = p2.i;\n          this.removeItem_(s1, s2, list, rtree);\n          if (s2 === start) {\n            start = s3;\n          }\n          processedEars = true;\n        }\n      }\n    }\n    // Else we have a reflex point.\n    s0 = list.getPrevItem();\n    s1 = list.getCurrItem();\n    s2 = list.nextItem();\n    s3 = list.getNextItem();\n  } while (s1 !== start && list.getLength() > 3);\n\n  return processedEars;\n};\n\n\n/**\n * @private\n * @param {ol.structs.LinkedList} list Linked list of the polygon.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n * @param {boolean=} opt_touch Resolve touching segments.\n * @return {boolean} There were resolved intersections.\n*/\nol.render.webgl.PolygonReplay.prototype.resolveLocalSelfIntersections_ = function(\n    list, rtree, opt_touch) {\n  var start = list.firstItem();\n  list.nextItem();\n  var s0 = start;\n  var s1 = list.nextItem();\n  var resolvedIntersections = false;\n\n  do {\n    var intersection = this.calculateIntersection_(s0.p0, s0.p1, s1.p0, s1.p1,\n        opt_touch);\n    if (intersection) {\n      var breakCond = false;\n      var numVertices = this.vertices.length;\n      var numIndices = this.indices.length;\n      var n = numVertices / 2;\n      var seg = list.prevItem();\n      list.removeItem();\n      rtree.remove(seg);\n      breakCond = (seg === start);\n      var p;\n      if (opt_touch) {\n        if (intersection[0] === s0.p0.x && intersection[1] === s0.p0.y) {\n          list.prevItem();\n          p = s0.p0;\n          s1.p0 = p;\n          rtree.remove(s0);\n          breakCond = breakCond || (s0 === start);\n        } else {\n          p = s1.p1;\n          s0.p1 = p;\n          rtree.remove(s1);\n          breakCond = breakCond || (s1 === start);\n        }\n        list.removeItem();\n      } else {\n        p = this.createPoint_(intersection[0], intersection[1], n);\n        s0.p1 = p;\n        s1.p0 = p;\n        rtree.update([Math.min(s0.p0.x, s0.p1.x), Math.min(s0.p0.y, s0.p1.y),\n          Math.max(s0.p0.x, s0.p1.x), Math.max(s0.p0.y, s0.p1.y)], s0);\n        rtree.update([Math.min(s1.p0.x, s1.p1.x), Math.min(s1.p0.y, s1.p1.y),\n          Math.max(s1.p0.x, s1.p1.x), Math.max(s1.p0.y, s1.p1.y)], s1);\n      }\n\n      this.indices[numIndices++] = seg.p0.i;\n      this.indices[numIndices++] = seg.p1.i;\n      this.indices[numIndices++] = p.i;\n\n      resolvedIntersections = true;\n      if (breakCond) {\n        break;\n      }\n    }\n\n    s0 = list.getPrevItem();\n    s1 = list.nextItem();\n  } while (s0 !== start);\n  return resolvedIntersections;\n};\n\n\n/**\n * @private\n * @param {ol.structs.LinkedList} list Linked list of the polygon.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n * @return {boolean} The polygon is simple.\n */\nol.render.webgl.PolygonReplay.prototype.isSimple_ = function(list, rtree) {\n  var start = list.firstItem();\n  var seg = start;\n  do {\n    if (this.getIntersections_(seg, rtree).length) {\n      return false;\n    }\n    seg = list.nextItem();\n  } while (seg !== start);\n  return true;\n};\n\n\n/**\n * @private\n * @param {ol.structs.LinkedList} list Linked list of the polygon.\n * @return {boolean} Orientation is clockwise.\n */\nol.render.webgl.PolygonReplay.prototype.isClockwise_ = function(list) {\n  var length = list.getLength() * 2;\n  var flatCoordinates = new Array(length);\n  var start = list.firstItem();\n  var seg = start;\n  var i = 0;\n  do {\n    flatCoordinates[i++] = seg.p0.x;\n    flatCoordinates[i++] = seg.p0.y;\n    seg = list.nextItem();\n  } while (seg !== start);\n  return ol.geom.flat.orient.linearRingIsClockwise(flatCoordinates, 0, length, 2);\n};\n\n\n/**\n * @private\n * @param {ol.structs.LinkedList} list Linked list of the polygon.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n */\nol.render.webgl.PolygonReplay.prototype.splitPolygon_ = function(list, rtree) {\n  var start = list.firstItem();\n  var s0 = start;\n  do {\n    var intersections = this.getIntersections_(s0, rtree);\n    if (intersections.length) {\n      var s1 = intersections[0];\n      var n = this.vertices.length / 2;\n      var intersection = this.calculateIntersection_(s0.p0,\n          s0.p1, s1.p0, s1.p1);\n      var p = this.createPoint_(intersection[0], intersection[1], n);\n      var newPolygon = new ol.structs.LinkedList();\n      var newRtree = new ol.structs.RBush();\n      this.insertItem_(p, s0.p1, newPolygon, newRtree);\n      s0.p1 = p;\n      rtree.update([Math.min(s0.p0.x, p.x), Math.min(s0.p0.y, p.y),\n        Math.max(s0.p0.x, p.x), Math.max(s0.p0.y, p.y)], s0);\n      var currItem = list.nextItem();\n      while (currItem !== s1) {\n        this.insertItem_(currItem.p0, currItem.p1, newPolygon, newRtree);\n        rtree.remove(currItem);\n        list.removeItem();\n        currItem = list.getCurrItem();\n      }\n      this.insertItem_(s1.p0, p, newPolygon, newRtree);\n      s1.p0 = p;\n      rtree.update([Math.min(s1.p1.x, p.x), Math.min(s1.p1.y, p.y),\n        Math.max(s1.p1.x, p.x), Math.max(s1.p1.y, p.y)], s1);\n      this.classifyPoints_(list, rtree, false);\n      this.triangulate_(list, rtree);\n      this.classifyPoints_(newPolygon, newRtree, false);\n      this.triangulate_(newPolygon, newRtree);\n      break;\n    }\n    s0 = list.nextItem();\n  } while (s0 !== start);\n};\n\n\n/**\n * @private\n * @param {number} x X coordinate.\n * @param {number} y Y coordinate.\n * @param {number} i Index.\n * @return {ol.WebglPolygonVertex} List item.\n */\nol.render.webgl.PolygonReplay.prototype.createPoint_ = function(x, y, i) {\n  var numVertices = this.vertices.length;\n  this.vertices[numVertices++] = x;\n  this.vertices[numVertices++] = y;\n  /** @type {ol.WebglPolygonVertex} */\n  var p = {\n    x: x,\n    y: y,\n    i: i,\n    reflex: undefined\n  };\n  return p;\n};\n\n\n/**\n * @private\n * @param {ol.WebglPolygonVertex} p0 First point of segment.\n * @param {ol.WebglPolygonVertex} p1 Second point of segment.\n * @param {ol.structs.LinkedList} list Polygon ring.\n * @param {ol.structs.RBush=} opt_rtree Insert the segment into the R-Tree.\n * @return {ol.WebglPolygonSegment} segment.\n */\nol.render.webgl.PolygonReplay.prototype.insertItem_ = function(p0, p1, list, opt_rtree) {\n  var seg = {\n    p0: p0,\n    p1: p1\n  };\n  list.insertItem(seg);\n  if (opt_rtree) {\n    opt_rtree.insert([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y),\n      Math.max(p0.x, p1.x), Math.max(p0.y, p1.y)], seg);\n  }\n  return seg;\n};\n\n\n /**\n  * @private\n  * @param {ol.WebglPolygonSegment} s0 Segment before the remove candidate.\n  * @param {ol.WebglPolygonSegment} s1 Remove candidate segment.\n  * @param {ol.structs.LinkedList} list Polygon ring.\n  * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n  */\nol.render.webgl.PolygonReplay.prototype.removeItem_ = function(s0, s1, list, rtree) {\n  if (list.getCurrItem() === s1) {\n    list.removeItem();\n    s0.p1 = s1.p1;\n    rtree.remove(s1);\n    rtree.update([Math.min(s0.p0.x, s0.p1.x), Math.min(s0.p0.y, s0.p1.y),\n      Math.max(s0.p0.x, s0.p1.x), Math.max(s0.p0.y, s0.p1.y)], s0);\n  }\n};\n\n\n/**\n * @private\n * @param {ol.WebglPolygonVertex} p0 First point.\n * @param {ol.WebglPolygonVertex} p1 Second point.\n * @param {ol.WebglPolygonVertex} p2 Third point.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n * @param {boolean=} opt_reflex Only include reflex points.\n * @return {Array.<ol.WebglPolygonVertex>} Points in the triangle.\n */\nol.render.webgl.PolygonReplay.prototype.getPointsInTriangle_ = function(p0, p1,\n    p2, rtree, opt_reflex) {\n  var i, ii, j, p;\n  var result = [];\n  var segmentsInExtent = rtree.getInExtent([Math.min(p0.x, p1.x, p2.x),\n    Math.min(p0.y, p1.y, p2.y), Math.max(p0.x, p1.x, p2.x), Math.max(p0.y,\n      p1.y, p2.y)]);\n  for (i = 0, ii = segmentsInExtent.length; i < ii; ++i) {\n    for (j in segmentsInExtent[i]) {\n      p = segmentsInExtent[i][j];\n      if (typeof p === 'object' && (!opt_reflex || p.reflex)) {\n        if ((p.x !== p0.x || p.y !== p0.y) && (p.x !== p1.x || p.y !== p1.y) &&\n            (p.x !== p2.x || p.y !== p2.y) && result.indexOf(p) === -1 &&\n            ol.geom.flat.contains.linearRingContainsXY([p0.x, p0.y, p1.x, p1.y,\n              p2.x, p2.y], 0, 6, 2, p.x, p.y)) {\n          result.push(p);\n        }\n      }\n    }\n  }\n  return result;\n};\n\n\n/**\n * @private\n * @param {ol.WebglPolygonSegment} segment Segment.\n * @param {ol.structs.RBush} rtree R-Tree of the polygon.\n * @param {boolean=} opt_touch Touching segments should be considered an intersection.\n * @return {Array.<ol.WebglPolygonSegment>} Intersecting segments.\n */\nol.render.webgl.PolygonReplay.prototype.getIntersections_ = function(segment, rtree, opt_touch) {\n  var p0 = segment.p0;\n  var p1 = segment.p1;\n  var segmentsInExtent = rtree.getInExtent([Math.min(p0.x, p1.x),\n    Math.min(p0.y, p1.y), Math.max(p0.x, p1.x), Math.max(p0.y, p1.y)]);\n  var result = [];\n  var i, ii;\n  for (i = 0, ii = segmentsInExtent.length; i < ii; ++i) {\n    var currSeg = segmentsInExtent[i];\n    if (segment !== currSeg && (opt_touch || currSeg.p0 !== p1 || currSeg.p1 !== p0) &&\n        this.calculateIntersection_(p0, p1, currSeg.p0, currSeg.p1, opt_touch)) {\n      result.push(currSeg);\n    }\n  }\n  return result;\n};\n\n\n/**\n * Line intersection algorithm by Paul Bourke.\n * @see http://paulbourke.net/geometry/pointlineplane/\n *\n * @private\n * @param {ol.WebglPolygonVertex} p0 First point.\n * @param {ol.WebglPolygonVertex} p1 Second point.\n * @param {ol.WebglPolygonVertex} p2 Third point.\n * @param {ol.WebglPolygonVertex} p3 Fourth point.\n * @param {boolean=} opt_touch Touching segments should be considered an intersection.\n * @return {Array.<number>|undefined} Intersection coordinates.\n */\nol.render.webgl.PolygonReplay.prototype.calculateIntersection_ = function(p0,\n    p1, p2, p3, opt_touch) {\n  var denom = (p3.y - p2.y) * (p1.x - p0.x) - (p3.x - p2.x) * (p1.y - p0.y);\n  if (denom !== 0) {\n    var ua = ((p3.x - p2.x) * (p0.y - p2.y) - (p3.y - p2.y) * (p0.x - p2.x)) / denom;\n    var ub = ((p1.x - p0.x) * (p0.y - p2.y) - (p1.y - p0.y) * (p0.x - p2.x)) / denom;\n    if ((!opt_touch && ua > ol.render.webgl.EPSILON && ua < 1 - ol.render.webgl.EPSILON &&\n        ub > ol.render.webgl.EPSILON && ub < 1 - ol.render.webgl.EPSILON) || (opt_touch &&\n        ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)) {\n      return [p0.x + ua * (p1.x - p0.x), p0.y + ua * (p1.y - p0.y)];\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @private\n * @param {ol.WebglPolygonVertex} p0 Point before the start of the diagonal.\n * @param {ol.WebglPolygonVertex} p1 Start point of the diagonal.\n * @param {ol.WebglPolygonVertex} p2 Ear candidate.\n * @param {ol.WebglPolygonVertex} p3 End point of the diagonal.\n * @param {ol.WebglPolygonVertex} p4 Point after the end of the diagonal.\n * @return {boolean} Diagonal is inside the polygon.\n */\nol.render.webgl.PolygonReplay.prototype.diagonalIsInside_ = function(p0, p1, p2, p3, p4) {\n  if (p1.reflex === undefined || p3.reflex === undefined) {\n    return false;\n  }\n  var p1IsLeftOf = (p2.x - p3.x) * (p1.y - p3.y) > (p2.y - p3.y) * (p1.x - p3.x);\n  var p1IsRightOf = (p4.x - p3.x) * (p1.y - p3.y) < (p4.y - p3.y) * (p1.x - p3.x);\n  var p3IsLeftOf = (p0.x - p1.x) * (p3.y - p1.y) > (p0.y - p1.y) * (p3.x - p1.x);\n  var p3IsRightOf = (p2.x - p1.x) * (p3.y - p1.y) < (p2.y - p1.y) * (p3.x - p1.x);\n  var p1InCone = p3.reflex ? p1IsRightOf || p1IsLeftOf : p1IsRightOf && p1IsLeftOf;\n  var p3InCone = p1.reflex ? p3IsRightOf || p3IsLeftOf : p3IsRightOf && p3IsLeftOf;\n  return p1InCone && p3InCone;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {\n  var polygons = multiPolygonGeometry.getPolygons();\n  var stride = multiPolygonGeometry.getStride();\n  var currIndex = this.indices.length;\n  var currLineIndex = this.lineStringReplay.getCurrentIndex();\n  var i, ii, j, jj;\n  for (i = 0, ii = polygons.length; i < ii; ++i) {\n    var linearRings = polygons[i].getLinearRings();\n    if (linearRings.length > 0) {\n      var flatCoordinates = linearRings[0].getFlatCoordinates();\n      flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,\n          stride, -this.origin[0], -this.origin[1]);\n      var holes = [];\n      var holeFlatCoords;\n      for (j = 1, jj = linearRings.length; j < jj; ++j) {\n        holeFlatCoords = linearRings[j].getFlatCoordinates();\n        holeFlatCoords = ol.geom.flat.transform.translate(holeFlatCoords, 0, holeFlatCoords.length,\n            stride, -this.origin[0], -this.origin[1]);\n        holes.push(holeFlatCoords);\n      }\n      this.lineStringReplay.drawPolygonCoordinates(flatCoordinates, holes, stride);\n      this.drawCoordinates_(flatCoordinates, holes, stride);\n    }\n  }\n  if (this.indices.length > currIndex) {\n    this.startIndices.push(currIndex);\n    this.startIndicesFeature.push(feature);\n    if (this.state_.changed) {\n      this.styleIndices_.push(currIndex);\n      this.state_.changed = false;\n    }\n  }\n  if (this.lineStringReplay.getCurrentIndex() > currLineIndex) {\n    this.lineStringReplay.setPolygonStyle(feature, currLineIndex);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {\n  var linearRings = polygonGeometry.getLinearRings();\n  var stride = polygonGeometry.getStride();\n  if (linearRings.length > 0) {\n    this.startIndices.push(this.indices.length);\n    this.startIndicesFeature.push(feature);\n    if (this.state_.changed) {\n      this.styleIndices_.push(this.indices.length);\n      this.state_.changed = false;\n    }\n    this.lineStringReplay.setPolygonStyle(feature);\n\n    var flatCoordinates = linearRings[0].getFlatCoordinates();\n    flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,\n        stride, -this.origin[0], -this.origin[1]);\n    var holes = [];\n    var i, ii, holeFlatCoords;\n    for (i = 1, ii = linearRings.length; i < ii; ++i) {\n      holeFlatCoords = linearRings[i].getFlatCoordinates();\n      holeFlatCoords = ol.geom.flat.transform.translate(holeFlatCoords, 0, holeFlatCoords.length,\n          stride, -this.origin[0], -this.origin[1]);\n      holes.push(holeFlatCoords);\n    }\n    this.lineStringReplay.drawPolygonCoordinates(flatCoordinates, holes, stride);\n    this.drawCoordinates_(flatCoordinates, holes, stride);\n  }\n};\n\n\n/**\n * @inheritDoc\n **/\nol.render.webgl.PolygonReplay.prototype.finish = function(context) {\n  // create, bind, and populate the vertices buffer\n  this.verticesBuffer = new ol.webgl.Buffer(this.vertices);\n\n  // create, bind, and populate the indices buffer\n  this.indicesBuffer = new ol.webgl.Buffer(this.indices);\n\n  this.startIndices.push(this.indices.length);\n\n  this.lineStringReplay.finish(context);\n\n  //Clean up, if there is nothing to draw\n  if (this.styleIndices_.length === 0 && this.styles_.length > 0) {\n    this.styles_ = [];\n  }\n\n  this.vertices = null;\n  this.indices = null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.getDeleteResourcesFunction = function(context) {\n  // We only delete our stuff here. The shaders and the program may\n  // be used by other PolygonReplay instances (for other layers). And\n  // they will be deleted when disposing of the ol.webgl.Context\n  // object.\n  ol.DEBUG && console.assert(this.verticesBuffer,\n      'verticesBuffer must not be null');\n  ol.DEBUG && console.assert(this.indicesBuffer,\n      'indicesBuffer must not be null');\n  var verticesBuffer = this.verticesBuffer;\n  var indicesBuffer = this.indicesBuffer;\n  var lineDeleter = this.lineStringReplay.getDeleteResourcesFunction(context);\n  return function() {\n    context.deleteBuffer(verticesBuffer);\n    context.deleteBuffer(indicesBuffer);\n    lineDeleter();\n  };\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {\n  // get the program\n  var fragmentShader, vertexShader;\n  fragmentShader = ol.render.webgl.polygonreplay.defaultshader.fragment;\n  vertexShader = ol.render.webgl.polygonreplay.defaultshader.vertex;\n  var program = context.getProgram(fragmentShader, vertexShader);\n\n  // get the locations\n  var locations;\n  if (!this.defaultLocations_) {\n    locations =\n        new ol.render.webgl.polygonreplay.defaultshader.Locations(gl, program);\n    this.defaultLocations_ = locations;\n  } else {\n    locations = this.defaultLocations_;\n  }\n\n  context.useProgram(program);\n\n  // enable the vertex attrib arrays\n  gl.enableVertexAttribArray(locations.a_position);\n  gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,\n      false, 8, 0);\n\n  return locations;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.shutDownProgram = function(gl, locations) {\n  gl.disableVertexAttribArray(locations.a_position);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {\n  //Save GL parameters.\n  var tmpDepthFunc = /** @type {number} */ (gl.getParameter(gl.DEPTH_FUNC));\n  var tmpDepthMask = /** @type {boolean} */ (gl.getParameter(gl.DEPTH_WRITEMASK));\n\n  if (!hitDetection) {\n    gl.enable(gl.DEPTH_TEST);\n    gl.depthMask(true);\n    gl.depthFunc(gl.NOTEQUAL);\n  }\n\n  if (!ol.obj.isEmpty(skippedFeaturesHash)) {\n    this.drawReplaySkipping_(gl, context, skippedFeaturesHash);\n  } else {\n    ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,\n        'number of styles and styleIndices match');\n\n    //Draw by style groups to minimize drawElements() calls.\n    var i, start, end, nextStyle;\n    end = this.startIndices[this.startIndices.length - 1];\n    for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n      start = this.styleIndices_[i];\n      nextStyle = this.styles_[i];\n      this.setFillStyle_(gl, nextStyle);\n      this.drawElements(gl, context, start, end);\n      end = start;\n    }\n  }\n  if (!hitDetection) {\n    gl.disable(gl.DEPTH_TEST);\n    gl.clear(gl.DEPTH_BUFFER_BIT);\n    //Restore GL parameters.\n    gl.depthMask(tmpDepthMask);\n    gl.depthFunc(tmpDepthFunc);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,\n    featureCallback, opt_hitExtent) {\n  ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,\n      'number of styles and styleIndices match');\n  ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,\n      'number of startIndices and startIndicesFeature match');\n\n  var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex;\n  featureIndex = this.startIndices.length - 2;\n  end = this.startIndices[featureIndex + 1];\n  for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n    nextStyle = this.styles_[i];\n    this.setFillStyle_(gl, nextStyle);\n    groupStart = this.styleIndices_[i];\n\n    while (featureIndex >= 0 &&\n        this.startIndices[featureIndex] >= groupStart) {\n      start = this.startIndices[featureIndex];\n      feature = this.startIndicesFeature[featureIndex];\n      featureUid = ol.getUid(feature).toString();\n\n      if (skippedFeaturesHash[featureUid] === undefined &&\n          feature.getGeometry() &&\n          (opt_hitExtent === undefined || ol.extent.intersects(\n              /** @type {Array<number>} */ (opt_hitExtent),\n              feature.getGeometry().getExtent()))) {\n        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        this.drawElements(gl, context, start, end);\n\n        var result = featureCallback(feature);\n\n        if (result) {\n          return result;\n        }\n\n      }\n      featureIndex--;\n      end = start;\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {ol.webgl.Context} context Context.\n * @param {Object} skippedFeaturesHash Ids of features to skip.\n */\nol.render.webgl.PolygonReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) {\n  ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,\n      'number of startIndices and startIndicesFeature match');\n\n  var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart;\n  featureIndex = this.startIndices.length - 2;\n  end = start = this.startIndices[featureIndex + 1];\n  for (i = this.styleIndices_.length - 1; i >= 0; --i) {\n    nextStyle = this.styles_[i];\n    this.setFillStyle_(gl, nextStyle);\n    groupStart = this.styleIndices_[i];\n\n    while (featureIndex >= 0 &&\n        this.startIndices[featureIndex] >= groupStart) {\n      featureStart = this.startIndices[featureIndex];\n      feature = this.startIndicesFeature[featureIndex];\n      featureUid = ol.getUid(feature).toString();\n\n      if (skippedFeaturesHash[featureUid]) {\n        if (start !== end) {\n          this.drawElements(gl, context, start, end);\n          gl.clear(gl.DEPTH_BUFFER_BIT);\n        }\n        end = featureStart;\n      }\n      featureIndex--;\n      start = featureStart;\n    }\n    if (start !== end) {\n      this.drawElements(gl, context, start, end);\n      gl.clear(gl.DEPTH_BUFFER_BIT);\n    }\n    start = end = groupStart;\n  }\n};\n\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl gl.\n * @param {Array.<number>} color Color.\n */\nol.render.webgl.PolygonReplay.prototype.setFillStyle_ = function(gl, color) {\n  gl.uniform4fv(this.defaultLocations_.u_color, color);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {\n  ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');\n  var fillStyleColor = fillStyle ? fillStyle.getColor() : [0, 0, 0, 0];\n  if (!(fillStyleColor instanceof CanvasGradient) &&\n      !(fillStyleColor instanceof CanvasPattern)) {\n    fillStyleColor = ol.color.asArray(fillStyleColor).map(function(c, i) {\n      return i != 3 ? c / 255 : c;\n    }) || ol.render.webgl.defaultFillStyle;\n  } else {\n    fillStyleColor = ol.render.webgl.defaultFillStyle;\n  }\n  if (!this.state_.fillColor || !ol.array.equals(fillStyleColor, this.state_.fillColor)) {\n    this.state_.fillColor = fillStyleColor;\n    this.state_.changed = true;\n    this.styles_.push(fillStyleColor);\n  }\n  //Provide a null stroke style, if no strokeStyle is provided. Required for the draw interaction to work.\n  if (strokeStyle) {\n    this.lineStringReplay.setFillStrokeStyle(null, strokeStyle);\n  } else {\n    var nullStrokeStyle = new ol.style.Stroke({\n      color: [0, 0, 0, 0],\n      lineWidth: 0\n    });\n    this.lineStringReplay.setFillStrokeStyle(null, nullStrokeStyle);\n  }\n};\n\ngoog.provide('ol.render.webgl.TextReplay');\n\ngoog.require('ol');\n\n/**\n * @constructor\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @struct\n */\nol.render.webgl.TextReplay = function(tolerance, maxExtent) {};\n\n/**\n * @param {ol.style.Text} textStyle Text style.\n */\nol.render.webgl.TextReplay.prototype.setTextStyle = function(textStyle) {};\n\n/**\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} opacity Global opacity.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.\n * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.\n * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting\n *  this extent are checked.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.webgl.TextReplay.prototype.replay = function(context,\n    center, resolution, rotation, size, pixelRatio,\n    opacity, skippedFeaturesHash,\n    featureCallback, oneByOne, opt_hitExtent) {\n  return undefined;\n};\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n */\nol.render.webgl.TextReplay.prototype.drawText = function(flatCoordinates, offset,\n    end, stride, geometry, feature) {};\n\n/**\n * @abstract\n * @param {ol.webgl.Context} context Context.\n */\nol.render.webgl.TextReplay.prototype.finish = function(context) {};\n\n/**\n * @param {ol.webgl.Context} context WebGL context.\n * @return {function()} Delete resources function.\n */\nol.render.webgl.TextReplay.prototype.getDeleteResourcesFunction = function(context) {\n  return ol.nullFunction;\n};\n\ngoog.provide('ol.render.webgl.ReplayGroup');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.render.replay');\ngoog.require('ol.render.ReplayGroup');\ngoog.require('ol.render.webgl');\ngoog.require('ol.render.webgl.CircleReplay');\ngoog.require('ol.render.webgl.ImageReplay');\ngoog.require('ol.render.webgl.LineStringReplay');\ngoog.require('ol.render.webgl.PolygonReplay');\ngoog.require('ol.render.webgl.TextReplay');\n\n/**\n * @constructor\n * @extends {ol.render.ReplayGroup}\n * @param {number} tolerance Tolerance.\n * @param {ol.Extent} maxExtent Max extent.\n * @param {number=} opt_renderBuffer Render buffer.\n * @struct\n */\nol.render.webgl.ReplayGroup = function(tolerance, maxExtent, opt_renderBuffer) {\n  ol.render.ReplayGroup.call(this);\n\n  /**\n   * @type {ol.Extent}\n   * @private\n   */\n  this.maxExtent_ = maxExtent;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.tolerance_ = tolerance;\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.renderBuffer_ = opt_renderBuffer;\n\n  /**\n   * @private\n   * @type {!Object.<string,\n   *        Object.<ol.render.ReplayType, ol.render.webgl.Replay>>}\n   */\n  this.replaysByZIndex_ = {};\n\n};\nol.inherits(ol.render.webgl.ReplayGroup, ol.render.ReplayGroup);\n\n\n/**\n * @param {ol.webgl.Context} context WebGL context.\n * @return {function()} Delete resources function.\n */\nol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = function(context) {\n  var functions = [];\n  var zKey;\n  for (zKey in this.replaysByZIndex_) {\n    var replays = this.replaysByZIndex_[zKey];\n    var replayKey;\n    for (replayKey in replays) {\n      functions.push(\n          replays[replayKey].getDeleteResourcesFunction(context));\n    }\n  }\n  return function() {\n    var length = functions.length;\n    var result;\n    for (var i = 0; i < length; i++) {\n      result = functions[i].apply(this, arguments);\n    }\n    return result;\n  };\n};\n\n\n/**\n * @param {ol.webgl.Context} context Context.\n */\nol.render.webgl.ReplayGroup.prototype.finish = function(context) {\n  var zKey;\n  for (zKey in this.replaysByZIndex_) {\n    var replays = this.replaysByZIndex_[zKey];\n    var replayKey;\n    for (replayKey in replays) {\n      replays[replayKey].finish(context);\n    }\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {\n  var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';\n  var replays = this.replaysByZIndex_[zIndexKey];\n  if (replays === undefined) {\n    replays = {};\n    this.replaysByZIndex_[zIndexKey] = replays;\n  }\n  var replay = replays[replayType];\n  if (replay === undefined) {\n    var Constructor = ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];\n    ol.DEBUG && console.assert(Constructor !== undefined,\n        replayType +\n        ' constructor missing from ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_');\n    replay = new Constructor(this.tolerance_, this.maxExtent_);\n    replays[replayType] = replay;\n  }\n  return replay;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.ReplayGroup.prototype.isEmpty = function() {\n  return ol.obj.isEmpty(this.replaysByZIndex_);\n};\n\n\n/**\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} opacity Global opacity.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n */\nol.render.webgl.ReplayGroup.prototype.replay = function(context,\n    center, resolution, rotation, size, pixelRatio,\n    opacity, skippedFeaturesHash) {\n  /** @type {Array.<number>} */\n  var zs = Object.keys(this.replaysByZIndex_).map(Number);\n  zs.sort(ol.array.numberSafeCompareFunction);\n\n  var i, ii, j, jj, replays, replay;\n  for (i = 0, ii = zs.length; i < ii; ++i) {\n    replays = this.replaysByZIndex_[zs[i].toString()];\n    for (j = 0, jj = ol.render.replay.ORDER.length; j < jj; ++j) {\n      replay = replays[ol.render.replay.ORDER[j]];\n      if (replay !== undefined) {\n        replay.replay(context,\n            center, resolution, rotation, size, pixelRatio,\n            opacity, skippedFeaturesHash,\n            undefined, false);\n      }\n    }\n  }\n};\n\n\n/**\n * @private\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} opacity Global opacity.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.\n * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.\n * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting\n *  this extent are checked.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context,\n    center, resolution, rotation, size, pixelRatio, opacity,\n    skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) {\n  /** @type {Array.<number>} */\n  var zs = Object.keys(this.replaysByZIndex_).map(Number);\n  zs.sort(function(a, b) {\n    return b - a;\n  });\n\n  var i, ii, j, replays, replay, result;\n  for (i = 0, ii = zs.length; i < ii; ++i) {\n    replays = this.replaysByZIndex_[zs[i].toString()];\n    for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {\n      replay = replays[ol.render.replay.ORDER[j]];\n      if (replay !== undefined) {\n        result = replay.replay(context,\n            center, resolution, rotation, size, pixelRatio, opacity,\n            skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent);\n        if (result) {\n          return result;\n        }\n      }\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} opacity Global opacity.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @param {function((ol.Feature|ol.render.Feature)): T|undefined} callback Feature callback.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(\n    coordinate, context, center, resolution, rotation, size, pixelRatio,\n    opacity, skippedFeaturesHash,\n    callback) {\n  var gl = context.getGL();\n  gl.bindFramebuffer(\n      gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());\n\n\n  /**\n   * @type {ol.Extent}\n   */\n  var hitExtent;\n  if (this.renderBuffer_ !== undefined) {\n    // build an extent around the coordinate, so that only features that\n    // intersect this extent are checked\n    hitExtent = ol.extent.buffer(\n        ol.extent.createOrUpdateFromCoordinate(coordinate),\n        resolution * this.renderBuffer_);\n  }\n\n  return this.replayHitDetection_(context,\n      coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_,\n      pixelRatio, opacity, skippedFeaturesHash,\n      /**\n       * @param {ol.Feature|ol.render.Feature} feature Feature.\n       * @return {?} Callback result.\n       */\n      function(feature) {\n        var imageData = new Uint8Array(4);\n        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);\n\n        if (imageData[3] > 0) {\n          var result = callback(feature);\n          if (result) {\n            return result;\n          }\n        }\n      }, true, hitExtent);\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} opacity Global opacity.\n * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features\n *  to skip.\n * @return {boolean} Is there a feature at the given coordinate?\n */\nol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function(\n    coordinate, context, center, resolution, rotation, size, pixelRatio,\n    opacity, skippedFeaturesHash) {\n  var gl = context.getGL();\n  gl.bindFramebuffer(\n      gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());\n\n  var hasFeature = this.replayHitDetection_(context,\n      coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_,\n      pixelRatio, opacity, skippedFeaturesHash,\n      /**\n       * @param {ol.Feature|ol.render.Feature} feature Feature.\n       * @return {boolean} Is there a feature?\n       */\n      function(feature) {\n        var imageData = new Uint8Array(4);\n        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);\n        return imageData[3] > 0;\n      }, false);\n\n  return hasFeature !== undefined;\n};\n\n/**\n * @const\n * @private\n * @type {Array.<number>}\n */\nol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_ = [1, 1];\n\n/**\n * @const\n * @private\n * @type {Object.<ol.render.ReplayType,\n *                function(new: ol.render.webgl.Replay, number,\n *                ol.Extent)>}\n */\nol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_ = {\n  'Circle': ol.render.webgl.CircleReplay,\n  'Image': ol.render.webgl.ImageReplay,\n  'LineString': ol.render.webgl.LineStringReplay,\n  'Polygon': ol.render.webgl.PolygonReplay,\n  'Text': ol.render.webgl.TextReplay\n};\n\ngoog.provide('ol.render.webgl.Immediate');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.render.ReplayType');\ngoog.require('ol.render.VectorContext');\ngoog.require('ol.render.webgl.ReplayGroup');\ngoog.require('ol.render.webgl');\n\n\n/**\n * @constructor\n * @extends {ol.render.VectorContext}\n * @param {ol.webgl.Context} context Context.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {ol.Size} size Size.\n * @param {ol.Extent} extent Extent.\n * @param {number} pixelRatio Pixel ratio.\n * @struct\n */\nol.render.webgl.Immediate = function(context, center, resolution, rotation, size, extent, pixelRatio) {\n  ol.render.VectorContext.call(this);\n\n  /**\n   * @private\n   */\n  this.context_ = context;\n\n  /**\n   * @private\n   */\n  this.center_ = center;\n\n  /**\n   * @private\n   */\n  this.extent_ = extent;\n\n  /**\n   * @private\n   */\n  this.pixelRatio_ = pixelRatio;\n\n  /**\n   * @private\n   */\n  this.size_ = size;\n\n  /**\n   * @private\n   */\n  this.rotation_ = rotation;\n\n  /**\n   * @private\n   */\n  this.resolution_ = resolution;\n\n  /**\n   * @private\n   * @type {ol.style.Image}\n   */\n  this.imageStyle_ = null;\n\n  /**\n   * @private\n   * @type {ol.style.Fill}\n   */\n  this.fillStyle_ = null;\n\n  /**\n   * @private\n   * @type {ol.style.Stroke}\n   */\n  this.strokeStyle_ = null;\n\n};\nol.inherits(ol.render.webgl.Immediate, ol.render.VectorContext);\n\n\n/**\n * Set the rendering style.  Note that since this is an immediate rendering API,\n * any `zIndex` on the provided style will be ignored.\n *\n * @param {ol.style.Style} style The rendering style.\n * @api\n */\nol.render.webgl.Immediate.prototype.setStyle = function(style) {\n  this.setFillStrokeStyle(style.getFill(), style.getStroke());\n  this.setImageStyle(style.getImage());\n};\n\n\n/**\n * Render a geometry into the canvas.  Call\n * {@link ol.render.webgl.Immediate#setStyle} first to set the rendering style.\n *\n * @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render.\n * @api\n */\nol.render.webgl.Immediate.prototype.drawGeometry = function(geometry) {\n  var type = geometry.getType();\n  switch (type) {\n    case ol.geom.GeometryType.POINT:\n      this.drawPoint(/** @type {ol.geom.Point} */ (geometry), null);\n      break;\n    case ol.geom.GeometryType.LINE_STRING:\n      this.drawLineString(/** @type {ol.geom.LineString} */ (geometry), null);\n      break;\n    case ol.geom.GeometryType.POLYGON:\n      this.drawPolygon(/** @type {ol.geom.Polygon} */ (geometry), null);\n      break;\n    case ol.geom.GeometryType.MULTI_POINT:\n      this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry), null);\n      break;\n    case ol.geom.GeometryType.MULTI_LINE_STRING:\n      this.drawMultiLineString(/** @type {ol.geom.MultiLineString} */ (geometry), null);\n      break;\n    case ol.geom.GeometryType.MULTI_POLYGON:\n      this.drawMultiPolygon(/** @type {ol.geom.MultiPolygon} */ (geometry), null);\n      break;\n    case ol.geom.GeometryType.GEOMETRY_COLLECTION:\n      this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry), null);\n      break;\n    case ol.geom.GeometryType.CIRCLE:\n      this.drawCircle(/** @type {ol.geom.Circle} */ (geometry), null);\n      break;\n    default:\n      ol.DEBUG && console.assert(false, 'Unsupported geometry type: ' + type);\n  }\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) {\n  var geometry = style.getGeometryFunction()(feature);\n  if (!geometry ||\n      !ol.extent.intersects(this.extent_, geometry.getExtent())) {\n    return;\n  }\n  this.setStyle(style);\n  ol.DEBUG && console.assert(geometry, 'geometry must be truthy');\n  this.drawGeometry(geometry);\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawGeometryCollection = function(geometry, data) {\n  var geometries = geometry.getGeometriesArray();\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    this.drawGeometry(geometries[i]);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawPoint = function(geometry, data) {\n  var context = this.context_;\n  var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);\n  var replay = /** @type {ol.render.webgl.ImageReplay} */ (\n      replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));\n  replay.setImageStyle(this.imageStyle_);\n  replay.drawPoint(geometry, data);\n  replay.finish(context);\n  // default colors\n  var opacity = 1;\n  var skippedFeatures = {};\n  var featureCallback;\n  var oneByOne = false;\n  replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,\n      this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,\n      oneByOne);\n  replay.getDeleteResourcesFunction(context)();\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawMultiPoint = function(geometry, data) {\n  var context = this.context_;\n  var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);\n  var replay = /** @type {ol.render.webgl.ImageReplay} */ (\n      replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));\n  replay.setImageStyle(this.imageStyle_);\n  replay.drawMultiPoint(geometry, data);\n  replay.finish(context);\n  var opacity = 1;\n  var skippedFeatures = {};\n  var featureCallback;\n  var oneByOne = false;\n  replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,\n      this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,\n      oneByOne);\n  replay.getDeleteResourcesFunction(context)();\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawLineString = function(geometry, data) {\n  var context = this.context_;\n  var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);\n  var replay = /** @type {ol.render.webgl.LineStringReplay} */ (\n      replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));\n  replay.setFillStrokeStyle(null, this.strokeStyle_);\n  replay.drawLineString(geometry, data);\n  replay.finish(context);\n  var opacity = 1;\n  var skippedFeatures = {};\n  var featureCallback;\n  var oneByOne = false;\n  replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,\n      this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,\n      oneByOne);\n  replay.getDeleteResourcesFunction(context)();\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawMultiLineString = function(geometry, data) {\n  var context = this.context_;\n  var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);\n  var replay = /** @type {ol.render.webgl.LineStringReplay} */ (\n      replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));\n  replay.setFillStrokeStyle(null, this.strokeStyle_);\n  replay.drawMultiLineString(geometry, data);\n  replay.finish(context);\n  var opacity = 1;\n  var skippedFeatures = {};\n  var featureCallback;\n  var oneByOne = false;\n  replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,\n      this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,\n      oneByOne);\n  replay.getDeleteResourcesFunction(context)();\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawPolygon = function(geometry, data) {\n  var context = this.context_;\n  var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);\n  var replay = /** @type {ol.render.webgl.PolygonReplay} */ (\n      replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));\n  replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);\n  replay.drawPolygon(geometry, data);\n  replay.finish(context);\n  var opacity = 1;\n  var skippedFeatures = {};\n  var featureCallback;\n  var oneByOne = false;\n  replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,\n      this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,\n      oneByOne);\n  replay.getDeleteResourcesFunction(context)();\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawMultiPolygon = function(geometry, data) {\n  var context = this.context_;\n  var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);\n  var replay = /** @type {ol.render.webgl.PolygonReplay} */ (\n      replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));\n  replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);\n  replay.drawMultiPolygon(geometry, data);\n  replay.finish(context);\n  var opacity = 1;\n  var skippedFeatures = {};\n  var featureCallback;\n  var oneByOne = false;\n  replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,\n      this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,\n      oneByOne);\n  replay.getDeleteResourcesFunction(context)();\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.drawCircle = function(geometry, data) {\n  var context = this.context_;\n  var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);\n  var replay = /** @type {ol.render.webgl.CircleReplay} */ (\n      replayGroup.getReplay(0, ol.render.ReplayType.CIRCLE));\n  replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);\n  replay.drawCircle(geometry, data);\n  replay.finish(context);\n  var opacity = 1;\n  var skippedFeatures = {};\n  var featureCallback;\n  var oneByOne = false;\n  replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,\n      this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,\n      oneByOne);\n  replay.getDeleteResourcesFunction(context)();\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) {\n  this.imageStyle_ = imageStyle;\n};\n\n\n/**\n * @inheritDoc\n */\nol.render.webgl.Immediate.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {\n  this.fillStyle_ = fillStyle;\n  this.strokeStyle_ = strokeStyle;\n};\n\n// This file is automatically generated, do not edit\ngoog.provide('ol.renderer.webgl.defaultmapshader');\n\ngoog.require('ol');\ngoog.require('ol.webgl.Fragment');\ngoog.require('ol.webgl.Vertex');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Fragment}\n * @struct\n */\nol.renderer.webgl.defaultmapshader.Fragment = function() {\n  ol.webgl.Fragment.call(this, ol.renderer.webgl.defaultmapshader.Fragment.SOURCE);\n};\nol.inherits(ol.renderer.webgl.defaultmapshader.Fragment, ol.webgl.Fragment);\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.defaultmapshader.Fragment.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';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.defaultmapshader.Fragment.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;}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.defaultmapshader.Fragment.SOURCE = ol.DEBUG ?\n    ol.renderer.webgl.defaultmapshader.Fragment.DEBUG_SOURCE :\n    ol.renderer.webgl.defaultmapshader.Fragment.OPTIMIZED_SOURCE;\n\n\nol.renderer.webgl.defaultmapshader.fragment = new ol.renderer.webgl.defaultmapshader.Fragment();\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Vertex}\n * @struct\n */\nol.renderer.webgl.defaultmapshader.Vertex = function() {\n  ol.webgl.Vertex.call(this, ol.renderer.webgl.defaultmapshader.Vertex.SOURCE);\n};\nol.inherits(ol.renderer.webgl.defaultmapshader.Vertex, ol.webgl.Vertex);\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.defaultmapshader.Vertex.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';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.defaultmapshader.Vertex.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;}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.defaultmapshader.Vertex.SOURCE = ol.DEBUG ?\n    ol.renderer.webgl.defaultmapshader.Vertex.DEBUG_SOURCE :\n    ol.renderer.webgl.defaultmapshader.Vertex.OPTIMIZED_SOURCE;\n\n\nol.renderer.webgl.defaultmapshader.vertex = new ol.renderer.webgl.defaultmapshader.Vertex();\n\n\n/**\n * @constructor\n * @param {WebGLRenderingContext} gl GL.\n * @param {WebGLProgram} program Program.\n * @struct\n */\nol.renderer.webgl.defaultmapshader.Locations = function(gl, program) {\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_opacity = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_opacity' : 'f');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_projectionMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_projectionMatrix' : 'e');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_texCoordMatrix = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_texCoordMatrix' : 'd');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_texture = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_texture' : 'g');\n\n  /**\n   * @type {number}\n   */\n  this.a_position = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_position' : 'b');\n\n  /**\n   * @type {number}\n   */\n  this.a_texCoord = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_texCoord' : 'c');\n};\n\ngoog.provide('ol.renderer.webgl.Layer');\n\ngoog.require('ol');\ngoog.require('ol.render.Event');\ngoog.require('ol.render.webgl.Immediate');\ngoog.require('ol.renderer.Layer');\ngoog.require('ol.renderer.webgl.defaultmapshader');\ngoog.require('ol.transform');\ngoog.require('ol.vec.Mat4');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Buffer');\ngoog.require('ol.webgl.Context');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.Layer}\n * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.\n * @param {ol.layer.Layer} layer Layer.\n */\nol.renderer.webgl.Layer = function(mapRenderer, layer) {\n\n  ol.renderer.Layer.call(this, layer);\n\n  /**\n   * @protected\n   * @type {ol.renderer.webgl.Map}\n   */\n  this.mapRenderer = mapRenderer;\n\n  /**\n   * @private\n   * @type {ol.webgl.Buffer}\n   */\n  this.arrayBuffer_ = new ol.webgl.Buffer([\n    -1, -1, 0, 0,\n    1, -1, 1, 0,\n    -1, 1, 0, 1,\n    1, 1, 1, 1\n  ]);\n\n  /**\n   * @protected\n   * @type {WebGLTexture}\n   */\n  this.texture = null;\n\n  /**\n   * @protected\n   * @type {WebGLFramebuffer}\n   */\n  this.framebuffer = null;\n\n  /**\n   * @protected\n   * @type {number|undefined}\n   */\n  this.framebufferDimension = undefined;\n\n  /**\n   * @protected\n   * @type {ol.Transform}\n   */\n  this.texCoordMatrix = ol.transform.create();\n\n  /**\n   * @protected\n   * @type {ol.Transform}\n   */\n  this.projectionMatrix = ol.transform.create();\n\n  /**\n   * @type {Array.<number>}\n   * @private\n   */\n  this.tmpMat4_ = ol.vec.Mat4.create();\n\n  /**\n   * @private\n   * @type {ol.renderer.webgl.defaultmapshader.Locations}\n   */\n  this.defaultLocations_ = null;\n\n};\nol.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer);\n\n\n/**\n * @param {olx.FrameState} frameState Frame state.\n * @param {number} framebufferDimension Framebuffer dimension.\n * @protected\n */\nol.renderer.webgl.Layer.prototype.bindFramebuffer = function(frameState, framebufferDimension) {\n\n  var gl = this.mapRenderer.getGL();\n\n  if (this.framebufferDimension === undefined ||\n      this.framebufferDimension != framebufferDimension) {\n    /**\n     * @param {WebGLRenderingContext} gl GL.\n     * @param {WebGLFramebuffer} framebuffer Framebuffer.\n     * @param {WebGLTexture} texture Texture.\n     */\n    var postRenderFunction = function(gl, framebuffer, texture) {\n      if (!gl.isContextLost()) {\n        gl.deleteFramebuffer(framebuffer);\n        gl.deleteTexture(texture);\n      }\n    }.bind(null, gl, this.framebuffer, this.texture);\n\n    frameState.postRenderFunctions.push(\n      /** @type {ol.PostRenderFunction} */ (postRenderFunction)\n    );\n\n    var texture = ol.webgl.Context.createEmptyTexture(\n        gl, framebufferDimension, framebufferDimension);\n\n    var framebuffer = gl.createFramebuffer();\n    gl.bindFramebuffer(ol.webgl.FRAMEBUFFER, framebuffer);\n    gl.framebufferTexture2D(ol.webgl.FRAMEBUFFER,\n        ol.webgl.COLOR_ATTACHMENT0, ol.webgl.TEXTURE_2D, texture, 0);\n\n    this.texture = texture;\n    this.framebuffer = framebuffer;\n    this.framebufferDimension = framebufferDimension;\n\n  } else {\n    gl.bindFramebuffer(ol.webgl.FRAMEBUFFER, this.framebuffer);\n  }\n\n};\n\n\n/**\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.LayerState} layerState Layer state.\n * @param {ol.webgl.Context} context Context.\n */\nol.renderer.webgl.Layer.prototype.composeFrame = function(frameState, layerState, context) {\n\n  this.dispatchComposeEvent_(\n      ol.render.Event.Type.PRECOMPOSE, context, frameState);\n\n  context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.arrayBuffer_);\n\n  var gl = context.getGL();\n\n  var fragmentShader = ol.renderer.webgl.defaultmapshader.fragment;\n  var vertexShader = ol.renderer.webgl.defaultmapshader.vertex;\n\n  var program = context.getProgram(fragmentShader, vertexShader);\n\n  var locations;\n  if (!this.defaultLocations_) {\n    locations =\n        new ol.renderer.webgl.defaultmapshader.Locations(gl, program);\n    this.defaultLocations_ = locations;\n  } else {\n    locations = this.defaultLocations_;\n  }\n\n  if (context.useProgram(program)) {\n    gl.enableVertexAttribArray(locations.a_position);\n    gl.vertexAttribPointer(\n        locations.a_position, 2, ol.webgl.FLOAT, false, 16, 0);\n    gl.enableVertexAttribArray(locations.a_texCoord);\n    gl.vertexAttribPointer(\n        locations.a_texCoord, 2, ol.webgl.FLOAT, false, 16, 8);\n    gl.uniform1i(locations.u_texture, 0);\n  }\n\n  gl.uniformMatrix4fv(locations.u_texCoordMatrix, false,\n      ol.vec.Mat4.fromTransform(this.tmpMat4_, this.getTexCoordMatrix()));\n  gl.uniformMatrix4fv(locations.u_projectionMatrix, false,\n      ol.vec.Mat4.fromTransform(this.tmpMat4_, this.getProjectionMatrix()));\n  gl.uniform1f(locations.u_opacity, layerState.opacity);\n  gl.bindTexture(ol.webgl.TEXTURE_2D, this.getTexture());\n  gl.drawArrays(ol.webgl.TRIANGLE_STRIP, 0, 4);\n\n  this.dispatchComposeEvent_(\n      ol.render.Event.Type.POSTCOMPOSE, context, frameState);\n\n};\n\n\n/**\n * @param {ol.render.Event.Type} type Event type.\n * @param {ol.webgl.Context} context WebGL context.\n * @param {olx.FrameState} frameState Frame state.\n * @private\n */\nol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState) {\n  var layer = this.getLayer();\n  if (layer.hasListener(type)) {\n    var viewState = frameState.viewState;\n    var resolution = viewState.resolution;\n    var pixelRatio = frameState.pixelRatio;\n    var extent = frameState.extent;\n    var center = viewState.center;\n    var rotation = viewState.rotation;\n    var size = frameState.size;\n\n    var render = new ol.render.webgl.Immediate(\n        context, center, resolution, rotation, size, extent, pixelRatio);\n    var composeEvent = new ol.render.Event(\n        type, render, frameState, null, context);\n    layer.dispatchEvent(composeEvent);\n  }\n};\n\n\n/**\n * @return {!ol.Transform} Matrix.\n */\nol.renderer.webgl.Layer.prototype.getTexCoordMatrix = function() {\n  return this.texCoordMatrix;\n};\n\n\n/**\n * @return {WebGLTexture} Texture.\n */\nol.renderer.webgl.Layer.prototype.getTexture = function() {\n  return this.texture;\n};\n\n\n/**\n * @return {!ol.Transform} Matrix.\n */\nol.renderer.webgl.Layer.prototype.getProjectionMatrix = function() {\n  return this.projectionMatrix;\n};\n\n\n/**\n * Handle webglcontextlost.\n */\nol.renderer.webgl.Layer.prototype.handleWebGLContextLost = function() {\n  this.texture = null;\n  this.framebuffer = null;\n  this.framebufferDimension = undefined;\n};\n\n\n/**\n * @abstract\n * @param {olx.FrameState} frameState Frame state.\n * @param {ol.LayerState} layerState Layer state.\n * @param {ol.webgl.Context} context Context.\n * @return {boolean} whether composeFrame should be called.\n */\nol.renderer.webgl.Layer.prototype.prepareFrame = function(frameState, layerState, context) {};\n\n\n/**\n * @abstract\n * @param {ol.Pixel} pixel Pixel.\n * @param {olx.FrameState} frameState FrameState.\n * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer\n *     callback.\n * @param {S} thisArg Value to use as `this` when executing `callback`.\n * @return {T|undefined} Callback result.\n * @template S,T,U\n */\nol.renderer.webgl.Layer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {};\n\ngoog.provide('ol.ImageCanvas');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.ImageBase');\n\n\n/**\n * @constructor\n * @extends {ol.ImageBase}\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {Array.<ol.Attribution>} attributions Attributions.\n * @param {HTMLCanvasElement} canvas Canvas.\n * @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to\n *     support asynchronous canvas drawing.\n */\nol.ImageCanvas = function(extent, resolution, pixelRatio, attributions,\n    canvas, opt_loader) {\n\n  /**\n   * Optional canvas loader function.\n   * @type {?ol.ImageCanvasLoader}\n   * @private\n   */\n  this.loader_ = opt_loader !== undefined ? opt_loader : null;\n\n  var state = opt_loader !== undefined ?\n      ol.Image.State.IDLE : ol.Image.State.LOADED;\n\n  ol.ImageBase.call(this, extent, resolution, pixelRatio, state, attributions);\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = canvas;\n\n  /**\n   * @private\n   * @type {Error}\n   */\n  this.error_ = null;\n\n};\nol.inherits(ol.ImageCanvas, ol.ImageBase);\n\n\n/**\n * Get any error associated with asynchronous rendering.\n * @return {Error} Any error that occurred during rendering.\n */\nol.ImageCanvas.prototype.getError = function() {\n  return this.error_;\n};\n\n\n/**\n * Handle async drawing complete.\n * @param {Error} err Any error during drawing.\n * @private\n */\nol.ImageCanvas.prototype.handleLoad_ = function(err) {\n  if (err) {\n    this.error_ = err;\n    this.state = ol.Image.State.ERROR;\n  } else {\n    this.state = ol.Image.State.LOADED;\n  }\n  this.changed();\n};\n\n\n/**\n * Trigger drawing on canvas.\n */\nol.ImageCanvas.prototype.load = function() {\n  if (this.state == ol.Image.State.IDLE) {\n    ol.DEBUG && console.assert(this.loader_, 'this.loader_ must be set');\n    this.state = ol.Image.State.LOADING;\n    this.changed();\n    this.loader_(this.handleLoad_.bind(this));\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.ImageCanvas.prototype.getImage = function(opt_context) {\n  return this.canvas_;\n};\n\ngoog.provide('ol.reproj');\n\ngoog.require('ol');\ngoog.require('ol.dom');\ngoog.require('ol.extent');\ngoog.require('ol.math');\ngoog.require('ol.proj');\n\n\n/**\n * We need to employ more sophisticated solution\n * if the web browser antialiases clipping edges on canvas.\n *\n * Currently only Chrome does not antialias the edges, but this is probably\n * going to be \"fixed\" in the future: http://crbug.com/424291\n *\n * @type {boolean}\n * @private\n */\nol.reproj.browserAntialiasesClip_ = (function() {\n  // Adapted from http://stackoverflow.com/questions/4565112/javascript-how-to-find-out-if-the-user-browser-is-chrome\n  var isOpera = navigator.userAgent.indexOf('OPR') > -1;\n  var isIEedge = navigator.userAgent.indexOf('Edge') > -1;\n  return !(\n    !navigator.userAgent.match('CriOS') &&  // Not Chrome on iOS\n    'chrome' in window && // Has chrome in window\n    navigator.vendor === 'Google Inc.' && // Vendor is Google.\n    isOpera == false && // Not Opera\n    isIEedge == false // Not Edge\n  );\n})();\n\n\n/**\n * Calculates ideal resolution to use from the source in order to achieve\n * pixel mapping as close as possible to 1:1 during reprojection.\n * The resolution is calculated regardless of what resolutions\n * are actually available in the dataset (TileGrid, Image, ...).\n *\n * @param {ol.proj.Projection} sourceProj Source projection.\n * @param {ol.proj.Projection} targetProj Target projection.\n * @param {ol.Coordinate} targetCenter Target center.\n * @param {number} targetResolution Target resolution.\n * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0.\n */\nol.reproj.calculateSourceResolution = function(sourceProj, targetProj,\n    targetCenter, targetResolution) {\n\n  var sourceCenter = ol.proj.transform(targetCenter, targetProj, sourceProj);\n\n  // calculate the ideal resolution of the source data\n  var sourceResolution =\n      ol.proj.getPointResolution(targetProj, targetResolution, targetCenter);\n\n  var targetMetersPerUnit = targetProj.getMetersPerUnit();\n  if (targetMetersPerUnit !== undefined) {\n    sourceResolution *= targetMetersPerUnit;\n  }\n  var sourceMetersPerUnit = sourceProj.getMetersPerUnit();\n  if (sourceMetersPerUnit !== undefined) {\n    sourceResolution /= sourceMetersPerUnit;\n  }\n\n  // Based on the projection properties, the point resolution at the specified\n  // coordinates may be slightly different. We need to reverse-compensate this\n  // in order to achieve optimal results.\n\n  var compensationFactor =\n      ol.proj.getPointResolution(sourceProj, sourceResolution, sourceCenter) /\n      sourceResolution;\n\n  if (isFinite(compensationFactor) && compensationFactor > 0) {\n    sourceResolution /= compensationFactor;\n  }\n\n  return sourceResolution;\n};\n\n\n/**\n * Enlarge the clipping triangle point by 1 pixel to ensure the edges overlap\n * in order to mask gaps caused by antialiasing.\n *\n * @param {number} centroidX Centroid of the triangle (x coordinate in pixels).\n * @param {number} centroidY Centroid of the triangle (y coordinate in pixels).\n * @param {number} x X coordinate of the point (in pixels).\n * @param {number} y Y coordinate of the point (in pixels).\n * @return {ol.Coordinate} New point 1 px farther from the centroid.\n * @private\n */\nol.reproj.enlargeClipPoint_ = function(centroidX, centroidY, x, y) {\n  var dX = x - centroidX, dY = y - centroidY;\n  var distance = Math.sqrt(dX * dX + dY * dY);\n  return [Math.round(x + dX / distance), Math.round(y + dY / distance)];\n};\n\n\n/**\n * Renders the source data into new canvas based on the triangulation.\n *\n * @param {number} width Width of the canvas.\n * @param {number} height Height of the canvas.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} sourceResolution Source resolution.\n * @param {ol.Extent} sourceExtent Extent of the data source.\n * @param {number} targetResolution Target resolution.\n * @param {ol.Extent} targetExtent Target extent.\n * @param {ol.reproj.Triangulation} triangulation Calculated triangulation.\n * @param {Array.<{extent: ol.Extent,\n *                 image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources\n *             Array of sources.\n * @param {number} gutter Gutter of the sources.\n * @param {boolean=} opt_renderEdges Render reprojection edges.\n * @return {HTMLCanvasElement} Canvas with reprojected data.\n */\nol.reproj.render = function(width, height, pixelRatio,\n    sourceResolution, sourceExtent, targetResolution, targetExtent,\n    triangulation, sources, gutter, opt_renderEdges) {\n\n  var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width),\n                                             Math.round(pixelRatio * height));\n\n  if (sources.length === 0) {\n    return context.canvas;\n  }\n\n  context.scale(pixelRatio, pixelRatio);\n\n  var sourceDataExtent = ol.extent.createEmpty();\n  sources.forEach(function(src, i, arr) {\n    ol.extent.extend(sourceDataExtent, src.extent);\n  });\n\n  var canvasWidthInUnits = ol.extent.getWidth(sourceDataExtent);\n  var canvasHeightInUnits = ol.extent.getHeight(sourceDataExtent);\n  var stitchContext = ol.dom.createCanvasContext2D(\n      Math.round(pixelRatio * canvasWidthInUnits / sourceResolution),\n      Math.round(pixelRatio * canvasHeightInUnits / sourceResolution));\n\n  var stitchScale = pixelRatio / sourceResolution;\n\n  sources.forEach(function(src, i, arr) {\n    var xPos = src.extent[0] - sourceDataExtent[0];\n    var yPos = -(src.extent[3] - sourceDataExtent[3]);\n    var srcWidth = ol.extent.getWidth(src.extent);\n    var srcHeight = ol.extent.getHeight(src.extent);\n\n    stitchContext.drawImage(\n        src.image,\n        gutter, gutter,\n        src.image.width - 2 * gutter, src.image.height - 2 * gutter,\n        xPos * stitchScale, yPos * stitchScale,\n        srcWidth * stitchScale, srcHeight * stitchScale);\n  });\n\n  var targetTopLeft = ol.extent.getTopLeft(targetExtent);\n\n  triangulation.getTriangles().forEach(function(triangle, i, arr) {\n    /* Calculate affine transform (src -> dst)\n     * Resulting matrix can be used to transform coordinate\n     * from `sourceProjection` to destination pixels.\n     *\n     * To optimize number of context calls and increase numerical stability,\n     * we also do the following operations:\n     * trans(-topLeftExtentCorner), scale(1 / targetResolution), scale(1, -1)\n     * here before solving the linear system so [ui, vi] are pixel coordinates.\n     *\n     * Src points: xi, yi\n     * Dst points: ui, vi\n     * Affine coefficients: aij\n     *\n     * | x0 y0 1  0  0 0 |   |a00|   |u0|\n     * | x1 y1 1  0  0 0 |   |a01|   |u1|\n     * | x2 y2 1  0  0 0 | x |a02| = |u2|\n     * |  0  0 0 x0 y0 1 |   |a10|   |v0|\n     * |  0  0 0 x1 y1 1 |   |a11|   |v1|\n     * |  0  0 0 x2 y2 1 |   |a12|   |v2|\n     */\n    var source = triangle.source, target = triangle.target;\n    var x0 = source[0][0], y0 = source[0][1],\n        x1 = source[1][0], y1 = source[1][1],\n        x2 = source[2][0], y2 = source[2][1];\n    var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution,\n        v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution;\n    var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution,\n        v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution;\n    var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution,\n        v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution;\n\n    // Shift all the source points to improve numerical stability\n    // of all the subsequent calculations. The [x0, y0] is used here.\n    // This is also used to simplify the linear system.\n    var sourceNumericalShiftX = x0, sourceNumericalShiftY = y0;\n    x0 = 0;\n    y0 = 0;\n    x1 -= sourceNumericalShiftX;\n    y1 -= sourceNumericalShiftY;\n    x2 -= sourceNumericalShiftX;\n    y2 -= sourceNumericalShiftY;\n\n    var augmentedMatrix = [\n      [x1, y1, 0, 0, u1 - u0],\n      [x2, y2, 0, 0, u2 - u0],\n      [0, 0, x1, y1, v1 - v0],\n      [0, 0, x2, y2, v2 - v0]\n    ];\n    var affineCoefs = ol.math.solveLinearSystem(augmentedMatrix);\n    if (!affineCoefs) {\n      return;\n    }\n\n    context.save();\n    context.beginPath();\n    if (ol.reproj.browserAntialiasesClip_) {\n      var centroidX = (u0 + u1 + u2) / 3, centroidY = (v0 + v1 + v2) / 3;\n      var p0 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u0, v0);\n      var p1 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u1, v1);\n      var p2 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u2, v2);\n\n      context.moveTo(p1[0], p1[1]);\n      context.lineTo(p0[0], p0[1]);\n      context.lineTo(p2[0], p2[1]);\n    } else {\n      context.moveTo(u1, v1);\n      context.lineTo(u0, v0);\n      context.lineTo(u2, v2);\n    }\n    context.clip();\n\n    context.transform(\n        affineCoefs[0], affineCoefs[2], affineCoefs[1], affineCoefs[3], u0, v0);\n\n    context.translate(sourceDataExtent[0] - sourceNumericalShiftX,\n                      sourceDataExtent[3] - sourceNumericalShiftY);\n\n    context.scale(sourceResolution / pixelRatio,\n                  -sourceResolution / pixelRatio);\n\n    context.drawImage(stitchContext.canvas, 0, 0);\n    context.restore();\n  });\n\n  if (opt_renderEdges) {\n    context.save();\n\n    context.strokeStyle = 'black';\n    context.lineWidth = 1;\n\n    triangulation.getTriangles().forEach(function(triangle, i, arr) {\n      var target = triangle.target;\n      var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution,\n          v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution;\n      var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution,\n          v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution;\n      var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution,\n          v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution;\n\n      context.beginPath();\n      context.moveTo(u1, v1);\n      context.lineTo(u0, v0);\n      context.lineTo(u2, v2);\n      context.closePath();\n      context.stroke();\n    });\n\n    context.restore();\n  }\n  return context.canvas;\n};\n\ngoog.provide('ol.reproj.Triangulation');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.math');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Class containing triangulation of the given target extent.\n * Used for determining source data and the reprojection itself.\n *\n * @param {ol.proj.Projection} sourceProj Source projection.\n * @param {ol.proj.Projection} targetProj Target projection.\n * @param {ol.Extent} targetExtent Target extent to triangulate.\n * @param {ol.Extent} maxSourceExtent Maximal source extent that can be used.\n * @param {number} errorThreshold Acceptable error (in source units).\n * @constructor\n */\nol.reproj.Triangulation = function(sourceProj, targetProj, targetExtent,\n    maxSourceExtent, errorThreshold) {\n\n  /**\n   * @type {ol.proj.Projection}\n   * @private\n   */\n  this.sourceProj_ = sourceProj;\n\n  /**\n   * @type {ol.proj.Projection}\n   * @private\n   */\n  this.targetProj_ = targetProj;\n\n  /** @type {!Object.<string, ol.Coordinate>} */\n  var transformInvCache = {};\n  var transformInv = ol.proj.getTransform(this.targetProj_, this.sourceProj_);\n\n  /**\n   * @param {ol.Coordinate} c A coordinate.\n   * @return {ol.Coordinate} Transformed coordinate.\n   * @private\n   */\n  this.transformInv_ = function(c) {\n    var key = c[0] + '/' + c[1];\n    if (!transformInvCache[key]) {\n      transformInvCache[key] = transformInv(c);\n    }\n    return transformInvCache[key];\n  };\n\n  /**\n   * @type {ol.Extent}\n   * @private\n   */\n  this.maxSourceExtent_ = maxSourceExtent;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.errorThresholdSquared_ = errorThreshold * errorThreshold;\n\n  /**\n   * @type {Array.<ol.ReprojTriangle>}\n   * @private\n   */\n  this.triangles_ = [];\n\n  /**\n   * Indicates that the triangulation crosses edge of the source projection.\n   * @type {boolean}\n   * @private\n   */\n  this.wrapsXInSource_ = false;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.canWrapXInSource_ = this.sourceProj_.canWrapX() &&\n      !!maxSourceExtent &&\n      !!this.sourceProj_.getExtent() &&\n      (ol.extent.getWidth(maxSourceExtent) ==\n       ol.extent.getWidth(this.sourceProj_.getExtent()));\n\n  /**\n   * @type {?number}\n   * @private\n   */\n  this.sourceWorldWidth_ = this.sourceProj_.getExtent() ?\n      ol.extent.getWidth(this.sourceProj_.getExtent()) : null;\n\n  /**\n   * @type {?number}\n   * @private\n   */\n  this.targetWorldWidth_ = this.targetProj_.getExtent() ?\n      ol.extent.getWidth(this.targetProj_.getExtent()) : null;\n\n  var destinationTopLeft = ol.extent.getTopLeft(targetExtent);\n  var destinationTopRight = ol.extent.getTopRight(targetExtent);\n  var destinationBottomRight = ol.extent.getBottomRight(targetExtent);\n  var destinationBottomLeft = ol.extent.getBottomLeft(targetExtent);\n  var sourceTopLeft = this.transformInv_(destinationTopLeft);\n  var sourceTopRight = this.transformInv_(destinationTopRight);\n  var sourceBottomRight = this.transformInv_(destinationBottomRight);\n  var sourceBottomLeft = this.transformInv_(destinationBottomLeft);\n\n  this.addQuad_(\n      destinationTopLeft, destinationTopRight,\n      destinationBottomRight, destinationBottomLeft,\n      sourceTopLeft, sourceTopRight, sourceBottomRight, sourceBottomLeft,\n      ol.RASTER_REPROJECTION_MAX_SUBDIVISION);\n\n  if (this.wrapsXInSource_) {\n    // Fix coordinates (ol.proj returns wrapped coordinates, \"unwrap\" here).\n    // This significantly simplifies the rest of the reprojection process.\n\n    ol.DEBUG && console.assert(this.sourceWorldWidth_ !== null);\n    var leftBound = Infinity;\n    this.triangles_.forEach(function(triangle, i, arr) {\n      leftBound = Math.min(leftBound,\n          triangle.source[0][0], triangle.source[1][0], triangle.source[2][0]);\n    });\n\n    // Shift triangles to be as close to `leftBound` as possible\n    // (if the distance is more than `worldWidth / 2` it can be closer.\n    this.triangles_.forEach(function(triangle) {\n      if (Math.max(triangle.source[0][0], triangle.source[1][0],\n          triangle.source[2][0]) - leftBound > this.sourceWorldWidth_ / 2) {\n        var newTriangle = [[triangle.source[0][0], triangle.source[0][1]],\n                           [triangle.source[1][0], triangle.source[1][1]],\n                           [triangle.source[2][0], triangle.source[2][1]]];\n        if ((newTriangle[0][0] - leftBound) > this.sourceWorldWidth_ / 2) {\n          newTriangle[0][0] -= this.sourceWorldWidth_;\n        }\n        if ((newTriangle[1][0] - leftBound) > this.sourceWorldWidth_ / 2) {\n          newTriangle[1][0] -= this.sourceWorldWidth_;\n        }\n        if ((newTriangle[2][0] - leftBound) > this.sourceWorldWidth_ / 2) {\n          newTriangle[2][0] -= this.sourceWorldWidth_;\n        }\n\n        // Rarely (if the extent contains both the dateline and prime meridian)\n        // the shift can in turn break some triangles.\n        // Detect this here and don't shift in such cases.\n        var minX = Math.min(\n            newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]);\n        var maxX = Math.max(\n            newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]);\n        if ((maxX - minX) < this.sourceWorldWidth_ / 2) {\n          triangle.source = newTriangle;\n        }\n      }\n    }, this);\n  }\n\n  transformInvCache = {};\n};\n\n\n/**\n * Adds triangle to the triangulation.\n * @param {ol.Coordinate} a The target a coordinate.\n * @param {ol.Coordinate} b The target b coordinate.\n * @param {ol.Coordinate} c The target c coordinate.\n * @param {ol.Coordinate} aSrc The source a coordinate.\n * @param {ol.Coordinate} bSrc The source b coordinate.\n * @param {ol.Coordinate} cSrc The source c coordinate.\n * @private\n */\nol.reproj.Triangulation.prototype.addTriangle_ = function(a, b, c,\n    aSrc, bSrc, cSrc) {\n  this.triangles_.push({\n    source: [aSrc, bSrc, cSrc],\n    target: [a, b, c]\n  });\n};\n\n\n/**\n * Adds quad (points in clock-wise order) to the triangulation\n * (and reprojects the vertices) if valid.\n * Performs quad subdivision if needed to increase precision.\n *\n * @param {ol.Coordinate} a The target a coordinate.\n * @param {ol.Coordinate} b The target b coordinate.\n * @param {ol.Coordinate} c The target c coordinate.\n * @param {ol.Coordinate} d The target d coordinate.\n * @param {ol.Coordinate} aSrc The source a coordinate.\n * @param {ol.Coordinate} bSrc The source b coordinate.\n * @param {ol.Coordinate} cSrc The source c coordinate.\n * @param {ol.Coordinate} dSrc The source d coordinate.\n * @param {number} maxSubdivision Maximal allowed subdivision of the quad.\n * @private\n */\nol.reproj.Triangulation.prototype.addQuad_ = function(a, b, c, d,\n    aSrc, bSrc, cSrc, dSrc, maxSubdivision) {\n\n  var sourceQuadExtent = ol.extent.boundingExtent([aSrc, bSrc, cSrc, dSrc]);\n  var sourceCoverageX = this.sourceWorldWidth_ ?\n      ol.extent.getWidth(sourceQuadExtent) / this.sourceWorldWidth_ : null;\n  var sourceWorldWidth = /** @type {number} */ (this.sourceWorldWidth_);\n\n  // when the quad is wrapped in the source projection\n  // it covers most of the projection extent, but not fully\n  var wrapsX = this.sourceProj_.canWrapX() &&\n               sourceCoverageX > 0.5 && sourceCoverageX < 1;\n\n  var needsSubdivision = false;\n\n  if (maxSubdivision > 0) {\n    if (this.targetProj_.isGlobal() && this.targetWorldWidth_) {\n      var targetQuadExtent = ol.extent.boundingExtent([a, b, c, d]);\n      var targetCoverageX =\n          ol.extent.getWidth(targetQuadExtent) / this.targetWorldWidth_;\n      needsSubdivision |=\n          targetCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH;\n    }\n    if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) {\n      needsSubdivision |=\n          sourceCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH;\n    }\n  }\n\n  if (!needsSubdivision && this.maxSourceExtent_) {\n    if (!ol.extent.intersects(sourceQuadExtent, this.maxSourceExtent_)) {\n      // whole quad outside source projection extent -> ignore\n      return;\n    }\n  }\n\n  if (!needsSubdivision) {\n    if (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) ||\n        !isFinite(bSrc[0]) || !isFinite(bSrc[1]) ||\n        !isFinite(cSrc[0]) || !isFinite(cSrc[1]) ||\n        !isFinite(dSrc[0]) || !isFinite(dSrc[1])) {\n      if (maxSubdivision > 0) {\n        needsSubdivision = true;\n      } else {\n        return;\n      }\n    }\n  }\n\n  if (maxSubdivision > 0) {\n    if (!needsSubdivision) {\n      var center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2];\n      var centerSrc = this.transformInv_(center);\n\n      var dx;\n      if (wrapsX) {\n        var centerSrcEstimX =\n            (ol.math.modulo(aSrc[0], sourceWorldWidth) +\n             ol.math.modulo(cSrc[0], sourceWorldWidth)) / 2;\n        dx = centerSrcEstimX -\n            ol.math.modulo(centerSrc[0], sourceWorldWidth);\n      } else {\n        dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0];\n      }\n      var dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1];\n      var centerSrcErrorSquared = dx * dx + dy * dy;\n      needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_;\n    }\n    if (needsSubdivision) {\n      if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) {\n        // split horizontally (top & bottom)\n        var bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2];\n        var bcSrc = this.transformInv_(bc);\n        var da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2];\n        var daSrc = this.transformInv_(da);\n\n        this.addQuad_(\n            a, b, bc, da, aSrc, bSrc, bcSrc, daSrc, maxSubdivision - 1);\n        this.addQuad_(\n            da, bc, c, d, daSrc, bcSrc, cSrc, dSrc, maxSubdivision - 1);\n      } else {\n        // split vertically (left & right)\n        var ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];\n        var abSrc = this.transformInv_(ab);\n        var cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2];\n        var cdSrc = this.transformInv_(cd);\n\n        this.addQuad_(\n            a, ab, cd, d, aSrc, abSrc, cdSrc, dSrc, maxSubdivision - 1);\n        this.addQuad_(\n            ab, b, c, cd, abSrc, bSrc, cSrc, cdSrc, maxSubdivision - 1);\n      }\n      return;\n    }\n  }\n\n  if (wrapsX) {\n    if (!this.canWrapXInSource_) {\n      return;\n    }\n    this.wrapsXInSource_ = true;\n  }\n\n  this.addTriangle_(a, c, d, aSrc, cSrc, dSrc);\n  this.addTriangle_(a, b, c, aSrc, bSrc, cSrc);\n};\n\n\n/**\n * Calculates extent of the 'source' coordinates from all the triangles.\n *\n * @return {ol.Extent} Calculated extent.\n */\nol.reproj.Triangulation.prototype.calculateSourceExtent = function() {\n  var extent = ol.extent.createEmpty();\n\n  this.triangles_.forEach(function(triangle, i, arr) {\n    var src = triangle.source;\n    ol.extent.extendCoordinate(extent, src[0]);\n    ol.extent.extendCoordinate(extent, src[1]);\n    ol.extent.extendCoordinate(extent, src[2]);\n  });\n\n  return extent;\n};\n\n\n/**\n * @return {Array.<ol.ReprojTriangle>} Array of the calculated triangles.\n */\nol.reproj.Triangulation.prototype.getTriangles = function() {\n  return this.triangles_;\n};\n\ngoog.provide('ol.reproj.Image');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.ImageBase');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.reproj');\ngoog.require('ol.reproj.Triangulation');\n\n\n/**\n * @classdesc\n * Class encapsulating single reprojected image.\n * See {@link ol.source.Image}.\n *\n * @constructor\n * @extends {ol.ImageBase}\n * @param {ol.proj.Projection} sourceProj Source projection (of the data).\n * @param {ol.proj.Projection} targetProj Target projection.\n * @param {ol.Extent} targetExtent Target extent.\n * @param {number} targetResolution Target resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.ReprojImageFunctionType} getImageFunction\n *     Function returning source images (extent, resolution, pixelRatio).\n */\nol.reproj.Image = function(sourceProj, targetProj,\n    targetExtent, targetResolution, pixelRatio, getImageFunction) {\n\n  /**\n   * @private\n   * @type {ol.proj.Projection}\n   */\n  this.targetProj_ = targetProj;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.maxSourceExtent_ = sourceProj.getExtent();\n  var maxTargetExtent = targetProj.getExtent();\n\n  var limitedTargetExtent = maxTargetExtent ?\n      ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent;\n\n  var targetCenter = ol.extent.getCenter(limitedTargetExtent);\n  var sourceResolution = ol.reproj.calculateSourceResolution(\n      sourceProj, targetProj, targetCenter, targetResolution);\n\n  var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD;\n\n  /**\n   * @private\n   * @type {!ol.reproj.Triangulation}\n   */\n  this.triangulation_ = new ol.reproj.Triangulation(\n      sourceProj, targetProj, limitedTargetExtent, this.maxSourceExtent_,\n      sourceResolution * errorThresholdInPixels);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.targetResolution_ = targetResolution;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.targetExtent_ = targetExtent;\n\n  var sourceExtent = this.triangulation_.calculateSourceExtent();\n\n  /**\n   * @private\n   * @type {ol.ImageBase}\n   */\n  this.sourceImage_ =\n      getImageFunction(sourceExtent, sourceResolution, pixelRatio);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.sourcePixelRatio_ =\n      this.sourceImage_ ? this.sourceImage_.getPixelRatio() : 1;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = null;\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.sourceListenerKey_ = null;\n\n\n  var state = ol.Image.State.LOADED;\n  var attributions = [];\n\n  if (this.sourceImage_) {\n    state = ol.Image.State.IDLE;\n    attributions = this.sourceImage_.getAttributions();\n  }\n\n  ol.ImageBase.call(this, targetExtent, targetResolution, this.sourcePixelRatio_,\n            state, attributions);\n};\nol.inherits(ol.reproj.Image, ol.ImageBase);\n\n\n/**\n * @inheritDoc\n */\nol.reproj.Image.prototype.disposeInternal = function() {\n  if (this.state == ol.Image.State.LOADING) {\n    this.unlistenSource_();\n  }\n  ol.ImageBase.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * @inheritDoc\n */\nol.reproj.Image.prototype.getImage = function(opt_context) {\n  return this.canvas_;\n};\n\n\n/**\n * @return {ol.proj.Projection} Projection.\n */\nol.reproj.Image.prototype.getProjection = function() {\n  return this.targetProj_;\n};\n\n\n/**\n * @private\n */\nol.reproj.Image.prototype.reproject_ = function() {\n  var sourceState = this.sourceImage_.getState();\n  if (sourceState == ol.Image.State.LOADED) {\n    var width = ol.extent.getWidth(this.targetExtent_) / this.targetResolution_;\n    var height =\n        ol.extent.getHeight(this.targetExtent_) / this.targetResolution_;\n\n    this.canvas_ = ol.reproj.render(width, height, this.sourcePixelRatio_,\n        this.sourceImage_.getResolution(), this.maxSourceExtent_,\n        this.targetResolution_, this.targetExtent_, this.triangulation_, [{\n          extent: this.sourceImage_.getExtent(),\n          image: this.sourceImage_.getImage()\n        }], 0);\n  }\n  this.state = sourceState;\n  this.changed();\n};\n\n\n/**\n * @inheritDoc\n */\nol.reproj.Image.prototype.load = function() {\n  if (this.state == ol.Image.State.IDLE) {\n    this.state = ol.Image.State.LOADING;\n    this.changed();\n\n    var sourceState = this.sourceImage_.getState();\n    if (sourceState == ol.Image.State.LOADED ||\n        sourceState == ol.Image.State.ERROR) {\n      this.reproject_();\n    } else {\n      this.sourceListenerKey_ = ol.events.listen(this.sourceImage_,\n          ol.events.EventType.CHANGE, function(e) {\n            var sourceState = this.sourceImage_.getState();\n            if (sourceState == ol.Image.State.LOADED ||\n                sourceState == ol.Image.State.ERROR) {\n              this.unlistenSource_();\n              this.reproject_();\n            }\n          }, this);\n      this.sourceImage_.load();\n    }\n  }\n};\n\n\n/**\n * @private\n */\nol.reproj.Image.prototype.unlistenSource_ = function() {\n  ol.DEBUG && console.assert(this.sourceListenerKey_,\n      'this.sourceListenerKey_ should not be null');\n  ol.events.unlistenByKey(/** @type {!ol.EventsKey} */ (this.sourceListenerKey_));\n  this.sourceListenerKey_ = null;\n};\n\ngoog.provide('ol.source.Source');\n\ngoog.require('ol');\ngoog.require('ol.Attribution');\ngoog.require('ol.Object');\ngoog.require('ol.proj');\ngoog.require('ol.source.State');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for {@link ol.layer.Layer} sources.\n *\n * A generic `change` event is triggered when the state of the source changes.\n *\n * @constructor\n * @extends {ol.Object}\n * @param {ol.SourceSourceOptions} options Source options.\n * @api stable\n */\nol.source.Source = function(options) {\n\n  ol.Object.call(this);\n\n  /**\n   * @private\n   * @type {ol.proj.Projection}\n   */\n  this.projection_ = ol.proj.get(options.projection);\n\n  /**\n   * @private\n   * @type {Array.<ol.Attribution>}\n   */\n  this.attributions_ = ol.source.Source.toAttributionsArray_(options.attributions);\n\n  /**\n   * @private\n   * @type {string|olx.LogoOptions|undefined}\n   */\n  this.logo_ = options.logo;\n\n  /**\n   * @private\n   * @type {ol.source.State}\n   */\n  this.state_ = options.state !== undefined ?\n      options.state : ol.source.State.READY;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false;\n\n};\nol.inherits(ol.source.Source, ol.Object);\n\n/**\n * Turns various ways of defining an attribution to an array of `ol.Attributions`.\n *\n * @param {ol.AttributionLike|undefined}\n *     attributionLike The attributions as string, array of strings,\n *     `ol.Attribution`, array of `ol.Attribution` or undefined.\n * @return {Array.<ol.Attribution>} The array of `ol.Attribution` or null if\n *     `undefined` was given.\n */\nol.source.Source.toAttributionsArray_ = function(attributionLike) {\n  if (typeof attributionLike === 'string') {\n    return [new ol.Attribution({html: attributionLike})];\n  } else if (attributionLike instanceof ol.Attribution) {\n    return [attributionLike];\n  } else if (Array.isArray(attributionLike)) {\n    var len = attributionLike.length;\n    var attributions = new Array(len);\n    for (var i = 0; i < len; i++) {\n      var item = attributionLike[i];\n      if (typeof item === 'string') {\n        attributions[i] = new ol.Attribution({html: item});\n      } else {\n        attributions[i] = item;\n      }\n    }\n    return attributions;\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {number} hitTolerance Hit tolerance in pixels.\n * @param {Object.<string, boolean>} skippedFeatureUids Skipped feature uids.\n * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature\n *     callback.\n * @return {T|undefined} Callback result.\n * @template T\n */\nol.source.Source.prototype.forEachFeatureAtCoordinate = ol.nullFunction;\n\n\n/**\n * Get the attributions of the source.\n * @return {Array.<ol.Attribution>} Attributions.\n * @api stable\n */\nol.source.Source.prototype.getAttributions = function() {\n  return this.attributions_;\n};\n\n\n/**\n * Get the logo of the source.\n * @return {string|olx.LogoOptions|undefined} Logo.\n * @api stable\n */\nol.source.Source.prototype.getLogo = function() {\n  return this.logo_;\n};\n\n\n/**\n * Get the projection of the source.\n * @return {ol.proj.Projection} Projection.\n * @api\n */\nol.source.Source.prototype.getProjection = function() {\n  return this.projection_;\n};\n\n\n/**\n * @abstract\n * @return {Array.<number>|undefined} Resolutions.\n */\nol.source.Source.prototype.getResolutions = function() {};\n\n\n/**\n * Get the state of the source, see {@link ol.source.State} for possible states.\n * @return {ol.source.State} State.\n * @api\n */\nol.source.Source.prototype.getState = function() {\n  return this.state_;\n};\n\n\n/**\n * @return {boolean|undefined} Wrap X.\n */\nol.source.Source.prototype.getWrapX = function() {\n  return this.wrapX_;\n};\n\n\n/**\n * Refreshes the source and finally dispatches a 'change' event.\n * @api\n */\nol.source.Source.prototype.refresh = function() {\n  this.changed();\n};\n\n\n/**\n * Set the attributions of the source.\n * @param {ol.AttributionLike|undefined} attributions Attributions.\n *     Can be passed as `string`, `Array<string>`, `{@link ol.Attribution}`,\n *     `Array<{@link ol.Attribution}>` or `undefined`.\n * @api\n */\nol.source.Source.prototype.setAttributions = function(attributions) {\n  this.attributions_ = ol.source.Source.toAttributionsArray_(attributions);\n  this.changed();\n};\n\n\n/**\n * Set the logo of the source.\n * @param {string|olx.LogoOptions|undefined} logo Logo.\n */\nol.source.Source.prototype.setLogo = function(logo) {\n  this.logo_ = logo;\n};\n\n\n/**\n * Set the state of the source.\n * @param {ol.source.State} state State.\n * @protected\n */\nol.source.Source.prototype.setState = function(state) {\n  this.state_ = state;\n  this.changed();\n};\n\ngoog.provide('ol.source.Image');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.array');\ngoog.require('ol.events.Event');\ngoog.require('ol.extent');\ngoog.require('ol.proj');\ngoog.require('ol.reproj.Image');\ngoog.require('ol.source.Source');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for sources providing a single image.\n *\n * @constructor\n * @extends {ol.source.Source}\n * @param {ol.SourceImageOptions} options Single image source options.\n * @api\n */\nol.source.Image = function(options) {\n\n  ol.source.Source.call(this, {\n    attributions: options.attributions,\n    extent: options.extent,\n    logo: options.logo,\n    projection: options.projection,\n    state: options.state\n  });\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.resolutions_ = options.resolutions !== undefined ?\n      options.resolutions : null;\n  ol.DEBUG && console.assert(!this.resolutions_ ||\n      ol.array.isSorted(this.resolutions_,\n          function(a, b) {\n            return b - a;\n          }, true), 'resolutions must be null or sorted in descending order');\n\n\n  /**\n   * @private\n   * @type {ol.reproj.Image}\n   */\n  this.reprojectedImage_ = null;\n\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.reprojectedRevision_ = 0;\n\n};\nol.inherits(ol.source.Image, ol.source.Source);\n\n\n/**\n * @return {Array.<number>} Resolutions.\n */\nol.source.Image.prototype.getResolutions = function() {\n  return this.resolutions_;\n};\n\n\n/**\n * @protected\n * @param {number} resolution Resolution.\n * @return {number} Resolution.\n */\nol.source.Image.prototype.findNearestResolution = function(resolution) {\n  if (this.resolutions_) {\n    var idx = ol.array.linearFindNearest(this.resolutions_, resolution, 0);\n    resolution = this.resolutions_[idx];\n  }\n  return resolution;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @return {ol.ImageBase} Single image.\n */\nol.source.Image.prototype.getImage = function(extent, resolution, pixelRatio, projection) {\n  var sourceProjection = this.getProjection();\n  if (!ol.ENABLE_RASTER_REPROJECTION ||\n      !sourceProjection ||\n      !projection ||\n      ol.proj.equivalent(sourceProjection, projection)) {\n    if (sourceProjection) {\n      projection = sourceProjection;\n    }\n    return this.getImageInternal(extent, resolution, pixelRatio, projection);\n  } else {\n    if (this.reprojectedImage_) {\n      if (this.reprojectedRevision_ == this.getRevision() &&\n          ol.proj.equivalent(\n              this.reprojectedImage_.getProjection(), projection) &&\n          this.reprojectedImage_.getResolution() == resolution &&\n          this.reprojectedImage_.getPixelRatio() == pixelRatio &&\n          ol.extent.equals(this.reprojectedImage_.getExtent(), extent)) {\n        return this.reprojectedImage_;\n      }\n      this.reprojectedImage_.dispose();\n      this.reprojectedImage_ = null;\n    }\n\n    this.reprojectedImage_ = new ol.reproj.Image(\n        sourceProjection, projection, extent, resolution, pixelRatio,\n        function(extent, resolution, pixelRatio) {\n          return this.getImageInternal(extent, resolution,\n              pixelRatio, sourceProjection);\n        }.bind(this));\n    this.reprojectedRevision_ = this.getRevision();\n\n    return this.reprojectedImage_;\n  }\n};\n\n\n/**\n * @abstract\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @return {ol.ImageBase} Single image.\n * @protected\n */\nol.source.Image.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {};\n\n\n/**\n * Handle image change events.\n * @param {ol.events.Event} event Event.\n * @protected\n */\nol.source.Image.prototype.handleImageChange = function(event) {\n  var image = /** @type {ol.Image} */ (event.target);\n  switch (image.getState()) {\n    case ol.Image.State.LOADING:\n      this.dispatchEvent(\n          new ol.source.Image.Event(ol.source.Image.EventType.IMAGELOADSTART,\n              image));\n      break;\n    case ol.Image.State.LOADED:\n      this.dispatchEvent(\n          new ol.source.Image.Event(ol.source.Image.EventType.IMAGELOADEND,\n              image));\n      break;\n    case ol.Image.State.ERROR:\n      this.dispatchEvent(\n          new ol.source.Image.Event(ol.source.Image.EventType.IMAGELOADERROR,\n              image));\n      break;\n    default:\n      // pass\n  }\n};\n\n\n/**\n * Default image load function for image sources that use ol.Image image\n * instances.\n * @param {ol.Image} image Image.\n * @param {string} src Source.\n */\nol.source.Image.defaultImageLoadFunction = function(image, src) {\n  image.getImage().src = src;\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.source.Image} instances are instances of this\n * type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.source.ImageEvent}\n * @param {string} type Type.\n * @param {ol.Image} image The image.\n */\nol.source.Image.Event = function(type, image) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The image related to the event.\n   * @type {ol.Image}\n   * @api\n   */\n  this.image = image;\n\n};\nol.inherits(ol.source.Image.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.source.Image.EventType = {\n\n  /**\n   * Triggered when an image starts loading.\n   * @event ol.source.Image.Event#imageloadstart\n   * @api\n   */\n  IMAGELOADSTART: 'imageloadstart',\n\n  /**\n   * Triggered when an image finishes loading.\n   * @event ol.source.Image.Event#imageloadend\n   * @api\n   */\n  IMAGELOADEND: 'imageloadend',\n\n  /**\n   * Triggered if image loading results in an error.\n   * @event ol.source.Image.Event#imageloaderror\n   * @api\n   */\n  IMAGELOADERROR: 'imageloaderror'\n\n};\n\ngoog.provide('ol.source.ImageCanvas');\n\ngoog.require('ol');\ngoog.require('ol.ImageCanvas');\ngoog.require('ol.extent');\ngoog.require('ol.source.Image');\n\n\n/**\n * @classdesc\n * Base class for image sources where a canvas element is the image.\n *\n * @constructor\n * @extends {ol.source.Image}\n * @param {olx.source.ImageCanvasOptions} options Constructor options.\n * @api\n */\nol.source.ImageCanvas = function(options) {\n\n  ol.source.Image.call(this, {\n    attributions: options.attributions,\n    logo: options.logo,\n    projection: options.projection,\n    resolutions: options.resolutions,\n    state: options.state\n  });\n\n  /**\n   * @private\n   * @type {ol.CanvasFunctionType}\n   */\n  this.canvasFunction_ = options.canvasFunction;\n\n  /**\n   * @private\n   * @type {ol.ImageCanvas}\n   */\n  this.canvas_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.ratio_ = options.ratio !== undefined ?\n      options.ratio : 1.5;\n\n};\nol.inherits(ol.source.ImageCanvas, ol.source.Image);\n\n\n/**\n * @inheritDoc\n */\nol.source.ImageCanvas.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {\n  resolution = this.findNearestResolution(resolution);\n\n  var canvas = this.canvas_;\n  if (canvas &&\n      this.renderedRevision_ == this.getRevision() &&\n      canvas.getResolution() == resolution &&\n      canvas.getPixelRatio() == pixelRatio &&\n      ol.extent.containsExtent(canvas.getExtent(), extent)) {\n    return canvas;\n  }\n\n  extent = extent.slice();\n  ol.extent.scaleFromCenter(extent, this.ratio_);\n  var width = ol.extent.getWidth(extent) / resolution;\n  var height = ol.extent.getHeight(extent) / resolution;\n  var size = [width * pixelRatio, height * pixelRatio];\n\n  var canvasElement = this.canvasFunction_(\n      extent, resolution, pixelRatio, size, projection);\n  if (canvasElement) {\n    canvas = new ol.ImageCanvas(extent, resolution, pixelRatio,\n        this.getAttributions(), canvasElement);\n  }\n  this.canvas_ = canvas;\n  this.renderedRevision_ = this.getRevision();\n\n  return canvas;\n};\n\ngoog.provide('ol.source.ImageVector');\n\ngoog.require('ol');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.render.canvas.ReplayGroup');\ngoog.require('ol.renderer.vector');\ngoog.require('ol.source.ImageCanvas');\ngoog.require('ol.style.Style');\ngoog.require('ol.transform');\n\n\n/**\n * @classdesc\n * An image source whose images are canvas elements into which vector features\n * read from a vector source (`ol.source.Vector`) are drawn. An\n * `ol.source.ImageVector` object is to be used as the `source` of an image\n * layer (`ol.layer.Image`). Image layers are rotated, scaled, and translated,\n * as opposed to being re-rendered, during animations and interactions. So, like\n * any other image layer, an image layer configured with an\n * `ol.source.ImageVector` will exhibit this behaviour. This is in contrast to a\n * vector layer, where vector features are re-drawn during animations and\n * interactions.\n *\n * @constructor\n * @extends {ol.source.ImageCanvas}\n * @param {olx.source.ImageVectorOptions} options Options.\n * @api\n */\nol.source.ImageVector = function(options) {\n\n  /**\n   * @private\n   * @type {ol.source.Vector}\n   */\n  this.source_ = options.source;\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.transform_ = ol.transform.create();\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.canvasContext_ = ol.dom.createCanvasContext2D();\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.canvasSize_ = [0, 0];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderBuffer_ = options.renderBuffer == undefined ? 100 : options.renderBuffer;\n\n  /**\n   * @private\n   * @type {ol.render.canvas.ReplayGroup}\n   */\n  this.replayGroup_ = null;\n\n  ol.source.ImageCanvas.call(this, {\n    attributions: options.attributions,\n    canvasFunction: this.canvasFunctionInternal_.bind(this),\n    logo: options.logo,\n    projection: options.projection,\n    ratio: options.ratio,\n    resolutions: options.resolutions,\n    state: this.source_.getState()\n  });\n\n  /**\n   * User provided style.\n   * @type {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}\n   * @private\n   */\n  this.style_ = null;\n\n  /**\n   * Style function for use within the library.\n   * @type {ol.StyleFunction|undefined}\n   * @private\n   */\n  this.styleFunction_ = undefined;\n\n  this.setStyle(options.style);\n\n  ol.events.listen(this.source_, ol.events.EventType.CHANGE,\n      this.handleSourceChange_, this);\n\n};\nol.inherits(ol.source.ImageVector, ol.source.ImageCanvas);\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Size} size Size.\n * @param {ol.proj.Projection} projection Projection;\n * @return {HTMLCanvasElement} Canvas element.\n * @private\n */\nol.source.ImageVector.prototype.canvasFunctionInternal_ = function(extent, resolution, pixelRatio, size, projection) {\n\n  var replayGroup = new ol.render.canvas.ReplayGroup(\n      ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,\n      resolution, this.source_.getOverlaps(), this.renderBuffer_);\n\n  this.source_.loadFeatures(extent, resolution, projection);\n\n  var loading = false;\n  this.source_.forEachFeatureInExtent(extent,\n      /**\n       * @param {ol.Feature} feature Feature.\n       */\n      function(feature) {\n        loading = loading ||\n            this.renderFeature_(feature, resolution, pixelRatio, replayGroup);\n      }, this);\n  replayGroup.finish();\n\n  if (loading) {\n    return null;\n  }\n\n  if (this.canvasSize_[0] != size[0] || this.canvasSize_[1] != size[1]) {\n    this.canvasContext_.canvas.width = size[0];\n    this.canvasContext_.canvas.height = size[1];\n    this.canvasSize_[0] = size[0];\n    this.canvasSize_[1] = size[1];\n  } else {\n    this.canvasContext_.clearRect(0, 0, size[0], size[1]);\n  }\n\n  var transform = this.getTransform_(ol.extent.getCenter(extent),\n      resolution, pixelRatio, size);\n  replayGroup.replay(this.canvasContext_, pixelRatio, transform, 0, {});\n\n  this.replayGroup_ = replayGroup;\n\n  return this.canvasContext_.canvas;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function(\n    coordinate, resolution, rotation, hitTolerance, skippedFeatureUids, callback) {\n  if (!this.replayGroup_) {\n    return undefined;\n  } else {\n    /** @type {Object.<string, boolean>} */\n    var features = {};\n    return this.replayGroup_.forEachFeatureAtCoordinate(\n        coordinate, resolution, 0, hitTolerance, skippedFeatureUids,\n        /**\n         * @param {ol.Feature|ol.render.Feature} feature Feature.\n         * @return {?} Callback result.\n         */\n        function(feature) {\n          var key = ol.getUid(feature).toString();\n          if (!(key in features)) {\n            features[key] = true;\n            return callback(feature);\n          }\n        });\n  }\n};\n\n\n/**\n * Get a reference to the wrapped source.\n * @return {ol.source.Vector} Source.\n * @api\n */\nol.source.ImageVector.prototype.getSource = function() {\n  return this.source_;\n};\n\n\n/**\n * Get the style for features.  This returns whatever was passed to the `style`\n * option at construction or to the `setStyle` method.\n * @return {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}\n *     Layer style.\n * @api stable\n */\nol.source.ImageVector.prototype.getStyle = function() {\n  return this.style_;\n};\n\n\n/**\n * Get the style function.\n * @return {ol.StyleFunction|undefined} Layer style function.\n * @api stable\n */\nol.source.ImageVector.prototype.getStyleFunction = function() {\n  return this.styleFunction_;\n};\n\n\n/**\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Size} size Size.\n * @return {!ol.Transform} Transform.\n * @private\n */\nol.source.ImageVector.prototype.getTransform_ = function(center, resolution, pixelRatio, size) {\n  var dx1 = size[0] / 2;\n  var dy1 = size[1] / 2;\n  var sx = pixelRatio / resolution;\n  var sy = -sx;\n  var dx2 = -center[0];\n  var dy2 = -center[1];\n\n  return ol.transform.compose(this.transform_, dx1, dy1, sx, sy, 0, dx2, dy2);\n};\n\n\n/**\n * Handle changes in image style state.\n * @param {ol.events.Event} event Image style change event.\n * @private\n */\nol.source.ImageVector.prototype.handleImageChange_ = function(event) {\n  this.changed();\n};\n\n\n/**\n * @private\n */\nol.source.ImageVector.prototype.handleSourceChange_ = function() {\n  // setState will trigger a CHANGE event, so we always rely\n  // change events by calling setState.\n  this.setState(this.source_.getState());\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.\n * @return {boolean} `true` if an image is loading.\n * @private\n */\nol.source.ImageVector.prototype.renderFeature_ = function(feature, resolution, pixelRatio, replayGroup) {\n  var styles;\n  var styleFunction = feature.getStyleFunction();\n  if (styleFunction) {\n    styles = styleFunction.call(feature, resolution);\n  } else if (this.styleFunction_) {\n    styles = this.styleFunction_(feature, resolution);\n  }\n  if (!styles) {\n    return false;\n  }\n  var i, ii, loading = false;\n  if (!Array.isArray(styles)) {\n    styles = [styles];\n  }\n  for (i = 0, ii = styles.length; i < ii; ++i) {\n    loading = ol.renderer.vector.renderFeature(\n        replayGroup, feature, styles[i],\n        ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),\n        this.handleImageChange_, this) || loading;\n  }\n  return loading;\n};\n\n\n/**\n * Set the style for features.  This can be a single style object, an array\n * of styles, or a function that takes a feature and resolution and returns\n * an array of styles. If it is `undefined` the default style is used. If\n * it is `null` the layer has no style (a `null` style), so only features\n * that have their own styles will be rendered in the layer. See\n * {@link ol.style} for information on the default style.\n * @param {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined}\n *     style Layer style.\n * @api stable\n */\nol.source.ImageVector.prototype.setStyle = function(style) {\n  this.style_ = style !== undefined ? style : ol.style.Style.defaultFunction;\n  this.styleFunction_ = !style ?\n      undefined : ol.style.Style.createFunction(this.style_);\n  this.changed();\n};\n\ngoog.provide('ol.renderer.webgl.ImageLayer');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.dom');\ngoog.require('ol.extent');\ngoog.require('ol.functions');\ngoog.require('ol.proj');\ngoog.require('ol.renderer.webgl.Layer');\ngoog.require('ol.source.ImageVector');\ngoog.require('ol.transform');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Context');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.webgl.Layer}\n * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.\n * @param {ol.layer.Image} imageLayer Tile layer.\n */\nol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) {\n\n  ol.renderer.webgl.Layer.call(this, mapRenderer, imageLayer);\n\n  /**\n   * The last rendered image.\n   * @private\n   * @type {?ol.ImageBase}\n   */\n  this.image_ = null;\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.hitCanvasContext_ = null;\n\n  /**\n   * @private\n   * @type {?ol.Transform}\n   */\n  this.hitTransformationMatrix_ = null;\n\n};\nol.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer);\n\n\n/**\n * @param {ol.ImageBase} image Image.\n * @private\n * @return {WebGLTexture} Texture.\n */\nol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) {\n\n  // We meet the conditions to work with non-power of two textures.\n  // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support\n  // http://learningwebgl.com/blog/?p=2101\n\n  var imageElement = image.getImage();\n  var gl = this.mapRenderer.getGL();\n\n  return ol.webgl.Context.createTexture(\n      gl, imageElement, ol.webgl.CLAMP_TO_EDGE, ol.webgl.CLAMP_TO_EDGE);\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {\n  var layer = this.getLayer();\n  var source = layer.getSource();\n  var resolution = frameState.viewState.resolution;\n  var rotation = frameState.viewState.rotation;\n  var skippedFeatureUids = frameState.skippedFeatureUids;\n  return source.forEachFeatureAtCoordinate(\n      coordinate, resolution, rotation, hitTolerance, skippedFeatureUids,\n\n      /**\n       * @param {ol.Feature|ol.render.Feature} feature Feature.\n       * @return {?} Callback result.\n       */\n      function(feature) {\n        return callback.call(thisArg, feature, layer);\n      });\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.ImageLayer.prototype.prepareFrame = function(frameState, layerState, context) {\n\n  var gl = this.mapRenderer.getGL();\n\n  var pixelRatio = frameState.pixelRatio;\n  var viewState = frameState.viewState;\n  var viewCenter = viewState.center;\n  var viewResolution = viewState.resolution;\n  var viewRotation = viewState.rotation;\n\n  var image = this.image_;\n  var texture = this.texture;\n  var imageLayer = /** @type {ol.layer.Image} */ (this.getLayer());\n  var imageSource = imageLayer.getSource();\n\n  var hints = frameState.viewHints;\n\n  var renderedExtent = frameState.extent;\n  if (layerState.extent !== undefined) {\n    renderedExtent = ol.extent.getIntersection(\n        renderedExtent, layerState.extent);\n  }\n  if (!hints[ol.View.Hint.ANIMATING] && !hints[ol.View.Hint.INTERACTING] &&\n      !ol.extent.isEmpty(renderedExtent)) {\n    var projection = viewState.projection;\n    if (!ol.ENABLE_RASTER_REPROJECTION) {\n      var sourceProjection = imageSource.getProjection();\n      if (sourceProjection) {\n        ol.DEBUG && console.assert(ol.proj.equivalent(projection, sourceProjection),\n            'projection and sourceProjection are equivalent');\n        projection = sourceProjection;\n      }\n    }\n    var image_ = imageSource.getImage(renderedExtent, viewResolution,\n        pixelRatio, projection);\n    if (image_) {\n      var loaded = this.loadImage(image_);\n      if (loaded) {\n        image = image_;\n        texture = this.createTexture_(image_);\n        if (this.texture) {\n          /**\n           * @param {WebGLRenderingContext} gl GL.\n           * @param {WebGLTexture} texture Texture.\n           */\n          var postRenderFunction = function(gl, texture) {\n            if (!gl.isContextLost()) {\n              gl.deleteTexture(texture);\n            }\n          }.bind(null, gl, this.texture);\n          frameState.postRenderFunctions.push(\n            /** @type {ol.PostRenderFunction} */ (postRenderFunction)\n          );\n        }\n      }\n    }\n  }\n\n  if (image) {\n    ol.DEBUG && console.assert(texture, 'texture is truthy');\n\n    var canvas = this.mapRenderer.getContext().getCanvas();\n\n    this.updateProjectionMatrix_(canvas.width, canvas.height,\n        pixelRatio, viewCenter, viewResolution, viewRotation,\n        image.getExtent());\n    this.hitTransformationMatrix_ = null;\n\n    // Translate and scale to flip the Y coord.\n    var texCoordMatrix = this.texCoordMatrix;\n    ol.transform.reset(texCoordMatrix);\n    ol.transform.scale(texCoordMatrix, 1, -1);\n    ol.transform.translate(texCoordMatrix, 0, -1);\n\n    this.image_ = image;\n    this.texture = texture;\n\n    this.updateAttributions(frameState.attributions, image.getAttributions());\n    this.updateLogos(frameState, imageSource);\n  }\n\n  return !!image;\n};\n\n\n/**\n * @param {number} canvasWidth Canvas width.\n * @param {number} canvasHeight Canvas height.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.Coordinate} viewCenter View center.\n * @param {number} viewResolution View resolution.\n * @param {number} viewRotation View rotation.\n * @param {ol.Extent} imageExtent Image extent.\n * @private\n */\nol.renderer.webgl.ImageLayer.prototype.updateProjectionMatrix_ = function(canvasWidth, canvasHeight, pixelRatio,\n        viewCenter, viewResolution, viewRotation, imageExtent) {\n\n  var canvasExtentWidth = canvasWidth * viewResolution;\n  var canvasExtentHeight = canvasHeight * viewResolution;\n\n  var projectionMatrix = this.projectionMatrix;\n  ol.transform.reset(projectionMatrix);\n  ol.transform.scale(projectionMatrix,\n      pixelRatio * 2 / canvasExtentWidth,\n      pixelRatio * 2 / canvasExtentHeight);\n  ol.transform.rotate(projectionMatrix, -viewRotation);\n  ol.transform.translate(projectionMatrix,\n      imageExtent[0] - viewCenter[0],\n      imageExtent[1] - viewCenter[1]);\n  ol.transform.scale(projectionMatrix,\n      (imageExtent[2] - imageExtent[0]) / 2,\n      (imageExtent[3] - imageExtent[1]) / 2);\n  ol.transform.translate(projectionMatrix, 1, 1);\n\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = function(coordinate, frameState) {\n  var hasFeature = this.forEachFeatureAtCoordinate(\n      coordinate, frameState, 0, ol.functions.TRUE, this);\n  return hasFeature !== undefined;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {\n  if (!this.image_ || !this.image_.getImage()) {\n    return undefined;\n  }\n\n  if (this.getLayer().getSource() instanceof ol.source.ImageVector) {\n    // for ImageVector sources use the original hit-detection logic,\n    // so that for example also transparent polygons are detected\n    var coordinate = ol.transform.apply(\n        frameState.pixelToCoordinateTransform, pixel.slice());\n    var hasFeature = this.forEachFeatureAtCoordinate(\n        coordinate, frameState, 0, ol.functions.TRUE, this);\n\n    if (hasFeature) {\n      return callback.call(thisArg, this.getLayer(), null);\n    } else {\n      return undefined;\n    }\n  } else {\n    var imageSize =\n        [this.image_.getImage().width, this.image_.getImage().height];\n\n    if (!this.hitTransformationMatrix_) {\n      this.hitTransformationMatrix_ = this.getHitTransformationMatrix_(\n          frameState.size, imageSize);\n    }\n\n    var pixelOnFrameBuffer = ol.transform.apply(\n        this.hitTransformationMatrix_, pixel.slice());\n\n    if (pixelOnFrameBuffer[0] < 0 || pixelOnFrameBuffer[0] > imageSize[0] ||\n        pixelOnFrameBuffer[1] < 0 || pixelOnFrameBuffer[1] > imageSize[1]) {\n      // outside the image, no need to check\n      return undefined;\n    }\n\n    if (!this.hitCanvasContext_) {\n      this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);\n    }\n\n    this.hitCanvasContext_.clearRect(0, 0, 1, 1);\n    this.hitCanvasContext_.drawImage(this.image_.getImage(),\n        pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 0, 0, 1, 1);\n\n    var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data;\n    if (imageData[3] > 0) {\n      return callback.call(thisArg, this.getLayer(),  imageData);\n    } else {\n      return undefined;\n    }\n  }\n};\n\n\n/**\n * The transformation matrix to get the pixel on the image for a\n * pixel on the map.\n * @param {ol.Size} mapSize The map size.\n * @param {ol.Size} imageSize The image size.\n * @return {ol.Transform} The transformation matrix.\n * @private\n */\nol.renderer.webgl.ImageLayer.prototype.getHitTransformationMatrix_ = function(mapSize, imageSize) {\n  // the first matrix takes a map pixel, flips the y-axis and scales to\n  // a range between -1 ... 1\n  var mapCoordTransform = ol.transform.create();\n  ol.transform.translate(mapCoordTransform, -1, -1);\n  ol.transform.scale(mapCoordTransform, 2 / mapSize[0], 2 / mapSize[1]);\n  ol.transform.translate(mapCoordTransform, 0, mapSize[1]);\n  ol.transform.scale(mapCoordTransform, 1, -1);\n\n  // the second matrix is the inverse of the projection matrix used in the\n  // shader for drawing\n  var projectionMatrixInv = ol.transform.invert(this.projectionMatrix.slice());\n\n  // the third matrix scales to the image dimensions and flips the y-axis again\n  var transform = ol.transform.create();\n  ol.transform.translate(transform, 0, imageSize[1]);\n  ol.transform.scale(transform, 1, -1);\n  ol.transform.scale(transform, imageSize[0] / 2, imageSize[1] / 2);\n  ol.transform.translate(transform, 1, 1);\n\n  ol.transform.multiply(transform, projectionMatrixInv);\n  ol.transform.multiply(transform, mapCoordTransform);\n\n  return transform;\n};\n\n// This file is automatically generated, do not edit\ngoog.provide('ol.renderer.webgl.tilelayershader');\n\ngoog.require('ol');\ngoog.require('ol.webgl.Fragment');\ngoog.require('ol.webgl.Vertex');\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Fragment}\n * @struct\n */\nol.renderer.webgl.tilelayershader.Fragment = function() {\n  ol.webgl.Fragment.call(this, ol.renderer.webgl.tilelayershader.Fragment.SOURCE);\n};\nol.inherits(ol.renderer.webgl.tilelayershader.Fragment, ol.webgl.Fragment);\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.tilelayershader.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';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.tilelayershader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform sampler2D e;void main(void){gl_FragColor=texture2D(e,a);}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.tilelayershader.Fragment.SOURCE = ol.DEBUG ?\n    ol.renderer.webgl.tilelayershader.Fragment.DEBUG_SOURCE :\n    ol.renderer.webgl.tilelayershader.Fragment.OPTIMIZED_SOURCE;\n\n\nol.renderer.webgl.tilelayershader.fragment = new ol.renderer.webgl.tilelayershader.Fragment();\n\n\n/**\n * @constructor\n * @extends {ol.webgl.Vertex}\n * @struct\n */\nol.renderer.webgl.tilelayershader.Vertex = function() {\n  ol.webgl.Vertex.call(this, ol.renderer.webgl.tilelayershader.Vertex.SOURCE);\n};\nol.inherits(ol.renderer.webgl.tilelayershader.Vertex, ol.webgl.Vertex);\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.tilelayershader.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';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.tilelayershader.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;}';\n\n\n/**\n * @const\n * @type {string}\n */\nol.renderer.webgl.tilelayershader.Vertex.SOURCE = ol.DEBUG ?\n    ol.renderer.webgl.tilelayershader.Vertex.DEBUG_SOURCE :\n    ol.renderer.webgl.tilelayershader.Vertex.OPTIMIZED_SOURCE;\n\n\nol.renderer.webgl.tilelayershader.vertex = new ol.renderer.webgl.tilelayershader.Vertex();\n\n\n/**\n * @constructor\n * @param {WebGLRenderingContext} gl GL.\n * @param {WebGLProgram} program Program.\n * @struct\n */\nol.renderer.webgl.tilelayershader.Locations = function(gl, program) {\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_texture = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_texture' : 'e');\n\n  /**\n   * @type {WebGLUniformLocation}\n   */\n  this.u_tileOffset = gl.getUniformLocation(\n      program, ol.DEBUG ? 'u_tileOffset' : 'd');\n\n  /**\n   * @type {number}\n   */\n  this.a_position = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_position' : 'b');\n\n  /**\n   * @type {number}\n   */\n  this.a_texCoord = gl.getAttribLocation(\n      program, ol.DEBUG ? 'a_texCoord' : 'c');\n};\n\n// FIXME large resolutions lead to too large framebuffers :-(\n// FIXME animated shaders! check in redraw\n\ngoog.provide('ol.renderer.webgl.TileLayer');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.TileRange');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.math');\ngoog.require('ol.renderer.webgl.Layer');\ngoog.require('ol.renderer.webgl.tilelayershader');\ngoog.require('ol.size');\ngoog.require('ol.transform');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Buffer');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.webgl.Layer}\n * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.\n * @param {ol.layer.Tile} tileLayer Tile layer.\n */\nol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) {\n\n  ol.renderer.webgl.Layer.call(this, mapRenderer, tileLayer);\n\n  /**\n   * @private\n   * @type {ol.webgl.Fragment}\n   */\n  this.fragmentShader_ = ol.renderer.webgl.tilelayershader.fragment;\n\n  /**\n   * @private\n   * @type {ol.webgl.Vertex}\n   */\n  this.vertexShader_ = ol.renderer.webgl.tilelayershader.vertex;\n\n  /**\n   * @private\n   * @type {ol.renderer.webgl.tilelayershader.Locations}\n   */\n  this.locations_ = null;\n\n  /**\n   * @private\n   * @type {ol.webgl.Buffer}\n   */\n  this.renderArrayBuffer_ = new ol.webgl.Buffer([\n    0, 0, 0, 1,\n    1, 0, 1, 1,\n    0, 1, 0, 0,\n    1, 1, 1, 0\n  ]);\n\n  /**\n   * @private\n   * @type {ol.TileRange}\n   */\n  this.renderedTileRange_ = null;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.renderedFramebufferExtent_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_ = -1;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.tmpSize_ = [0, 0];\n\n};\nol.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer);\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.TileLayer.prototype.disposeInternal = function() {\n  var context = this.mapRenderer.getContext();\n  context.deleteBuffer(this.renderArrayBuffer_);\n  ol.renderer.webgl.Layer.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Create a function that adds loaded tiles to the tile lookup.\n * @param {ol.source.Tile} source Tile source.\n * @param {ol.proj.Projection} projection Projection of the tiles.\n * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded\n *     tiles by zoom level.\n * @return {function(number, ol.TileRange):boolean} A function that can be\n *     called with a zoom level and a tile range to add loaded tiles to the\n *     lookup.\n * @protected\n */\nol.renderer.webgl.TileLayer.prototype.createLoadedTileFinder = function(source, projection, tiles) {\n  var mapRenderer = this.mapRenderer;\n\n  return (\n      /**\n       * @param {number} zoom Zoom level.\n       * @param {ol.TileRange} tileRange Tile range.\n       * @return {boolean} The tile range is fully loaded.\n       */\n      function(zoom, tileRange) {\n        function callback(tile) {\n          var loaded = mapRenderer.isTileTextureLoaded(tile);\n          if (loaded) {\n            if (!tiles[zoom]) {\n              tiles[zoom] = {};\n            }\n            tiles[zoom][tile.tileCoord.toString()] = tile;\n          }\n          return loaded;\n        }\n        return source.forEachLoadedTile(projection, zoom, tileRange, callback);\n      });\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() {\n  ol.renderer.webgl.Layer.prototype.handleWebGLContextLost.call(this);\n  this.locations_ = null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.TileLayer.prototype.prepareFrame = function(frameState, layerState, context) {\n\n  var mapRenderer = this.mapRenderer;\n  var gl = context.getGL();\n\n  var viewState = frameState.viewState;\n  var projection = viewState.projection;\n\n  var tileLayer = /** @type {ol.layer.Tile} */ (this.getLayer());\n  var tileSource = tileLayer.getSource();\n  var tileGrid = tileSource.getTileGridForProjection(projection);\n  var z = tileGrid.getZForResolution(viewState.resolution);\n  var tileResolution = tileGrid.getResolution(z);\n\n  var tilePixelSize =\n      tileSource.getTilePixelSize(z, frameState.pixelRatio, projection);\n  var pixelRatio = tilePixelSize[0] /\n      ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0];\n  var tilePixelResolution = tileResolution / pixelRatio;\n  var tileGutter = tileSource.getTilePixelRatio(pixelRatio) * tileSource.getGutter(projection);\n\n  var center = viewState.center;\n  var extent = frameState.extent;\n  var tileRange = tileGrid.getTileRangeForExtentAndResolution(\n      extent, tileResolution);\n\n  var framebufferExtent;\n  if (this.renderedTileRange_ &&\n      this.renderedTileRange_.equals(tileRange) &&\n      this.renderedRevision_ == tileSource.getRevision()) {\n    framebufferExtent = this.renderedFramebufferExtent_;\n  } else {\n\n    var tileRangeSize = tileRange.getSize();\n\n    var maxDimension = Math.max(\n        tileRangeSize[0] * tilePixelSize[0],\n        tileRangeSize[1] * tilePixelSize[1]);\n    var framebufferDimension = ol.math.roundUpToPowerOfTwo(maxDimension);\n    var framebufferExtentDimension = tilePixelResolution * framebufferDimension;\n    var origin = tileGrid.getOrigin(z);\n    var minX = origin[0] +\n        tileRange.minX * tilePixelSize[0] * tilePixelResolution;\n    var minY = origin[1] +\n        tileRange.minY * tilePixelSize[1] * tilePixelResolution;\n    framebufferExtent = [\n      minX, minY,\n      minX + framebufferExtentDimension, minY + framebufferExtentDimension\n    ];\n\n    this.bindFramebuffer(frameState, framebufferDimension);\n    gl.viewport(0, 0, framebufferDimension, framebufferDimension);\n\n    gl.clearColor(0, 0, 0, 0);\n    gl.clear(ol.webgl.COLOR_BUFFER_BIT);\n    gl.disable(ol.webgl.BLEND);\n\n    var program = context.getProgram(this.fragmentShader_, this.vertexShader_);\n    context.useProgram(program);\n    if (!this.locations_) {\n      this.locations_ =\n          new ol.renderer.webgl.tilelayershader.Locations(gl, program);\n    }\n\n    context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.renderArrayBuffer_);\n    gl.enableVertexAttribArray(this.locations_.a_position);\n    gl.vertexAttribPointer(\n        this.locations_.a_position, 2, ol.webgl.FLOAT, false, 16, 0);\n    gl.enableVertexAttribArray(this.locations_.a_texCoord);\n    gl.vertexAttribPointer(\n        this.locations_.a_texCoord, 2, ol.webgl.FLOAT, false, 16, 8);\n    gl.uniform1i(this.locations_.u_texture, 0);\n\n    /**\n     * @type {Object.<number, Object.<string, ol.Tile>>}\n     */\n    var tilesToDrawByZ = {};\n    tilesToDrawByZ[z] = {};\n\n    var findLoadedTiles = this.createLoadedTileFinder(\n        tileSource, projection, tilesToDrawByZ);\n\n    var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();\n    var allTilesLoaded = true;\n    var tmpExtent = ol.extent.createEmpty();\n    var tmpTileRange = new ol.TileRange(0, 0, 0, 0);\n    var childTileRange, drawable, fullyLoaded, tile, tileState;\n    var x, y, tileExtent;\n    for (x = tileRange.minX; x <= tileRange.maxX; ++x) {\n      for (y = tileRange.minY; y <= tileRange.maxY; ++y) {\n\n        tile = tileSource.getTile(z, x, y, pixelRatio, projection);\n        if (layerState.extent !== undefined) {\n          // ignore tiles outside layer extent\n          tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent);\n          if (!ol.extent.intersects(tileExtent, layerState.extent)) {\n            continue;\n          }\n        }\n        tileState = tile.getState();\n        drawable = tileState == ol.Tile.State.LOADED ||\n            tileState == ol.Tile.State.EMPTY ||\n            tileState == ol.Tile.State.ERROR && !useInterimTilesOnError;\n        if (!drawable) {\n          tile = tile.getInterimTile();\n        }\n        tileState = tile.getState();\n        if (tileState == ol.Tile.State.LOADED) {\n          if (mapRenderer.isTileTextureLoaded(tile)) {\n            tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;\n            continue;\n          }\n        } else if (tileState == ol.Tile.State.EMPTY ||\n                   (tileState == ol.Tile.State.ERROR &&\n                    !useInterimTilesOnError)) {\n          continue;\n        }\n\n        allTilesLoaded = false;\n        fullyLoaded = tileGrid.forEachTileCoordParentTileRange(\n            tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);\n        if (!fullyLoaded) {\n          childTileRange = tileGrid.getTileCoordChildTileRange(\n              tile.tileCoord, tmpTileRange, tmpExtent);\n          if (childTileRange) {\n            findLoadedTiles(z + 1, childTileRange);\n          }\n        }\n\n      }\n\n    }\n\n    /** @type {Array.<number>} */\n    var zs = Object.keys(tilesToDrawByZ).map(Number);\n    zs.sort(ol.array.numberSafeCompareFunction);\n    var u_tileOffset = new Float32Array(4);\n    var i, ii, tileKey, tilesToDraw;\n    for (i = 0, ii = zs.length; i < ii; ++i) {\n      tilesToDraw = tilesToDrawByZ[zs[i]];\n      for (tileKey in tilesToDraw) {\n        tile = tilesToDraw[tileKey];\n        tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent);\n        u_tileOffset[0] = 2 * (tileExtent[2] - tileExtent[0]) /\n            framebufferExtentDimension;\n        u_tileOffset[1] = 2 * (tileExtent[3] - tileExtent[1]) /\n            framebufferExtentDimension;\n        u_tileOffset[2] = 2 * (tileExtent[0] - framebufferExtent[0]) /\n            framebufferExtentDimension - 1;\n        u_tileOffset[3] = 2 * (tileExtent[1] - framebufferExtent[1]) /\n            framebufferExtentDimension - 1;\n        gl.uniform4fv(this.locations_.u_tileOffset, u_tileOffset);\n        mapRenderer.bindTileTexture(tile, tilePixelSize,\n            tileGutter * pixelRatio, ol.webgl.LINEAR, ol.webgl.LINEAR);\n        gl.drawArrays(ol.webgl.TRIANGLE_STRIP, 0, 4);\n      }\n    }\n\n    if (allTilesLoaded) {\n      this.renderedTileRange_ = tileRange;\n      this.renderedFramebufferExtent_ = framebufferExtent;\n      this.renderedRevision_ = tileSource.getRevision();\n    } else {\n      this.renderedTileRange_ = null;\n      this.renderedFramebufferExtent_ = null;\n      this.renderedRevision_ = -1;\n      frameState.animate = true;\n    }\n\n  }\n\n  this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);\n  var tileTextureQueue = mapRenderer.getTileTextureQueue();\n  this.manageTilePyramid(\n      frameState, tileSource, tileGrid, pixelRatio, projection, extent, z,\n      tileLayer.getPreload(),\n      /**\n       * @param {ol.Tile} tile Tile.\n       */\n      function(tile) {\n        if (tile.getState() == ol.Tile.State.LOADED &&\n            !mapRenderer.isTileTextureLoaded(tile) &&\n            !tileTextureQueue.isKeyQueued(tile.getKey())) {\n          tileTextureQueue.enqueue([\n            tile,\n            tileGrid.getTileCoordCenter(tile.tileCoord),\n            tileGrid.getResolution(tile.tileCoord[0]),\n            tilePixelSize, tileGutter * pixelRatio\n          ]);\n        }\n      }, this);\n  this.scheduleExpireCache(frameState, tileSource);\n  this.updateLogos(frameState, tileSource);\n\n  var texCoordMatrix = this.texCoordMatrix;\n  ol.transform.reset(texCoordMatrix);\n  ol.transform.translate(texCoordMatrix,\n      (Math.round(center[0] / tileResolution) * tileResolution - framebufferExtent[0]) /\n          (framebufferExtent[2] - framebufferExtent[0]),\n      (Math.round(center[1] / tileResolution) * tileResolution - framebufferExtent[1]) /\n          (framebufferExtent[3] - framebufferExtent[1]));\n  if (viewState.rotation !== 0) {\n    ol.transform.rotate(texCoordMatrix, viewState.rotation);\n  }\n  ol.transform.scale(texCoordMatrix,\n      frameState.size[0] * viewState.resolution /\n          (framebufferExtent[2] - framebufferExtent[0]),\n      frameState.size[1] * viewState.resolution /\n          (framebufferExtent[3] - framebufferExtent[1]));\n  ol.transform.translate(texCoordMatrix, -0.5, -0.5);\n\n  return true;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {\n  if (!this.framebuffer) {\n    return undefined;\n  }\n\n  var pixelOnMapScaled = [\n    pixel[0] / frameState.size[0],\n    (frameState.size[1] - pixel[1]) / frameState.size[1]];\n\n  var pixelOnFrameBufferScaled = ol.transform.apply(\n      this.texCoordMatrix, pixelOnMapScaled.slice());\n  var pixelOnFrameBuffer = [\n    pixelOnFrameBufferScaled[0] * this.framebufferDimension,\n    pixelOnFrameBufferScaled[1] * this.framebufferDimension];\n\n  var gl = this.mapRenderer.getContext().getGL();\n  gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);\n  var imageData = new Uint8Array(4);\n  gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1,\n      gl.RGBA, gl.UNSIGNED_BYTE, imageData);\n\n  if (imageData[3] > 0) {\n    return callback.call(thisArg, this.getLayer(), imageData);\n  } else {\n    return undefined;\n  }\n};\n\ngoog.provide('ol.renderer.webgl.VectorLayer');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.extent');\ngoog.require('ol.render.webgl.ReplayGroup');\ngoog.require('ol.renderer.vector');\ngoog.require('ol.renderer.webgl.Layer');\ngoog.require('ol.transform');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.webgl.Layer}\n * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.\n * @param {ol.layer.Vector} vectorLayer Vector layer.\n */\nol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) {\n\n  ol.renderer.webgl.Layer.call(this, mapRenderer, vectorLayer);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.dirty_ = false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedResolution_ = NaN;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.renderedExtent_ = ol.extent.createEmpty();\n\n  /**\n   * @private\n   * @type {function(ol.Feature, ol.Feature): number|null}\n   */\n  this.renderedRenderOrder_ = null;\n\n  /**\n   * @private\n   * @type {ol.render.webgl.ReplayGroup}\n   */\n  this.replayGroup_ = null;\n\n  /**\n   * The last layer state.\n   * @private\n   * @type {?ol.LayerState}\n   */\n  this.layerState_ = null;\n\n};\nol.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer);\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.VectorLayer.prototype.composeFrame = function(frameState, layerState, context) {\n  this.layerState_ = layerState;\n  var viewState = frameState.viewState;\n  var replayGroup = this.replayGroup_;\n  var size = frameState.size;\n  var pixelRatio = frameState.pixelRatio;\n  var gl = this.mapRenderer.getGL();\n  if (replayGroup && !replayGroup.isEmpty()) {\n    gl.enable(gl.SCISSOR_TEST);\n    gl.scissor(0, 0, size[0] * pixelRatio, size[1] * pixelRatio);\n    replayGroup.replay(context,\n        viewState.center, viewState.resolution, viewState.rotation,\n        size, pixelRatio, layerState.opacity,\n        layerState.managed ? frameState.skippedFeatureUids : {});\n    gl.disable(gl.SCISSOR_TEST);\n  }\n\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() {\n  var replayGroup = this.replayGroup_;\n  if (replayGroup) {\n    var context = this.mapRenderer.getContext();\n    replayGroup.getDeleteResourcesFunction(context)();\n    this.replayGroup_ = null;\n  }\n  ol.renderer.webgl.Layer.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {\n  if (!this.replayGroup_ || !this.layerState_) {\n    return undefined;\n  } else {\n    var context = this.mapRenderer.getContext();\n    var viewState = frameState.viewState;\n    var layer = this.getLayer();\n    var layerState = this.layerState_;\n    /** @type {Object.<string, boolean>} */\n    var features = {};\n    return this.replayGroup_.forEachFeatureAtCoordinate(coordinate,\n        context, viewState.center, viewState.resolution, viewState.rotation,\n        frameState.size, frameState.pixelRatio, layerState.opacity,\n        {},\n        /**\n         * @param {ol.Feature|ol.render.Feature} feature Feature.\n         * @return {?} Callback result.\n         */\n        function(feature) {\n          var key = ol.getUid(feature).toString();\n          if (!(key in features)) {\n            features[key] = true;\n            return callback.call(thisArg, feature, layer);\n          }\n        });\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = function(coordinate, frameState) {\n  if (!this.replayGroup_ || !this.layerState_) {\n    return false;\n  } else {\n    var context = this.mapRenderer.getContext();\n    var viewState = frameState.viewState;\n    var layerState = this.layerState_;\n    return this.replayGroup_.hasFeatureAtCoordinate(coordinate,\n        context, viewState.center, viewState.resolution, viewState.rotation,\n        frameState.size, frameState.pixelRatio, layerState.opacity,\n        frameState.skippedFeatureUids);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {\n  var coordinate = ol.transform.apply(\n      frameState.pixelToCoordinateTransform, pixel.slice());\n  var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState);\n\n  if (hasFeature) {\n    return callback.call(thisArg, this.getLayer(), null);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * Handle changes in image style state.\n * @param {ol.events.Event} event Image style change event.\n * @private\n */\nol.renderer.webgl.VectorLayer.prototype.handleStyleImageChange_ = function(event) {\n  this.renderIfReadyAndVisible();\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.VectorLayer.prototype.prepareFrame = function(frameState, layerState, context) {\n\n  var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());\n  var vectorSource = vectorLayer.getSource();\n\n  this.updateAttributions(\n      frameState.attributions, vectorSource.getAttributions());\n  this.updateLogos(frameState, vectorSource);\n\n  var animating = frameState.viewHints[ol.View.Hint.ANIMATING];\n  var interacting = frameState.viewHints[ol.View.Hint.INTERACTING];\n  var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();\n  var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();\n\n  if (!this.dirty_ && (!updateWhileAnimating && animating) ||\n      (!updateWhileInteracting && interacting)) {\n    return true;\n  }\n\n  var frameStateExtent = frameState.extent;\n  var viewState = frameState.viewState;\n  var projection = viewState.projection;\n  var resolution = viewState.resolution;\n  var pixelRatio = frameState.pixelRatio;\n  var vectorLayerRevision = vectorLayer.getRevision();\n  var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();\n  var vectorLayerRenderOrder = vectorLayer.getRenderOrder();\n\n  if (vectorLayerRenderOrder === undefined) {\n    vectorLayerRenderOrder = ol.renderer.vector.defaultOrder;\n  }\n\n  var extent = ol.extent.buffer(frameStateExtent,\n      vectorLayerRenderBuffer * resolution);\n\n  if (!this.dirty_ &&\n      this.renderedResolution_ == resolution &&\n      this.renderedRevision_ == vectorLayerRevision &&\n      this.renderedRenderOrder_ == vectorLayerRenderOrder &&\n      ol.extent.containsExtent(this.renderedExtent_, extent)) {\n    return true;\n  }\n\n  if (this.replayGroup_) {\n    frameState.postRenderFunctions.push(\n        this.replayGroup_.getDeleteResourcesFunction(context));\n  }\n\n  this.dirty_ = false;\n\n  var replayGroup = new ol.render.webgl.ReplayGroup(\n      ol.renderer.vector.getTolerance(resolution, pixelRatio),\n      extent, vectorLayer.getRenderBuffer());\n  vectorSource.loadFeatures(extent, resolution, projection);\n  /**\n   * @param {ol.Feature} feature Feature.\n   * @this {ol.renderer.webgl.VectorLayer}\n   */\n  var renderFeature = function(feature) {\n    var styles;\n    var styleFunction = feature.getStyleFunction();\n    if (styleFunction) {\n      styles = styleFunction.call(feature, resolution);\n    } else {\n      styleFunction = vectorLayer.getStyleFunction();\n      if (styleFunction) {\n        styles = styleFunction(feature, resolution);\n      }\n    }\n    if (styles) {\n      var dirty = this.renderFeature(\n          feature, resolution, pixelRatio, styles, replayGroup);\n      this.dirty_ = this.dirty_ || dirty;\n    }\n  };\n  if (vectorLayerRenderOrder) {\n    /** @type {Array.<ol.Feature>} */\n    var features = [];\n    vectorSource.forEachFeatureInExtent(extent,\n        /**\n         * @param {ol.Feature} feature Feature.\n         */\n        function(feature) {\n          features.push(feature);\n        }, this);\n    features.sort(vectorLayerRenderOrder);\n    features.forEach(renderFeature, this);\n  } else {\n    vectorSource.forEachFeatureInExtent(extent, renderFeature, this);\n  }\n  replayGroup.finish(context);\n\n  this.renderedResolution_ = resolution;\n  this.renderedRevision_ = vectorLayerRevision;\n  this.renderedRenderOrder_ = vectorLayerRenderOrder;\n  this.renderedExtent_ = extent;\n  this.replayGroup_ = replayGroup;\n\n  return true;\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of\n *     styles.\n * @param {ol.render.webgl.ReplayGroup} replayGroup Replay group.\n * @return {boolean} `true` if an image is loading.\n */\nol.renderer.webgl.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {\n  if (!styles) {\n    return false;\n  }\n  var loading = false;\n  if (Array.isArray(styles)) {\n    for (var i = styles.length - 1, ii = 0; i >= ii; --i) {\n      loading = ol.renderer.vector.renderFeature(\n          replayGroup, feature, styles[i],\n          ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),\n          this.handleStyleImageChange_, this) || loading;\n    }\n  } else {\n    loading = ol.renderer.vector.renderFeature(\n        replayGroup, feature, styles,\n        ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),\n        this.handleStyleImageChange_, this) || loading;\n  }\n  return loading;\n};\n\ngoog.provide('ol.structs.LRUCache');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.obj');\n\n\n/**\n * Implements a Least-Recently-Used cache where the keys do not conflict with\n * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring\n * items from the cache is the responsibility of the user.\n * @constructor\n * @struct\n * @template T\n */\nol.structs.LRUCache = function() {\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.count_ = 0;\n\n  /**\n   * @private\n   * @type {!Object.<string, ol.LRUCacheEntry>}\n   */\n  this.entries_ = {};\n\n  /**\n   * @private\n   * @type {?ol.LRUCacheEntry}\n   */\n  this.oldest_ = null;\n\n  /**\n   * @private\n   * @type {?ol.LRUCacheEntry}\n   */\n  this.newest_ = null;\n\n};\n\n\nif (ol.DEBUG) {\n  /**\n   * FIXME empty description for jsdoc\n   */\n  ol.structs.LRUCache.prototype.assertValid = function() {\n    if (this.count_ === 0) {\n      console.assert(ol.obj.isEmpty(this.entries_),\n          'entries must be an empty object (count = 0)');\n      console.assert(!this.oldest_,\n          'oldest must be null (count = 0)');\n      console.assert(!this.newest_,\n          'newest must be null (count = 0)');\n    } else {\n      console.assert(Object.keys(this.entries_).length == this.count_,\n          'number of entries matches count');\n      console.assert(this.oldest_,\n          'we have an oldest entry');\n      console.assert(!this.oldest_.older,\n          'no entry is older than oldest');\n      console.assert(this.newest_,\n          'we have a newest entry');\n      console.assert(!this.newest_.newer,\n          'no entry is newer than newest');\n      var i, entry;\n      var older = null;\n      i = 0;\n      for (entry = this.oldest_; entry; entry = entry.newer) {\n        console.assert(entry.older === older,\n            'entry.older links to correct older');\n        older = entry;\n        ++i;\n      }\n      console.assert(i == this.count_, 'iterated correct amount of times');\n      var newer = null;\n      i = 0;\n      for (entry = this.newest_; entry; entry = entry.older) {\n        console.assert(entry.newer === newer,\n            'entry.newer links to correct newer');\n        newer = entry;\n        ++i;\n      }\n      console.assert(i == this.count_, 'iterated correct amount of times');\n    }\n  };\n}\n\n\n/**\n * FIXME empty description for jsdoc\n */\nol.structs.LRUCache.prototype.clear = function() {\n  this.count_ = 0;\n  this.entries_ = {};\n  this.oldest_ = null;\n  this.newest_ = null;\n};\n\n\n/**\n * @param {string} key Key.\n * @return {boolean} Contains key.\n */\nol.structs.LRUCache.prototype.containsKey = function(key) {\n  return this.entries_.hasOwnProperty(key);\n};\n\n\n/**\n * @param {function(this: S, T, string, ol.structs.LRUCache): ?} f The function\n *     to call for every entry from the oldest to the newer. This function takes\n *     3 arguments (the entry value, the entry key and the LRUCache object).\n *     The return value is ignored.\n * @param {S=} opt_this The object to use as `this` in `f`.\n * @template S\n */\nol.structs.LRUCache.prototype.forEach = function(f, opt_this) {\n  var entry = this.oldest_;\n  while (entry) {\n    f.call(opt_this, entry.value_, entry.key_, this);\n    entry = entry.newer;\n  }\n};\n\n\n/**\n * @param {string} key Key.\n * @return {T} Value.\n */\nol.structs.LRUCache.prototype.get = function(key) {\n  var entry = this.entries_[key];\n  ol.asserts.assert(entry !== undefined,\n      15); // Tried to get a value for a key that does not exist in the cache\n  if (entry === this.newest_) {\n    return entry.value_;\n  } else if (entry === this.oldest_) {\n    this.oldest_ = /** @type {ol.LRUCacheEntry} */ (this.oldest_.newer);\n    this.oldest_.older = null;\n  } else {\n    entry.newer.older = entry.older;\n    entry.older.newer = entry.newer;\n  }\n  entry.newer = null;\n  entry.older = this.newest_;\n  this.newest_.newer = entry;\n  this.newest_ = entry;\n  return entry.value_;\n};\n\n\n/**\n * @return {number} Count.\n */\nol.structs.LRUCache.prototype.getCount = function() {\n  return this.count_;\n};\n\n\n/**\n * @return {Array.<string>} Keys.\n */\nol.structs.LRUCache.prototype.getKeys = function() {\n  var keys = new Array(this.count_);\n  var i = 0;\n  var entry;\n  for (entry = this.newest_; entry; entry = entry.older) {\n    keys[i++] = entry.key_;\n  }\n  ol.DEBUG && console.assert(i == this.count_, 'iterated correct number of times');\n  return keys;\n};\n\n\n/**\n * @return {Array.<T>} Values.\n */\nol.structs.LRUCache.prototype.getValues = function() {\n  var values = new Array(this.count_);\n  var i = 0;\n  var entry;\n  for (entry = this.newest_; entry; entry = entry.older) {\n    values[i++] = entry.value_;\n  }\n  ol.DEBUG && console.assert(i == this.count_, 'iterated correct number of times');\n  return values;\n};\n\n\n/**\n * @return {T} Last value.\n */\nol.structs.LRUCache.prototype.peekLast = function() {\n  ol.DEBUG && console.assert(this.oldest_, 'oldest must not be null');\n  return this.oldest_.value_;\n};\n\n\n/**\n * @return {string} Last key.\n */\nol.structs.LRUCache.prototype.peekLastKey = function() {\n  ol.DEBUG && console.assert(this.oldest_, 'oldest must not be null');\n  return this.oldest_.key_;\n};\n\n\n/**\n * @return {T} value Value.\n */\nol.structs.LRUCache.prototype.pop = function() {\n  ol.DEBUG && console.assert(this.oldest_, 'oldest must not be null');\n  ol.DEBUG && console.assert(this.newest_, 'newest must not be null');\n  var entry = this.oldest_;\n  ol.DEBUG && console.assert(entry.key_ in this.entries_,\n      'oldest is indexed in entries');\n  delete this.entries_[entry.key_];\n  if (entry.newer) {\n    entry.newer.older = null;\n  }\n  this.oldest_ = /** @type {ol.LRUCacheEntry} */ (entry.newer);\n  if (!this.oldest_) {\n    this.newest_ = null;\n  }\n  --this.count_;\n  return entry.value_;\n};\n\n\n/**\n * @param {string} key Key.\n * @param {T} value Value.\n */\nol.structs.LRUCache.prototype.replace = function(key, value) {\n  this.get(key);  // update `newest_`\n  this.entries_[key].value_ = value;\n};\n\n\n/**\n * @param {string} key Key.\n * @param {T} value Value.\n */\nol.structs.LRUCache.prototype.set = function(key, value) {\n  ol.DEBUG && console.assert(!(key in {}),\n      'key is not a standard property of objects (e.g. \"__proto__\")');\n  ol.asserts.assert(!(key in this.entries_),\n      16); // Tried to set a value for a key that is used already\n  var entry = /** @type {ol.LRUCacheEntry} */ ({\n    key_: key,\n    newer: null,\n    older: this.newest_,\n    value_: value\n  });\n  if (!this.newest_) {\n    this.oldest_ = entry;\n  } else {\n    this.newest_.newer = entry;\n  }\n  this.newest_ = entry;\n  this.entries_[key] = entry;\n  ++this.count_;\n};\n\n// FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE)\n\ngoog.provide('ol.renderer.webgl.Map');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.css');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.layer.Image');\ngoog.require('ol.layer.Layer');\ngoog.require('ol.layer.Tile');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.render.Event');\ngoog.require('ol.render.webgl.Immediate');\ngoog.require('ol.renderer.Map');\ngoog.require('ol.renderer.Type');\ngoog.require('ol.renderer.webgl.ImageLayer');\ngoog.require('ol.renderer.webgl.TileLayer');\ngoog.require('ol.renderer.webgl.VectorLayer');\ngoog.require('ol.source.State');\ngoog.require('ol.structs.LRUCache');\ngoog.require('ol.structs.PriorityQueue');\ngoog.require('ol.webgl');\ngoog.require('ol.webgl.Context');\ngoog.require('ol.webgl.ContextEventType');\n\n\n/**\n * @constructor\n * @extends {ol.renderer.Map}\n * @param {Element} container Container.\n * @param {ol.Map} map Map.\n */\nol.renderer.webgl.Map = function(container, map) {\n\n  ol.renderer.Map.call(this, container, map);\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = /** @type {HTMLCanvasElement} */\n      (document.createElement('CANVAS'));\n  this.canvas_.style.width = '100%';\n  this.canvas_.style.height = '100%';\n  this.canvas_.className = ol.css.CLASS_UNSELECTABLE;\n  container.insertBefore(this.canvas_, container.childNodes[0] || null);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.clipTileCanvasWidth_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.clipTileCanvasHeight_ = 0;\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.clipTileContext_ = ol.dom.createCanvasContext2D();\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.renderedVisible_ = true;\n\n  /**\n   * @private\n   * @type {WebGLRenderingContext}\n   */\n  this.gl_ = ol.webgl.getContext(this.canvas_, {\n    antialias: true,\n    depth: true,\n    failIfMajorPerformanceCaveat: true,\n    preserveDrawingBuffer: false,\n    stencil: true\n  });\n  ol.DEBUG && console.assert(this.gl_, 'got a WebGLRenderingContext');\n\n  /**\n   * @private\n   * @type {ol.webgl.Context}\n   */\n  this.context_ = new ol.webgl.Context(this.canvas_, this.gl_);\n\n  ol.events.listen(this.canvas_, ol.webgl.ContextEventType.LOST,\n      this.handleWebGLContextLost, this);\n  ol.events.listen(this.canvas_, ol.webgl.ContextEventType.RESTORED,\n      this.handleWebGLContextRestored, this);\n\n  /**\n   * @private\n   * @type {ol.structs.LRUCache.<ol.WebglTextureCacheEntry|null>}\n   */\n  this.textureCache_ = new ol.structs.LRUCache();\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.focus_ = null;\n\n  /**\n   * @private\n   * @type {ol.structs.PriorityQueue.<Array>}\n   */\n  this.tileTextureQueue_ = new ol.structs.PriorityQueue(\n      /**\n       * @param {Array.<*>} element Element.\n       * @return {number} Priority.\n       * @this {ol.renderer.webgl.Map}\n       */\n      (function(element) {\n        var tileCenter = /** @type {ol.Coordinate} */ (element[1]);\n        var tileResolution = /** @type {number} */ (element[2]);\n        var deltaX = tileCenter[0] - this.focus_[0];\n        var deltaY = tileCenter[1] - this.focus_[1];\n        return 65536 * Math.log(tileResolution) +\n            Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;\n      }).bind(this),\n      /**\n       * @param {Array.<*>} element Element.\n       * @return {string} Key.\n       */\n      function(element) {\n        return /** @type {ol.Tile} */ (element[0]).getKey();\n      });\n\n\n /**\n  * @param {ol.Map} map Map.\n  * @param {?olx.FrameState} frameState Frame state.\n  * @return {boolean} false.\n  * @this {ol.renderer.webgl.Map}\n  */\n  this.loadNextTileTexture_ =\n      function(map, frameState) {\n        if (!this.tileTextureQueue_.isEmpty()) {\n          this.tileTextureQueue_.reprioritize();\n          var element = this.tileTextureQueue_.dequeue();\n          var tile = /** @type {ol.Tile} */ (element[0]);\n          var tileSize = /** @type {ol.Size} */ (element[3]);\n          var tileGutter = /** @type {number} */ (element[4]);\n          this.bindTileTexture(\n              tile, tileSize, tileGutter, ol.webgl.LINEAR, ol.webgl.LINEAR);\n        }\n        return false;\n      }.bind(this);\n\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.textureCacheFrameMarkerCount_ = 0;\n\n  this.initializeGL_();\n\n};\nol.inherits(ol.renderer.webgl.Map, ol.renderer.Map);\n\n\n/**\n * @param {ol.Tile} tile Tile.\n * @param {ol.Size} tileSize Tile size.\n * @param {number} tileGutter Tile gutter.\n * @param {number} magFilter Mag filter.\n * @param {number} minFilter Min filter.\n */\nol.renderer.webgl.Map.prototype.bindTileTexture = function(tile, tileSize, tileGutter, magFilter, minFilter) {\n  var gl = this.getGL();\n  var tileKey = tile.getKey();\n  if (this.textureCache_.containsKey(tileKey)) {\n    var textureCacheEntry = this.textureCache_.get(tileKey);\n    gl.bindTexture(ol.webgl.TEXTURE_2D, textureCacheEntry.texture);\n    if (textureCacheEntry.magFilter != magFilter) {\n      gl.texParameteri(\n          ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MAG_FILTER, magFilter);\n      textureCacheEntry.magFilter = magFilter;\n    }\n    if (textureCacheEntry.minFilter != minFilter) {\n      gl.texParameteri(\n          ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MIN_FILTER, minFilter);\n      textureCacheEntry.minFilter = minFilter;\n    }\n  } else {\n    var texture = gl.createTexture();\n    gl.bindTexture(ol.webgl.TEXTURE_2D, texture);\n    if (tileGutter > 0) {\n      var clipTileCanvas = this.clipTileContext_.canvas;\n      var clipTileContext = this.clipTileContext_;\n      if (this.clipTileCanvasWidth_ !== tileSize[0] ||\n          this.clipTileCanvasHeight_ !== tileSize[1]) {\n        clipTileCanvas.width = tileSize[0];\n        clipTileCanvas.height = tileSize[1];\n        this.clipTileCanvasWidth_ = tileSize[0];\n        this.clipTileCanvasHeight_ = tileSize[1];\n      } else {\n        clipTileContext.clearRect(0, 0, tileSize[0], tileSize[1]);\n      }\n      clipTileContext.drawImage(tile.getImage(), tileGutter, tileGutter,\n          tileSize[0], tileSize[1], 0, 0, tileSize[0], tileSize[1]);\n      gl.texImage2D(ol.webgl.TEXTURE_2D, 0,\n          ol.webgl.RGBA, ol.webgl.RGBA,\n          ol.webgl.UNSIGNED_BYTE, clipTileCanvas);\n    } else {\n      gl.texImage2D(ol.webgl.TEXTURE_2D, 0,\n          ol.webgl.RGBA, ol.webgl.RGBA,\n          ol.webgl.UNSIGNED_BYTE, tile.getImage());\n    }\n    gl.texParameteri(\n        ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MAG_FILTER, magFilter);\n    gl.texParameteri(\n        ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MIN_FILTER, minFilter);\n    gl.texParameteri(ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_S,\n        ol.webgl.CLAMP_TO_EDGE);\n    gl.texParameteri(ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_T,\n        ol.webgl.CLAMP_TO_EDGE);\n    this.textureCache_.set(tileKey, {\n      texture: texture,\n      magFilter: magFilter,\n      minFilter: minFilter\n    });\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.Map.prototype.createLayerRenderer = function(layer) {\n  if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) {\n    return new ol.renderer.webgl.ImageLayer(this, layer);\n  } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) {\n    return new ol.renderer.webgl.TileLayer(this, layer);\n  } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) {\n    return new ol.renderer.webgl.VectorLayer(this, layer);\n  } else {\n    ol.DEBUG && console.assert(false, 'unexpected layer configuration');\n    return null;\n  }\n};\n\n\n/**\n * @param {ol.render.Event.Type} type Event type.\n * @param {olx.FrameState} frameState Frame state.\n * @private\n */\nol.renderer.webgl.Map.prototype.dispatchComposeEvent_ = function(type, frameState) {\n  var map = this.getMap();\n  if (map.hasListener(type)) {\n    var context = this.context_;\n\n    var extent = frameState.extent;\n    var size = frameState.size;\n    var viewState = frameState.viewState;\n    var pixelRatio = frameState.pixelRatio;\n\n    var resolution = viewState.resolution;\n    var center = viewState.center;\n    var rotation = viewState.rotation;\n\n    var vectorContext = new ol.render.webgl.Immediate(context,\n        center, resolution, rotation, size, extent, pixelRatio);\n    var composeEvent = new ol.render.Event(type, vectorContext,\n        frameState, null, context);\n    map.dispatchEvent(composeEvent);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.Map.prototype.disposeInternal = function() {\n  var gl = this.getGL();\n  if (!gl.isContextLost()) {\n    this.textureCache_.forEach(\n        /**\n         * @param {?ol.WebglTextureCacheEntry} textureCacheEntry\n         *     Texture cache entry.\n         */\n        function(textureCacheEntry) {\n          if (textureCacheEntry) {\n            gl.deleteTexture(textureCacheEntry.texture);\n          }\n        });\n  }\n  this.context_.dispose();\n  ol.renderer.Map.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * @param {ol.Map} map Map.\n * @param {olx.FrameState} frameState Frame state.\n * @private\n */\nol.renderer.webgl.Map.prototype.expireCache_ = function(map, frameState) {\n  var gl = this.getGL();\n  var textureCacheEntry;\n  while (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ >\n      ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) {\n    textureCacheEntry = this.textureCache_.peekLast();\n    if (!textureCacheEntry) {\n      if (+this.textureCache_.peekLastKey() == frameState.index) {\n        break;\n      } else {\n        --this.textureCacheFrameMarkerCount_;\n      }\n    } else {\n      gl.deleteTexture(textureCacheEntry.texture);\n    }\n    this.textureCache_.pop();\n  }\n};\n\n\n/**\n * @return {ol.webgl.Context} The context.\n */\nol.renderer.webgl.Map.prototype.getContext = function() {\n  return this.context_;\n};\n\n\n/**\n * @return {WebGLRenderingContext} GL.\n */\nol.renderer.webgl.Map.prototype.getGL = function() {\n  return this.gl_;\n};\n\n\n/**\n * @return {ol.structs.PriorityQueue.<Array>} Tile texture queue.\n */\nol.renderer.webgl.Map.prototype.getTileTextureQueue = function() {\n  return this.tileTextureQueue_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.Map.prototype.getType = function() {\n  return ol.renderer.Type.WEBGL;\n};\n\n\n/**\n * @param {ol.events.Event} event Event.\n * @protected\n */\nol.renderer.webgl.Map.prototype.handleWebGLContextLost = function(event) {\n  event.preventDefault();\n  this.textureCache_.clear();\n  this.textureCacheFrameMarkerCount_ = 0;\n\n  var renderers = this.getLayerRenderers();\n  for (var id in renderers) {\n    var renderer = /** @type {ol.renderer.webgl.Layer} */ (renderers[id]);\n    renderer.handleWebGLContextLost();\n  }\n};\n\n\n/**\n * @protected\n */\nol.renderer.webgl.Map.prototype.handleWebGLContextRestored = function() {\n  this.initializeGL_();\n  this.getMap().render();\n};\n\n\n/**\n * @private\n */\nol.renderer.webgl.Map.prototype.initializeGL_ = function() {\n  var gl = this.gl_;\n  gl.activeTexture(ol.webgl.TEXTURE0);\n  gl.blendFuncSeparate(\n      ol.webgl.SRC_ALPHA, ol.webgl.ONE_MINUS_SRC_ALPHA,\n      ol.webgl.ONE, ol.webgl.ONE_MINUS_SRC_ALPHA);\n  gl.disable(ol.webgl.CULL_FACE);\n  gl.disable(ol.webgl.DEPTH_TEST);\n  gl.disable(ol.webgl.SCISSOR_TEST);\n  gl.disable(ol.webgl.STENCIL_TEST);\n};\n\n\n/**\n * @param {ol.Tile} tile Tile.\n * @return {boolean} Is tile texture loaded.\n */\nol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) {\n  return this.textureCache_.containsKey(tile.getKey());\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {\n\n  var context = this.getContext();\n  var gl = this.getGL();\n\n  if (gl.isContextLost()) {\n    return false;\n  }\n\n  if (!frameState) {\n    if (this.renderedVisible_) {\n      this.canvas_.style.display = 'none';\n      this.renderedVisible_ = false;\n    }\n    return false;\n  }\n\n  this.focus_ = frameState.focus;\n\n  this.textureCache_.set((-frameState.index).toString(), null);\n  ++this.textureCacheFrameMarkerCount_;\n\n  this.dispatchComposeEvent_(ol.render.Event.Type.PRECOMPOSE, frameState);\n\n  /** @type {Array.<ol.LayerState>} */\n  var layerStatesToDraw = [];\n  var layerStatesArray = frameState.layerStatesArray;\n  ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);\n\n  var viewResolution = frameState.viewState.resolution;\n  var i, ii, layerRenderer, layerState;\n  for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {\n    layerState = layerStatesArray[i];\n    if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&\n        layerState.sourceState == ol.source.State.READY) {\n      layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layerState.layer));\n      if (layerRenderer.prepareFrame(frameState, layerState, context)) {\n        layerStatesToDraw.push(layerState);\n      }\n    }\n  }\n\n  var width = frameState.size[0] * frameState.pixelRatio;\n  var height = frameState.size[1] * frameState.pixelRatio;\n  if (this.canvas_.width != width || this.canvas_.height != height) {\n    this.canvas_.width = width;\n    this.canvas_.height = height;\n  }\n\n  gl.bindFramebuffer(ol.webgl.FRAMEBUFFER, null);\n\n  gl.clearColor(0, 0, 0, 0);\n  gl.clear(ol.webgl.COLOR_BUFFER_BIT);\n  gl.enable(ol.webgl.BLEND);\n  gl.viewport(0, 0, this.canvas_.width, this.canvas_.height);\n\n  for (i = 0, ii = layerStatesToDraw.length; i < ii; ++i) {\n    layerState = layerStatesToDraw[i];\n    layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layerState.layer));\n    layerRenderer.composeFrame(frameState, layerState, context);\n  }\n\n  if (!this.renderedVisible_) {\n    this.canvas_.style.display = '';\n    this.renderedVisible_ = true;\n  }\n\n  this.calculateMatrices2D(frameState);\n\n  if (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ >\n      ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) {\n    frameState.postRenderFunctions.push(\n      /** @type {ol.PostRenderFunction} */ (this.expireCache_.bind(this))\n    );\n  }\n\n  if (!this.tileTextureQueue_.isEmpty()) {\n    frameState.postRenderFunctions.push(this.loadNextTileTexture_);\n    frameState.animate = true;\n  }\n\n  this.dispatchComposeEvent_(ol.render.Event.Type.POSTCOMPOSE, frameState);\n\n  this.scheduleRemoveUnusedLayerRenderers(frameState);\n  this.scheduleExpireIconCache(frameState);\n\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg,\n        layerFilter, thisArg2) {\n  var result;\n\n  if (this.getGL().isContextLost()) {\n    return false;\n  }\n\n  var viewState = frameState.viewState;\n\n  var layerStates = frameState.layerStatesArray;\n  var numLayers = layerStates.length;\n  var i;\n  for (i = numLayers - 1; i >= 0; --i) {\n    var layerState = layerStates[i];\n    var layer = layerState.layer;\n    if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&\n        layerFilter.call(thisArg2, layer)) {\n      var layerRenderer = this.getLayerRenderer(layer);\n      result = layerRenderer.forEachFeatureAtCoordinate(\n          coordinate, frameState, hitTolerance, callback, thisArg);\n      if (result) {\n        return result;\n      }\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.Map.prototype.hasFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, layerFilter, thisArg) {\n  var hasFeature = false;\n\n  if (this.getGL().isContextLost()) {\n    return false;\n  }\n\n  var viewState = frameState.viewState;\n\n  var layerStates = frameState.layerStatesArray;\n  var numLayers = layerStates.length;\n  var i;\n  for (i = numLayers - 1; i >= 0; --i) {\n    var layerState = layerStates[i];\n    var layer = layerState.layer;\n    if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&\n        layerFilter.call(thisArg, layer)) {\n      var layerRenderer = this.getLayerRenderer(layer);\n      hasFeature =\n          layerRenderer.hasFeatureAtCoordinate(coordinate, frameState);\n      if (hasFeature) {\n        return true;\n      }\n    }\n  }\n  return hasFeature;\n};\n\n\n/**\n * @inheritDoc\n */\nol.renderer.webgl.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,\n        layerFilter, thisArg2) {\n  if (this.getGL().isContextLost()) {\n    return false;\n  }\n\n  var viewState = frameState.viewState;\n  var result;\n\n  var layerStates = frameState.layerStatesArray;\n  var numLayers = layerStates.length;\n  var i;\n  for (i = numLayers - 1; i >= 0; --i) {\n    var layerState = layerStates[i];\n    var layer = layerState.layer;\n    if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&\n        layerFilter.call(thisArg, layer)) {\n      var layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layer));\n      result = layerRenderer.forEachLayerAtPixel(\n          pixel, frameState, callback, thisArg);\n      if (result) {\n        return result;\n      }\n    }\n  }\n  return undefined;\n};\n\n// FIXME recheck layer/map projection compatibility when projection changes\n// FIXME layer renderers should skip when they can't reproject\n// FIXME add tilt and height?\n\ngoog.provide('ol.Map');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.MapBrowserEventHandler');\ngoog.require('ol.MapEvent');\ngoog.require('ol.Object');\ngoog.require('ol.TileQueue');\ngoog.require('ol.View');\ngoog.require('ol.asserts');\ngoog.require('ol.control');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.functions');\ngoog.require('ol.has');\ngoog.require('ol.interaction');\ngoog.require('ol.layer.Group');\ngoog.require('ol.obj');\ngoog.require('ol.proj.common');\ngoog.require('ol.renderer.Type');\ngoog.require('ol.renderer.Map');\ngoog.require('ol.renderer.canvas.Map');\ngoog.require('ol.renderer.webgl.Map');\ngoog.require('ol.size');\ngoog.require('ol.structs.PriorityQueue');\ngoog.require('ol.transform');\n\n\n/**\n * @const\n * @type {string}\n */\nol.OL3_URL = 'https://openlayers.org/';\n\n\n/**\n * @const\n * @type {string}\n */\nol.OL3_LOGO_URL = 'data:image/png;base64,' +\n    'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBI' +\n    'WXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAA' +\n    'AhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszW' +\n    'WMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvY' +\n    'asvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvX' +\n    'H1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1Vk' +\n    'bMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW' +\n    '2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLP' +\n    'VcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqT' +\n    'acrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaar' +\n    'ldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+Hi' +\n    'zeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDn' +\n    'BAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSF' +\n    'hYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJ' +\n    'REFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxC' +\n    'Brb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe' +\n    '0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8' +\n    'a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7a' +\n    'hgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCn' +\n    'B3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDg' +\n    'q82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC';\n\n\n/**\n * @type {Array.<ol.renderer.Type>}\n * @const\n */\nol.DEFAULT_RENDERER_TYPES = [\n  ol.renderer.Type.CANVAS,\n  ol.renderer.Type.WEBGL\n];\n\n\n/**\n * @classdesc\n * The map is the core component of OpenLayers. For a map to render, a view,\n * one or more layers, and a target container are needed:\n *\n *     var map = new ol.Map({\n *       view: new ol.View({\n *         center: [0, 0],\n *         zoom: 1\n *       }),\n *       layers: [\n *         new ol.layer.Tile({\n *           source: new ol.source.OSM()\n *         })\n *       ],\n *       target: 'map'\n *     });\n *\n * The above snippet creates a map using a {@link ol.layer.Tile} to display\n * {@link ol.source.OSM} OSM data and render it to a DOM element with the\n * id `map`.\n *\n * The constructor places a viewport container (with CSS class name\n * `ol-viewport`) in the target element (see `getViewport()`), and then two\n * further elements within the viewport: one with CSS class name\n * `ol-overlaycontainer-stopevent` for controls and some overlays, and one with\n * CSS class name `ol-overlaycontainer` for other overlays (see the `stopEvent`\n * option of {@link ol.Overlay} for the difference). The map itself is placed in\n * a further element within the viewport.\n *\n * Layers are stored as a `ol.Collection` in layerGroups. A top-level group is\n * provided by the library. This is what is accessed by `getLayerGroup` and\n * `setLayerGroup`. Layers entered in the options are added to this group, and\n * `addLayer` and `removeLayer` change the layer collection in the group.\n * `getLayers` is a convenience function for `getLayerGroup().getLayers()`.\n * Note that `ol.layer.Group` is a subclass of `ol.layer.Base`, so layers\n * entered in the options or added with `addLayer` can be groups, which can\n * contain further groups, and so on.\n *\n * @constructor\n * @extends {ol.Object}\n * @param {olx.MapOptions} options Map options.\n * @fires ol.MapBrowserEvent\n * @fires ol.MapEvent\n * @fires ol.render.Event#postcompose\n * @fires ol.render.Event#precompose\n * @api stable\n */\nol.Map = function(options) {\n\n  ol.Object.call(this);\n\n  var optionsInternal = ol.Map.createOptionsInternal(options);\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.loadTilesWhileAnimating_ =\n      options.loadTilesWhileAnimating !== undefined ?\n          options.loadTilesWhileAnimating : false;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.loadTilesWhileInteracting_ =\n      options.loadTilesWhileInteracting !== undefined ?\n          options.loadTilesWhileInteracting : false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.pixelRatio_ = options.pixelRatio !== undefined ?\n      options.pixelRatio : ol.has.DEVICE_PIXEL_RATIO;\n\n  /**\n   * @private\n   * @type {Object.<string, string>}\n   */\n  this.logos_ = optionsInternal.logos;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.animationDelayKey_;\n\n  /**\n   * @private\n   */\n  this.animationDelay_ = function() {\n    this.animationDelayKey_ = undefined;\n    this.renderFrame_.call(this, Date.now());\n  }.bind(this);\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.coordinateToPixelTransform_ = ol.transform.create();\n\n  /**\n   * @private\n   * @type {ol.Transform}\n   */\n  this.pixelToCoordinateTransform_ = ol.transform.create();\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.frameIndex_ = 0;\n\n  /**\n   * @private\n   * @type {?olx.FrameState}\n   */\n  this.frameState_ = null;\n\n  /**\n   * The extent at the previous 'moveend' event.\n   * @private\n   * @type {ol.Extent}\n   */\n  this.previousExtent_ = ol.extent.createEmpty();\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.viewPropertyListenerKey_ = null;\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.viewChangeListenerKey_ = null;\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.layerGroupPropertyListenerKeys_ = null;\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.viewport_ = document.createElement('DIV');\n  this.viewport_.className = 'ol-viewport' + (ol.has.TOUCH ? ' ol-touch' : '');\n  this.viewport_.style.position = 'relative';\n  this.viewport_.style.overflow = 'hidden';\n  this.viewport_.style.width = '100%';\n  this.viewport_.style.height = '100%';\n  // prevent page zoom on IE >= 10 browsers\n  this.viewport_.style.msTouchAction = 'none';\n  this.viewport_.style.touchAction = 'none';\n\n  /**\n   * @private\n   * @type {!Element}\n   */\n  this.overlayContainer_ = document.createElement('DIV');\n  this.overlayContainer_.className = 'ol-overlaycontainer';\n  this.viewport_.appendChild(this.overlayContainer_);\n\n  /**\n   * @private\n   * @type {!Element}\n   */\n  this.overlayContainerStopEvent_ = document.createElement('DIV');\n  this.overlayContainerStopEvent_.className = 'ol-overlaycontainer-stopevent';\n  var overlayEvents = [\n    ol.events.EventType.CLICK,\n    ol.events.EventType.DBLCLICK,\n    ol.events.EventType.MOUSEDOWN,\n    ol.events.EventType.TOUCHSTART,\n    ol.events.EventType.MSPOINTERDOWN,\n    ol.MapBrowserEvent.EventType.POINTERDOWN,\n    ol.events.EventType.MOUSEWHEEL,\n    ol.events.EventType.WHEEL\n  ];\n  for (var i = 0, ii = overlayEvents.length; i < ii; ++i) {\n    ol.events.listen(this.overlayContainerStopEvent_, overlayEvents[i],\n        ol.events.Event.stopPropagation);\n  }\n  this.viewport_.appendChild(this.overlayContainerStopEvent_);\n\n  /**\n   * @private\n   * @type {ol.MapBrowserEventHandler}\n   */\n  this.mapBrowserEventHandler_ = new ol.MapBrowserEventHandler(this);\n  for (var key in ol.MapBrowserEvent.EventType) {\n    ol.events.listen(this.mapBrowserEventHandler_, ol.MapBrowserEvent.EventType[key],\n        this.handleMapBrowserEvent, this);\n  }\n\n  /**\n   * @private\n   * @type {Element|Document}\n   */\n  this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget;\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.keyHandlerKeys_ = null;\n\n  ol.events.listen(this.viewport_, ol.events.EventType.WHEEL,\n      this.handleBrowserEvent, this);\n  ol.events.listen(this.viewport_, ol.events.EventType.MOUSEWHEEL,\n      this.handleBrowserEvent, this);\n\n  /**\n   * @type {ol.Collection.<ol.control.Control>}\n   * @private\n   */\n  this.controls_ = optionsInternal.controls;\n\n  /**\n   * @type {ol.Collection.<ol.interaction.Interaction>}\n   * @private\n   */\n  this.interactions_ = optionsInternal.interactions;\n\n  /**\n   * @type {ol.Collection.<ol.Overlay>}\n   * @private\n   */\n  this.overlays_ = optionsInternal.overlays;\n\n  /**\n   * A lookup of overlays by id.\n   * @private\n   * @type {Object.<string, ol.Overlay>}\n   */\n  this.overlayIdIndex_ = {};\n\n  /**\n   * @type {ol.renderer.Map}\n   * @private\n   */\n  this.renderer_ = new optionsInternal.rendererConstructor(this.viewport_, this);\n\n  /**\n   * @type {function(Event)|undefined}\n   * @private\n   */\n  this.handleResize_;\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.focus_ = null;\n\n  /**\n   * @private\n   * @type {Array.<ol.PreRenderFunction>}\n   */\n  this.preRenderFunctions_ = [];\n\n  /**\n   * @private\n   * @type {Array.<ol.PostRenderFunction>}\n   */\n  this.postRenderFunctions_ = [];\n\n  /**\n   * @private\n   * @type {ol.TileQueue}\n   */\n  this.tileQueue_ = new ol.TileQueue(\n      this.getTilePriority.bind(this),\n      this.handleTileChange_.bind(this));\n\n  /**\n   * Uids of features to skip at rendering time.\n   * @type {Object.<string, boolean>}\n   * @private\n   */\n  this.skippedFeatureUids_ = {};\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Map.Property.LAYERGROUP),\n      this.handleLayerGroupChanged_, this);\n  ol.events.listen(this, ol.Object.getChangeEventType(ol.Map.Property.VIEW),\n      this.handleViewChanged_, this);\n  ol.events.listen(this, ol.Object.getChangeEventType(ol.Map.Property.SIZE),\n      this.handleSizeChanged_, this);\n  ol.events.listen(this, ol.Object.getChangeEventType(ol.Map.Property.TARGET),\n      this.handleTargetChanged_, this);\n\n  // setProperties will trigger the rendering of the map if the map\n  // is \"defined\" already.\n  this.setProperties(optionsInternal.values);\n\n  this.controls_.forEach(\n      /**\n       * @param {ol.control.Control} control Control.\n       * @this {ol.Map}\n       */\n      function(control) {\n        control.setMap(this);\n      }, this);\n\n  ol.events.listen(this.controls_, ol.Collection.EventType.ADD,\n      /**\n       * @param {ol.Collection.Event} event Collection event.\n       */\n      function(event) {\n        event.element.setMap(this);\n      }, this);\n\n  ol.events.listen(this.controls_, ol.Collection.EventType.REMOVE,\n      /**\n       * @param {ol.Collection.Event} event Collection event.\n       */\n      function(event) {\n        event.element.setMap(null);\n      }, this);\n\n  this.interactions_.forEach(\n      /**\n       * @param {ol.interaction.Interaction} interaction Interaction.\n       * @this {ol.Map}\n       */\n      function(interaction) {\n        interaction.setMap(this);\n      }, this);\n\n  ol.events.listen(this.interactions_, ol.Collection.EventType.ADD,\n      /**\n       * @param {ol.Collection.Event} event Collection event.\n       */\n      function(event) {\n        event.element.setMap(this);\n      }, this);\n\n  ol.events.listen(this.interactions_, ol.Collection.EventType.REMOVE,\n      /**\n       * @param {ol.Collection.Event} event Collection event.\n       */\n      function(event) {\n        event.element.setMap(null);\n      }, this);\n\n  this.overlays_.forEach(this.addOverlayInternal_, this);\n\n  ol.events.listen(this.overlays_, ol.Collection.EventType.ADD,\n      /**\n       * @param {ol.Collection.Event} event Collection event.\n       */\n      function(event) {\n        this.addOverlayInternal_(/** @type {ol.Overlay} */ (event.element));\n      }, this);\n\n  ol.events.listen(this.overlays_, ol.Collection.EventType.REMOVE,\n      /**\n       * @param {ol.Collection.Event} event Collection event.\n       */\n      function(event) {\n        var overlay = /** @type {ol.Overlay} */ (event.element);\n        var id = overlay.getId();\n        if (id !== undefined) {\n          delete this.overlayIdIndex_[id.toString()];\n        }\n        event.element.setMap(null);\n      }, this);\n\n};\nol.inherits(ol.Map, ol.Object);\n\n\n/**\n * Add the given control to the map.\n * @param {ol.control.Control} control Control.\n * @api stable\n */\nol.Map.prototype.addControl = function(control) {\n  this.getControls().push(control);\n};\n\n\n/**\n * Add the given interaction to the map.\n * @param {ol.interaction.Interaction} interaction Interaction to add.\n * @api stable\n */\nol.Map.prototype.addInteraction = function(interaction) {\n  this.getInteractions().push(interaction);\n};\n\n\n/**\n * Adds the given layer to the top of this map. If you want to add a layer\n * elsewhere in the stack, use `getLayers()` and the methods available on\n * {@link ol.Collection}.\n * @param {ol.layer.Base} layer Layer.\n * @api stable\n */\nol.Map.prototype.addLayer = function(layer) {\n  var layers = this.getLayerGroup().getLayers();\n  layers.push(layer);\n};\n\n\n/**\n * Add the given overlay to the map.\n * @param {ol.Overlay} overlay Overlay.\n * @api stable\n */\nol.Map.prototype.addOverlay = function(overlay) {\n  this.getOverlays().push(overlay);\n};\n\n\n/**\n * This deals with map's overlay collection changes.\n * @param {ol.Overlay} overlay Overlay.\n * @private\n */\nol.Map.prototype.addOverlayInternal_ = function(overlay) {\n  var id = overlay.getId();\n  if (id !== undefined) {\n    this.overlayIdIndex_[id.toString()] = overlay;\n  }\n  overlay.setMap(this);\n};\n\n\n/**\n * Deprecated (use {@link ol.View#animate} instead).\n * Add functions to be called before rendering. This can be used for attaching\n * animations before updating the map's view.  The {@link ol.animation}\n * namespace provides several static methods for creating prerender functions.\n * @param {...ol.PreRenderFunction} var_args Any number of pre-render functions.\n * @api\n */\nol.Map.prototype.beforeRender = function(var_args) {\n  ol.DEBUG && console.warn('map.beforeRender() is deprecated.  Use view.animate() instead.');\n  this.render();\n  Array.prototype.push.apply(this.preRenderFunctions_, arguments);\n};\n\n\n/**\n *\n * @inheritDoc\n */\nol.Map.prototype.disposeInternal = function() {\n  this.mapBrowserEventHandler_.dispose();\n  this.renderer_.dispose();\n  ol.events.unlisten(this.viewport_, ol.events.EventType.WHEEL,\n      this.handleBrowserEvent, this);\n  ol.events.unlisten(this.viewport_, ol.events.EventType.MOUSEWHEEL,\n      this.handleBrowserEvent, this);\n  if (this.handleResize_ !== undefined) {\n    window.removeEventListener(ol.events.EventType.RESIZE,\n        this.handleResize_, false);\n    this.handleResize_ = undefined;\n  }\n  if (this.animationDelayKey_) {\n    cancelAnimationFrame(this.animationDelayKey_);\n    this.animationDelayKey_ = undefined;\n  }\n  this.setTarget(null);\n  ol.Object.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Detect features that intersect a pixel on the viewport, and execute a\n * callback with each intersecting feature. Layers included in the detection can\n * be configured through `opt_layerFilter`.\n * @param {ol.Pixel} pixel Pixel.\n * @param {function(this: S, (ol.Feature|ol.render.Feature),\n *     ol.layer.Layer): T} callback Feature callback. The callback will be\n *     called with two arguments. The first argument is one\n *     {@link ol.Feature feature} or\n *     {@link ol.render.Feature render feature} at the pixel, the second is\n *     the {@link ol.layer.Layer layer} of the feature and will be null for\n *     unmanaged layers. To stop detection, callback functions can return a\n *     truthy value.\n * @param {olx.AtPixelOptions=} opt_options Optional options.\n * @return {T|undefined} Callback result, i.e. the return value of last\n * callback execution, or the first truthy callback return value.\n * @template S,T\n * @api stable\n */\nol.Map.prototype.forEachFeatureAtPixel = function(pixel, callback, opt_options) {\n  if (!this.frameState_) {\n    return;\n  }\n  var coordinate = this.getCoordinateFromPixel(pixel);\n  opt_options = opt_options !== undefined ? opt_options : {};\n  var hitTolerance = opt_options.hitTolerance !== undefined ?\n    opt_options.hitTolerance * this.frameState_.pixelRatio : 0;\n  var layerFilter = opt_options.layerFilter !== undefined ?\n    opt_options.layerFilter : ol.functions.TRUE;\n  return this.renderer_.forEachFeatureAtCoordinate(\n      coordinate, this.frameState_, hitTolerance, callback, null,\n      layerFilter, null);\n};\n\n\n/**\n * Detect layers that have a color value at a pixel on the viewport, and\n * execute a callback with each matching layer. Layers included in the\n * detection can be configured through `opt_layerFilter`.\n * @param {ol.Pixel} pixel Pixel.\n * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback\n *     Layer callback. This callback will recieve two arguments: first is the\n *     {@link ol.layer.Layer layer}, second argument is an array representing\n *     [R, G, B, A] pixel values (0 - 255) and will be `null` for layer types\n *     that do not currently support this argument. To stop detection, callback\n *     functions can return a truthy value.\n * @param {S=} opt_this Value to use as `this` when executing `callback`.\n * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer\n *     filter function. The filter function will receive one argument, the\n *     {@link ol.layer.Layer layer-candidate} and it should return a boolean\n *     value. Only layers which are visible and for which this function returns\n *     `true` will be tested for features. By default, all visible layers will\n *     be tested.\n * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.\n * @return {T|undefined} Callback result, i.e. the return value of last\n * callback execution, or the first truthy callback return value.\n * @template S,T,U\n * @api stable\n */\nol.Map.prototype.forEachLayerAtPixel = function(pixel, callback, opt_this, opt_layerFilter, opt_this2) {\n  if (!this.frameState_) {\n    return;\n  }\n  var thisArg = opt_this !== undefined ? opt_this : null;\n  var layerFilter = opt_layerFilter !== undefined ?\n      opt_layerFilter : ol.functions.TRUE;\n  var thisArg2 = opt_this2 !== undefined ? opt_this2 : null;\n  return this.renderer_.forEachLayerAtPixel(\n      pixel, this.frameState_, callback, thisArg,\n      layerFilter, thisArg2);\n};\n\n\n/**\n * Detect if features intersect a pixel on the viewport. Layers included in the\n * detection can be configured through `opt_layerFilter`.\n * @param {ol.Pixel} pixel Pixel.\n * @param {olx.AtPixelOptions=} opt_options Optional options.\n * @return {boolean} Is there a feature at the given pixel?\n * @template U\n * @api\n */\nol.Map.prototype.hasFeatureAtPixel = function(pixel, opt_options) {\n  if (!this.frameState_) {\n    return false;\n  }\n  var coordinate = this.getCoordinateFromPixel(pixel);\n  opt_options = opt_options !== undefined ? opt_options : {};\n  var layerFilter = opt_options.layerFilter !== undefined ?\n      opt_options.layerFilter : ol.functions.TRUE;\n  var hitTolerance = opt_options.hitTolerance !== undefined ?\n    opt_options.hitTolerance * this.frameState_.pixelRatio : 0;\n  return this.renderer_.hasFeatureAtCoordinate(\n      coordinate, this.frameState_, hitTolerance, layerFilter, null);\n};\n\n\n/**\n * Returns the coordinate in view projection for a browser event.\n * @param {Event} event Event.\n * @return {ol.Coordinate} Coordinate.\n * @api stable\n */\nol.Map.prototype.getEventCoordinate = function(event) {\n  return this.getCoordinateFromPixel(this.getEventPixel(event));\n};\n\n\n/**\n * Returns the map pixel position for a browser event relative to the viewport.\n * @param {Event} event Event.\n * @return {ol.Pixel} Pixel.\n * @api stable\n */\nol.Map.prototype.getEventPixel = function(event) {\n  var viewportPosition = this.viewport_.getBoundingClientRect();\n  var eventPosition = event.changedTouches ? event.changedTouches[0] : event;\n  return [\n    eventPosition.clientX - viewportPosition.left,\n    eventPosition.clientY - viewportPosition.top\n  ];\n};\n\n\n/**\n * Get the target in which this map is rendered.\n * Note that this returns what is entered as an option or in setTarget:\n * if that was an element, it returns an element; if a string, it returns that.\n * @return {Element|string|undefined} The Element or id of the Element that the\n *     map is rendered in.\n * @observable\n * @api stable\n */\nol.Map.prototype.getTarget = function() {\n  return /** @type {Element|string|undefined} */ (\n      this.get(ol.Map.Property.TARGET));\n};\n\n\n/**\n * Get the DOM element into which this map is rendered. In contrast to\n * `getTarget` this method always return an `Element`, or `null` if the\n * map has no target.\n * @return {Element} The element that the map is rendered in.\n * @api\n */\nol.Map.prototype.getTargetElement = function() {\n  var target = this.getTarget();\n  if (target !== undefined) {\n    return typeof target === 'string' ?\n      document.getElementById(target) :\n      target;\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * Get the coordinate for a given pixel.  This returns a coordinate in the\n * map view projection.\n * @param {ol.Pixel} pixel Pixel position in the map viewport.\n * @return {ol.Coordinate} The coordinate for the pixel position.\n * @api stable\n */\nol.Map.prototype.getCoordinateFromPixel = function(pixel) {\n  var frameState = this.frameState_;\n  if (!frameState) {\n    return null;\n  } else {\n    return ol.transform.apply(frameState.pixelToCoordinateTransform, pixel.slice());\n  }\n};\n\n\n/**\n * Get the map controls. Modifying this collection changes the controls\n * associated with the map.\n * @return {ol.Collection.<ol.control.Control>} Controls.\n * @api stable\n */\nol.Map.prototype.getControls = function() {\n  return this.controls_;\n};\n\n\n/**\n * Get the map overlays. Modifying this collection changes the overlays\n * associated with the map.\n * @return {ol.Collection.<ol.Overlay>} Overlays.\n * @api stable\n */\nol.Map.prototype.getOverlays = function() {\n  return this.overlays_;\n};\n\n\n/**\n * Get an overlay by its identifier (the value returned by overlay.getId()).\n * Note that the index treats string and numeric identifiers as the same. So\n * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`.\n * @param {string|number} id Overlay identifier.\n * @return {ol.Overlay} Overlay.\n * @api\n */\nol.Map.prototype.getOverlayById = function(id) {\n  var overlay = this.overlayIdIndex_[id.toString()];\n  return overlay !== undefined ? overlay : null;\n};\n\n\n/**\n * Get the map interactions. Modifying this collection changes the interactions\n * associated with the map.\n *\n * Interactions are used for e.g. pan, zoom and rotate.\n * @return {ol.Collection.<ol.interaction.Interaction>} Interactions.\n * @api stable\n */\nol.Map.prototype.getInteractions = function() {\n  return this.interactions_;\n};\n\n\n/**\n * Get the layergroup associated with this map.\n * @return {ol.layer.Group} A layer group containing the layers in this map.\n * @observable\n * @api stable\n */\nol.Map.prototype.getLayerGroup = function() {\n  return /** @type {ol.layer.Group} */ (this.get(ol.Map.Property.LAYERGROUP));\n};\n\n\n/**\n * Get the collection of layers associated with this map.\n * @return {!ol.Collection.<ol.layer.Base>} Layers.\n * @api stable\n */\nol.Map.prototype.getLayers = function() {\n  var layers = this.getLayerGroup().getLayers();\n  return layers;\n};\n\n\n/**\n * Get the pixel for a coordinate.  This takes a coordinate in the map view\n * projection and returns the corresponding pixel.\n * @param {ol.Coordinate} coordinate A map coordinate.\n * @return {ol.Pixel} A pixel position in the map viewport.\n * @api stable\n */\nol.Map.prototype.getPixelFromCoordinate = function(coordinate) {\n  var frameState = this.frameState_;\n  if (!frameState) {\n    return null;\n  } else {\n    return ol.transform.apply(frameState.coordinateToPixelTransform,\n        coordinate.slice(0, 2));\n  }\n};\n\n\n/**\n * Get the map renderer.\n * @return {ol.renderer.Map} Renderer\n */\nol.Map.prototype.getRenderer = function() {\n  return this.renderer_;\n};\n\n\n/**\n * Get the size of this map.\n * @return {ol.Size|undefined} The size in pixels of the map in the DOM.\n * @observable\n * @api stable\n */\nol.Map.prototype.getSize = function() {\n  return /** @type {ol.Size|undefined} */ (this.get(ol.Map.Property.SIZE));\n};\n\n\n/**\n * Get the view associated with this map. A view manages properties such as\n * center and resolution.\n * @return {ol.View} The view that controls this map.\n * @observable\n * @api stable\n */\nol.Map.prototype.getView = function() {\n  return /** @type {ol.View} */ (this.get(ol.Map.Property.VIEW));\n};\n\n\n/**\n * Get the element that serves as the map viewport.\n * @return {Element} Viewport.\n * @api stable\n */\nol.Map.prototype.getViewport = function() {\n  return this.viewport_;\n};\n\n\n/**\n * Get the element that serves as the container for overlays.  Elements added to\n * this container will let mousedown and touchstart events through to the map,\n * so clicks and gestures on an overlay will trigger {@link ol.MapBrowserEvent}\n * events.\n * @return {!Element} The map's overlay container.\n */\nol.Map.prototype.getOverlayContainer = function() {\n  return this.overlayContainer_;\n};\n\n\n/**\n * Get the element that serves as a container for overlays that don't allow\n * event propagation. Elements added to this container won't let mousedown and\n * touchstart events through to the map, so clicks and gestures on an overlay\n * don't trigger any {@link ol.MapBrowserEvent}.\n * @return {!Element} The map's overlay container that stops events.\n */\nol.Map.prototype.getOverlayContainerStopEvent = function() {\n  return this.overlayContainerStopEvent_;\n};\n\n\n/**\n * @param {ol.Tile} tile Tile.\n * @param {string} tileSourceKey Tile source key.\n * @param {ol.Coordinate} tileCenter Tile center.\n * @param {number} tileResolution Tile resolution.\n * @return {number} Tile priority.\n */\nol.Map.prototype.getTilePriority = function(tile, tileSourceKey, tileCenter, tileResolution) {\n  // Filter out tiles at higher zoom levels than the current zoom level, or that\n  // are outside the visible extent.\n  var frameState = this.frameState_;\n  if (!frameState || !(tileSourceKey in frameState.wantedTiles)) {\n    return ol.structs.PriorityQueue.DROP;\n  }\n  if (!frameState.wantedTiles[tileSourceKey][tile.getKey()]) {\n    return ol.structs.PriorityQueue.DROP;\n  }\n  // Prioritize the highest zoom level tiles closest to the focus.\n  // Tiles at higher zoom levels are prioritized using Math.log(tileResolution).\n  // Within a zoom level, tiles are prioritized by the distance in pixels\n  // between the center of the tile and the focus.  The factor of 65536 means\n  // that the prioritization should behave as desired for tiles up to\n  // 65536 * Math.log(2) = 45426 pixels from the focus.\n  var deltaX = tileCenter[0] - frameState.focus[0];\n  var deltaY = tileCenter[1] - frameState.focus[1];\n  return 65536 * Math.log(tileResolution) +\n      Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;\n};\n\n\n/**\n * @param {Event} browserEvent Browser event.\n * @param {string=} opt_type Type.\n */\nol.Map.prototype.handleBrowserEvent = function(browserEvent, opt_type) {\n  var type = opt_type || browserEvent.type;\n  var mapBrowserEvent = new ol.MapBrowserEvent(type, this, browserEvent);\n  this.handleMapBrowserEvent(mapBrowserEvent);\n};\n\n\n/**\n * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle.\n */\nol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {\n  if (!this.frameState_) {\n    // With no view defined, we cannot translate pixels into geographical\n    // coordinates so interactions cannot be used.\n    return;\n  }\n  this.focus_ = mapBrowserEvent.coordinate;\n  mapBrowserEvent.frameState = this.frameState_;\n  var interactionsArray = this.getInteractions().getArray();\n  var i;\n  if (this.dispatchEvent(mapBrowserEvent) !== false) {\n    for (i = interactionsArray.length - 1; i >= 0; i--) {\n      var interaction = interactionsArray[i];\n      if (!interaction.getActive()) {\n        continue;\n      }\n      var cont = interaction.handleEvent(mapBrowserEvent);\n      if (!cont) {\n        break;\n      }\n    }\n  }\n};\n\n\n/**\n * @protected\n */\nol.Map.prototype.handlePostRender = function() {\n\n  var frameState = this.frameState_;\n\n  // Manage the tile queue\n  // Image loads are expensive and a limited resource, so try to use them\n  // efficiently:\n  // * When the view is static we allow a large number of parallel tile loads\n  //   to complete the frame as quickly as possible.\n  // * When animating or interacting, image loads can cause janks, so we reduce\n  //   the maximum number of loads per frame and limit the number of parallel\n  //   tile loads to remain reactive to view changes and to reduce the chance of\n  //   loading tiles that will quickly disappear from view.\n  var tileQueue = this.tileQueue_;\n  if (!tileQueue.isEmpty()) {\n    var maxTotalLoading = 16;\n    var maxNewLoads = maxTotalLoading;\n    if (frameState) {\n      var hints = frameState.viewHints;\n      if (hints[ol.View.Hint.ANIMATING]) {\n        maxTotalLoading = this.loadTilesWhileAnimating_ ? 8 : 0;\n        maxNewLoads = 2;\n      }\n      if (hints[ol.View.Hint.INTERACTING]) {\n        maxTotalLoading = this.loadTilesWhileInteracting_ ? 8 : 0;\n        maxNewLoads = 2;\n      }\n    }\n    if (tileQueue.getTilesLoading() < maxTotalLoading) {\n      tileQueue.reprioritize(); // FIXME only call if view has changed\n      tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);\n    }\n  }\n\n  var postRenderFunctions = this.postRenderFunctions_;\n  var i, ii;\n  for (i = 0, ii = postRenderFunctions.length; i < ii; ++i) {\n    postRenderFunctions[i](this, frameState);\n  }\n  postRenderFunctions.length = 0;\n};\n\n\n/**\n * @private\n */\nol.Map.prototype.handleSizeChanged_ = function() {\n  this.render();\n};\n\n\n/**\n * @private\n */\nol.Map.prototype.handleTargetChanged_ = function() {\n  // target may be undefined, null, a string or an Element.\n  // If it's a string we convert it to an Element before proceeding.\n  // If it's not now an Element we remove the viewport from the DOM.\n  // If it's an Element we append the viewport element to it.\n\n  var targetElement;\n  if (this.getTarget()) {\n    targetElement = this.getTargetElement();\n    ol.DEBUG && console.assert(targetElement !== null,\n        'expects a non-null value for targetElement');\n  }\n\n  if (this.keyHandlerKeys_) {\n    for (var i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {\n      ol.events.unlistenByKey(this.keyHandlerKeys_[i]);\n    }\n    this.keyHandlerKeys_ = null;\n  }\n\n  if (!targetElement) {\n    ol.dom.removeNode(this.viewport_);\n    if (this.handleResize_ !== undefined) {\n      window.removeEventListener(ol.events.EventType.RESIZE,\n          this.handleResize_, false);\n      this.handleResize_ = undefined;\n    }\n  } else {\n    targetElement.appendChild(this.viewport_);\n\n    var keyboardEventTarget = !this.keyboardEventTarget_ ?\n        targetElement : this.keyboardEventTarget_;\n    this.keyHandlerKeys_ = [\n      ol.events.listen(keyboardEventTarget, ol.events.EventType.KEYDOWN,\n          this.handleBrowserEvent, this),\n      ol.events.listen(keyboardEventTarget, ol.events.EventType.KEYPRESS,\n          this.handleBrowserEvent, this)\n    ];\n\n    if (!this.handleResize_) {\n      this.handleResize_ = this.updateSize.bind(this);\n      window.addEventListener(ol.events.EventType.RESIZE,\n          this.handleResize_, false);\n    }\n  }\n\n  this.updateSize();\n  // updateSize calls setSize, so no need to call this.render\n  // ourselves here.\n};\n\n\n/**\n * @private\n */\nol.Map.prototype.handleTileChange_ = function() {\n  this.render();\n};\n\n\n/**\n * @private\n */\nol.Map.prototype.handleViewPropertyChanged_ = function() {\n  this.render();\n};\n\n\n/**\n * @private\n */\nol.Map.prototype.handleViewChanged_ = function() {\n  if (this.viewPropertyListenerKey_) {\n    ol.events.unlistenByKey(this.viewPropertyListenerKey_);\n    this.viewPropertyListenerKey_ = null;\n  }\n  if (this.viewChangeListenerKey_) {\n    ol.events.unlistenByKey(this.viewChangeListenerKey_);\n    this.viewChangeListenerKey_ = null;\n  }\n  var view = this.getView();\n  if (view) {\n    this.viewPropertyListenerKey_ = ol.events.listen(\n        view, ol.Object.EventType.PROPERTYCHANGE,\n        this.handleViewPropertyChanged_, this);\n    this.viewChangeListenerKey_ = ol.events.listen(\n        view, ol.events.EventType.CHANGE,\n        this.handleViewPropertyChanged_, this);\n  }\n  this.render();\n};\n\n\n/**\n * @private\n */\nol.Map.prototype.handleLayerGroupChanged_ = function() {\n  if (this.layerGroupPropertyListenerKeys_) {\n    this.layerGroupPropertyListenerKeys_.forEach(ol.events.unlistenByKey);\n    this.layerGroupPropertyListenerKeys_ = null;\n  }\n  var layerGroup = this.getLayerGroup();\n  if (layerGroup) {\n    this.layerGroupPropertyListenerKeys_ = [\n      ol.events.listen(\n          layerGroup, ol.Object.EventType.PROPERTYCHANGE,\n          this.render, this),\n      ol.events.listen(\n          layerGroup, ol.events.EventType.CHANGE,\n          this.render, this)\n    ];\n  }\n  this.render();\n};\n\n\n/**\n * @return {boolean} Is rendered.\n */\nol.Map.prototype.isRendered = function() {\n  return !!this.frameState_;\n};\n\n\n/**\n * Requests an immediate render in a synchronous manner.\n * @api stable\n */\nol.Map.prototype.renderSync = function() {\n  if (this.animationDelayKey_) {\n    cancelAnimationFrame(this.animationDelayKey_);\n  }\n  this.animationDelay_();\n};\n\n\n/**\n * Request a map rendering (at the next animation frame).\n * @api stable\n */\nol.Map.prototype.render = function() {\n  if (this.animationDelayKey_ === undefined) {\n    this.animationDelayKey_ = requestAnimationFrame(\n        this.animationDelay_);\n  }\n};\n\n\n/**\n * Remove the given control from the map.\n * @param {ol.control.Control} control Control.\n * @return {ol.control.Control|undefined} The removed control (or undefined\n *     if the control was not found).\n * @api stable\n */\nol.Map.prototype.removeControl = function(control) {\n  return this.getControls().remove(control);\n};\n\n\n/**\n * Remove the given interaction from the map.\n * @param {ol.interaction.Interaction} interaction Interaction to remove.\n * @return {ol.interaction.Interaction|undefined} The removed interaction (or\n *     undefined if the interaction was not found).\n * @api stable\n */\nol.Map.prototype.removeInteraction = function(interaction) {\n  return this.getInteractions().remove(interaction);\n};\n\n\n/**\n * Removes the given layer from the map.\n * @param {ol.layer.Base} layer Layer.\n * @return {ol.layer.Base|undefined} The removed layer (or undefined if the\n *     layer was not found).\n * @api stable\n */\nol.Map.prototype.removeLayer = function(layer) {\n  var layers = this.getLayerGroup().getLayers();\n  return layers.remove(layer);\n};\n\n\n/**\n * Remove the given overlay from the map.\n * @param {ol.Overlay} overlay Overlay.\n * @return {ol.Overlay|undefined} The removed overlay (or undefined\n *     if the overlay was not found).\n * @api stable\n */\nol.Map.prototype.removeOverlay = function(overlay) {\n  return this.getOverlays().remove(overlay);\n};\n\n\n/**\n * @param {number} time Time.\n * @private\n */\nol.Map.prototype.renderFrame_ = function(time) {\n  var i, ii, viewState;\n\n  var size = this.getSize();\n  var view = this.getView();\n  var extent = ol.extent.createEmpty();\n  /** @type {?olx.FrameState} */\n  var frameState = null;\n  if (size !== undefined && ol.size.hasArea(size) && view && view.isDef()) {\n    var viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined);\n    var layerStatesArray = this.getLayerGroup().getLayerStatesArray();\n    var layerStates = {};\n    for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {\n      layerStates[ol.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];\n    }\n    viewState = view.getState();\n    frameState = /** @type {olx.FrameState} */ ({\n      animate: false,\n      attributions: {},\n      coordinateToPixelTransform: this.coordinateToPixelTransform_,\n      extent: extent,\n      focus: !this.focus_ ? viewState.center : this.focus_,\n      index: this.frameIndex_++,\n      layerStates: layerStates,\n      layerStatesArray: layerStatesArray,\n      logos: ol.obj.assign({}, this.logos_),\n      pixelRatio: this.pixelRatio_,\n      pixelToCoordinateTransform: this.pixelToCoordinateTransform_,\n      postRenderFunctions: [],\n      size: size,\n      skippedFeatureUids: this.skippedFeatureUids_,\n      tileQueue: this.tileQueue_,\n      time: time,\n      usedTiles: {},\n      viewState: viewState,\n      viewHints: viewHints,\n      wantedTiles: {}\n    });\n  }\n\n  if (frameState) {\n    var preRenderFunctions = this.preRenderFunctions_;\n    var n = 0, preRenderFunction;\n    for (i = 0, ii = preRenderFunctions.length; i < ii; ++i) {\n      preRenderFunction = preRenderFunctions[i];\n      if (preRenderFunction(this, frameState)) {\n        preRenderFunctions[n++] = preRenderFunction;\n      }\n    }\n    preRenderFunctions.length = n;\n\n    frameState.extent = ol.extent.getForViewAndSize(viewState.center,\n        viewState.resolution, viewState.rotation, frameState.size, extent);\n  }\n\n  this.frameState_ = frameState;\n  this.renderer_.renderFrame(frameState);\n\n  if (frameState) {\n    if (frameState.animate) {\n      this.render();\n    }\n    Array.prototype.push.apply(\n        this.postRenderFunctions_, frameState.postRenderFunctions);\n\n    var idle = this.preRenderFunctions_.length === 0 &&\n        !frameState.viewHints[ol.View.Hint.ANIMATING] &&\n        !frameState.viewHints[ol.View.Hint.INTERACTING] &&\n        !ol.extent.equals(frameState.extent, this.previousExtent_);\n\n    if (idle) {\n      this.dispatchEvent(\n          new ol.MapEvent(ol.MapEvent.Type.MOVEEND, this, frameState));\n      ol.extent.clone(frameState.extent, this.previousExtent_);\n    }\n  }\n\n  this.dispatchEvent(\n      new ol.MapEvent(ol.MapEvent.Type.POSTRENDER, this, frameState));\n\n  setTimeout(this.handlePostRender.bind(this), 0);\n\n};\n\n\n/**\n * Sets the layergroup of this map.\n * @param {ol.layer.Group} layerGroup A layer group containing the layers in\n *     this map.\n * @observable\n * @api stable\n */\nol.Map.prototype.setLayerGroup = function(layerGroup) {\n  this.set(ol.Map.Property.LAYERGROUP, layerGroup);\n};\n\n\n/**\n * Set the size of this map.\n * @param {ol.Size|undefined} size The size in pixels of the map in the DOM.\n * @observable\n * @api\n */\nol.Map.prototype.setSize = function(size) {\n  this.set(ol.Map.Property.SIZE, size);\n};\n\n\n/**\n * Set the target element to render this map into.\n * @param {Element|string|undefined} target The Element or id of the Element\n *     that the map is rendered in.\n * @observable\n * @api stable\n */\nol.Map.prototype.setTarget = function(target) {\n  this.set(ol.Map.Property.TARGET, target);\n};\n\n\n/**\n * Set the view for this map.\n * @param {ol.View} view The view that controls this map.\n * @observable\n * @api stable\n */\nol.Map.prototype.setView = function(view) {\n  this.set(ol.Map.Property.VIEW, view);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n */\nol.Map.prototype.skipFeature = function(feature) {\n  var featureUid = ol.getUid(feature).toString();\n  this.skippedFeatureUids_[featureUid] = true;\n  this.render();\n};\n\n\n/**\n * Force a recalculation of the map viewport size.  This should be called when\n * third-party code changes the size of the map viewport.\n * @api stable\n */\nol.Map.prototype.updateSize = function() {\n  var targetElement = this.getTargetElement();\n\n  if (!targetElement) {\n    this.setSize(undefined);\n  } else {\n    var computedStyle = getComputedStyle(targetElement);\n    this.setSize([\n      targetElement.offsetWidth -\n          parseFloat(computedStyle['borderLeftWidth']) -\n          parseFloat(computedStyle['paddingLeft']) -\n          parseFloat(computedStyle['paddingRight']) -\n          parseFloat(computedStyle['borderRightWidth']),\n      targetElement.offsetHeight -\n          parseFloat(computedStyle['borderTopWidth']) -\n          parseFloat(computedStyle['paddingTop']) -\n          parseFloat(computedStyle['paddingBottom']) -\n          parseFloat(computedStyle['borderBottomWidth'])\n    ]);\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n */\nol.Map.prototype.unskipFeature = function(feature) {\n  var featureUid = ol.getUid(feature).toString();\n  delete this.skippedFeatureUids_[featureUid];\n  this.render();\n};\n\n\n/**\n * @param {olx.MapOptions} options Map options.\n * @return {ol.MapOptionsInternal} Internal map options.\n */\nol.Map.createOptionsInternal = function(options) {\n\n  /**\n   * @type {Element|Document}\n   */\n  var keyboardEventTarget = null;\n  if (options.keyboardEventTarget !== undefined) {\n    keyboardEventTarget = typeof options.keyboardEventTarget === 'string' ?\n        document.getElementById(options.keyboardEventTarget) :\n        options.keyboardEventTarget;\n  }\n\n  /**\n   * @type {Object.<string, *>}\n   */\n  var values = {};\n\n  var logos = {};\n  if (options.logo === undefined ||\n      (typeof options.logo === 'boolean' && options.logo)) {\n    logos[ol.OL3_LOGO_URL] = ol.OL3_URL;\n  } else {\n    var logo = options.logo;\n    if (typeof logo === 'string') {\n      logos[logo] = '';\n    } else if (logo instanceof HTMLElement) {\n      logos[ol.getUid(logo).toString()] = logo;\n    } else if (logo) {\n      ol.asserts.assert(typeof logo.href == 'string', 44); // `logo.href` should be a string.\n      ol.asserts.assert(typeof logo.src == 'string', 45); // `logo.src` should be a string.\n      logos[logo.src] = logo.href;\n    }\n  }\n\n  var layerGroup = (options.layers instanceof ol.layer.Group) ?\n      options.layers : new ol.layer.Group({layers: options.layers});\n  values[ol.Map.Property.LAYERGROUP] = layerGroup;\n\n  values[ol.Map.Property.TARGET] = options.target;\n\n  values[ol.Map.Property.VIEW] = options.view !== undefined ?\n      options.view : new ol.View();\n\n  /**\n   * @type {function(new: ol.renderer.Map, Element, ol.Map)}\n   */\n  var rendererConstructor = ol.renderer.Map;\n\n  /**\n   * @type {Array.<ol.renderer.Type>}\n   */\n  var rendererTypes;\n  if (options.renderer !== undefined) {\n    if (Array.isArray(options.renderer)) {\n      rendererTypes = options.renderer;\n    } else if (typeof options.renderer === 'string') {\n      rendererTypes = [options.renderer];\n    } else {\n      ol.asserts.assert(false, 46); // Incorrect format for `renderer` option\n    }\n    if (rendererTypes.indexOf(/** @type {ol.renderer.Type} */ ('dom')) >= 0) {\n      ol.DEBUG && console.assert(false, 'The DOM render has been removed');\n      rendererTypes = rendererTypes.concat(ol.DEFAULT_RENDERER_TYPES);\n    }\n  } else {\n    rendererTypes = ol.DEFAULT_RENDERER_TYPES;\n  }\n\n  var i, ii;\n  for (i = 0, ii = rendererTypes.length; i < ii; ++i) {\n    /** @type {ol.renderer.Type} */\n    var rendererType = rendererTypes[i];\n    if (ol.ENABLE_CANVAS && rendererType == ol.renderer.Type.CANVAS) {\n      if (ol.has.CANVAS) {\n        rendererConstructor = ol.renderer.canvas.Map;\n        break;\n      }\n    } else if (ol.ENABLE_WEBGL && rendererType == ol.renderer.Type.WEBGL) {\n      if (ol.has.WEBGL) {\n        rendererConstructor = ol.renderer.webgl.Map;\n        break;\n      }\n    }\n  }\n\n  var controls;\n  if (options.controls !== undefined) {\n    if (Array.isArray(options.controls)) {\n      controls = new ol.Collection(options.controls.slice());\n    } else {\n      ol.asserts.assert(options.controls instanceof ol.Collection,\n          47); // Expected `controls` to be an array or an `ol.Collection`\n      controls = options.controls;\n    }\n  } else {\n    controls = ol.control.defaults();\n  }\n\n  var interactions;\n  if (options.interactions !== undefined) {\n    if (Array.isArray(options.interactions)) {\n      interactions = new ol.Collection(options.interactions.slice());\n    } else {\n      ol.asserts.assert(options.interactions instanceof ol.Collection,\n          48); // Expected `interactions` to be an array or an `ol.Collection`\n      interactions = options.interactions;\n    }\n  } else {\n    interactions = ol.interaction.defaults();\n  }\n\n  var overlays;\n  if (options.overlays !== undefined) {\n    if (Array.isArray(options.overlays)) {\n      overlays = new ol.Collection(options.overlays.slice());\n    } else {\n      ol.asserts.assert(options.overlays instanceof ol.Collection,\n          49); // Expected `overlays` to be an array or an `ol.Collection`\n      overlays = options.overlays;\n    }\n  } else {\n    overlays = new ol.Collection();\n  }\n\n  return {\n    controls: controls,\n    interactions: interactions,\n    keyboardEventTarget: keyboardEventTarget,\n    logos: logos,\n    overlays: overlays,\n    rendererConstructor: rendererConstructor,\n    values: values\n  };\n\n};\n\n/**\n * @enum {string}\n */\nol.Map.Property = {\n  LAYERGROUP: 'layergroup',\n  SIZE: 'size',\n  TARGET: 'target',\n  VIEW: 'view'\n};\n\n\nol.proj.common.add();\n\ngoog.provide('ol.Overlay');\n\ngoog.require('ol');\ngoog.require('ol.MapEvent');\ngoog.require('ol.Object');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.extent');\n\n\n/**\n * @classdesc\n * An element to be displayed over the map and attached to a single map\n * location.  Like {@link ol.control.Control}, Overlays are visible widgets.\n * Unlike Controls, they are not in a fixed position on the screen, but are tied\n * to a geographical coordinate, so panning the map will move an Overlay but not\n * a Control.\n *\n * Example:\n *\n *     var popup = new ol.Overlay({\n *       element: document.getElementById('popup')\n *     });\n *     popup.setPosition(coordinate);\n *     map.addOverlay(popup);\n *\n * @constructor\n * @extends {ol.Object}\n * @param {olx.OverlayOptions} options Overlay options.\n * @api stable\n */\nol.Overlay = function(options) {\n\n  ol.Object.call(this);\n\n  /**\n   * @private\n   * @type {number|string|undefined}\n   */\n  this.id_ = options.id;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.insertFirst_ = options.insertFirst !== undefined ?\n      options.insertFirst : true;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.stopEvent_ = options.stopEvent !== undefined ? options.stopEvent : true;\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.element_ = document.createElement('DIV');\n  this.element_.className = 'ol-overlay-container';\n  this.element_.style.position = 'absolute';\n\n  /**\n   * @protected\n   * @type {boolean}\n   */\n  this.autoPan = options.autoPan !== undefined ? options.autoPan : false;\n\n  /**\n   * @private\n   * @type {olx.OverlayPanOptions}\n   */\n  this.autoPanAnimation_ = options.autoPanAnimation ||\n      /** @type {olx.OverlayPanOptions} */ ({});\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.autoPanMargin_ = options.autoPanMargin !== undefined ?\n      options.autoPanMargin : 20;\n\n  /**\n   * @private\n   * @type {{bottom_: string,\n   *         left_: string,\n   *         right_: string,\n   *         top_: string,\n   *         visible: boolean}}\n   */\n  this.rendered_ = {\n    bottom_: '',\n    left_: '',\n    right_: '',\n    top_: '',\n    visible: true\n  };\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.mapPostrenderListenerKey_ = null;\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Overlay.Property.ELEMENT),\n      this.handleElementChanged, this);\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Overlay.Property.MAP),\n      this.handleMapChanged, this);\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Overlay.Property.OFFSET),\n      this.handleOffsetChanged, this);\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Overlay.Property.POSITION),\n      this.handlePositionChanged, this);\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Overlay.Property.POSITIONING),\n      this.handlePositioningChanged, this);\n\n  if (options.element !== undefined) {\n    this.setElement(options.element);\n  }\n\n  this.setOffset(options.offset !== undefined ? options.offset : [0, 0]);\n\n  this.setPositioning(options.positioning !== undefined ?\n      /** @type {ol.Overlay.Positioning} */ (options.positioning) :\n      ol.Overlay.Positioning.TOP_LEFT);\n\n  if (options.position !== undefined) {\n    this.setPosition(options.position);\n  }\n\n};\nol.inherits(ol.Overlay, ol.Object);\n\n\n/**\n * Get the DOM element of this overlay.\n * @return {Element|undefined} The Element containing the overlay.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.getElement = function() {\n  return /** @type {Element|undefined} */ (\n      this.get(ol.Overlay.Property.ELEMENT));\n};\n\n\n/**\n * Get the overlay identifier which is set on constructor.\n * @return {number|string|undefined} Id.\n * @api\n */\nol.Overlay.prototype.getId = function() {\n  return this.id_;\n};\n\n\n/**\n * Get the map associated with this overlay.\n * @return {ol.Map|undefined} The map that the overlay is part of.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.getMap = function() {\n  return /** @type {ol.Map|undefined} */ (\n      this.get(ol.Overlay.Property.MAP));\n};\n\n\n/**\n * Get the offset of this overlay.\n * @return {Array.<number>} The offset.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.getOffset = function() {\n  return /** @type {Array.<number>} */ (\n      this.get(ol.Overlay.Property.OFFSET));\n};\n\n\n/**\n * Get the current position of this overlay.\n * @return {ol.Coordinate|undefined} The spatial point that the overlay is\n *     anchored at.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.getPosition = function() {\n  return /** @type {ol.Coordinate|undefined} */ (\n      this.get(ol.Overlay.Property.POSITION));\n};\n\n\n/**\n * Get the current positioning of this overlay.\n * @return {ol.Overlay.Positioning} How the overlay is positioned\n *     relative to its point on the map.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.getPositioning = function() {\n  return /** @type {ol.Overlay.Positioning} */ (\n      this.get(ol.Overlay.Property.POSITIONING));\n};\n\n\n/**\n * @protected\n */\nol.Overlay.prototype.handleElementChanged = function() {\n  ol.dom.removeChildren(this.element_);\n  var element = this.getElement();\n  if (element) {\n    this.element_.appendChild(element);\n  }\n};\n\n\n/**\n * @protected\n */\nol.Overlay.prototype.handleMapChanged = function() {\n  if (this.mapPostrenderListenerKey_) {\n    ol.dom.removeNode(this.element_);\n    ol.events.unlistenByKey(this.mapPostrenderListenerKey_);\n    this.mapPostrenderListenerKey_ = null;\n  }\n  var map = this.getMap();\n  if (map) {\n    this.mapPostrenderListenerKey_ = ol.events.listen(map,\n        ol.MapEvent.Type.POSTRENDER, this.render, this);\n    this.updatePixelPosition();\n    var container = this.stopEvent_ ?\n        map.getOverlayContainerStopEvent() : map.getOverlayContainer();\n    if (this.insertFirst_) {\n      container.insertBefore(this.element_, container.childNodes[0] || null);\n    } else {\n      container.appendChild(this.element_);\n    }\n  }\n};\n\n\n/**\n * @protected\n */\nol.Overlay.prototype.render = function() {\n  this.updatePixelPosition();\n};\n\n\n/**\n * @protected\n */\nol.Overlay.prototype.handleOffsetChanged = function() {\n  this.updatePixelPosition();\n};\n\n\n/**\n * @protected\n */\nol.Overlay.prototype.handlePositionChanged = function() {\n  this.updatePixelPosition();\n  if (this.get(ol.Overlay.Property.POSITION) !== undefined && this.autoPan) {\n    this.panIntoView_();\n  }\n};\n\n\n/**\n * @protected\n */\nol.Overlay.prototype.handlePositioningChanged = function() {\n  this.updatePixelPosition();\n};\n\n\n/**\n * Set the DOM element to be associated with this overlay.\n * @param {Element|undefined} element The Element containing the overlay.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.setElement = function(element) {\n  this.set(ol.Overlay.Property.ELEMENT, element);\n};\n\n\n/**\n * Set the map to be associated with this overlay.\n * @param {ol.Map|undefined} map The map that the overlay is part of.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.setMap = function(map) {\n  this.set(ol.Overlay.Property.MAP, map);\n};\n\n\n/**\n * Set the offset for this overlay.\n * @param {Array.<number>} offset Offset.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.setOffset = function(offset) {\n  this.set(ol.Overlay.Property.OFFSET, offset);\n};\n\n\n/**\n * Set the position for this overlay. If the position is `undefined` the\n * overlay is hidden.\n * @param {ol.Coordinate|undefined} position The spatial point that the overlay\n *     is anchored at.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.setPosition = function(position) {\n  this.set(ol.Overlay.Property.POSITION, position);\n};\n\n\n/**\n * Pan the map so that the overlay is entirely visible in the current viewport\n * (if necessary).\n * @private\n */\nol.Overlay.prototype.panIntoView_ = function() {\n  var map = this.getMap();\n\n  if (map === undefined || !map.getTargetElement()) {\n    return;\n  }\n\n  var mapRect = this.getRect_(map.getTargetElement(), map.getSize());\n  var element = /** @type {!Element} */ (this.getElement());\n  var overlayRect = this.getRect_(element,\n      [ol.dom.outerWidth(element), ol.dom.outerHeight(element)]);\n\n  var margin = this.autoPanMargin_;\n  if (!ol.extent.containsExtent(mapRect, overlayRect)) {\n    // the overlay is not completely inside the viewport, so pan the map\n    var offsetLeft = overlayRect[0] - mapRect[0];\n    var offsetRight = mapRect[2] - overlayRect[2];\n    var offsetTop = overlayRect[1] - mapRect[1];\n    var offsetBottom = mapRect[3] - overlayRect[3];\n\n    var delta = [0, 0];\n    if (offsetLeft < 0) {\n      // move map to the left\n      delta[0] = offsetLeft - margin;\n    } else if (offsetRight < 0) {\n      // move map to the right\n      delta[0] = Math.abs(offsetRight) + margin;\n    }\n    if (offsetTop < 0) {\n      // move map up\n      delta[1] = offsetTop - margin;\n    } else if (offsetBottom < 0) {\n      // move map down\n      delta[1] = Math.abs(offsetBottom) + margin;\n    }\n\n    if (delta[0] !== 0 || delta[1] !== 0) {\n      var center = /** @type {ol.Coordinate} */ (map.getView().getCenter());\n      var centerPx = map.getPixelFromCoordinate(center);\n      var newCenterPx = [\n        centerPx[0] + delta[0],\n        centerPx[1] + delta[1]\n      ];\n\n      map.getView().animate({\n        center: map.getCoordinateFromPixel(newCenterPx),\n        duration: this.autoPanAnimation_.duration,\n        easing: this.autoPanAnimation_.easing\n      });\n    }\n  }\n};\n\n\n/**\n * Get the extent of an element relative to the document\n * @param {Element|undefined} element The element.\n * @param {ol.Size|undefined} size The size of the element.\n * @return {ol.Extent} The extent.\n * @private\n */\nol.Overlay.prototype.getRect_ = function(element, size) {\n  var box = element.getBoundingClientRect();\n  var offsetX = box.left + window.pageXOffset;\n  var offsetY = box.top + window.pageYOffset;\n  return [\n    offsetX,\n    offsetY,\n    offsetX + size[0],\n    offsetY + size[1]\n  ];\n};\n\n\n/**\n * Set the positioning for this overlay.\n * @param {ol.Overlay.Positioning} positioning how the overlay is\n *     positioned relative to its point on the map.\n * @observable\n * @api stable\n */\nol.Overlay.prototype.setPositioning = function(positioning) {\n  this.set(ol.Overlay.Property.POSITIONING, positioning);\n};\n\n\n/**\n * Modify the visibility of the element.\n * @param {boolean} visible Element visibility.\n * @protected\n */\nol.Overlay.prototype.setVisible = function(visible) {\n  if (this.rendered_.visible !== visible) {\n    this.element_.style.display = visible ? '' : 'none';\n    this.rendered_.visible = visible;\n  }\n};\n\n\n/**\n * Update pixel position.\n * @protected\n */\nol.Overlay.prototype.updatePixelPosition = function() {\n  var map = this.getMap();\n  var position = this.getPosition();\n  if (map === undefined || !map.isRendered() || position === undefined) {\n    this.setVisible(false);\n    return;\n  }\n\n  var pixel = map.getPixelFromCoordinate(position);\n  var mapSize = map.getSize();\n  this.updateRenderedPosition(pixel, mapSize);\n};\n\n\n/**\n * @param {ol.Pixel} pixel The pixel location.\n * @param {ol.Size|undefined} mapSize The map size.\n * @protected\n */\nol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) {\n  var style = this.element_.style;\n  var offset = this.getOffset();\n\n  var positioning = this.getPositioning();\n  ol.DEBUG && console.assert(positioning !== undefined,\n      'positioning should be defined');\n\n  var offsetX = offset[0];\n  var offsetY = offset[1];\n  if (positioning == ol.Overlay.Positioning.BOTTOM_RIGHT ||\n      positioning == ol.Overlay.Positioning.CENTER_RIGHT ||\n      positioning == ol.Overlay.Positioning.TOP_RIGHT) {\n    if (this.rendered_.left_ !== '') {\n      this.rendered_.left_ = style.left = '';\n    }\n    var right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';\n    if (this.rendered_.right_ != right) {\n      this.rendered_.right_ = style.right = right;\n    }\n  } else {\n    if (this.rendered_.right_ !== '') {\n      this.rendered_.right_ = style.right = '';\n    }\n    if (positioning == ol.Overlay.Positioning.BOTTOM_CENTER ||\n        positioning == ol.Overlay.Positioning.CENTER_CENTER ||\n        positioning == ol.Overlay.Positioning.TOP_CENTER) {\n      offsetX -= this.element_.offsetWidth / 2;\n    }\n    var left = Math.round(pixel[0] + offsetX) + 'px';\n    if (this.rendered_.left_ != left) {\n      this.rendered_.left_ = style.left = left;\n    }\n  }\n  if (positioning == ol.Overlay.Positioning.BOTTOM_LEFT ||\n      positioning == ol.Overlay.Positioning.BOTTOM_CENTER ||\n      positioning == ol.Overlay.Positioning.BOTTOM_RIGHT) {\n    if (this.rendered_.top_ !== '') {\n      this.rendered_.top_ = style.top = '';\n    }\n    var bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';\n    if (this.rendered_.bottom_ != bottom) {\n      this.rendered_.bottom_ = style.bottom = bottom;\n    }\n  } else {\n    if (this.rendered_.bottom_ !== '') {\n      this.rendered_.bottom_ = style.bottom = '';\n    }\n    if (positioning == ol.Overlay.Positioning.CENTER_LEFT ||\n        positioning == ol.Overlay.Positioning.CENTER_CENTER ||\n        positioning == ol.Overlay.Positioning.CENTER_RIGHT) {\n      offsetY -= this.element_.offsetHeight / 2;\n    }\n    var top = Math.round(pixel[1] + offsetY) + 'px';\n    if (this.rendered_.top_ != top) {\n      this.rendered_.top_ = style.top = top;\n    }\n  }\n\n  this.setVisible(true);\n};\n\n\n/**\n * Overlay position: `'bottom-left'`, `'bottom-center'`,  `'bottom-right'`,\n * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`,\n * `'top-center'`, `'top-right'`\n * @enum {string}\n */\nol.Overlay.Positioning = {\n  BOTTOM_LEFT: 'bottom-left',\n  BOTTOM_CENTER: 'bottom-center',\n  BOTTOM_RIGHT: 'bottom-right',\n  CENTER_LEFT: 'center-left',\n  CENTER_CENTER: 'center-center',\n  CENTER_RIGHT: 'center-right',\n  TOP_LEFT: 'top-left',\n  TOP_CENTER: 'top-center',\n  TOP_RIGHT: 'top-right'\n};\n\n\n/**\n * @enum {string}\n */\nol.Overlay.Property = {\n  ELEMENT: 'element',\n  MAP: 'map',\n  OFFSET: 'offset',\n  POSITION: 'position',\n  POSITIONING: 'positioning'\n};\n\ngoog.provide('ol.control.OverviewMap');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.Map');\ngoog.require('ol.MapEvent');\ngoog.require('ol.Object');\ngoog.require('ol.Overlay');\ngoog.require('ol.View');\ngoog.require('ol.control.Control');\ngoog.require('ol.coordinate');\ngoog.require('ol.css');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\n\n\n/**\n * Create a new control with a map acting as an overview map for an other\n * defined map.\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.OverviewMapOptions=} opt_options OverviewMap options.\n * @api\n */\nol.control.OverviewMap = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.collapsible_ = options.collapsible !== undefined ?\n      options.collapsible : true;\n\n  if (!this.collapsible_) {\n    this.collapsed_ = false;\n  }\n\n  var className = options.className !== undefined ? options.className : 'ol-overviewmap';\n\n  var tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Overview map';\n\n  var collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\\u00AB';\n\n  if (typeof collapseLabel === 'string') {\n    /**\n     * @private\n     * @type {Node}\n     */\n    this.collapseLabel_ = document.createElement('span');\n    this.collapseLabel_.textContent = collapseLabel;\n  } else {\n    this.collapseLabel_ = collapseLabel;\n  }\n\n  var label = options.label !== undefined ? options.label : '\\u00BB';\n\n\n  if (typeof label === 'string') {\n    /**\n     * @private\n     * @type {Node}\n     */\n    this.label_ = document.createElement('span');\n    this.label_.textContent = label;\n  } else {\n    this.label_ = label;\n  }\n\n  var activeLabel = (this.collapsible_ && !this.collapsed_) ?\n      this.collapseLabel_ : this.label_;\n  var button = document.createElement('button');\n  button.setAttribute('type', 'button');\n  button.title = tipLabel;\n  button.appendChild(activeLabel);\n\n  ol.events.listen(button, ol.events.EventType.CLICK,\n      this.handleClick_, this);\n\n  var ovmapDiv = document.createElement('DIV');\n  ovmapDiv.className = 'ol-overviewmap-map';\n\n  /**\n   * @type {ol.Map}\n   * @private\n   */\n  this.ovmap_ = new ol.Map({\n    controls: new ol.Collection(),\n    interactions: new ol.Collection(),\n    target: ovmapDiv,\n    view: options.view\n  });\n  var ovmap = this.ovmap_;\n\n  if (options.layers) {\n    options.layers.forEach(\n        /**\n       * @param {ol.layer.Layer} layer Layer.\n       */\n        function(layer) {\n          ovmap.addLayer(layer);\n        }, this);\n  }\n\n  var box = document.createElement('DIV');\n  box.className = 'ol-overviewmap-box';\n  box.style.boxSizing = 'border-box';\n\n  /**\n   * @type {ol.Overlay}\n   * @private\n   */\n  this.boxOverlay_ = new ol.Overlay({\n    position: [0, 0],\n    positioning: ol.Overlay.Positioning.BOTTOM_LEFT,\n    element: box\n  });\n  this.ovmap_.addOverlay(this.boxOverlay_);\n\n  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +\n      ol.css.CLASS_CONTROL +\n      (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +\n      (this.collapsible_ ? '' : ' ol-uncollapsible');\n  var element = document.createElement('div');\n  element.className = cssClasses;\n  element.appendChild(ovmapDiv);\n  element.appendChild(button);\n\n  var render = options.render ? options.render : ol.control.OverviewMap.render;\n\n  ol.control.Control.call(this, {\n    element: element,\n    render: render,\n    target: options.target\n  });\n};\nol.inherits(ol.control.OverviewMap, ol.control.Control);\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.control.OverviewMap.prototype.setMap = function(map) {\n  var oldMap = this.getMap();\n  if (map === oldMap) {\n    return;\n  }\n  if (oldMap) {\n    var oldView = oldMap.getView();\n    if (oldView) {\n      this.unbindView_(oldView);\n    }\n  }\n  ol.control.Control.prototype.setMap.call(this, map);\n\n  if (map) {\n    this.listenerKeys.push(ol.events.listen(\n        map, ol.Object.EventType.PROPERTYCHANGE,\n        this.handleMapPropertyChange_, this));\n\n    // TODO: to really support map switching, this would need to be reworked\n    if (this.ovmap_.getLayers().getLength() === 0) {\n      this.ovmap_.setLayerGroup(map.getLayerGroup());\n    }\n\n    var view = map.getView();\n    if (view) {\n      this.bindView_(view);\n      if (view.isDef()) {\n        this.ovmap_.updateSize();\n        this.resetExtent_();\n      }\n    }\n  }\n};\n\n\n/**\n * Handle map property changes.  This only deals with changes to the map's view.\n * @param {ol.Object.Event} event The propertychange event.\n * @private\n */\nol.control.OverviewMap.prototype.handleMapPropertyChange_ = function(event) {\n  if (event.key === ol.Map.Property.VIEW) {\n    var oldView = /** @type {ol.View} */ (event.oldValue);\n    if (oldView) {\n      this.unbindView_(oldView);\n    }\n    var newView = this.getMap().getView();\n    this.bindView_(newView);\n  }\n};\n\n\n/**\n * Register listeners for view property changes.\n * @param {ol.View} view The view.\n * @private\n */\nol.control.OverviewMap.prototype.bindView_ = function(view) {\n  ol.events.listen(view,\n      ol.Object.getChangeEventType(ol.View.Property.ROTATION),\n      this.handleRotationChanged_, this);\n};\n\n\n/**\n * Unregister listeners for view property changes.\n * @param {ol.View} view The view.\n * @private\n */\nol.control.OverviewMap.prototype.unbindView_ = function(view) {\n  ol.events.unlisten(view,\n      ol.Object.getChangeEventType(ol.View.Property.ROTATION),\n      this.handleRotationChanged_, this);\n};\n\n\n/**\n * Handle rotation changes to the main map.\n * TODO: This should rotate the extent rectrangle instead of the\n * overview map's view.\n * @private\n */\nol.control.OverviewMap.prototype.handleRotationChanged_ = function() {\n  this.ovmap_.getView().setRotation(this.getMap().getView().getRotation());\n};\n\n\n/**\n * Update the overview map element.\n * @param {ol.MapEvent} mapEvent Map event.\n * @this {ol.control.OverviewMap}\n * @api\n */\nol.control.OverviewMap.render = function(mapEvent) {\n  this.validateExtent_();\n  this.updateBox_();\n};\n\n\n/**\n * Reset the overview map extent if the box size (width or\n * height) is less than the size of the overview map size times minRatio\n * or is greater than the size of the overview size times maxRatio.\n *\n * If the map extent was not reset, the box size can fits in the defined\n * ratio sizes. This method then checks if is contained inside the overview\n * map current extent. If not, recenter the overview map to the current\n * main map center location.\n * @private\n */\nol.control.OverviewMap.prototype.validateExtent_ = function() {\n  var map = this.getMap();\n  var ovmap = this.ovmap_;\n\n  if (!map.isRendered() || !ovmap.isRendered()) {\n    return;\n  }\n\n  var mapSize = /** @type {ol.Size} */ (map.getSize());\n\n  var view = map.getView();\n  var extent = view.calculateExtent(mapSize);\n\n  var ovmapSize = /** @type {ol.Size} */ (ovmap.getSize());\n\n  var ovview = ovmap.getView();\n  var ovextent = ovview.calculateExtent(ovmapSize);\n\n  var topLeftPixel =\n      ovmap.getPixelFromCoordinate(ol.extent.getTopLeft(extent));\n  var bottomRightPixel =\n      ovmap.getPixelFromCoordinate(ol.extent.getBottomRight(extent));\n\n  var boxWidth = Math.abs(topLeftPixel[0] - bottomRightPixel[0]);\n  var boxHeight = Math.abs(topLeftPixel[1] - bottomRightPixel[1]);\n\n  var ovmapWidth = ovmapSize[0];\n  var ovmapHeight = ovmapSize[1];\n\n  if (boxWidth < ovmapWidth * ol.OVERVIEWMAP_MIN_RATIO ||\n      boxHeight < ovmapHeight * ol.OVERVIEWMAP_MIN_RATIO ||\n      boxWidth > ovmapWidth * ol.OVERVIEWMAP_MAX_RATIO ||\n      boxHeight > ovmapHeight * ol.OVERVIEWMAP_MAX_RATIO) {\n    this.resetExtent_();\n  } else if (!ol.extent.containsExtent(ovextent, extent)) {\n    this.recenter_();\n  }\n};\n\n\n/**\n * Reset the overview map extent to half calculated min and max ratio times\n * the extent of the main map.\n * @private\n */\nol.control.OverviewMap.prototype.resetExtent_ = function() {\n  if (ol.OVERVIEWMAP_MAX_RATIO === 0 || ol.OVERVIEWMAP_MIN_RATIO === 0) {\n    return;\n  }\n\n  var map = this.getMap();\n  var ovmap = this.ovmap_;\n\n  var mapSize = /** @type {ol.Size} */ (map.getSize());\n\n  var view = map.getView();\n  var extent = view.calculateExtent(mapSize);\n\n  var ovmapSize = /** @type {ol.Size} */ (ovmap.getSize());\n\n  var ovview = ovmap.getView();\n\n  // get how many times the current map overview could hold different\n  // box sizes using the min and max ratio, pick the step in the middle used\n  // to calculate the extent from the main map to set it to the overview map,\n  var steps = Math.log(\n      ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2;\n  var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO);\n  ol.extent.scaleFromCenter(extent, ratio);\n  ovview.fit(extent, ovmapSize);\n};\n\n\n/**\n * Set the center of the overview map to the map center without changing its\n * resolution.\n * @private\n */\nol.control.OverviewMap.prototype.recenter_ = function() {\n  var map = this.getMap();\n  var ovmap = this.ovmap_;\n\n  var view = map.getView();\n\n  var ovview = ovmap.getView();\n\n  ovview.setCenter(view.getCenter());\n};\n\n\n/**\n * Update the box using the main map extent\n * @private\n */\nol.control.OverviewMap.prototype.updateBox_ = function() {\n  var map = this.getMap();\n  var ovmap = this.ovmap_;\n\n  if (!map.isRendered() || !ovmap.isRendered()) {\n    return;\n  }\n\n  var mapSize = /** @type {ol.Size} */ (map.getSize());\n\n  var view = map.getView();\n\n  var ovview = ovmap.getView();\n\n  var rotation = view.getRotation();\n\n  var overlay = this.boxOverlay_;\n  var box = this.boxOverlay_.getElement();\n  var extent = view.calculateExtent(mapSize);\n  var ovresolution = ovview.getResolution();\n  var bottomLeft = ol.extent.getBottomLeft(extent);\n  var topRight = ol.extent.getTopRight(extent);\n\n  // set position using bottom left coordinates\n  var rotateBottomLeft = this.calculateCoordinateRotate_(rotation, bottomLeft);\n  overlay.setPosition(rotateBottomLeft);\n\n  // set box size calculated from map extent size and overview map resolution\n  if (box) {\n    box.style.width = Math.abs((bottomLeft[0] - topRight[0]) / ovresolution) + 'px';\n    box.style.height = Math.abs((topRight[1] - bottomLeft[1]) / ovresolution) + 'px';\n  }\n};\n\n\n/**\n * @param {number} rotation Target rotation.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @return {ol.Coordinate|undefined} Coordinate for rotation and center anchor.\n * @private\n */\nol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function(\n    rotation, coordinate) {\n  var coordinateRotate;\n\n  var map = this.getMap();\n  var view = map.getView();\n\n  var currentCenter = view.getCenter();\n\n  if (currentCenter) {\n    coordinateRotate = [\n      coordinate[0] - currentCenter[0],\n      coordinate[1] - currentCenter[1]\n    ];\n    ol.coordinate.rotate(coordinateRotate, rotation);\n    ol.coordinate.add(coordinateRotate, currentCenter);\n  }\n  return coordinateRotate;\n};\n\n\n/**\n * @param {Event} event The event to handle\n * @private\n */\nol.control.OverviewMap.prototype.handleClick_ = function(event) {\n  event.preventDefault();\n  this.handleToggle_();\n};\n\n\n/**\n * @private\n */\nol.control.OverviewMap.prototype.handleToggle_ = function() {\n  this.element.classList.toggle('ol-collapsed');\n  if (this.collapsed_) {\n    ol.dom.replaceNode(this.collapseLabel_, this.label_);\n  } else {\n    ol.dom.replaceNode(this.label_, this.collapseLabel_);\n  }\n  this.collapsed_ = !this.collapsed_;\n\n  // manage overview map if it had not been rendered before and control\n  // is expanded\n  var ovmap = this.ovmap_;\n  if (!this.collapsed_ && !ovmap.isRendered()) {\n    ovmap.updateSize();\n    this.resetExtent_();\n    ol.events.listenOnce(ovmap, ol.MapEvent.Type.POSTRENDER,\n        function(event) {\n          this.updateBox_();\n        },\n        this);\n  }\n};\n\n\n/**\n * Return `true` if the overview map is collapsible, `false` otherwise.\n * @return {boolean} True if the widget is collapsible.\n * @api stable\n */\nol.control.OverviewMap.prototype.getCollapsible = function() {\n  return this.collapsible_;\n};\n\n\n/**\n * Set whether the overview map should be collapsible.\n * @param {boolean} collapsible True if the widget is collapsible.\n * @api stable\n */\nol.control.OverviewMap.prototype.setCollapsible = function(collapsible) {\n  if (this.collapsible_ === collapsible) {\n    return;\n  }\n  this.collapsible_ = collapsible;\n  this.element.classList.toggle('ol-uncollapsible');\n  if (!collapsible && this.collapsed_) {\n    this.handleToggle_();\n  }\n};\n\n\n/**\n * Collapse or expand the overview map according to the passed parameter. Will\n * not do anything if the overview map isn't collapsible or if the current\n * collapsed state is already the one requested.\n * @param {boolean} collapsed True if the widget is collapsed.\n * @api stable\n */\nol.control.OverviewMap.prototype.setCollapsed = function(collapsed) {\n  if (!this.collapsible_ || this.collapsed_ === collapsed) {\n    return;\n  }\n  this.handleToggle_();\n};\n\n\n/**\n * Determine if the overview map is collapsed.\n * @return {boolean} The overview map is collapsed.\n * @api stable\n */\nol.control.OverviewMap.prototype.getCollapsed = function() {\n  return this.collapsed_;\n};\n\n\n/**\n * Return the overview map.\n * @return {ol.Map} Overview map.\n * @api\n */\nol.control.OverviewMap.prototype.getOverviewMap = function() {\n  return this.ovmap_;\n};\n\ngoog.provide('ol.control.ScaleLine');\n\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.asserts');\ngoog.require('ol.control.Control');\ngoog.require('ol.css');\ngoog.require('ol.events');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Units');\n\n\n/**\n * @classdesc\n * A control displaying rough y-axis distances, calculated for the center of the\n * viewport. For conformal projections (e.g. EPSG:3857, the default view\n * projection in OpenLayers), the scale is valid for all directions.\n * No scale line will be shown when the y-axis distance of a pixel at the\n * viewport center cannot be calculated in the view projection.\n * By default the scale line will show in the bottom left portion of the map,\n * but this can be changed by using the css selector `.ol-scale-line`.\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.ScaleLineOptions=} opt_options Scale line options.\n * @api stable\n */\nol.control.ScaleLine = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  var className = options.className !== undefined ? options.className : 'ol-scale-line';\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.innerElement_ = document.createElement('DIV');\n  this.innerElement_.className = className + '-inner';\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.element_ = document.createElement('DIV');\n  this.element_.className = className + ' ' + ol.css.CLASS_UNSELECTABLE;\n  this.element_.appendChild(this.innerElement_);\n\n  /**\n   * @private\n   * @type {?olx.ViewState}\n   */\n  this.viewState_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.renderedVisible_ = false;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.renderedWidth_ = undefined;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.renderedHTML_ = '';\n\n  var render = options.render ? options.render : ol.control.ScaleLine.render;\n\n  ol.control.Control.call(this, {\n    element: this.element_,\n    render: render,\n    target: options.target\n  });\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.control.ScaleLine.Property.UNITS),\n      this.handleUnitsChanged_, this);\n\n  this.setUnits(/** @type {ol.control.ScaleLine.Units} */ (options.units) ||\n      ol.control.ScaleLine.Units.METRIC);\n\n};\nol.inherits(ol.control.ScaleLine, ol.control.Control);\n\n\n/**\n * @const\n * @type {Array.<number>}\n */\nol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5];\n\n\n/**\n * Return the units to use in the scale line.\n * @return {ol.control.ScaleLine.Units|undefined} The units to use in the scale\n *     line.\n * @observable\n * @api stable\n */\nol.control.ScaleLine.prototype.getUnits = function() {\n  return /** @type {ol.control.ScaleLine.Units|undefined} */ (\n      this.get(ol.control.ScaleLine.Property.UNITS));\n};\n\n\n/**\n * Update the scale line element.\n * @param {ol.MapEvent} mapEvent Map event.\n * @this {ol.control.ScaleLine}\n * @api\n */\nol.control.ScaleLine.render = function(mapEvent) {\n  var frameState = mapEvent.frameState;\n  if (!frameState) {\n    this.viewState_ = null;\n  } else {\n    this.viewState_ = frameState.viewState;\n  }\n  this.updateElement_();\n};\n\n\n/**\n * @private\n */\nol.control.ScaleLine.prototype.handleUnitsChanged_ = function() {\n  this.updateElement_();\n};\n\n\n/**\n * Set the units to use in the scale line.\n * @param {ol.control.ScaleLine.Units} units The units to use in the scale line.\n * @observable\n * @api stable\n */\nol.control.ScaleLine.prototype.setUnits = function(units) {\n  this.set(ol.control.ScaleLine.Property.UNITS, units);\n};\n\n\n/**\n * @private\n */\nol.control.ScaleLine.prototype.updateElement_ = function() {\n  var viewState = this.viewState_;\n\n  if (!viewState) {\n    if (this.renderedVisible_) {\n      this.element_.style.display = 'none';\n      this.renderedVisible_ = false;\n    }\n    return;\n  }\n\n  var center = viewState.center;\n  var projection = viewState.projection;\n  var metersPerUnit = projection.getMetersPerUnit();\n  var pointResolution =\n      ol.proj.getPointResolution(projection, viewState.resolution, center) *\n      metersPerUnit;\n\n  var nominalCount = this.minWidth_ * pointResolution;\n  var suffix = '';\n  var units = this.getUnits();\n  if (units == ol.control.ScaleLine.Units.DEGREES) {\n    var metersPerDegree = ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES];\n    pointResolution /= metersPerDegree;\n    if (nominalCount < metersPerDegree / 60) {\n      suffix = '\\u2033'; // seconds\n      pointResolution *= 3600;\n    } else if (nominalCount < metersPerDegree) {\n      suffix = '\\u2032'; // minutes\n      pointResolution *= 60;\n    } else {\n      suffix = '\\u00b0'; // degrees\n    }\n  } else if (units == ol.control.ScaleLine.Units.IMPERIAL) {\n    if (nominalCount < 0.9144) {\n      suffix = 'in';\n      pointResolution /= 0.0254;\n    } else if (nominalCount < 1609.344) {\n      suffix = 'ft';\n      pointResolution /= 0.3048;\n    } else {\n      suffix = 'mi';\n      pointResolution /= 1609.344;\n    }\n  } else if (units == ol.control.ScaleLine.Units.NAUTICAL) {\n    pointResolution /= 1852;\n    suffix = 'nm';\n  } else if (units == ol.control.ScaleLine.Units.METRIC) {\n    if (nominalCount < 1) {\n      suffix = 'mm';\n      pointResolution *= 1000;\n    } else if (nominalCount < 1000) {\n      suffix = 'm';\n    } else {\n      suffix = 'km';\n      pointResolution /= 1000;\n    }\n  } else if (units == ol.control.ScaleLine.Units.US) {\n    if (nominalCount < 0.9144) {\n      suffix = 'in';\n      pointResolution *= 39.37;\n    } else if (nominalCount < 1609.344) {\n      suffix = 'ft';\n      pointResolution /= 0.30480061;\n    } else {\n      suffix = 'mi';\n      pointResolution /= 1609.3472;\n    }\n  } else {\n    ol.asserts.assert(false, 33); // Invalid units\n  }\n\n  var i = 3 * Math.floor(\n      Math.log(this.minWidth_ * pointResolution) / Math.log(10));\n  var count, width;\n  while (true) {\n    count = ol.control.ScaleLine.LEADING_DIGITS[((i % 3) + 3) % 3] *\n        Math.pow(10, Math.floor(i / 3));\n    width = Math.round(count / pointResolution);\n    if (isNaN(width)) {\n      this.element_.style.display = 'none';\n      this.renderedVisible_ = false;\n      return;\n    } else if (width >= this.minWidth_) {\n      break;\n    }\n    ++i;\n  }\n\n  var html = count + ' ' + suffix;\n  if (this.renderedHTML_ != html) {\n    this.innerElement_.innerHTML = html;\n    this.renderedHTML_ = html;\n  }\n\n  if (this.renderedWidth_ != width) {\n    this.innerElement_.style.width = width + 'px';\n    this.renderedWidth_ = width;\n  }\n\n  if (!this.renderedVisible_) {\n    this.element_.style.display = '';\n    this.renderedVisible_ = true;\n  }\n\n};\n\n\n/**\n * @enum {string}\n * @api\n */\nol.control.ScaleLine.Property = {\n  UNITS: 'units'\n};\n\n\n/**\n * Units for the scale line. Supported values are `'degrees'`, `'imperial'`,\n * `'nautical'`, `'metric'`, `'us'`.\n * @enum {string}\n */\nol.control.ScaleLine.Units = {\n  DEGREES: 'degrees',\n  IMPERIAL: 'imperial',\n  NAUTICAL: 'nautical',\n  METRIC: 'metric',\n  US: 'us'\n};\n\n// FIXME should possibly show tooltip when dragging?\n\ngoog.provide('ol.control.ZoomSlider');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.control.Control');\ngoog.require('ol.css');\ngoog.require('ol.easing');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.EventType');\ngoog.require('ol.math');\ngoog.require('ol.pointer.EventType');\ngoog.require('ol.pointer.PointerEventHandler');\n\n\n/**\n * @classdesc\n * A slider type of control for zooming.\n *\n * Example:\n *\n *     map.addControl(new ol.control.ZoomSlider());\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options.\n * @api stable\n */\nol.control.ZoomSlider = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * Will hold the current resolution of the view.\n   *\n   * @type {number|undefined}\n   * @private\n   */\n  this.currentResolution_ = undefined;\n\n  /**\n   * The direction of the slider. Will be determined from actual display of the\n   * container and defaults to ol.control.ZoomSlider.direction.VERTICAL.\n   *\n   * @type {ol.control.ZoomSlider.direction}\n   * @private\n   */\n  this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.dragging_;\n\n  /**\n   * @type {!Array.<ol.EventsKey>}\n   * @private\n   */\n  this.dragListenerKeys_ = [];\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.heightLimit_ = 0;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.widthLimit_ = 0;\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.previousX_;\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.previousY_;\n\n  /**\n   * The calculated thumb size (border box plus margins).  Set when initSlider_\n   * is called.\n   * @type {ol.Size}\n   * @private\n   */\n  this.thumbSize_ = null;\n\n  /**\n   * Whether the slider is initialized.\n   * @type {boolean}\n   * @private\n   */\n  this.sliderInitialized_ = false;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 200;\n\n  var className = options.className !== undefined ? options.className : 'ol-zoomslider';\n  var thumbElement = document.createElement('button');\n  thumbElement.setAttribute('type', 'button');\n  thumbElement.className = className + '-thumb ' + ol.css.CLASS_UNSELECTABLE;\n  var containerElement = document.createElement('div');\n  containerElement.className = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + ol.css.CLASS_CONTROL;\n  containerElement.appendChild(thumbElement);\n  /**\n   * @type {ol.pointer.PointerEventHandler}\n   * @private\n   */\n  this.dragger_ = new ol.pointer.PointerEventHandler(containerElement);\n\n  ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERDOWN,\n      this.handleDraggerStart_, this);\n  ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERMOVE,\n      this.handleDraggerDrag_, this);\n  ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERUP,\n      this.handleDraggerEnd_, this);\n\n  ol.events.listen(containerElement, ol.events.EventType.CLICK,\n      this.handleContainerClick_, this);\n  ol.events.listen(thumbElement, ol.events.EventType.CLICK,\n      ol.events.Event.stopPropagation);\n\n  var render = options.render ? options.render : ol.control.ZoomSlider.render;\n\n  ol.control.Control.call(this, {\n    element: containerElement,\n    render: render\n  });\n};\nol.inherits(ol.control.ZoomSlider, ol.control.Control);\n\n\n/**\n * @inheritDoc\n */\nol.control.ZoomSlider.prototype.disposeInternal = function() {\n  this.dragger_.dispose();\n  ol.control.Control.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * The enum for available directions.\n *\n * @enum {number}\n */\nol.control.ZoomSlider.direction = {\n  VERTICAL: 0,\n  HORIZONTAL: 1\n};\n\n\n/**\n * @inheritDoc\n */\nol.control.ZoomSlider.prototype.setMap = function(map) {\n  ol.control.Control.prototype.setMap.call(this, map);\n  if (map) {\n    map.render();\n  }\n};\n\n\n/**\n * Initializes the slider element. This will determine and set this controls\n * direction_ and also constrain the dragging of the thumb to always be within\n * the bounds of the container.\n *\n * @private\n */\nol.control.ZoomSlider.prototype.initSlider_ = function() {\n  var container = this.element;\n  var containerSize = {\n    width: container.offsetWidth, height: container.offsetHeight\n  };\n\n  var thumb = container.firstElementChild;\n  var computedStyle = getComputedStyle(thumb);\n  var thumbWidth = thumb.offsetWidth +\n      parseFloat(computedStyle['marginRight']) +\n      parseFloat(computedStyle['marginLeft']);\n  var thumbHeight = thumb.offsetHeight +\n      parseFloat(computedStyle['marginTop']) +\n      parseFloat(computedStyle['marginBottom']);\n  this.thumbSize_ = [thumbWidth, thumbHeight];\n\n  if (containerSize.width > containerSize.height) {\n    this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL;\n    this.widthLimit_ = containerSize.width - thumbWidth;\n  } else {\n    this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;\n    this.heightLimit_ = containerSize.height - thumbHeight;\n  }\n  this.sliderInitialized_ = true;\n};\n\n\n/**\n * Update the zoomslider element.\n * @param {ol.MapEvent} mapEvent Map event.\n * @this {ol.control.ZoomSlider}\n * @api\n */\nol.control.ZoomSlider.render = function(mapEvent) {\n  if (!mapEvent.frameState) {\n    return;\n  }\n  if (!this.sliderInitialized_) {\n    this.initSlider_();\n  }\n  var res = mapEvent.frameState.viewState.resolution;\n  if (res !== this.currentResolution_) {\n    this.currentResolution_ = res;\n    this.setThumbPosition_(res);\n  }\n};\n\n\n/**\n * @param {Event} event The browser event to handle.\n * @private\n */\nol.control.ZoomSlider.prototype.handleContainerClick_ = function(event) {\n  var view = this.getMap().getView();\n\n  var relativePosition = this.getRelativePosition_(\n      event.offsetX - this.thumbSize_[0] / 2,\n      event.offsetY - this.thumbSize_[1] / 2);\n\n  var resolution = this.getResolutionForPosition_(relativePosition);\n\n  view.animate({\n    resolution: view.constrainResolution(resolution),\n    duration: this.duration_,\n    easing: ol.easing.easeOut\n  });\n};\n\n\n/**\n * Handle dragger start events.\n * @param {ol.pointer.PointerEvent} event The drag event.\n * @private\n */\nol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {\n  if (!this.dragging_ &&\n      event.originalEvent.target === this.element.firstElementChild) {\n    this.getMap().getView().setHint(ol.View.Hint.INTERACTING, 1);\n    this.previousX_ = event.clientX;\n    this.previousY_ = event.clientY;\n    this.dragging_ = true;\n\n    if (this.dragListenerKeys_.length === 0) {\n      var drag = this.handleDraggerDrag_;\n      var end = this.handleDraggerEnd_;\n      this.dragListenerKeys_.push(\n        ol.events.listen(document, ol.events.EventType.MOUSEMOVE, drag, this),\n        ol.events.listen(document, ol.events.EventType.TOUCHMOVE, drag, this),\n        ol.events.listen(document, ol.pointer.EventType.POINTERMOVE, drag, this),\n        ol.events.listen(document, ol.events.EventType.MOUSEUP, end, this),\n        ol.events.listen(document, ol.events.EventType.TOUCHEND, end, this),\n        ol.events.listen(document, ol.pointer.EventType.POINTERUP, end, this)\n      );\n    }\n  }\n};\n\n\n/**\n * Handle dragger drag events.\n *\n * @param {ol.pointer.PointerEvent|Event} event The drag event.\n * @private\n */\nol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {\n  if (this.dragging_) {\n    var element = this.element.firstElementChild;\n    var deltaX = event.clientX - this.previousX_ + parseInt(element.style.left, 10);\n    var deltaY = event.clientY - this.previousY_ + parseInt(element.style.top, 10);\n    var relativePosition = this.getRelativePosition_(deltaX, deltaY);\n    this.currentResolution_ = this.getResolutionForPosition_(relativePosition);\n    this.getMap().getView().setResolution(this.currentResolution_);\n    this.setThumbPosition_(this.currentResolution_);\n    this.previousX_ = event.clientX;\n    this.previousY_ = event.clientY;\n  }\n};\n\n\n/**\n * Handle dragger end events.\n * @param {ol.pointer.PointerEvent|Event} event The drag event.\n * @private\n */\nol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) {\n  if (this.dragging_) {\n    var view = this.getMap().getView();\n    view.setHint(ol.View.Hint.INTERACTING, -1);\n\n    view.animate({\n      resolution: view.constrainResolution(this.currentResolution_),\n      duration: this.duration_,\n      easing: ol.easing.easeOut\n    });\n\n    this.dragging_ = false;\n    this.previousX_ = undefined;\n    this.previousY_ = undefined;\n    this.dragListenerKeys_.forEach(ol.events.unlistenByKey);\n    this.dragListenerKeys_.length = 0;\n  }\n};\n\n\n/**\n * Positions the thumb inside its container according to the given resolution.\n *\n * @param {number} res The res.\n * @private\n */\nol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) {\n  var position = this.getPositionForResolution_(res);\n  var thumb = this.element.firstElementChild;\n\n  if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) {\n    thumb.style.left = this.widthLimit_ * position + 'px';\n  } else {\n    thumb.style.top = this.heightLimit_ * position + 'px';\n  }\n};\n\n\n/**\n * Calculates the relative position of the thumb given x and y offsets.  The\n * relative position scales from 0 to 1.  The x and y offsets are assumed to be\n * in pixel units within the dragger limits.\n *\n * @param {number} x Pixel position relative to the left of the slider.\n * @param {number} y Pixel position relative to the top of the slider.\n * @return {number} The relative position of the thumb.\n * @private\n */\nol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) {\n  var amount;\n  if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) {\n    amount = x / this.widthLimit_;\n  } else {\n    amount = y / this.heightLimit_;\n  }\n  return ol.math.clamp(amount, 0, 1);\n};\n\n\n/**\n * Calculates the corresponding resolution of the thumb given its relative\n * position (where 0 is the minimum and 1 is the maximum).\n *\n * @param {number} position The relative position of the thumb.\n * @return {number} The corresponding resolution.\n * @private\n */\nol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) {\n  var fn = this.getMap().getView().getResolutionForValueFunction();\n  return fn(1 - position);\n};\n\n\n/**\n * Determines the relative position of the slider for the given resolution.  A\n * relative position of 0 corresponds to the minimum view resolution.  A\n * relative position of 1 corresponds to the maximum view resolution.\n *\n * @param {number} res The resolution.\n * @return {number} The relative position value (between 0 and 1).\n * @private\n */\nol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) {\n  var fn = this.getMap().getView().getValueForResolutionFunction();\n  return 1 - fn(res);\n};\n\ngoog.provide('ol.control.ZoomToExtent');\n\ngoog.require('ol');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.control.Control');\ngoog.require('ol.css');\n\n\n/**\n * @classdesc\n * A button control which, when pressed, changes the map view to a specific\n * extent. To style this control use the css selector `.ol-zoom-extent`.\n *\n * @constructor\n * @extends {ol.control.Control}\n * @param {olx.control.ZoomToExtentOptions=} opt_options Options.\n * @api stable\n */\nol.control.ZoomToExtent = function(opt_options) {\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @type {ol.Extent}\n   * @private\n   */\n  this.extent_ = options.extent ? options.extent : null;\n\n  var className = options.className !== undefined ? options.className :\n      'ol-zoom-extent';\n\n  var label = options.label !== undefined ? options.label : 'E';\n  var tipLabel = options.tipLabel !== undefined ?\n      options.tipLabel : 'Fit to extent';\n  var button = document.createElement('button');\n  button.setAttribute('type', 'button');\n  button.title = tipLabel;\n  button.appendChild(\n    typeof label === 'string' ? document.createTextNode(label) : label\n  );\n\n  ol.events.listen(button, ol.events.EventType.CLICK,\n      this.handleClick_, this);\n\n  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +\n      ol.css.CLASS_CONTROL;\n  var element = document.createElement('div');\n  element.className = cssClasses;\n  element.appendChild(button);\n\n  ol.control.Control.call(this, {\n    element: element,\n    target: options.target\n  });\n};\nol.inherits(ol.control.ZoomToExtent, ol.control.Control);\n\n\n/**\n * @param {Event} event The event to handle\n * @private\n */\nol.control.ZoomToExtent.prototype.handleClick_ = function(event) {\n  event.preventDefault();\n  this.handleZoomToExtent_();\n};\n\n\n/**\n * @private\n */\nol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() {\n  var map = this.getMap();\n  var view = map.getView();\n  var extent = !this.extent_ ? view.getProjection().getExtent() : this.extent_;\n  var size = /** @type {ol.Size} */ (map.getSize());\n  view.fit(extent, size);\n};\n\ngoog.provide('ol.DeviceOrientation');\n\ngoog.require('ol.events');\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.has');\ngoog.require('ol.math');\n\n\n/**\n * @classdesc\n * The ol.DeviceOrientation class provides access to information from\n * DeviceOrientation events.  See the [HTML 5 DeviceOrientation Specification](\n * http://www.w3.org/TR/orientation-event/) for more details.\n *\n * Many new computers, and especially mobile phones\n * and tablets, provide hardware support for device orientation. Web\n * developers targeting mobile devices will be especially interested in this\n * class.\n *\n * Device orientation data are relative to a common starting point. For mobile\n * devices, the starting point is to lay your phone face up on a table with the\n * top of the phone pointing north. This represents the zero state. All\n * angles are then relative to this state. For computers, it is the same except\n * the screen is open at 90 degrees.\n *\n * Device orientation is reported as three angles - `alpha`, `beta`, and\n * `gamma` - relative to the starting position along the three planar axes X, Y\n * and Z. The X axis runs from the left edge to the right edge through the\n * middle of the device. Similarly, the Y axis runs from the bottom to the top\n * of the device through the middle. The Z axis runs from the back to the front\n * through the middle. In the starting position, the X axis points to the\n * right, the Y axis points away from you and the Z axis points straight up\n * from the device lying flat.\n *\n * The three angles representing the device orientation are relative to the\n * three axes. `alpha` indicates how much the device has been rotated around the\n * Z axis, which is commonly interpreted as the compass heading (see note\n * below). `beta` indicates how much the device has been rotated around the X\n * axis, or how much it is tilted from front to back.  `gamma` indicates how\n * much the device has been rotated around the Y axis, or how much it is tilted\n * from left to right.\n *\n * For most browsers, the `alpha` value returns the compass heading so if the\n * device points north, it will be 0.  With Safari on iOS, the 0 value of\n * `alpha` is calculated from when device orientation was first requested.\n * ol.DeviceOrientation provides the `heading` property which normalizes this\n * behavior across all browsers for you.\n *\n * It is important to note that the HTML 5 DeviceOrientation specification\n * indicates that `alpha`, `beta` and `gamma` are in degrees while the\n * equivalent properties in ol.DeviceOrientation are in radians for consistency\n * with all other uses of angles throughout OpenLayers.\n *\n * To get notified of device orientation changes, register a listener for the\n * generic `change` event on your `ol.DeviceOrientation` instance.\n *\n * @see {@link http://www.w3.org/TR/orientation-event/}\n *\n * @constructor\n * @extends {ol.Object}\n * @param {olx.DeviceOrientationOptions=} opt_options Options.\n * @api\n */\nol.DeviceOrientation = function(opt_options) {\n\n  ol.Object.call(this);\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.listenerKey_ = null;\n\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.DeviceOrientation.Property.TRACKING),\n      this.handleTrackingChanged_, this);\n\n  this.setTracking(options.tracking !== undefined ? options.tracking : false);\n\n};\nol.inherits(ol.DeviceOrientation, ol.Object);\n\n\n/**\n * @inheritDoc\n */\nol.DeviceOrientation.prototype.disposeInternal = function() {\n  this.setTracking(false);\n  ol.Object.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * @private\n * @param {Event} originalEvent Event.\n */\nol.DeviceOrientation.prototype.orientationChange_ = function(originalEvent) {\n  var event = /** @type {DeviceOrientationEvent} */ (originalEvent);\n  if (event.alpha !== null) {\n    var alpha = ol.math.toRadians(event.alpha);\n    this.set(ol.DeviceOrientation.Property.ALPHA, alpha);\n    // event.absolute is undefined in iOS.\n    if (typeof event.absolute === 'boolean' && event.absolute) {\n      this.set(ol.DeviceOrientation.Property.HEADING, alpha);\n    } else if (typeof event.webkitCompassHeading === 'number' &&\n               event.webkitCompassAccuracy != -1) {\n      var heading = ol.math.toRadians(event.webkitCompassHeading);\n      this.set(ol.DeviceOrientation.Property.HEADING, heading);\n    }\n  }\n  if (event.beta !== null) {\n    this.set(ol.DeviceOrientation.Property.BETA,\n        ol.math.toRadians(event.beta));\n  }\n  if (event.gamma !== null) {\n    this.set(ol.DeviceOrientation.Property.GAMMA,\n        ol.math.toRadians(event.gamma));\n  }\n  this.changed();\n};\n\n\n/**\n * Rotation around the device z-axis (in radians).\n * @return {number|undefined} The euler angle in radians of the device from the\n *     standard Z axis.\n * @observable\n * @api\n */\nol.DeviceOrientation.prototype.getAlpha = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.DeviceOrientation.Property.ALPHA));\n};\n\n\n/**\n * Rotation around the device x-axis (in radians).\n * @return {number|undefined} The euler angle in radians of the device from the\n *     planar X axis.\n * @observable\n * @api\n */\nol.DeviceOrientation.prototype.getBeta = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.DeviceOrientation.Property.BETA));\n};\n\n\n/**\n * Rotation around the device y-axis (in radians).\n * @return {number|undefined} The euler angle in radians of the device from the\n *     planar Y axis.\n * @observable\n * @api\n */\nol.DeviceOrientation.prototype.getGamma = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.DeviceOrientation.Property.GAMMA));\n};\n\n\n/**\n * The heading of the device relative to north (in radians).\n * @return {number|undefined} The heading of the device relative to north, in\n *     radians, normalizing for different browser behavior.\n * @observable\n * @api\n */\nol.DeviceOrientation.prototype.getHeading = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.DeviceOrientation.Property.HEADING));\n};\n\n\n/**\n * Determine if orientation is being tracked.\n * @return {boolean} Changes in device orientation are being tracked.\n * @observable\n * @api\n */\nol.DeviceOrientation.prototype.getTracking = function() {\n  return /** @type {boolean} */ (\n      this.get(ol.DeviceOrientation.Property.TRACKING));\n};\n\n\n/**\n * @private\n */\nol.DeviceOrientation.prototype.handleTrackingChanged_ = function() {\n  if (ol.has.DEVICE_ORIENTATION) {\n    var tracking = this.getTracking();\n    if (tracking && !this.listenerKey_) {\n      this.listenerKey_ = ol.events.listen(window, 'deviceorientation',\n          this.orientationChange_, this);\n    } else if (!tracking && this.listenerKey_ !== null) {\n      ol.events.unlistenByKey(this.listenerKey_);\n      this.listenerKey_ = null;\n    }\n  }\n};\n\n\n/**\n * Enable or disable tracking of device orientation events.\n * @param {boolean} tracking The status of tracking changes to alpha, beta and\n *     gamma. If true, changes are tracked and reported immediately.\n * @observable\n * @api\n */\nol.DeviceOrientation.prototype.setTracking = function(tracking) {\n  this.set(ol.DeviceOrientation.Property.TRACKING, tracking);\n};\n\n\n/**\n * @enum {string}\n */\nol.DeviceOrientation.Property = {\n  ALPHA: 'alpha',\n  BETA: 'beta',\n  GAMMA: 'gamma',\n  HEADING: 'heading',\n  TRACKING: 'tracking'\n};\n\ngoog.provide('ol.Feature');\n\ngoog.require('ol.asserts');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.geom.Geometry');\ngoog.require('ol.style.Style');\n\n\n/**\n * @classdesc\n * A vector object for geographic features with a geometry and other\n * attribute properties, similar to the features in vector file formats like\n * GeoJSON.\n *\n * Features can be styled individually with `setStyle`; otherwise they use the\n * style of their vector layer.\n *\n * Note that attribute properties are set as {@link ol.Object} properties on\n * the feature object, so they are observable, and have get/set accessors.\n *\n * Typically, a feature has a single geometry property. You can set the\n * geometry using the `setGeometry` method and get it with `getGeometry`.\n * It is possible to store more than one geometry on a feature using attribute\n * properties. By default, the geometry used for rendering is identified by\n * the property name `geometry`. If you want to use another geometry property\n * for rendering, use the `setGeometryName` method to change the attribute\n * property associated with the geometry for the feature.  For example:\n *\n * ```js\n * var feature = new ol.Feature({\n *   geometry: new ol.geom.Polygon(polyCoords),\n *   labelPoint: new ol.geom.Point(labelCoords),\n *   name: 'My Polygon'\n * });\n *\n * // get the polygon geometry\n * var poly = feature.getGeometry();\n *\n * // Render the feature as a point using the coordinates from labelPoint\n * feature.setGeometryName('labelPoint');\n *\n * // get the point geometry\n * var point = feature.getGeometry();\n * ```\n *\n * @constructor\n * @extends {ol.Object}\n * @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties\n *     You may pass a Geometry object directly, or an object literal\n *     containing properties.  If you pass an object literal, you may\n *     include a Geometry associated with a `geometry` key.\n * @api stable\n */\nol.Feature = function(opt_geometryOrProperties) {\n\n  ol.Object.call(this);\n\n  /**\n   * @private\n   * @type {number|string|undefined}\n   */\n  this.id_ = undefined;\n\n  /**\n   * @type {string}\n   * @private\n   */\n  this.geometryName_ = 'geometry';\n\n  /**\n   * User provided style.\n   * @private\n   * @type {ol.style.Style|Array.<ol.style.Style>|\n   *     ol.FeatureStyleFunction}\n   */\n  this.style_ = null;\n\n  /**\n   * @private\n   * @type {ol.FeatureStyleFunction|undefined}\n   */\n  this.styleFunction_ = undefined;\n\n  /**\n   * @private\n   * @type {?ol.EventsKey}\n   */\n  this.geometryChangeKey_ = null;\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(this.geometryName_),\n      this.handleGeometryChanged_, this);\n\n  if (opt_geometryOrProperties !== undefined) {\n    if (opt_geometryOrProperties instanceof ol.geom.Geometry ||\n        !opt_geometryOrProperties) {\n      var geometry = opt_geometryOrProperties;\n      this.setGeometry(geometry);\n    } else {\n      /** @type {Object.<string, *>} */\n      var properties = opt_geometryOrProperties;\n      this.setProperties(properties);\n    }\n  }\n};\nol.inherits(ol.Feature, ol.Object);\n\n\n/**\n * Clone this feature. If the original feature has a geometry it\n * is also cloned. The feature id is not set in the clone.\n * @return {ol.Feature} The clone.\n * @api stable\n */\nol.Feature.prototype.clone = function() {\n  var clone = new ol.Feature(this.getProperties());\n  clone.setGeometryName(this.getGeometryName());\n  var geometry = this.getGeometry();\n  if (geometry) {\n    clone.setGeometry(geometry.clone());\n  }\n  var style = this.getStyle();\n  if (style) {\n    clone.setStyle(style);\n  }\n  return clone;\n};\n\n\n/**\n * Get the feature's default geometry.  A feature may have any number of named\n * geometries.  The \"default\" geometry (the one that is rendered by default) is\n * set when calling {@link ol.Feature#setGeometry}.\n * @return {ol.geom.Geometry|undefined} The default geometry for the feature.\n * @api stable\n * @observable\n */\nol.Feature.prototype.getGeometry = function() {\n  return /** @type {ol.geom.Geometry|undefined} */ (\n      this.get(this.geometryName_));\n};\n\n\n/**\n * Get the feature identifier.  This is a stable identifier for the feature and\n * is either set when reading data from a remote source or set explicitly by\n * calling {@link ol.Feature#setId}.\n * @return {number|string|undefined} Id.\n * @api stable\n * @observable\n */\nol.Feature.prototype.getId = function() {\n  return this.id_;\n};\n\n\n/**\n * Get the name of the feature's default geometry.  By default, the default\n * geometry is named `geometry`.\n * @return {string} Get the property name associated with the default geometry\n *     for this feature.\n * @api stable\n */\nol.Feature.prototype.getGeometryName = function() {\n  return this.geometryName_;\n};\n\n\n/**\n * Get the feature's style. Will return what was provided to the\n * {@link ol.Feature#setStyle} method.\n * @return {ol.style.Style|Array.<ol.style.Style>|\n *     ol.FeatureStyleFunction} The feature style.\n * @api stable\n * @observable\n */\nol.Feature.prototype.getStyle = function() {\n  return this.style_;\n};\n\n\n/**\n * Get the feature's style function.\n * @return {ol.FeatureStyleFunction|undefined} Return a function\n * representing the current style of this feature.\n * @api stable\n */\nol.Feature.prototype.getStyleFunction = function() {\n  return this.styleFunction_;\n};\n\n\n/**\n * @private\n */\nol.Feature.prototype.handleGeometryChange_ = function() {\n  this.changed();\n};\n\n\n/**\n * @private\n */\nol.Feature.prototype.handleGeometryChanged_ = function() {\n  if (this.geometryChangeKey_) {\n    ol.events.unlistenByKey(this.geometryChangeKey_);\n    this.geometryChangeKey_ = null;\n  }\n  var geometry = this.getGeometry();\n  if (geometry) {\n    this.geometryChangeKey_ = ol.events.listen(geometry,\n        ol.events.EventType.CHANGE, this.handleGeometryChange_, this);\n  }\n  this.changed();\n};\n\n\n/**\n * Set the default geometry for the feature.  This will update the property\n * with the name returned by {@link ol.Feature#getGeometryName}.\n * @param {ol.geom.Geometry|undefined} geometry The new geometry.\n * @api stable\n * @observable\n */\nol.Feature.prototype.setGeometry = function(geometry) {\n  this.set(this.geometryName_, geometry);\n};\n\n\n/**\n * Set the style for the feature.  This can be a single style object, an array\n * of styles, or a function that takes a resolution and returns an array of\n * styles. If it is `null` the feature has no style (a `null` style).\n * @param {ol.style.Style|Array.<ol.style.Style>|\n *     ol.FeatureStyleFunction} style Style for this feature.\n * @api stable\n * @observable\n */\nol.Feature.prototype.setStyle = function(style) {\n  this.style_ = style;\n  this.styleFunction_ = !style ?\n      undefined : ol.Feature.createStyleFunction(style);\n  this.changed();\n};\n\n\n/**\n * Set the feature id.  The feature id is considered stable and may be used when\n * requesting features or comparing identifiers returned from a remote source.\n * The feature id can be used with the {@link ol.source.Vector#getFeatureById}\n * method.\n * @param {number|string|undefined} id The feature id.\n * @api stable\n * @observable\n */\nol.Feature.prototype.setId = function(id) {\n  this.id_ = id;\n  this.changed();\n};\n\n\n/**\n * Set the property name to be used when getting the feature's default geometry.\n * When calling {@link ol.Feature#getGeometry}, the value of the property with\n * this name will be returned.\n * @param {string} name The property name of the default geometry.\n * @api stable\n */\nol.Feature.prototype.setGeometryName = function(name) {\n  ol.events.unlisten(\n      this, ol.Object.getChangeEventType(this.geometryName_),\n      this.handleGeometryChanged_, this);\n  this.geometryName_ = name;\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(this.geometryName_),\n      this.handleGeometryChanged_, this);\n  this.handleGeometryChanged_();\n};\n\n\n/**\n * Convert the provided object into a feature style function.  Functions passed\n * through unchanged.  Arrays of ol.style.Style or single style objects wrapped\n * in a new feature style function.\n * @param {ol.FeatureStyleFunction|!Array.<ol.style.Style>|!ol.style.Style} obj\n *     A feature style function, a single style, or an array of styles.\n * @return {ol.FeatureStyleFunction} A style function.\n */\nol.Feature.createStyleFunction = function(obj) {\n  var styleFunction;\n\n  if (typeof obj === 'function') {\n    styleFunction = obj;\n  } else {\n    /**\n     * @type {Array.<ol.style.Style>}\n     */\n    var styles;\n    if (Array.isArray(obj)) {\n      styles = obj;\n    } else {\n      ol.asserts.assert(obj instanceof ol.style.Style,\n          41); // Expected an `ol.style.Style` or an array of `ol.style.Style`\n      styles = [obj];\n    }\n    styleFunction = function() {\n      return styles;\n    };\n  }\n  return styleFunction;\n};\n\ngoog.provide('ol.format.FormatType');\n\n\n/**\n * @enum {string}\n */\nol.format.FormatType = {\n  ARRAY_BUFFER: 'arraybuffer',\n  JSON: 'json',\n  TEXT: 'text',\n  XML: 'xml'\n};\n\ngoog.provide('ol.xml');\n\ngoog.require('ol');\ngoog.require('ol.array');\n\n\n/**\n * This document should be used when creating nodes for XML serializations. This\n * document is also used by {@link ol.xml.createElementNS} and\n * {@link ol.xml.setAttributeNS}\n * @const\n * @type {Document}\n */\nol.xml.DOCUMENT = document.implementation.createDocument('', '', null);\n\n\n/**\n * @param {string} namespaceURI Namespace URI.\n * @param {string} qualifiedName Qualified name.\n * @return {Node} Node.\n */\nol.xml.createElementNS = function(namespaceURI, qualifiedName) {\n  return ol.xml.DOCUMENT.createElementNS(namespaceURI, qualifiedName);\n};\n\n\n/**\n * Recursively grab all text content of child nodes into a single string.\n * @param {Node} node Node.\n * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line\n * breaks.\n * @return {string} All text content.\n * @api\n */\nol.xml.getAllTextContent = function(node, normalizeWhitespace) {\n  return ol.xml.getAllTextContent_(node, normalizeWhitespace, []).join('');\n};\n\n\n/**\n * Recursively grab all text content of child nodes into a single string.\n * @param {Node} node Node.\n * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line\n * breaks.\n * @param {Array.<string>} accumulator Accumulator.\n * @private\n * @return {Array.<string>} Accumulator.\n */\nol.xml.getAllTextContent_ = function(node, normalizeWhitespace, accumulator) {\n  if (node.nodeType == Node.CDATA_SECTION_NODE ||\n      node.nodeType == Node.TEXT_NODE) {\n    if (normalizeWhitespace) {\n      accumulator.push(String(node.nodeValue).replace(/(\\r\\n|\\r|\\n)/g, ''));\n    } else {\n      accumulator.push(node.nodeValue);\n    }\n  } else {\n    var n;\n    for (n = node.firstChild; n; n = n.nextSibling) {\n      ol.xml.getAllTextContent_(n, normalizeWhitespace, accumulator);\n    }\n  }\n  return accumulator;\n};\n\n\n/**\n * @param {?} value Value.\n * @return {boolean} Is document.\n */\nol.xml.isDocument = function(value) {\n  return value instanceof Document;\n};\n\n\n/**\n * @param {?} value Value.\n * @return {boolean} Is node.\n */\nol.xml.isNode = function(value) {\n  return value instanceof Node;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {?string} namespaceURI Namespace URI.\n * @param {string} name Attribute name.\n * @return {string} Value\n */\nol.xml.getAttributeNS = function(node, namespaceURI, name) {\n  return node.getAttributeNS(namespaceURI, name) || '';\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {?string} namespaceURI Namespace URI.\n * @param {string} name Attribute name.\n * @param {string|number} value Value.\n */\nol.xml.setAttributeNS = function(node, namespaceURI, name, value) {\n  node.setAttributeNS(namespaceURI, name, value);\n};\n\n\n/**\n * Parse an XML string to an XML Document.\n * @param {string} xml XML.\n * @return {Document} Document.\n * @api\n */\nol.xml.parse = function(xml) {\n  return new DOMParser().parseFromString(xml, 'application/xml');\n};\n\n\n/**\n * Make an array extender function for extending the array at the top of the\n * object stack.\n * @param {function(this: T, Node, Array.<*>): (Array.<*>|undefined)}\n *     valueReader Value reader.\n * @param {T=} opt_this The object to use as `this` in `valueReader`.\n * @return {ol.XmlParser} Parser.\n * @template T\n */\nol.xml.makeArrayExtender = function(valueReader, opt_this) {\n  return (\n      /**\n       * @param {Node} node Node.\n       * @param {Array.<*>} objectStack Object stack.\n       */\n      function(node, objectStack) {\n        var value = valueReader.call(opt_this, node, objectStack);\n        if (value !== undefined) {\n          ol.DEBUG && console.assert(Array.isArray(value),\n              'valueReader function is expected to return an array of values');\n          var array = /** @type {Array.<*>} */\n              (objectStack[objectStack.length - 1]);\n          ol.DEBUG && console.assert(Array.isArray(array),\n              'objectStack is supposed to be an array of arrays');\n          ol.array.extend(array, value);\n        }\n      });\n};\n\n\n/**\n * Make an array pusher function for pushing to the array at the top of the\n * object stack.\n * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.\n * @param {T=} opt_this The object to use as `this` in `valueReader`.\n * @return {ol.XmlParser} Parser.\n * @template T\n */\nol.xml.makeArrayPusher = function(valueReader, opt_this) {\n  return (\n      /**\n       * @param {Node} node Node.\n       * @param {Array.<*>} objectStack Object stack.\n       */\n      function(node, objectStack) {\n        var value = valueReader.call(opt_this !== undefined ? opt_this : this,\n            node, objectStack);\n        if (value !== undefined) {\n          var array = objectStack[objectStack.length - 1];\n          ol.DEBUG && console.assert(Array.isArray(array),\n              'objectStack is supposed to be an array of arrays');\n          array.push(value);\n        }\n      });\n};\n\n\n/**\n * Make an object stack replacer function for replacing the object at the\n * top of the stack.\n * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.\n * @param {T=} opt_this The object to use as `this` in `valueReader`.\n * @return {ol.XmlParser} Parser.\n * @template T\n */\nol.xml.makeReplacer = function(valueReader, opt_this) {\n  return (\n      /**\n       * @param {Node} node Node.\n       * @param {Array.<*>} objectStack Object stack.\n       */\n      function(node, objectStack) {\n        var value = valueReader.call(opt_this !== undefined ? opt_this : this,\n            node, objectStack);\n        if (value !== undefined) {\n          objectStack[objectStack.length - 1] = value;\n        }\n      });\n};\n\n\n/**\n * Make an object property pusher function for adding a property to the\n * object at the top of the stack.\n * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.\n * @param {string=} opt_property Property.\n * @param {T=} opt_this The object to use as `this` in `valueReader`.\n * @return {ol.XmlParser} Parser.\n * @template T\n */\nol.xml.makeObjectPropertyPusher = function(valueReader, opt_property, opt_this) {\n  ol.DEBUG && console.assert(valueReader !== undefined,\n      'undefined valueReader, expected function(this: T, Node, Array.<*>)');\n  return (\n      /**\n       * @param {Node} node Node.\n       * @param {Array.<*>} objectStack Object stack.\n       */\n      function(node, objectStack) {\n        var value = valueReader.call(opt_this !== undefined ? opt_this : this,\n            node, objectStack);\n        if (value !== undefined) {\n          var object = /** @type {Object} */\n              (objectStack[objectStack.length - 1]);\n          var property = opt_property !== undefined ?\n              opt_property : node.localName;\n          var array;\n          if (property in object) {\n            array = object[property];\n          } else {\n            array = object[property] = [];\n          }\n          array.push(value);\n        }\n      });\n};\n\n\n/**\n * Make an object property setter function.\n * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.\n * @param {string=} opt_property Property.\n * @param {T=} opt_this The object to use as `this` in `valueReader`.\n * @return {ol.XmlParser} Parser.\n * @template T\n */\nol.xml.makeObjectPropertySetter = function(valueReader, opt_property, opt_this) {\n  ol.DEBUG && console.assert(valueReader !== undefined,\n      'undefined valueReader, expected function(this: T, Node, Array.<*>)');\n  return (\n      /**\n       * @param {Node} node Node.\n       * @param {Array.<*>} objectStack Object stack.\n       */\n      function(node, objectStack) {\n        var value = valueReader.call(opt_this !== undefined ? opt_this : this,\n            node, objectStack);\n        if (value !== undefined) {\n          var object = /** @type {Object} */\n              (objectStack[objectStack.length - 1]);\n          var property = opt_property !== undefined ?\n              opt_property : node.localName;\n          object[property] = value;\n        }\n      });\n};\n\n\n/**\n * Create a serializer that appends nodes written by its `nodeWriter` to its\n * designated parent. The parent is the `node` of the\n * {@link ol.XmlNodeStackItem} at the top of the `objectStack`.\n * @param {function(this: T, Node, V, Array.<*>)}\n *     nodeWriter Node writer.\n * @param {T=} opt_this The object to use as `this` in `nodeWriter`.\n * @return {ol.XmlSerializer} Serializer.\n * @template T, V\n */\nol.xml.makeChildAppender = function(nodeWriter, opt_this) {\n  return function(node, value, objectStack) {\n    nodeWriter.call(opt_this !== undefined ? opt_this : this,\n        node, value, objectStack);\n    var parent = objectStack[objectStack.length - 1];\n    var parentNode = parent.node;\n    ol.DEBUG && console.assert(ol.xml.isNode(parentNode) ||\n        ol.xml.isDocument(parentNode),\n        'expected parentNode %s to be a Node or a Document', parentNode);\n    parentNode.appendChild(node);\n  };\n};\n\n\n/**\n * Create a serializer that calls the provided `nodeWriter` from\n * {@link ol.xml.serialize}. This can be used by the parent writer to have the\n * 'nodeWriter' called with an array of values when the `nodeWriter` was\n * designed to serialize a single item. An example would be a LineString\n * geometry writer, which could be reused for writing MultiLineString\n * geometries.\n * @param {function(this: T, Node, V, Array.<*>)}\n *     nodeWriter Node writer.\n * @param {T=} opt_this The object to use as `this` in `nodeWriter`.\n * @return {ol.XmlSerializer} Serializer.\n * @template T, V\n */\nol.xml.makeArraySerializer = function(nodeWriter, opt_this) {\n  var serializersNS, nodeFactory;\n  return function(node, value, objectStack) {\n    if (serializersNS === undefined) {\n      serializersNS = {};\n      var serializers = {};\n      serializers[node.localName] = nodeWriter;\n      serializersNS[node.namespaceURI] = serializers;\n      nodeFactory = ol.xml.makeSimpleNodeFactory(node.localName);\n    }\n    ol.xml.serialize(serializersNS, nodeFactory, value, objectStack);\n  };\n};\n\n\n/**\n * Create a node factory which can use the `opt_keys` passed to\n * {@link ol.xml.serialize} or {@link ol.xml.pushSerializeAndPop} as node names,\n * or a fixed node name. The namespace of the created nodes can either be fixed,\n * or the parent namespace will be used.\n * @param {string=} opt_nodeName Fixed node name which will be used for all\n *     created nodes. If not provided, the 3rd argument to the resulting node\n *     factory needs to be provided and will be the nodeName.\n * @param {string=} opt_namespaceURI Fixed namespace URI which will be used for\n *     all created nodes. If not provided, the namespace of the parent node will\n *     be used.\n * @return {function(*, Array.<*>, string=): (Node|undefined)} Node factory.\n */\nol.xml.makeSimpleNodeFactory = function(opt_nodeName, opt_namespaceURI) {\n  var fixedNodeName = opt_nodeName;\n  return (\n      /**\n       * @param {*} value Value.\n       * @param {Array.<*>} objectStack Object stack.\n       * @param {string=} opt_nodeName Node name.\n       * @return {Node} Node.\n       */\n      function(value, objectStack, opt_nodeName) {\n        var context = objectStack[objectStack.length - 1];\n        var node = context.node;\n        ol.DEBUG && console.assert(ol.xml.isNode(node) || ol.xml.isDocument(node),\n            'expected node %s to be a Node or a Document', node);\n        var nodeName = fixedNodeName;\n        if (nodeName === undefined) {\n          nodeName = opt_nodeName;\n        }\n        var namespaceURI = opt_namespaceURI;\n        if (opt_namespaceURI === undefined) {\n          namespaceURI = node.namespaceURI;\n        }\n        ol.DEBUG && console.assert(nodeName !== undefined, 'nodeName was undefined');\n        return ol.xml.createElementNS(namespaceURI, /** @type {string} */ (nodeName));\n      }\n  );\n};\n\n\n/**\n * A node factory that creates a node using the parent's `namespaceURI` and the\n * `nodeName` passed by {@link ol.xml.serialize} or\n * {@link ol.xml.pushSerializeAndPop} to the node factory.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n */\nol.xml.OBJECT_PROPERTY_NODE_FACTORY = ol.xml.makeSimpleNodeFactory();\n\n\n/**\n * Create an array of `values` to be used with {@link ol.xml.serialize} or\n * {@link ol.xml.pushSerializeAndPop}, where `orderedKeys` has to be provided as\n * `opt_key` argument.\n * @param {Object.<string, V>} object Key-value pairs for the sequence. Keys can\n *     be a subset of the `orderedKeys`.\n * @param {Array.<string>} orderedKeys Keys in the order of the sequence.\n * @return {Array.<V>} Values in the order of the sequence. The resulting array\n *     has the same length as the `orderedKeys` array. Values that are not\n *     present in `object` will be `undefined` in the resulting array.\n * @template V\n */\nol.xml.makeSequence = function(object, orderedKeys) {\n  var length = orderedKeys.length;\n  var sequence = new Array(length);\n  for (var i = 0; i < length; ++i) {\n    sequence[i] = object[orderedKeys[i]];\n  }\n  return sequence;\n};\n\n\n/**\n * Create a namespaced structure, using the same values for each namespace.\n * This can be used as a starting point for versioned parsers, when only a few\n * values are version specific.\n * @param {Array.<string>} namespaceURIs Namespace URIs.\n * @param {T} structure Structure.\n * @param {Object.<string, T>=} opt_structureNS Namespaced structure to add to.\n * @return {Object.<string, T>} Namespaced structure.\n * @template T\n */\nol.xml.makeStructureNS = function(namespaceURIs, structure, opt_structureNS) {\n  /**\n   * @type {Object.<string, *>}\n   */\n  var structureNS = opt_structureNS !== undefined ? opt_structureNS : {};\n  var i, ii;\n  for (i = 0, ii = namespaceURIs.length; i < ii; ++i) {\n    structureNS[namespaceURIs[i]] = structure;\n  }\n  return structureNS;\n};\n\n\n/**\n * Parse a node using the parsers and object stack.\n * @param {Object.<string, Object.<string, ol.XmlParser>>} parsersNS\n *     Parsers by namespace.\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @param {*=} opt_this The object to use as `this`.\n */\nol.xml.parseNode = function(parsersNS, node, objectStack, opt_this) {\n  var n;\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    var parsers = parsersNS[n.namespaceURI];\n    if (parsers !== undefined) {\n      var parser = parsers[n.localName];\n      if (parser !== undefined) {\n        parser.call(opt_this, n, objectStack);\n      }\n    }\n  }\n};\n\n\n/**\n * Push an object on top of the stack, parse and return the popped object.\n * @param {T} object Object.\n * @param {Object.<string, Object.<string, ol.XmlParser>>} parsersNS\n *     Parsers by namespace.\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @param {*=} opt_this The object to use as `this`.\n * @return {T} Object.\n * @template T\n */\nol.xml.pushParseAndPop = function(\n    object, parsersNS, node, objectStack, opt_this) {\n  objectStack.push(object);\n  ol.xml.parseNode(parsersNS, node, objectStack, opt_this);\n  return objectStack.pop();\n};\n\n\n/**\n * Walk through an array of `values` and call a serializer for each value.\n * @param {Object.<string, Object.<string, ol.XmlSerializer>>} serializersNS\n *     Namespaced serializers.\n * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory\n *     Node factory. The `nodeFactory` creates the node whose namespace and name\n *     will be used to choose a node writer from `serializersNS`. This\n *     separation allows us to decide what kind of node to create, depending on\n *     the value we want to serialize. An example for this would be different\n *     geometry writers based on the geometry type.\n * @param {Array.<*>} values Values to serialize. An example would be an array\n *     of {@link ol.Feature} instances.\n * @param {Array.<*>} objectStack Node stack.\n * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the\n *     `nodeFactory`. This is used for serializing object literals where the\n *     node name relates to the property key. The array length of `opt_keys` has\n *     to match the length of `values`. For serializing a sequence, `opt_keys`\n *     determines the order of the sequence.\n * @param {T=} opt_this The object to use as `this` for the node factory and\n *     serializers.\n * @template T\n */\nol.xml.serialize = function(\n    serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) {\n  var length = (opt_keys !== undefined ? opt_keys : values).length;\n  var value, node;\n  for (var i = 0; i < length; ++i) {\n    value = values[i];\n    if (value !== undefined) {\n      node = nodeFactory.call(opt_this, value, objectStack,\n          opt_keys !== undefined ? opt_keys[i] : undefined);\n      if (node !== undefined) {\n        serializersNS[node.namespaceURI][node.localName]\n            .call(opt_this, node, value, objectStack);\n      }\n    }\n  }\n};\n\n\n/**\n * @param {O} object Object.\n * @param {Object.<string, Object.<string, ol.XmlSerializer>>} serializersNS\n *     Namespaced serializers.\n * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory\n *     Node factory. The `nodeFactory` creates the node whose namespace and name\n *     will be used to choose a node writer from `serializersNS`. This\n *     separation allows us to decide what kind of node to create, depending on\n *     the value we want to serialize. An example for this would be different\n *     geometry writers based on the geometry type.\n * @param {Array.<*>} values Values to serialize. An example would be an array\n *     of {@link ol.Feature} instances.\n * @param {Array.<*>} objectStack Node stack.\n * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the\n *     `nodeFactory`. This is used for serializing object literals where the\n *     node name relates to the property key. The array length of `opt_keys` has\n *     to match the length of `values`. For serializing a sequence, `opt_keys`\n *     determines the order of the sequence.\n * @param {T=} opt_this The object to use as `this` for the node factory and\n *     serializers.\n * @return {O|undefined} Object.\n * @template O, T\n */\nol.xml.pushSerializeAndPop = function(object,\n    serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) {\n  objectStack.push(object);\n  ol.xml.serialize(\n      serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this);\n  return objectStack.pop();\n};\n\ngoog.provide('ol.featureloader');\n\ngoog.require('ol');\ngoog.require('ol.format.FormatType');\ngoog.require('ol.xml');\n\n\n/**\n * @param {string|ol.FeatureUrlFunction} url Feature URL service.\n * @param {ol.format.Feature} format Feature format.\n * @param {function(this:ol.VectorTile, Array.<ol.Feature>, ol.proj.Projection)|function(this:ol.source.Vector, Array.<ol.Feature>)} success\n *     Function called with the loaded features and optionally with the data\n *     projection. Called with the vector tile or source as `this`.\n * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure\n *     Function called when loading failed. Called with the vector tile or\n *     source as `this`.\n * @return {ol.FeatureLoader} The feature loader.\n */\nol.featureloader.loadFeaturesXhr = function(url, format, success, failure) {\n  return (\n      /**\n       * @param {ol.Extent} extent Extent.\n       * @param {number} resolution Resolution.\n       * @param {ol.proj.Projection} projection Projection.\n       * @this {ol.source.Vector|ol.VectorTile}\n       */\n      function(extent, resolution, projection) {\n        var xhr = new XMLHttpRequest();\n        xhr.open('GET',\n            typeof url === 'function' ? url(extent, resolution, projection) : url,\n            true);\n        if (format.getType() == ol.format.FormatType.ARRAY_BUFFER) {\n          xhr.responseType = 'arraybuffer';\n        }\n        /**\n         * @param {Event} event Event.\n         * @private\n         */\n        xhr.onload = function(event) {\n          // status will be 0 for file:// urls\n          if (!xhr.status || xhr.status >= 200 && xhr.status < 300) {\n            var type = format.getType();\n            /** @type {Document|Node|Object|string|undefined} */\n            var source;\n            if (type == ol.format.FormatType.JSON ||\n                type == ol.format.FormatType.TEXT) {\n              source = xhr.responseText;\n            } else if (type == ol.format.FormatType.XML) {\n              source = xhr.responseXML;\n              if (!source) {\n                source = ol.xml.parse(xhr.responseText);\n              }\n            } else if (type == ol.format.FormatType.ARRAY_BUFFER) {\n              source = /** @type {ArrayBuffer} */ (xhr.response);\n            }\n            if (source) {\n              success.call(this, format.readFeatures(source,\n                  {featureProjection: projection}),\n                  format.readProjection(source));\n            } else {\n              failure.call(this);\n            }\n          } else {\n            failure.call(this);\n          }\n        }.bind(this);\n        xhr.send();\n      });\n};\n\n\n/**\n * Create an XHR feature loader for a `url` and `format`. The feature loader\n * loads features (with XHR), parses the features, and adds them to the\n * vector source.\n * @param {string|ol.FeatureUrlFunction} url Feature URL service.\n * @param {ol.format.Feature} format Feature format.\n * @return {ol.FeatureLoader} The feature loader.\n * @api\n */\nol.featureloader.xhr = function(url, format) {\n  return ol.featureloader.loadFeaturesXhr(url, format,\n      /**\n       * @param {Array.<ol.Feature>} features The loaded features.\n       * @param {ol.proj.Projection} dataProjection Data projection.\n       * @this {ol.source.Vector}\n       */\n      function(features, dataProjection) {\n        this.addFeatures(features);\n      }, /* FIXME handle error */ ol.nullFunction);\n};\n\ngoog.provide('ol.format.Feature');\n\ngoog.require('ol.geom.Geometry');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for feature formats.\n * {ol.format.Feature} subclasses provide the ability to decode and encode\n * {@link ol.Feature} objects from a variety of commonly used geospatial\n * file formats.  See the documentation for each format for more details.\n *\n * @constructor\n * @api stable\n */\nol.format.Feature = function() {\n\n  /**\n   * @protected\n   * @type {ol.proj.Projection}\n   */\n  this.defaultDataProjection = null;\n\n  /**\n   * @protected\n   * @type {ol.proj.Projection}\n   */\n  this.defaultFeatureProjection = null;\n\n};\n\n\n/**\n * @abstract\n * @return {Array.<string>} Extensions.\n */\nol.format.Feature.prototype.getExtensions = function() {};\n\n\n/**\n * Adds the data projection to the read options.\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @return {olx.format.ReadOptions|undefined} Options.\n * @protected\n */\nol.format.Feature.prototype.getReadOptions = function(source, opt_options) {\n  var options;\n  if (opt_options) {\n    options = {\n      dataProjection: opt_options.dataProjection ?\n          opt_options.dataProjection : this.readProjection(source),\n      featureProjection: opt_options.featureProjection\n    };\n  }\n  return this.adaptOptions(options);\n};\n\n\n/**\n * Sets the `defaultDataProjection` on the options, if no `dataProjection`\n * is set.\n * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options\n *     Options.\n * @protected\n * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined}\n *     Updated options.\n */\nol.format.Feature.prototype.adaptOptions = function(options) {\n  return ol.obj.assign({\n    dataProjection: this.defaultDataProjection,\n    featureProjection: this.defaultFeatureProjection\n  }, options);\n};\n\n\n/**\n * @abstract\n * @return {ol.format.FormatType} Format.\n */\nol.format.Feature.prototype.getType = function() {};\n\n\n/**\n * Read a single feature from a source.\n *\n * @abstract\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n */\nol.format.Feature.prototype.readFeature = function(source, opt_options) {};\n\n\n/**\n * Read all features from a source.\n *\n * @abstract\n * @param {Document|Node|ArrayBuffer|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n */\nol.format.Feature.prototype.readFeatures = function(source, opt_options) {};\n\n\n/**\n * Read a single geometry from a source.\n *\n * @abstract\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.Feature.prototype.readGeometry = function(source, opt_options) {};\n\n\n/**\n * Read the projection from a source.\n *\n * @abstract\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n */\nol.format.Feature.prototype.readProjection = function(source) {};\n\n\n/**\n * Encode a feature in this format.\n *\n * @abstract\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} Result.\n */\nol.format.Feature.prototype.writeFeature = function(feature, opt_options) {};\n\n\n/**\n * Encode an array of features in this format.\n *\n * @abstract\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} Result.\n */\nol.format.Feature.prototype.writeFeatures = function(features, opt_options) {};\n\n\n/**\n * Write a single geometry in this format.\n *\n * @abstract\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} Result.\n */\nol.format.Feature.prototype.writeGeometry = function(geometry, opt_options) {};\n\n\n/**\n * @param {ol.geom.Geometry|ol.Extent} geometry Geometry.\n * @param {boolean} write Set to true for writing, false for reading.\n * @param {(olx.format.WriteOptions|olx.format.ReadOptions)=} opt_options\n *     Options.\n * @return {ol.geom.Geometry|ol.Extent} Transformed geometry.\n * @protected\n */\nol.format.Feature.transformWithOptions = function(\n    geometry, write, opt_options) {\n  var featureProjection = opt_options ?\n      ol.proj.get(opt_options.featureProjection) : null;\n  var dataProjection = opt_options ?\n      ol.proj.get(opt_options.dataProjection) : null;\n  /**\n   * @type {ol.geom.Geometry|ol.Extent}\n   */\n  var transformed;\n  if (featureProjection && dataProjection &&\n      !ol.proj.equivalent(featureProjection, dataProjection)) {\n    if (geometry instanceof ol.geom.Geometry) {\n      transformed = (write ? geometry.clone() : geometry).transform(\n          write ? featureProjection : dataProjection,\n          write ? dataProjection : featureProjection);\n    } else {\n      // FIXME this is necessary because ol.format.GML treats extents\n      // as geometries\n      transformed = ol.proj.transformExtent(\n          write ? geometry.slice() : geometry,\n          write ? featureProjection : dataProjection,\n          write ? dataProjection : featureProjection);\n    }\n  } else {\n    transformed = geometry;\n  }\n  if (write && opt_options && opt_options.decimals) {\n    var power = Math.pow(10, opt_options.decimals);\n    // if decimals option on write, round each coordinate appropriately\n    /**\n     * @param {Array.<number>} coordinates Coordinates.\n     * @return {Array.<number>} Transformed coordinates.\n     */\n    var transform = function(coordinates) {\n      for (var i = 0, ii = coordinates.length; i < ii; ++i) {\n        coordinates[i] = Math.round(coordinates[i] * power) / power;\n      }\n      return coordinates;\n    };\n    if (Array.isArray(transformed)) {\n      transform(transformed);\n    } else {\n      transformed.applyTransform(transform);\n    }\n  }\n  return transformed;\n};\n\ngoog.provide('ol.format.JSONFeature');\n\ngoog.require('ol');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.FormatType');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for JSON feature formats.\n *\n * @constructor\n * @extends {ol.format.Feature}\n */\nol.format.JSONFeature = function() {\n  ol.format.Feature.call(this);\n};\nol.inherits(ol.format.JSONFeature, ol.format.Feature);\n\n\n/**\n * @param {Document|Node|Object|string} source Source.\n * @private\n * @return {Object} Object.\n */\nol.format.JSONFeature.prototype.getObject_ = function(source) {\n  if (typeof source === 'string') {\n    var object = JSON.parse(source);\n    return object ? /** @type {Object} */ (object) : null;\n  } else if (source !== null) {\n    return source;\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.getType = function() {\n  return ol.format.FormatType.JSON;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.readFeature = function(source, opt_options) {\n  return this.readFeatureFromObject(\n      this.getObject_(source), this.getReadOptions(source, opt_options));\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.readFeatures = function(source, opt_options) {\n  return this.readFeaturesFromObject(\n      this.getObject_(source), this.getReadOptions(source, opt_options));\n};\n\n\n/**\n * @abstract\n * @param {Object} object Object.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @protected\n * @return {ol.Feature} Feature.\n */\nol.format.JSONFeature.prototype.readFeatureFromObject = function(object, opt_options) {};\n\n\n/**\n * @abstract\n * @param {Object} object Object.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @protected\n * @return {Array.<ol.Feature>} Features.\n */\nol.format.JSONFeature.prototype.readFeaturesFromObject = function(object, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.readGeometry = function(source, opt_options) {\n  return this.readGeometryFromObject(\n      this.getObject_(source), this.getReadOptions(source, opt_options));\n};\n\n\n/**\n * @abstract\n * @param {Object} object Object.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @protected\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.JSONFeature.prototype.readGeometryFromObject = function(object, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.readProjection = function(source) {\n  return this.readProjectionFromObject(this.getObject_(source));\n};\n\n\n/**\n * @abstract\n * @param {Object} object Object.\n * @protected\n * @return {ol.proj.Projection} Projection.\n */\nol.format.JSONFeature.prototype.readProjectionFromObject = function(object) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) {\n  return JSON.stringify(this.writeFeatureObject(feature, opt_options));\n};\n\n\n/**\n * @abstract\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {Object} Object.\n */\nol.format.JSONFeature.prototype.writeFeatureObject = function(feature, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.writeFeatures = function(features, opt_options) {\n  return JSON.stringify(this.writeFeaturesObject(features, opt_options));\n};\n\n\n/**\n * @abstract\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {Object} Object.\n */\nol.format.JSONFeature.prototype.writeFeaturesObject = function(features, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.JSONFeature.prototype.writeGeometry = function(geometry, opt_options) {\n  return JSON.stringify(this.writeGeometryObject(geometry, opt_options));\n};\n\n\n/**\n * @abstract\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {Object} Object.\n */\nol.format.JSONFeature.prototype.writeGeometryObject = function(geometry, opt_options) {};\n\ngoog.provide('ol.geom.flat.interpolate');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.math');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} fraction Fraction.\n * @param {Array.<number>=} opt_dest Destination.\n * @return {Array.<number>} Destination.\n */\nol.geom.flat.interpolate.lineString = function(flatCoordinates, offset, end, stride, fraction, opt_dest) {\n  // FIXME does not work when vertices are repeated\n  // FIXME interpolate extra dimensions\n  ol.DEBUG && console.assert(0 <= fraction && fraction <= 1,\n      'fraction should be in between 0 and 1');\n  var pointX = NaN;\n  var pointY = NaN;\n  var n = (end - offset) / stride;\n  if (n === 0) {\n    ol.DEBUG && console.assert(false, 'n cannot be 0');\n  } else if (n == 1) {\n    pointX = flatCoordinates[offset];\n    pointY = flatCoordinates[offset + 1];\n  } else if (n == 2) {\n    pointX = (1 - fraction) * flatCoordinates[offset] +\n        fraction * flatCoordinates[offset + stride];\n    pointY = (1 - fraction) * flatCoordinates[offset + 1] +\n        fraction * flatCoordinates[offset + stride + 1];\n  } else {\n    var x1 = flatCoordinates[offset];\n    var y1 = flatCoordinates[offset + 1];\n    var length = 0;\n    var cumulativeLengths = [0];\n    var i;\n    for (i = offset + stride; i < end; i += stride) {\n      var x2 = flatCoordinates[i];\n      var y2 = flatCoordinates[i + 1];\n      length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n      cumulativeLengths.push(length);\n      x1 = x2;\n      y1 = y2;\n    }\n    var target = fraction * length;\n    var index = ol.array.binarySearch(cumulativeLengths, target);\n    if (index < 0) {\n      var t = (target - cumulativeLengths[-index - 2]) /\n          (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]);\n      var o = offset + (-index - 2) * stride;\n      pointX = ol.math.lerp(\n          flatCoordinates[o], flatCoordinates[o + stride], t);\n      pointY = ol.math.lerp(\n          flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t);\n    } else {\n      pointX = flatCoordinates[offset + index * stride];\n      pointY = flatCoordinates[offset + index * stride + 1];\n    }\n  }\n  if (opt_dest) {\n    opt_dest[0] = pointX;\n    opt_dest[1] = pointY;\n    return opt_dest;\n  } else {\n    return [pointX, pointY];\n  }\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} m M.\n * @param {boolean} extrapolate Extrapolate.\n * @return {ol.Coordinate} Coordinate.\n */\nol.geom.flat.interpolate.lineStringCoordinateAtM = function(flatCoordinates, offset, end, stride, m, extrapolate) {\n  if (end == offset) {\n    return null;\n  }\n  var coordinate;\n  if (m < flatCoordinates[offset + stride - 1]) {\n    if (extrapolate) {\n      coordinate = flatCoordinates.slice(offset, offset + stride);\n      coordinate[stride - 1] = m;\n      return coordinate;\n    } else {\n      return null;\n    }\n  } else if (flatCoordinates[end - 1] < m) {\n    if (extrapolate) {\n      coordinate = flatCoordinates.slice(end - stride, end);\n      coordinate[stride - 1] = m;\n      return coordinate;\n    } else {\n      return null;\n    }\n  }\n  // FIXME use O(1) search\n  if (m == flatCoordinates[offset + stride - 1]) {\n    return flatCoordinates.slice(offset, offset + stride);\n  }\n  var lo = offset / stride;\n  var hi = end / stride;\n  while (lo < hi) {\n    var mid = (lo + hi) >> 1;\n    if (m < flatCoordinates[(mid + 1) * stride - 1]) {\n      hi = mid;\n    } else {\n      lo = mid + 1;\n    }\n  }\n  var m0 = flatCoordinates[lo * stride - 1];\n  if (m == m0) {\n    return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride);\n  }\n  var m1 = flatCoordinates[(lo + 1) * stride - 1];\n  ol.DEBUG && console.assert(m0 < m, 'm0 should be less than m');\n  ol.DEBUG && console.assert(m <= m1, 'm should be less than or equal to m1');\n  var t = (m - m0) / (m1 - m0);\n  coordinate = [];\n  var i;\n  for (i = 0; i < stride - 1; ++i) {\n    coordinate.push(ol.math.lerp(flatCoordinates[(lo - 1) * stride + i],\n        flatCoordinates[lo * stride + i], t));\n  }\n  coordinate.push(m);\n  ol.DEBUG && console.assert(coordinate.length == stride,\n      'length of coordinate array should match stride');\n  return coordinate;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<number>} ends Ends.\n * @param {number} stride Stride.\n * @param {number} m M.\n * @param {boolean} extrapolate Extrapolate.\n * @param {boolean} interpolate Interpolate.\n * @return {ol.Coordinate} Coordinate.\n */\nol.geom.flat.interpolate.lineStringsCoordinateAtM = function(\n    flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) {\n  if (interpolate) {\n    return ol.geom.flat.interpolate.lineStringCoordinateAtM(\n        flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate);\n  }\n  var coordinate;\n  if (m < flatCoordinates[stride - 1]) {\n    if (extrapolate) {\n      coordinate = flatCoordinates.slice(0, stride);\n      coordinate[stride - 1] = m;\n      return coordinate;\n    } else {\n      return null;\n    }\n  }\n  if (flatCoordinates[flatCoordinates.length - 1] < m) {\n    if (extrapolate) {\n      coordinate = flatCoordinates.slice(flatCoordinates.length - stride);\n      coordinate[stride - 1] = m;\n      return coordinate;\n    } else {\n      return null;\n    }\n  }\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    if (offset == end) {\n      continue;\n    }\n    if (m < flatCoordinates[offset + stride - 1]) {\n      return null;\n    } else if (m <= flatCoordinates[end - 1]) {\n      return ol.geom.flat.interpolate.lineStringCoordinateAtM(\n          flatCoordinates, offset, end, stride, m, false);\n    }\n    offset = end;\n  }\n  ol.DEBUG && console.assert(false,\n      'ol.geom.flat.interpolate.lineStringsCoordinateAtM should have returned');\n  return null;\n};\n\ngoog.provide('ol.geom.flat.length');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Length.\n */\nol.geom.flat.length.lineString = function(flatCoordinates, offset, end, stride) {\n  var x1 = flatCoordinates[offset];\n  var y1 = flatCoordinates[offset + 1];\n  var length = 0;\n  var i;\n  for (i = offset + stride; i < end; i += stride) {\n    var x2 = flatCoordinates[i];\n    var y2 = flatCoordinates[i + 1];\n    length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n    x1 = x2;\n    y1 = y2;\n  }\n  return length;\n};\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Perimeter.\n */\nol.geom.flat.length.linearRing = function(flatCoordinates, offset, end, stride) {\n  var perimeter =\n      ol.geom.flat.length.lineString(flatCoordinates, offset, end, stride);\n  var dx = flatCoordinates[end - stride] - flatCoordinates[offset];\n  var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1];\n  perimeter += Math.sqrt(dx * dx + dy * dy);\n  return perimeter;\n};\n\ngoog.provide('ol.geom.LineString');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.closest');\ngoog.require('ol.geom.flat.deflate');\ngoog.require('ol.geom.flat.inflate');\ngoog.require('ol.geom.flat.interpolate');\ngoog.require('ol.geom.flat.intersectsextent');\ngoog.require('ol.geom.flat.length');\ngoog.require('ol.geom.flat.segments');\ngoog.require('ol.geom.flat.simplify');\n\n\n/**\n * @classdesc\n * Linestring geometry.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.LineString = function(coordinates, opt_layout) {\n\n  ol.geom.SimpleGeometry.call(this);\n\n  /**\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.flatMidpoint_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.flatMidpointRevision_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDelta_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDeltaRevision_ = -1;\n\n  this.setCoordinates(coordinates, opt_layout);\n\n};\nol.inherits(ol.geom.LineString, ol.geom.SimpleGeometry);\n\n\n/**\n * Append the passed coordinate to the coordinates of the linestring.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @api stable\n */\nol.geom.LineString.prototype.appendCoordinate = function(coordinate) {\n  ol.DEBUG && console.assert(coordinate.length == this.stride,\n      'length of coordinate array should match stride');\n  if (!this.flatCoordinates) {\n    this.flatCoordinates = coordinate.slice();\n  } else {\n    ol.array.extend(this.flatCoordinates, coordinate);\n  }\n  this.changed();\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.LineString} Clone.\n * @api stable\n */\nol.geom.LineString.prototype.clone = function() {\n  var lineString = new ol.geom.LineString(null);\n  lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n  return lineString;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.LineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  if (minSquaredDistance <\n      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {\n    return minSquaredDistance;\n  }\n  if (this.maxDeltaRevision_ != this.getRevision()) {\n    this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(\n        this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));\n    this.maxDeltaRevision_ = this.getRevision();\n  }\n  return ol.geom.flat.closest.getClosestPoint(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n      this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * Iterate over each segment, calling the provided callback.\n * If the callback returns a truthy value the function returns that\n * value immediately. Otherwise the function returns `false`.\n *\n * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function\n *     called for each segment.\n * @param {S=} opt_this The object to be used as the value of 'this'\n *     within callback.\n * @return {T|boolean} Value.\n * @template T,S\n * @api\n */\nol.geom.LineString.prototype.forEachSegment = function(callback, opt_this) {\n  return ol.geom.flat.segments.forEach(this.flatCoordinates, 0,\n      this.flatCoordinates.length, this.stride, callback, opt_this);\n};\n\n\n/**\n * Returns the coordinate at `m` using linear interpolation, or `null` if no\n * such coordinate exists.\n *\n * `opt_extrapolate` controls extrapolation beyond the range of Ms in the\n * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first\n * M will return the first coordinate and Ms greater than the last M will\n * return the last coordinate.\n *\n * @param {number} m M.\n * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.\n * @return {ol.Coordinate} Coordinate.\n * @api stable\n */\nol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {\n  if (this.layout != ol.geom.GeometryLayout.XYM &&\n      this.layout != ol.geom.GeometryLayout.XYZM) {\n    return null;\n  }\n  var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;\n  return ol.geom.flat.interpolate.lineStringCoordinateAtM(this.flatCoordinates, 0,\n      this.flatCoordinates.length, this.stride, m, extrapolate);\n};\n\n\n/**\n * Return the coordinates of the linestring.\n * @return {Array.<ol.Coordinate>} Coordinates.\n * @api stable\n */\nol.geom.LineString.prototype.getCoordinates = function() {\n  return ol.geom.flat.inflate.coordinates(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * Return the coordinate at the provided fraction along the linestring.\n * The `fraction` is a number between 0 and 1, where 0 is the start of the\n * linestring and 1 is the end.\n * @param {number} fraction Fraction.\n * @param {ol.Coordinate=} opt_dest Optional coordinate whose values will\n *     be modified. If not provided, a new coordinate will be returned.\n * @return {ol.Coordinate} Coordinate of the interpolated point.\n * @api\n */\nol.geom.LineString.prototype.getCoordinateAt = function(fraction, opt_dest) {\n  return ol.geom.flat.interpolate.lineString(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n      fraction, opt_dest);\n};\n\n\n/**\n * Return the length of the linestring on projected plane.\n * @return {number} Length (on projected plane).\n * @api stable\n */\nol.geom.LineString.prototype.getLength = function() {\n  return ol.geom.flat.length.lineString(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * @return {Array.<number>} Flat midpoint.\n */\nol.geom.LineString.prototype.getFlatMidpoint = function() {\n  if (this.flatMidpointRevision_ != this.getRevision()) {\n    this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);\n    this.flatMidpointRevision_ = this.getRevision();\n  }\n  return this.flatMidpoint_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.LineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n  var simplifiedFlatCoordinates = [];\n  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n      squaredTolerance, simplifiedFlatCoordinates, 0);\n  var simplifiedLineString = new ol.geom.LineString(null);\n  simplifiedLineString.setFlatCoordinates(\n      ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);\n  return simplifiedLineString;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.LineString.prototype.getType = function() {\n  return ol.geom.GeometryType.LINE_STRING;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.LineString.prototype.intersectsExtent = function(extent) {\n  return ol.geom.flat.intersectsextent.lineString(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n      extent);\n};\n\n\n/**\n * Set the coordinates of the linestring.\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.LineString.prototype.setCoordinates = function(coordinates, opt_layout) {\n  if (!coordinates) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);\n  } else {\n    this.setLayout(opt_layout, coordinates, 1);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(\n        this.flatCoordinates, 0, coordinates, this.stride);\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n */\nol.geom.LineString.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.changed();\n};\n\ngoog.provide('ol.geom.MultiLineString');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.closest');\ngoog.require('ol.geom.flat.deflate');\ngoog.require('ol.geom.flat.inflate');\ngoog.require('ol.geom.flat.interpolate');\ngoog.require('ol.geom.flat.intersectsextent');\ngoog.require('ol.geom.flat.simplify');\n\n\n/**\n * @classdesc\n * Multi-linestring geometry.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.MultiLineString = function(coordinates, opt_layout) {\n\n  ol.geom.SimpleGeometry.call(this);\n\n  /**\n   * @type {Array.<number>}\n   * @private\n   */\n  this.ends_ = [];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDelta_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDeltaRevision_ = -1;\n\n  this.setCoordinates(coordinates, opt_layout);\n\n};\nol.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry);\n\n\n/**\n * Append the passed linestring to the multilinestring.\n * @param {ol.geom.LineString} lineString LineString.\n * @api stable\n */\nol.geom.MultiLineString.prototype.appendLineString = function(lineString) {\n  ol.DEBUG && console.assert(lineString.getLayout() == this.layout,\n      'layout of lineString should match the layout');\n  if (!this.flatCoordinates) {\n    this.flatCoordinates = lineString.getFlatCoordinates().slice();\n  } else {\n    ol.array.extend(\n        this.flatCoordinates, lineString.getFlatCoordinates().slice());\n  }\n  this.ends_.push(this.flatCoordinates.length);\n  this.changed();\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.MultiLineString} Clone.\n * @api stable\n */\nol.geom.MultiLineString.prototype.clone = function() {\n  var multiLineString = new ol.geom.MultiLineString(null);\n  multiLineString.setFlatCoordinates(\n      this.layout, this.flatCoordinates.slice(), this.ends_.slice());\n  return multiLineString;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.MultiLineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  if (minSquaredDistance <\n      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {\n    return minSquaredDistance;\n  }\n  if (this.maxDeltaRevision_ != this.getRevision()) {\n    this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(\n        this.flatCoordinates, 0, this.ends_, this.stride, 0));\n    this.maxDeltaRevision_ = this.getRevision();\n  }\n  return ol.geom.flat.closest.getsClosestPoint(\n      this.flatCoordinates, 0, this.ends_, this.stride,\n      this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * Returns the coordinate at `m` using linear interpolation, or `null` if no\n * such coordinate exists.\n *\n * `opt_extrapolate` controls extrapolation beyond the range of Ms in the\n * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first\n * M will return the first coordinate and Ms greater than the last M will\n * return the last coordinate.\n *\n * `opt_interpolate` controls interpolation between consecutive LineStrings\n * within the MultiLineString. If `opt_interpolate` is `true` the coordinates\n * will be linearly interpolated between the last coordinate of one LineString\n * and the first coordinate of the next LineString.  If `opt_interpolate` is\n * `false` then the function will return `null` for Ms falling between\n * LineStrings.\n *\n * @param {number} m M.\n * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.\n * @param {boolean=} opt_interpolate Interpolate. Default is `false`.\n * @return {ol.Coordinate} Coordinate.\n * @api stable\n */\nol.geom.MultiLineString.prototype.getCoordinateAtM = function(m, opt_extrapolate, opt_interpolate) {\n  if ((this.layout != ol.geom.GeometryLayout.XYM &&\n       this.layout != ol.geom.GeometryLayout.XYZM) ||\n      this.flatCoordinates.length === 0) {\n    return null;\n  }\n  var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;\n  var interpolate = opt_interpolate !== undefined ? opt_interpolate : false;\n  return ol.geom.flat.interpolate.lineStringsCoordinateAtM(this.flatCoordinates, 0,\n      this.ends_, this.stride, m, extrapolate, interpolate);\n};\n\n\n/**\n * Return the coordinates of the multilinestring.\n * @return {Array.<Array.<ol.Coordinate>>} Coordinates.\n * @api stable\n */\nol.geom.MultiLineString.prototype.getCoordinates = function() {\n  return ol.geom.flat.inflate.coordinatess(\n      this.flatCoordinates, 0, this.ends_, this.stride);\n};\n\n\n/**\n * @return {Array.<number>} Ends.\n */\nol.geom.MultiLineString.prototype.getEnds = function() {\n  return this.ends_;\n};\n\n\n/**\n * Return the linestring at the specified index.\n * @param {number} index Index.\n * @return {ol.geom.LineString} LineString.\n * @api stable\n */\nol.geom.MultiLineString.prototype.getLineString = function(index) {\n  ol.DEBUG && console.assert(0 <= index && index < this.ends_.length,\n      'index should be in between 0 and length of the this.ends_ array');\n  if (index < 0 || this.ends_.length <= index) {\n    return null;\n  }\n  var lineString = new ol.geom.LineString(null);\n  lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice(\n      index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));\n  return lineString;\n};\n\n\n/**\n * Return the linestrings of this multilinestring.\n * @return {Array.<ol.geom.LineString>} LineStrings.\n * @api stable\n */\nol.geom.MultiLineString.prototype.getLineStrings = function() {\n  var flatCoordinates = this.flatCoordinates;\n  var ends = this.ends_;\n  var layout = this.layout;\n  /** @type {Array.<ol.geom.LineString>} */\n  var lineStrings = [];\n  var offset = 0;\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    var lineString = new ol.geom.LineString(null);\n    lineString.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));\n    lineStrings.push(lineString);\n    offset = end;\n  }\n  return lineStrings;\n};\n\n\n/**\n * @return {Array.<number>} Flat midpoints.\n */\nol.geom.MultiLineString.prototype.getFlatMidpoints = function() {\n  var midpoints = [];\n  var flatCoordinates = this.flatCoordinates;\n  var offset = 0;\n  var ends = this.ends_;\n  var stride = this.stride;\n  var i, ii;\n  for (i = 0, ii = ends.length; i < ii; ++i) {\n    var end = ends[i];\n    var midpoint = ol.geom.flat.interpolate.lineString(\n        flatCoordinates, offset, end, stride, 0.5);\n    ol.array.extend(midpoints, midpoint);\n    offset = end;\n  }\n  return midpoints;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.MultiLineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n  var simplifiedFlatCoordinates = [];\n  var simplifiedEnds = [];\n  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeuckers(\n      this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance,\n      simplifiedFlatCoordinates, 0, simplifiedEnds);\n  var simplifiedMultiLineString = new ol.geom.MultiLineString(null);\n  simplifiedMultiLineString.setFlatCoordinates(\n      ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);\n  return simplifiedMultiLineString;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.MultiLineString.prototype.getType = function() {\n  return ol.geom.GeometryType.MULTI_LINE_STRING;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.MultiLineString.prototype.intersectsExtent = function(extent) {\n  return ol.geom.flat.intersectsextent.lineStrings(\n      this.flatCoordinates, 0, this.ends_, this.stride, extent);\n};\n\n\n/**\n * Set the coordinates of the multilinestring.\n * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.MultiLineString.prototype.setCoordinates = function(coordinates, opt_layout) {\n  if (!coordinates) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);\n  } else {\n    this.setLayout(opt_layout, coordinates, 2);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    var ends = ol.geom.flat.deflate.coordinatess(\n        this.flatCoordinates, 0, coordinates, this.stride, this.ends_);\n    this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {Array.<number>} ends Ends.\n */\nol.geom.MultiLineString.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {\n  if (!flatCoordinates) {\n    ol.DEBUG && console.assert(ends && ends.length === 0,\n        'ends must be truthy and ends.length should be 0');\n  } else if (ends.length === 0) {\n    ol.DEBUG && console.assert(flatCoordinates.length === 0,\n        'flatCoordinates should be an empty array');\n  } else {\n    ol.DEBUG && console.assert(flatCoordinates.length == ends[ends.length - 1],\n        'length of flatCoordinates array should match the last value of ends');\n  }\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.ends_ = ends;\n  this.changed();\n};\n\n\n/**\n * @param {Array.<ol.geom.LineString>} lineStrings LineStrings.\n */\nol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) {\n  var layout = this.getLayout();\n  var flatCoordinates = [];\n  var ends = [];\n  var i, ii;\n  for (i = 0, ii = lineStrings.length; i < ii; ++i) {\n    var lineString = lineStrings[i];\n    if (i === 0) {\n      layout = lineString.getLayout();\n    } else {\n      // FIXME better handle the case of non-matching layouts\n      ol.DEBUG && console.assert(lineString.getLayout() == layout,\n          'layout of lineString should match layout');\n    }\n    ol.array.extend(flatCoordinates, lineString.getFlatCoordinates());\n    ends.push(flatCoordinates.length);\n  }\n  this.setFlatCoordinates(layout, flatCoordinates, ends);\n};\n\ngoog.provide('ol.geom.MultiPoint');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.deflate');\ngoog.require('ol.geom.flat.inflate');\ngoog.require('ol.math');\n\n\n/**\n * @classdesc\n * Multi-point geometry.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.MultiPoint = function(coordinates, opt_layout) {\n  ol.geom.SimpleGeometry.call(this);\n  this.setCoordinates(coordinates, opt_layout);\n};\nol.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry);\n\n\n/**\n * Append the passed point to this multipoint.\n * @param {ol.geom.Point} point Point.\n * @api stable\n */\nol.geom.MultiPoint.prototype.appendPoint = function(point) {\n  ol.DEBUG && console.assert(point.getLayout() == this.layout,\n      'the layout of point should match layout');\n  if (!this.flatCoordinates) {\n    this.flatCoordinates = point.getFlatCoordinates().slice();\n  } else {\n    ol.array.extend(this.flatCoordinates, point.getFlatCoordinates());\n  }\n  this.changed();\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.MultiPoint} Clone.\n * @api stable\n */\nol.geom.MultiPoint.prototype.clone = function() {\n  var multiPoint = new ol.geom.MultiPoint(null);\n  multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n  return multiPoint;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.MultiPoint.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  if (minSquaredDistance <\n      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {\n    return minSquaredDistance;\n  }\n  var flatCoordinates = this.flatCoordinates;\n  var stride = this.stride;\n  var i, ii, j;\n  for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {\n    var squaredDistance = ol.math.squaredDistance(\n        x, y, flatCoordinates[i], flatCoordinates[i + 1]);\n    if (squaredDistance < minSquaredDistance) {\n      minSquaredDistance = squaredDistance;\n      for (j = 0; j < stride; ++j) {\n        closestPoint[j] = flatCoordinates[i + j];\n      }\n      closestPoint.length = stride;\n    }\n  }\n  return minSquaredDistance;\n};\n\n\n/**\n * Return the coordinates of the multipoint.\n * @return {Array.<ol.Coordinate>} Coordinates.\n * @api stable\n */\nol.geom.MultiPoint.prototype.getCoordinates = function() {\n  return ol.geom.flat.inflate.coordinates(\n      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * Return the point at the specified index.\n * @param {number} index Index.\n * @return {ol.geom.Point} Point.\n * @api stable\n */\nol.geom.MultiPoint.prototype.getPoint = function(index) {\n  var n = !this.flatCoordinates ?\n      0 : this.flatCoordinates.length / this.stride;\n  ol.DEBUG && console.assert(0 <= index && index < n,\n      'index should be in between 0 and n');\n  if (index < 0 || n <= index) {\n    return null;\n  }\n  var point = new ol.geom.Point(null);\n  point.setFlatCoordinates(this.layout, this.flatCoordinates.slice(\n      index * this.stride, (index + 1) * this.stride));\n  return point;\n};\n\n\n/**\n * Return the points of this multipoint.\n * @return {Array.<ol.geom.Point>} Points.\n * @api stable\n */\nol.geom.MultiPoint.prototype.getPoints = function() {\n  var flatCoordinates = this.flatCoordinates;\n  var layout = this.layout;\n  var stride = this.stride;\n  /** @type {Array.<ol.geom.Point>} */\n  var points = [];\n  var i, ii;\n  for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {\n    var point = new ol.geom.Point(null);\n    point.setFlatCoordinates(layout, flatCoordinates.slice(i, i + stride));\n    points.push(point);\n  }\n  return points;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.MultiPoint.prototype.getType = function() {\n  return ol.geom.GeometryType.MULTI_POINT;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.MultiPoint.prototype.intersectsExtent = function(extent) {\n  var flatCoordinates = this.flatCoordinates;\n  var stride = this.stride;\n  var i, ii, x, y;\n  for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {\n    x = flatCoordinates[i];\n    y = flatCoordinates[i + 1];\n    if (ol.extent.containsXY(extent, x, y)) {\n      return true;\n    }\n  }\n  return false;\n};\n\n\n/**\n * Set the coordinates of the multipoint.\n * @param {Array.<ol.Coordinate>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.MultiPoint.prototype.setCoordinates = function(coordinates, opt_layout) {\n  if (!coordinates) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);\n  } else {\n    this.setLayout(opt_layout, coordinates, 1);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(\n        this.flatCoordinates, 0, coordinates, this.stride);\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n */\nol.geom.MultiPoint.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.changed();\n};\n\ngoog.provide('ol.geom.flat.center');\n\ngoog.require('ol.extent');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.<Array.<number>>} endss Endss.\n * @param {number} stride Stride.\n * @return {Array.<number>} Flat centers.\n */\nol.geom.flat.center.linearRingss = function(flatCoordinates, offset, endss, stride) {\n  var flatCenters = [];\n  var i, ii;\n  var extent = ol.extent.createEmpty();\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i];\n    extent = ol.extent.createOrUpdateFromFlatCoordinates(\n        flatCoordinates, offset, ends[0], stride);\n    flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2);\n    offset = ends[ends.length - 1];\n  }\n  return flatCenters;\n};\n\ngoog.provide('ol.geom.MultiPolygon');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.area');\ngoog.require('ol.geom.flat.center');\ngoog.require('ol.geom.flat.closest');\ngoog.require('ol.geom.flat.contains');\ngoog.require('ol.geom.flat.deflate');\ngoog.require('ol.geom.flat.inflate');\ngoog.require('ol.geom.flat.interiorpoint');\ngoog.require('ol.geom.flat.intersectsextent');\ngoog.require('ol.geom.flat.orient');\ngoog.require('ol.geom.flat.simplify');\n\n\n/**\n * @classdesc\n * Multi-polygon geometry.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.MultiPolygon = function(coordinates, opt_layout) {\n\n  ol.geom.SimpleGeometry.call(this);\n\n  /**\n   * @type {Array.<Array.<number>>}\n   * @private\n   */\n  this.endss_ = [];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.flatInteriorPointsRevision_ = -1;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.flatInteriorPoints_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDelta_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxDeltaRevision_ = -1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.orientedRevision_ = -1;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.orientedFlatCoordinates_ = null;\n\n  this.setCoordinates(coordinates, opt_layout);\n\n};\nol.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry);\n\n\n/**\n * Append the passed polygon to this multipolygon.\n * @param {ol.geom.Polygon} polygon Polygon.\n * @api stable\n */\nol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) {\n  ol.DEBUG && console.assert(polygon.getLayout() == this.layout,\n      'layout of polygon should match layout');\n  /** @type {Array.<number>} */\n  var ends;\n  if (!this.flatCoordinates) {\n    this.flatCoordinates = polygon.getFlatCoordinates().slice();\n    ends = polygon.getEnds().slice();\n    this.endss_.push();\n  } else {\n    var offset = this.flatCoordinates.length;\n    ol.array.extend(this.flatCoordinates, polygon.getFlatCoordinates());\n    ends = polygon.getEnds().slice();\n    var i, ii;\n    for (i = 0, ii = ends.length; i < ii; ++i) {\n      ends[i] += offset;\n    }\n  }\n  this.endss_.push(ends);\n  this.changed();\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.MultiPolygon} Clone.\n * @api stable\n */\nol.geom.MultiPolygon.prototype.clone = function() {\n  var multiPolygon = new ol.geom.MultiPolygon(null);\n\n  var len = this.endss_.length;\n  var newEndss = new Array(len);\n  for (var i = 0; i < len; ++i) {\n    newEndss[i] = this.endss_[i].slice();\n  }\n\n  multiPolygon.setFlatCoordinates(\n      this.layout, this.flatCoordinates.slice(), newEndss);\n  return multiPolygon;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.MultiPolygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  if (minSquaredDistance <\n      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {\n    return minSquaredDistance;\n  }\n  if (this.maxDeltaRevision_ != this.getRevision()) {\n    this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getssMaxSquaredDelta(\n        this.flatCoordinates, 0, this.endss_, this.stride, 0));\n    this.maxDeltaRevision_ = this.getRevision();\n  }\n  return ol.geom.flat.closest.getssClosestPoint(\n      this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,\n      this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.MultiPolygon.prototype.containsXY = function(x, y) {\n  return ol.geom.flat.contains.linearRingssContainsXY(\n      this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y);\n};\n\n\n/**\n * Return the area of the multipolygon on projected plane.\n * @return {number} Area (on projected plane).\n * @api stable\n */\nol.geom.MultiPolygon.prototype.getArea = function() {\n  return ol.geom.flat.area.linearRingss(\n      this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride);\n};\n\n\n/**\n * Get the coordinate array for this geometry.  This array has the structure\n * of a GeoJSON coordinate array for multi-polygons.\n *\n * @param {boolean=} opt_right Orient coordinates according to the right-hand\n *     rule (counter-clockwise for exterior and clockwise for interior rings).\n *     If `false`, coordinates will be oriented according to the left-hand rule\n *     (clockwise for exterior and counter-clockwise for interior rings).\n *     By default, coordinate orientation will depend on how the geometry was\n *     constructed.\n * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates.\n * @api stable\n */\nol.geom.MultiPolygon.prototype.getCoordinates = function(opt_right) {\n  var flatCoordinates;\n  if (opt_right !== undefined) {\n    flatCoordinates = this.getOrientedFlatCoordinates().slice();\n    ol.geom.flat.orient.orientLinearRingss(\n        flatCoordinates, 0, this.endss_, this.stride, opt_right);\n  } else {\n    flatCoordinates = this.flatCoordinates;\n  }\n\n  return ol.geom.flat.inflate.coordinatesss(\n      flatCoordinates, 0, this.endss_, this.stride);\n};\n\n\n/**\n * @return {Array.<Array.<number>>} Endss.\n */\nol.geom.MultiPolygon.prototype.getEndss = function() {\n  return this.endss_;\n};\n\n\n/**\n * @return {Array.<number>} Flat interior points.\n */\nol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() {\n  if (this.flatInteriorPointsRevision_ != this.getRevision()) {\n    var flatCenters = ol.geom.flat.center.linearRingss(\n        this.flatCoordinates, 0, this.endss_, this.stride);\n    this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss(\n        this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,\n        flatCenters);\n    this.flatInteriorPointsRevision_ = this.getRevision();\n  }\n  return this.flatInteriorPoints_;\n};\n\n\n/**\n * Return the interior points as {@link ol.geom.MultiPoint multipoint}.\n * @return {ol.geom.MultiPoint} Interior points.\n * @api stable\n */\nol.geom.MultiPolygon.prototype.getInteriorPoints = function() {\n  var interiorPoints = new ol.geom.MultiPoint(null);\n  interiorPoints.setFlatCoordinates(ol.geom.GeometryLayout.XY,\n      this.getFlatInteriorPoints().slice());\n  return interiorPoints;\n};\n\n\n/**\n * @return {Array.<number>} Oriented flat coordinates.\n */\nol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() {\n  if (this.orientedRevision_ != this.getRevision()) {\n    var flatCoordinates = this.flatCoordinates;\n    if (ol.geom.flat.orient.linearRingssAreOriented(\n        flatCoordinates, 0, this.endss_, this.stride)) {\n      this.orientedFlatCoordinates_ = flatCoordinates;\n    } else {\n      this.orientedFlatCoordinates_ = flatCoordinates.slice();\n      this.orientedFlatCoordinates_.length =\n          ol.geom.flat.orient.orientLinearRingss(\n              this.orientedFlatCoordinates_, 0, this.endss_, this.stride);\n    }\n    this.orientedRevision_ = this.getRevision();\n  }\n  return this.orientedFlatCoordinates_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.MultiPolygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n  var simplifiedFlatCoordinates = [];\n  var simplifiedEndss = [];\n  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizess(\n      this.flatCoordinates, 0, this.endss_, this.stride,\n      Math.sqrt(squaredTolerance),\n      simplifiedFlatCoordinates, 0, simplifiedEndss);\n  var simplifiedMultiPolygon = new ol.geom.MultiPolygon(null);\n  simplifiedMultiPolygon.setFlatCoordinates(\n      ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEndss);\n  return simplifiedMultiPolygon;\n};\n\n\n/**\n * Return the polygon at the specified index.\n * @param {number} index Index.\n * @return {ol.geom.Polygon} Polygon.\n * @api stable\n */\nol.geom.MultiPolygon.prototype.getPolygon = function(index) {\n  ol.DEBUG && console.assert(0 <= index && index < this.endss_.length,\n      'index should be in between 0 and the length of this.endss_');\n  if (index < 0 || this.endss_.length <= index) {\n    return null;\n  }\n  var offset;\n  if (index === 0) {\n    offset = 0;\n  } else {\n    var prevEnds = this.endss_[index - 1];\n    offset = prevEnds[prevEnds.length - 1];\n  }\n  var ends = this.endss_[index].slice();\n  var end = ends[ends.length - 1];\n  if (offset !== 0) {\n    var i, ii;\n    for (i = 0, ii = ends.length; i < ii; ++i) {\n      ends[i] -= offset;\n    }\n  }\n  var polygon = new ol.geom.Polygon(null);\n  polygon.setFlatCoordinates(\n      this.layout, this.flatCoordinates.slice(offset, end), ends);\n  return polygon;\n};\n\n\n/**\n * Return the polygons of this multipolygon.\n * @return {Array.<ol.geom.Polygon>} Polygons.\n * @api stable\n */\nol.geom.MultiPolygon.prototype.getPolygons = function() {\n  var layout = this.layout;\n  var flatCoordinates = this.flatCoordinates;\n  var endss = this.endss_;\n  var polygons = [];\n  var offset = 0;\n  var i, ii, j, jj;\n  for (i = 0, ii = endss.length; i < ii; ++i) {\n    var ends = endss[i].slice();\n    var end = ends[ends.length - 1];\n    if (offset !== 0) {\n      for (j = 0, jj = ends.length; j < jj; ++j) {\n        ends[j] -= offset;\n      }\n    }\n    var polygon = new ol.geom.Polygon(null);\n    polygon.setFlatCoordinates(\n        layout, flatCoordinates.slice(offset, end), ends);\n    polygons.push(polygon);\n    offset = end;\n  }\n  return polygons;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.MultiPolygon.prototype.getType = function() {\n  return ol.geom.GeometryType.MULTI_POLYGON;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) {\n  return ol.geom.flat.intersectsextent.linearRingss(\n      this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent);\n};\n\n\n/**\n * Set the coordinates of the multipolygon.\n * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api stable\n */\nol.geom.MultiPolygon.prototype.setCoordinates = function(coordinates, opt_layout) {\n  if (!coordinates) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.endss_);\n  } else {\n    this.setLayout(opt_layout, coordinates, 3);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    var endss = ol.geom.flat.deflate.coordinatesss(\n        this.flatCoordinates, 0, coordinates, this.stride, this.endss_);\n    if (endss.length === 0) {\n      this.flatCoordinates.length = 0;\n    } else {\n      var lastEnds = endss[endss.length - 1];\n      this.flatCoordinates.length = lastEnds.length === 0 ?\n          0 : lastEnds[lastEnds.length - 1];\n    }\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {Array.<Array.<number>>} endss Endss.\n */\nol.geom.MultiPolygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, endss) {\n  ol.DEBUG && console.assert(endss, 'endss must be truthy');\n  if (!flatCoordinates || flatCoordinates.length === 0) {\n    ol.DEBUG && console.assert(endss.length === 0, 'the length of endss should be 0');\n  } else {\n    ol.DEBUG && console.assert(endss.length > 0, 'endss cannot be an empty array');\n    var ends = endss[endss.length - 1];\n    ol.DEBUG && console.assert(flatCoordinates.length == ends[ends.length - 1],\n        'the length of flatCoordinates should be the last value of ends');\n  }\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.endss_ = endss;\n  this.changed();\n};\n\n\n/**\n * @param {Array.<ol.geom.Polygon>} polygons Polygons.\n */\nol.geom.MultiPolygon.prototype.setPolygons = function(polygons) {\n  var layout = this.getLayout();\n  var flatCoordinates = [];\n  var endss = [];\n  var i, ii, ends;\n  for (i = 0, ii = polygons.length; i < ii; ++i) {\n    var polygon = polygons[i];\n    if (i === 0) {\n      layout = polygon.getLayout();\n    } else {\n      // FIXME better handle the case of non-matching layouts\n      ol.DEBUG && console.assert(polygon.getLayout() == layout,\n          'layout of polygon should be layout');\n    }\n    var offset = flatCoordinates.length;\n    ends = polygon.getEnds();\n    var j, jj;\n    for (j = 0, jj = ends.length; j < jj; ++j) {\n      ends[j] += offset;\n    }\n    ol.array.extend(flatCoordinates, polygon.getFlatCoordinates());\n    endss.push(ends);\n  }\n  this.setFlatCoordinates(layout, flatCoordinates, endss);\n};\n\ngoog.provide('ol.format.EsriJSON');\n\ngoog.require('ol');\ngoog.require('ol.Feature');\ngoog.require('ol.array');\ngoog.require('ol.asserts');\ngoog.require('ol.extent');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.JSONFeature');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.LinearRing');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.geom.flat.orient');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the EsriJSON format.\n *\n * @constructor\n * @extends {ol.format.JSONFeature}\n * @param {olx.format.EsriJSONOptions=} opt_options Options.\n * @api\n */\nol.format.EsriJSON = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.JSONFeature.call(this);\n\n  /**\n   * Name of the geometry attribute for features.\n   * @type {string|undefined}\n   * @private\n   */\n  this.geometryName_ = options.geometryName;\n\n};\nol.inherits(ol.format.EsriJSON, ol.format.JSONFeature);\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @private\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.EsriJSON.readGeometry_ = function(object, opt_options) {\n  if (!object) {\n    return null;\n  }\n  /** @type {ol.geom.GeometryType} */\n  var type;\n  if (typeof object.x === 'number' && typeof object.y === 'number') {\n    type = ol.geom.GeometryType.POINT;\n  } else if (object.points) {\n    type = ol.geom.GeometryType.MULTI_POINT;\n  } else if (object.paths) {\n    if (object.paths.length === 1) {\n      type = ol.geom.GeometryType.LINE_STRING;\n    } else {\n      type = ol.geom.GeometryType.MULTI_LINE_STRING;\n    }\n  } else if (object.rings) {\n    var layout = ol.format.EsriJSON.getGeometryLayout_(object);\n    var rings = ol.format.EsriJSON.convertRings_(object.rings, layout);\n    object = /** @type {EsriJSONGeometry} */(ol.obj.assign({}, object));\n    if (rings.length === 1) {\n      type = ol.geom.GeometryType.POLYGON;\n      object.rings = rings[0];\n    } else {\n      type = ol.geom.GeometryType.MULTI_POLYGON;\n      object.rings = rings;\n    }\n  }\n  var geometryReader = ol.format.EsriJSON.GEOMETRY_READERS_[type];\n  return /** @type {ol.geom.Geometry} */ (\n      ol.format.Feature.transformWithOptions(\n          geometryReader(object), false, opt_options));\n};\n\n\n/**\n * Determines inner and outer rings.\n * Checks if any polygons in this array contain any other polygons in this\n * array. It is used for checking for holes.\n * Logic inspired by: https://github.com/Esri/terraformer-arcgis-parser\n * @param {Array.<!Array.<!Array.<number>>>} rings Rings.\n * @param {ol.geom.GeometryLayout} layout Geometry layout.\n * @private\n * @return {Array.<!Array.<!Array.<number>>>} Transoformed rings.\n */\nol.format.EsriJSON.convertRings_ = function(rings, layout) {\n  var outerRings = [];\n  var holes = [];\n  var i, ii;\n  for (i = 0, ii = rings.length; i < ii; ++i) {\n    var flatRing = ol.array.flatten(rings[i]);\n    // is this ring an outer ring? is it clockwise?\n    var clockwise = ol.geom.flat.orient.linearRingIsClockwise(flatRing, 0,\n        flatRing.length, layout.length);\n    if (clockwise) {\n      outerRings.push([rings[i]]);\n    } else {\n      holes.push(rings[i]);\n    }\n  }\n  while (holes.length) {\n    var hole = holes.shift();\n    var matched = false;\n    // loop over all outer rings and see if they contain our hole.\n    for (i = outerRings.length - 1; i >= 0; i--) {\n      var outerRing = outerRings[i][0];\n      if (ol.extent.containsExtent(new ol.geom.LinearRing(\n          outerRing).getExtent(),\n          new ol.geom.LinearRing(hole).getExtent())) {\n        // the hole is contained push it into our polygon\n        outerRings[i].push(hole);\n        matched = true;\n        break;\n      }\n    }\n    if (!matched) {\n      // no outer rings contain this hole turn it into and outer\n      // ring (reverse it)\n      outerRings.push([hole.reverse()]);\n    }\n  }\n  return outerRings;\n};\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Geometry} Point.\n */\nol.format.EsriJSON.readPointGeometry_ = function(object) {\n  ol.DEBUG && console.assert(typeof object.x === 'number', 'object.x should be number');\n  ol.DEBUG && console.assert(typeof object.y === 'number', 'object.y should be number');\n  var point;\n  if (object.m !== undefined && object.z !== undefined) {\n    point = new ol.geom.Point([object.x, object.y, object.z, object.m],\n        ol.geom.GeometryLayout.XYZM);\n  } else if (object.z !== undefined) {\n    point = new ol.geom.Point([object.x, object.y, object.z],\n        ol.geom.GeometryLayout.XYZ);\n  } else if (object.m !== undefined) {\n    point = new ol.geom.Point([object.x, object.y, object.m],\n        ol.geom.GeometryLayout.XYM);\n  } else {\n    point = new ol.geom.Point([object.x, object.y]);\n  }\n  return point;\n};\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Geometry} LineString.\n */\nol.format.EsriJSON.readLineStringGeometry_ = function(object) {\n  ol.DEBUG && console.assert(Array.isArray(object.paths),\n      'object.paths should be an array');\n  ol.DEBUG && console.assert(object.paths.length === 1,\n      'object.paths array length should be 1');\n  var layout = ol.format.EsriJSON.getGeometryLayout_(object);\n  return new ol.geom.LineString(object.paths[0], layout);\n};\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Geometry} MultiLineString.\n */\nol.format.EsriJSON.readMultiLineStringGeometry_ = function(object) {\n  ol.DEBUG && console.assert(Array.isArray(object.paths),\n      'object.paths should be an array');\n  ol.DEBUG && console.assert(object.paths.length > 1,\n      'object.paths array length should be more than 1');\n  var layout = ol.format.EsriJSON.getGeometryLayout_(object);\n  return new ol.geom.MultiLineString(object.paths, layout);\n};\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @private\n * @return {ol.geom.GeometryLayout} The geometry layout to use.\n */\nol.format.EsriJSON.getGeometryLayout_ = function(object) {\n  var layout = ol.geom.GeometryLayout.XY;\n  if (object.hasZ === true && object.hasM === true) {\n    layout = ol.geom.GeometryLayout.XYZM;\n  } else if (object.hasZ === true) {\n    layout = ol.geom.GeometryLayout.XYZ;\n  } else if (object.hasM === true) {\n    layout = ol.geom.GeometryLayout.XYM;\n  }\n  return layout;\n};\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Geometry} MultiPoint.\n */\nol.format.EsriJSON.readMultiPointGeometry_ = function(object) {\n  var layout = ol.format.EsriJSON.getGeometryLayout_(object);\n  return new ol.geom.MultiPoint(object.points, layout);\n};\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Geometry} MultiPolygon.\n */\nol.format.EsriJSON.readMultiPolygonGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.rings.length > 1,\n      'object.rings should have length larger than 1');\n  var layout = ol.format.EsriJSON.getGeometryLayout_(object);\n  return new ol.geom.MultiPolygon(\n      /** @type {Array.<Array.<Array.<Array.<number>>>>} */(object.rings),\n      layout);\n};\n\n\n/**\n * @param {EsriJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Geometry} Polygon.\n */\nol.format.EsriJSON.readPolygonGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.rings);\n  var layout = ol.format.EsriJSON.getGeometryLayout_(object);\n  return new ol.geom.Polygon(object.rings, layout);\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {EsriJSONGeometry} EsriJSON geometry.\n */\nol.format.EsriJSON.writePointGeometry_ = function(geometry, opt_options) {\n  var coordinates = /** @type {ol.geom.Point} */ (geometry).getCoordinates();\n  var esriJSON;\n  var layout = /** @type {ol.geom.Point} */ (geometry).getLayout();\n  if (layout === ol.geom.GeometryLayout.XYZ) {\n    esriJSON = /** @type {EsriJSONPoint} */ ({\n      x: coordinates[0],\n      y: coordinates[1],\n      z: coordinates[2]\n    });\n  } else if (layout === ol.geom.GeometryLayout.XYM) {\n    esriJSON = /** @type {EsriJSONPoint} */ ({\n      x: coordinates[0],\n      y: coordinates[1],\n      m: coordinates[2]\n    });\n  } else if (layout === ol.geom.GeometryLayout.XYZM) {\n    esriJSON = /** @type {EsriJSONPoint} */ ({\n      x: coordinates[0],\n      y: coordinates[1],\n      z: coordinates[2],\n      m: coordinates[3]\n    });\n  } else if (layout === ol.geom.GeometryLayout.XY) {\n    esriJSON = /** @type {EsriJSONPoint} */ ({\n      x: coordinates[0],\n      y: coordinates[1]\n    });\n  } else {\n    ol.asserts.assert(false, 34); // Invalid geometry layout\n  }\n  return /** @type {EsriJSONGeometry} */ (esriJSON);\n};\n\n\n/**\n * @param {ol.geom.SimpleGeometry} geometry Geometry.\n * @private\n * @return {Object} Object with boolean hasZ and hasM keys.\n */\nol.format.EsriJSON.getHasZM_ = function(geometry) {\n  var layout = geometry.getLayout();\n  return {\n    hasZ: (layout === ol.geom.GeometryLayout.XYZ ||\n        layout === ol.geom.GeometryLayout.XYZM),\n    hasM: (layout === ol.geom.GeometryLayout.XYM ||\n        layout === ol.geom.GeometryLayout.XYZM)\n  };\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {EsriJSONPolyline} EsriJSON geometry.\n */\nol.format.EsriJSON.writeLineStringGeometry_ = function(geometry, opt_options) {\n  var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.LineString} */ (geometry));\n  return /** @type {EsriJSONPolyline} */ ({\n    hasZ: hasZM.hasZ,\n    hasM: hasZM.hasM,\n    paths: [\n      /** @type {ol.geom.LineString} */ (geometry).getCoordinates()\n    ]\n  });\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {EsriJSONPolygon} EsriJSON geometry.\n */\nol.format.EsriJSON.writePolygonGeometry_ = function(geometry, opt_options) {\n  // Esri geometries use the left-hand rule\n  var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.Polygon} */ (geometry));\n  return /** @type {EsriJSONPolygon} */ ({\n    hasZ: hasZM.hasZ,\n    hasM: hasZM.hasM,\n    rings: /** @type {ol.geom.Polygon} */ (geometry).getCoordinates(false)\n  });\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {EsriJSONPolyline} EsriJSON geometry.\n */\nol.format.EsriJSON.writeMultiLineStringGeometry_ = function(geometry, opt_options) {\n  var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.MultiLineString} */ (geometry));\n  return /** @type {EsriJSONPolyline} */ ({\n    hasZ: hasZM.hasZ,\n    hasM: hasZM.hasM,\n    paths: /** @type {ol.geom.MultiLineString} */ (geometry).getCoordinates()\n  });\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {EsriJSONMultipoint} EsriJSON geometry.\n */\nol.format.EsriJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {\n  var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.MultiPoint} */ (geometry));\n  return /** @type {EsriJSONMultipoint} */ ({\n    hasZ: hasZM.hasZ,\n    hasM: hasZM.hasM,\n    points: /** @type {ol.geom.MultiPoint} */ (geometry).getCoordinates()\n  });\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {EsriJSONPolygon} EsriJSON geometry.\n */\nol.format.EsriJSON.writeMultiPolygonGeometry_ = function(geometry,\n    opt_options) {\n  var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.MultiPolygon} */ (geometry));\n  var coordinates = /** @type {ol.geom.MultiPolygon} */ (geometry).getCoordinates(false);\n  var output = [];\n  for (var i = 0; i < coordinates.length; i++) {\n    for (var x = coordinates[i].length - 1; x >= 0; x--) {\n      output.push(coordinates[i][x]);\n    }\n  }\n  return /** @type {EsriJSONPolygon} */ ({\n    hasZ: hasZM.hasZ,\n    hasM: hasZM.hasM,\n    rings: output\n  });\n};\n\n\n/**\n * @const\n * @private\n * @type {Object.<ol.geom.GeometryType, function(EsriJSONGeometry): ol.geom.Geometry>}\n */\nol.format.EsriJSON.GEOMETRY_READERS_ = {};\nol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POINT] =\n    ol.format.EsriJSON.readPointGeometry_;\nol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.LINE_STRING] =\n    ol.format.EsriJSON.readLineStringGeometry_;\nol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POLYGON] =\n    ol.format.EsriJSON.readPolygonGeometry_;\nol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POINT] =\n    ol.format.EsriJSON.readMultiPointGeometry_;\nol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_LINE_STRING] =\n    ol.format.EsriJSON.readMultiLineStringGeometry_;\nol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POLYGON] =\n    ol.format.EsriJSON.readMultiPolygonGeometry_;\n\n\n/**\n * @const\n * @private\n * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (EsriJSONGeometry)>}\n */\nol.format.EsriJSON.GEOMETRY_WRITERS_ = {};\nol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POINT] =\n    ol.format.EsriJSON.writePointGeometry_;\nol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.LINE_STRING] =\n    ol.format.EsriJSON.writeLineStringGeometry_;\nol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POLYGON] =\n    ol.format.EsriJSON.writePolygonGeometry_;\nol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POINT] =\n    ol.format.EsriJSON.writeMultiPointGeometry_;\nol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_LINE_STRING] =\n    ol.format.EsriJSON.writeMultiLineStringGeometry_;\nol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POLYGON] =\n    ol.format.EsriJSON.writeMultiPolygonGeometry_;\n\n\n/**\n * Read a feature from a EsriJSON Feature source.  Only works for Feature,\n * use `readFeatures` to read FeatureCollection source.\n *\n * @function\n * @param {ArrayBuffer|Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @api\n */\nol.format.EsriJSON.prototype.readFeature;\n\n\n/**\n * Read all features from a EsriJSON source.  Works with both Feature and\n * FeatureCollection sources.\n *\n * @function\n * @param {ArrayBuffer|Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api\n */\nol.format.EsriJSON.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.EsriJSON.prototype.readFeatureFromObject = function(\n    object, opt_options) {\n  var esriJSONFeature = /** @type {EsriJSONFeature} */ (object);\n  ol.DEBUG && console.assert(esriJSONFeature.geometry ||\n      esriJSONFeature.attributes,\n      'geometry or attributes should be defined');\n  var geometry = ol.format.EsriJSON.readGeometry_(esriJSONFeature.geometry,\n      opt_options);\n  var feature = new ol.Feature();\n  if (this.geometryName_) {\n    feature.setGeometryName(this.geometryName_);\n  }\n  feature.setGeometry(geometry);\n  if (opt_options && opt_options.idField &&\n      esriJSONFeature.attributes[opt_options.idField]) {\n    ol.DEBUG && console.assert(\n        typeof esriJSONFeature.attributes[opt_options.idField] === 'number',\n        'objectIdFieldName value should be a number');\n    feature.setId(/** @type {number} */(\n        esriJSONFeature.attributes[opt_options.idField]));\n  }\n  if (esriJSONFeature.attributes) {\n    feature.setProperties(esriJSONFeature.attributes);\n  }\n  return feature;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.EsriJSON.prototype.readFeaturesFromObject = function(\n    object, opt_options) {\n  var esriJSONObject = /** @type {EsriJSONObject} */ (object);\n  var options = opt_options ? opt_options : {};\n  if (esriJSONObject.features) {\n    var esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */\n        (object);\n    /** @type {Array.<ol.Feature>} */\n    var features = [];\n    var esriJSONFeatures = esriJSONFeatureCollection.features;\n    var i, ii;\n    options.idField = object.objectIdFieldName;\n    for (i = 0, ii = esriJSONFeatures.length; i < ii; ++i) {\n      features.push(this.readFeatureFromObject(esriJSONFeatures[i],\n          options));\n    }\n    return features;\n  } else {\n    return [this.readFeatureFromObject(object, options)];\n  }\n};\n\n\n/**\n * Read a geometry from a EsriJSON source.\n *\n * @function\n * @param {ArrayBuffer|Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.geom.Geometry} Geometry.\n * @api\n */\nol.format.EsriJSON.prototype.readGeometry;\n\n\n/**\n * @inheritDoc\n */\nol.format.EsriJSON.prototype.readGeometryFromObject = function(\n    object, opt_options) {\n  return ol.format.EsriJSON.readGeometry_(\n      /** @type {EsriJSONGeometry} */ (object), opt_options);\n};\n\n\n/**\n * Read the projection from a EsriJSON source.\n *\n * @function\n * @param {ArrayBuffer|Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n * @api\n */\nol.format.EsriJSON.prototype.readProjection;\n\n\n/**\n * @inheritDoc\n */\nol.format.EsriJSON.prototype.readProjectionFromObject = function(object) {\n  var esriJSONObject = /** @type {EsriJSONObject} */ (object);\n  if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) {\n    var crs = esriJSONObject.spatialReference.wkid;\n    return ol.proj.get('EPSG:' + crs);\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {EsriJSONGeometry} EsriJSON geometry.\n */\nol.format.EsriJSON.writeGeometry_ = function(geometry, opt_options) {\n  var geometryWriter = ol.format.EsriJSON.GEOMETRY_WRITERS_[geometry.getType()];\n  return geometryWriter(/** @type {ol.geom.Geometry} */ (\n      ol.format.Feature.transformWithOptions(geometry, true, opt_options)),\n      opt_options);\n};\n\n\n/**\n * Encode a geometry as a EsriJSON string.\n *\n * @function\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} EsriJSON.\n * @api\n */\nol.format.EsriJSON.prototype.writeGeometry;\n\n\n/**\n * Encode a geometry as a EsriJSON object.\n *\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {EsriJSONGeometry} Object.\n * @api\n */\nol.format.EsriJSON.prototype.writeGeometryObject = function(geometry,\n    opt_options) {\n  return ol.format.EsriJSON.writeGeometry_(geometry,\n      this.adaptOptions(opt_options));\n};\n\n\n/**\n * Encode a feature as a EsriJSON Feature string.\n *\n * @function\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} EsriJSON.\n * @api\n */\nol.format.EsriJSON.prototype.writeFeature;\n\n\n/**\n * Encode a feature as a esriJSON Feature object.\n *\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {Object} Object.\n * @api\n */\nol.format.EsriJSON.prototype.writeFeatureObject = function(\n    feature, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n  var object = {};\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    object['geometry'] =\n        ol.format.EsriJSON.writeGeometry_(geometry, opt_options);\n  }\n  var properties = feature.getProperties();\n  delete properties[feature.getGeometryName()];\n  if (!ol.obj.isEmpty(properties)) {\n    object['attributes'] = properties;\n  } else {\n    object['attributes'] = {};\n  }\n  if (opt_options && opt_options.featureProjection) {\n    object['spatialReference'] = /** @type {EsriJSONCRS} */({\n      wkid: ol.proj.get(\n          opt_options.featureProjection).getCode().split(':').pop()\n    });\n  }\n  return object;\n};\n\n\n/**\n * Encode an array of features as EsriJSON.\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} EsriJSON.\n * @api\n */\nol.format.EsriJSON.prototype.writeFeatures;\n\n\n/**\n * Encode an array of features as a EsriJSON object.\n *\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {Object} EsriJSON Object.\n * @api\n */\nol.format.EsriJSON.prototype.writeFeaturesObject = function(features, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n  var objects = [];\n  var i, ii;\n  for (i = 0, ii = features.length; i < ii; ++i) {\n    objects.push(this.writeFeatureObject(features[i], opt_options));\n  }\n  return /** @type {EsriJSONFeatureCollection} */ ({\n    'features': objects\n  });\n};\n\ngoog.provide('ol.format.filter.Filter');\n\ngoog.require('ol');\n\n\n/**\n * @classdesc\n * Abstract class; normally only used for creating subclasses and not instantiated in apps.\n * Base class for WFS GetFeature filters.\n *\n * @constructor\n * @param {!string} tagName The XML tag name for this filter.\n * @struct\n * @api\n */\nol.format.filter.Filter = function(tagName) {\n\n  /**\n   * @private\n   * @type {!string}\n   */\n  this.tagName_ = tagName;\n};\n\n/**\n * The XML tag name for a filter.\n * @returns {!string} Name.\n */\nol.format.filter.Filter.prototype.getTagName = function() {\n  return this.tagName_;\n};\n\ngoog.provide('ol.format.filter.Logical');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Filter');\n\n\n/**\n * @classdesc\n * Abstract class; normally only used for creating subclasses and not instantiated in apps.\n * Base class for WFS GetFeature logical filters.\n *\n * @constructor\n * @param {!string} tagName The XML tag name for this filter.\n * @extends {ol.format.filter.Filter}\n */\nol.format.filter.Logical = function(tagName) {\n  ol.format.filter.Filter.call(this, tagName);\n};\nol.inherits(ol.format.filter.Logical, ol.format.filter.Filter);\n\ngoog.provide('ol.format.filter.LogicalBinary');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Logical');\n\n\n/**\n * @classdesc\n * Abstract class; normally only used for creating subclasses and not instantiated in apps.\n * Base class for WFS GetFeature binary logical filters.\n *\n * @constructor\n * @param {!string} tagName The XML tag name for this filter.\n * @param {!ol.format.filter.Filter} conditionA First filter condition.\n * @param {!ol.format.filter.Filter} conditionB Second filter condition.\n * @extends {ol.format.filter.Logical}\n */\nol.format.filter.LogicalBinary = function(tagName, conditionA, conditionB) {\n\n  ol.format.filter.Logical.call(this, tagName);\n\n  /**\n   * @public\n   * @type {!ol.format.filter.Filter}\n   */\n  this.conditionA = conditionA;\n\n  /**\n   * @public\n   * @type {!ol.format.filter.Filter}\n   */\n  this.conditionB = conditionB;\n\n};\nol.inherits(ol.format.filter.LogicalBinary, ol.format.filter.Logical);\n\ngoog.provide('ol.format.filter.And');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.LogicalBinary');\n\n/**\n * @classdesc\n * Represents a logical `<And>` operator between two filter conditions.\n *\n * @constructor\n * @param {!ol.format.filter.Filter} conditionA First filter condition.\n * @param {!ol.format.filter.Filter} conditionB Second filter condition.\n * @extends {ol.format.filter.LogicalBinary}\n * @api\n */\nol.format.filter.And = function(conditionA, conditionB) {\n  ol.format.filter.LogicalBinary.call(this, 'And', conditionA, conditionB);\n};\nol.inherits(ol.format.filter.And, ol.format.filter.LogicalBinary);\n\ngoog.provide('ol.format.filter.Bbox');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Filter');\n\n\n/**\n * @classdesc\n * Represents a `<BBOX>` operator to test whether a geometry-valued property\n * intersects a fixed bounding box\n *\n * @constructor\n * @param {!string} geometryName Geometry name to use.\n * @param {!ol.Extent} extent Extent.\n * @param {string=} opt_srsName SRS name. No srsName attribute will be\n *    set on geometries when this is not provided.\n * @extends {ol.format.filter.Filter}\n * @api\n */\nol.format.filter.Bbox = function(geometryName, extent, opt_srsName) {\n\n  ol.format.filter.Filter.call(this, 'BBOX');\n\n  /**\n   * @public\n   * @type {!string}\n   */\n  this.geometryName = geometryName;\n\n  /**\n   * @public\n   * @type {ol.Extent}\n   */\n  this.extent = extent;\n\n  /**\n   * @public\n   * @type {string|undefined}\n   */\n  this.srsName = opt_srsName;\n};\nol.inherits(ol.format.filter.Bbox, ol.format.filter.Filter);\n\ngoog.provide('ol.format.filter.Comparison');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Filter');\n\n\n/**\n * @classdesc\n * Abstract class; normally only used for creating subclasses and not instantiated in apps.\n * Base class for WFS GetFeature property comparison filters.\n *\n * @constructor\n * @param {!string} tagName The XML tag name for this filter.\n * @param {!string} propertyName Name of the context property to compare.\n * @extends {ol.format.filter.Filter}\n * @api\n */\nol.format.filter.Comparison = function(tagName, propertyName) {\n\n  ol.format.filter.Filter.call(this, tagName);\n\n  /**\n   * @public\n   * @type {!string}\n   */\n  this.propertyName = propertyName;\n};\nol.inherits(ol.format.filter.Comparison, ol.format.filter.Filter);\n\ngoog.provide('ol.format.filter.ComparisonBinary');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Comparison');\n\n\n/**\n * @classdesc\n * Abstract class; normally only used for creating subclasses and not instantiated in apps.\n * Base class for WFS GetFeature property binary comparison filters.\n *\n * @constructor\n * @param {!string} tagName The XML tag name for this filter.\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!(string|number)} expression The value to compare.\n * @param {boolean=} opt_matchCase Case-sensitive?\n * @extends {ol.format.filter.Comparison}\n * @api\n */\nol.format.filter.ComparisonBinary = function(\n    tagName, propertyName, expression, opt_matchCase) {\n\n  ol.format.filter.Comparison.call(this, tagName, propertyName);\n\n  /**\n   * @public\n   * @type {!(string|number)}\n   */\n  this.expression = expression;\n\n  /**\n   * @public\n   * @type {boolean|undefined}\n   */\n  this.matchCase = opt_matchCase;\n};\nol.inherits(ol.format.filter.ComparisonBinary, ol.format.filter.Comparison);\n\ngoog.provide('ol.format.filter.EqualTo');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.ComparisonBinary');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsEqualTo>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!(string|number)} expression The value to compare.\n * @param {boolean=} opt_matchCase Case-sensitive?\n * @extends {ol.format.filter.ComparisonBinary}\n * @api\n */\nol.format.filter.EqualTo = function(propertyName, expression, opt_matchCase) {\n  ol.format.filter.ComparisonBinary.call(this, 'PropertyIsEqualTo', propertyName, expression, opt_matchCase);\n};\nol.inherits(ol.format.filter.EqualTo, ol.format.filter.ComparisonBinary);\n\ngoog.provide('ol.format.filter.GreaterThan');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.ComparisonBinary');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsGreaterThan>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @extends {ol.format.filter.ComparisonBinary}\n * @api\n */\nol.format.filter.GreaterThan = function(propertyName, expression) {\n  ol.format.filter.ComparisonBinary.call(this, 'PropertyIsGreaterThan', propertyName, expression);\n};\nol.inherits(ol.format.filter.GreaterThan, ol.format.filter.ComparisonBinary);\n\ngoog.provide('ol.format.filter.GreaterThanOrEqualTo');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.ComparisonBinary');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsGreaterThanOrEqualTo>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @extends {ol.format.filter.ComparisonBinary}\n * @api\n */\nol.format.filter.GreaterThanOrEqualTo = function(propertyName, expression) {\n  ol.format.filter.ComparisonBinary.call(this, 'PropertyIsGreaterThanOrEqualTo', propertyName, expression);\n};\nol.inherits(ol.format.filter.GreaterThanOrEqualTo, ol.format.filter.ComparisonBinary);\n\ngoog.provide('ol.format.filter.Spatial');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Filter');\n\n\n/**\n * @classdesc\n * Represents a spatial operator to test whether a geometry-valued property\n * relates to a given geometry.\n *\n * @constructor\n * @param {!string} tagName The XML tag name for this filter.\n * @param {!string} geometryName Geometry name to use.\n * @param {!ol.geom.Geometry} geometry Geometry.\n * @param {string=} opt_srsName SRS name. No srsName attribute will be\n *    set on geometries when this is not provided.\n * @extends {ol.format.filter.Filter}\n * @api\n */\nol.format.filter.Spatial = function(tagName, geometryName, geometry, opt_srsName) {\n\n  ol.format.filter.Filter.call(this, tagName);\n\n  /**\n   * @public\n   * @type {!string}\n   */\n  this.geometryName = geometryName || 'the_geom';\n\n  /**\n   * @public\n   * @type {ol.geom.Geometry}\n   */\n  this.geometry = geometry;\n\n  /**\n   * @public\n   * @type {string|undefined}\n   */\n  this.srsName = opt_srsName;\n};\nol.inherits(ol.format.filter.Spatial, ol.format.filter.Filter);\n\ngoog.provide('ol.format.filter.Intersects');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Spatial');\n\n\n/**\n * @classdesc\n * Represents a `<Intersects>` operator to test whether a geometry-valued property\n * intersects a given geometry.\n *\n * @constructor\n * @param {!string} geometryName Geometry name to use.\n * @param {!ol.geom.Geometry} geometry Geometry.\n * @param {string=} opt_srsName SRS name. No srsName attribute will be\n *    set on geometries when this is not provided.\n * @extends {ol.format.filter.Spatial}\n * @api\n */\nol.format.filter.Intersects = function(geometryName, geometry, opt_srsName) {\n\n  ol.format.filter.Spatial.call(this, 'Intersects', geometryName, geometry, opt_srsName);\n\n};\nol.inherits(ol.format.filter.Intersects, ol.format.filter.Spatial);\n\ngoog.provide('ol.format.filter.IsBetween');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Comparison');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsBetween>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} lowerBoundary The lower bound of the range.\n * @param {!number} upperBoundary The upper bound of the range.\n * @extends {ol.format.filter.Comparison}\n * @api\n */\nol.format.filter.IsBetween = function(propertyName, lowerBoundary, upperBoundary) {\n  ol.format.filter.Comparison.call(this, 'PropertyIsBetween', propertyName);\n\n  /**\n   * @public\n   * @type {!number}\n   */\n  this.lowerBoundary = lowerBoundary;\n\n  /**\n   * @public\n   * @type {!number}\n   */\n  this.upperBoundary = upperBoundary;\n};\nol.inherits(ol.format.filter.IsBetween, ol.format.filter.Comparison);\n\ngoog.provide('ol.format.filter.IsLike');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Comparison');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsLike>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!string} pattern Text pattern.\n * @param {string=} opt_wildCard Pattern character which matches any sequence of\n *    zero or more string characters. Default is '*'.\n * @param {string=} opt_singleChar pattern character which matches any single\n *    string character. Default is '.'.\n * @param {string=} opt_escapeChar Escape character which can be used to escape\n *    the pattern characters. Default is '!'.\n * @param {boolean=} opt_matchCase Case-sensitive?\n * @extends {ol.format.filter.Comparison}\n * @api\n */\nol.format.filter.IsLike = function(propertyName, pattern,\n    opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {\n  ol.format.filter.Comparison.call(this, 'PropertyIsLike', propertyName);\n\n  /**\n   * @public\n   * @type {!string}\n   */\n  this.pattern = pattern;\n\n  /**\n   * @public\n   * @type {!string}\n   */\n  this.wildCard = (opt_wildCard !== undefined) ? opt_wildCard : '*';\n\n  /**\n   * @public\n   * @type {!string}\n   */\n  this.singleChar = (opt_singleChar !== undefined) ? opt_singleChar : '.';\n\n  /**\n   * @public\n   * @type {!string}\n   */\n  this.escapeChar = (opt_escapeChar !== undefined) ? opt_escapeChar : '!';\n\n  /**\n   * @public\n   * @type {boolean|undefined}\n   */\n  this.matchCase = opt_matchCase;\n};\nol.inherits(ol.format.filter.IsLike, ol.format.filter.Comparison);\n\ngoog.provide('ol.format.filter.IsNull');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Comparison');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsNull>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @extends {ol.format.filter.Comparison}\n * @api\n */\nol.format.filter.IsNull = function(propertyName) {\n  ol.format.filter.Comparison.call(this, 'PropertyIsNull', propertyName);\n};\nol.inherits(ol.format.filter.IsNull, ol.format.filter.Comparison);\n\ngoog.provide('ol.format.filter.LessThan');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.ComparisonBinary');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsLessThan>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @extends {ol.format.filter.ComparisonBinary}\n * @api\n */\nol.format.filter.LessThan = function(propertyName, expression) {\n  ol.format.filter.ComparisonBinary.call(this, 'PropertyIsLessThan', propertyName, expression);\n};\nol.inherits(ol.format.filter.LessThan, ol.format.filter.ComparisonBinary);\n\ngoog.provide('ol.format.filter.LessThanOrEqualTo');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.ComparisonBinary');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsLessThanOrEqualTo>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @extends {ol.format.filter.ComparisonBinary}\n * @api\n */\nol.format.filter.LessThanOrEqualTo = function(propertyName, expression) {\n  ol.format.filter.ComparisonBinary.call(this, 'PropertyIsLessThanOrEqualTo', propertyName, expression);\n};\nol.inherits(ol.format.filter.LessThanOrEqualTo, ol.format.filter.ComparisonBinary);\n\ngoog.provide('ol.format.filter.Not');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Logical');\n\n\n/**\n * @classdesc\n * Represents a logical `<Not>` operator for a filter condition.\n *\n * @constructor\n * @param {!ol.format.filter.Filter} condition Filter condition.\n * @extends {ol.format.filter.Logical}\n * @api\n */\nol.format.filter.Not = function(condition) {\n\n  ol.format.filter.Logical.call(this, 'Not');\n\n  /**\n   * @public\n   * @type {!ol.format.filter.Filter}\n   */\n  this.condition = condition;\n};\nol.inherits(ol.format.filter.Not, ol.format.filter.Logical);\n\ngoog.provide('ol.format.filter.NotEqualTo');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.ComparisonBinary');\n\n\n/**\n * @classdesc\n * Represents a `<PropertyIsNotEqualTo>` comparison operator.\n *\n * @constructor\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!(string|number)} expression The value to compare.\n * @param {boolean=} opt_matchCase Case-sensitive?\n * @extends {ol.format.filter.ComparisonBinary}\n * @api\n */\nol.format.filter.NotEqualTo = function(propertyName, expression, opt_matchCase) {\n  ol.format.filter.ComparisonBinary.call(this, 'PropertyIsNotEqualTo', propertyName, expression, opt_matchCase);\n};\nol.inherits(ol.format.filter.NotEqualTo, ol.format.filter.ComparisonBinary);\n\ngoog.provide('ol.format.filter.Or');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.LogicalBinary');\n\n\n/**\n * @classdesc\n * Represents a logical `<Or>` operator between two filter conditions.\n *\n * @constructor\n * @param {!ol.format.filter.Filter} conditionA First filter condition.\n * @param {!ol.format.filter.Filter} conditionB Second filter condition.\n * @extends {ol.format.filter.LogicalBinary}\n * @api\n */\nol.format.filter.Or = function(conditionA, conditionB) {\n  ol.format.filter.LogicalBinary.call(this, 'Or', conditionA, conditionB);\n};\nol.inherits(ol.format.filter.Or, ol.format.filter.LogicalBinary);\n\ngoog.provide('ol.format.filter.Within');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.Spatial');\n\n\n/**\n * @classdesc\n * Represents a `<Within>` operator to test whether a geometry-valued property\n * is within a given geometry.\n *\n * @constructor\n * @param {!string} geometryName Geometry name to use.\n * @param {!ol.geom.Geometry} geometry Geometry.\n * @param {string=} opt_srsName SRS name. No srsName attribute will be\n *    set on geometries when this is not provided.\n * @extends {ol.format.filter.Spatial}\n * @api\n */\nol.format.filter.Within = function(geometryName, geometry, opt_srsName) {\n\n  ol.format.filter.Spatial.call(this, 'Within', geometryName, geometry, opt_srsName);\n\n};\nol.inherits(ol.format.filter.Within, ol.format.filter.Spatial);\n\ngoog.provide('ol.format.filter');\n\ngoog.require('ol');\ngoog.require('ol.format.filter.And');\ngoog.require('ol.format.filter.Bbox');\ngoog.require('ol.format.filter.EqualTo');\ngoog.require('ol.format.filter.GreaterThan');\ngoog.require('ol.format.filter.GreaterThanOrEqualTo');\ngoog.require('ol.format.filter.Intersects');\ngoog.require('ol.format.filter.IsBetween');\ngoog.require('ol.format.filter.IsLike');\ngoog.require('ol.format.filter.IsNull');\ngoog.require('ol.format.filter.LessThan');\ngoog.require('ol.format.filter.LessThanOrEqualTo');\ngoog.require('ol.format.filter.Not');\ngoog.require('ol.format.filter.NotEqualTo');\ngoog.require('ol.format.filter.Or');\ngoog.require('ol.format.filter.Within');\n\n\n/**\n * Create a logical `<And>` operator between two filter conditions.\n *\n * @param {!ol.format.filter.Filter} conditionA First filter condition.\n * @param {!ol.format.filter.Filter} conditionB Second filter condition.\n * @returns {!ol.format.filter.And} `<And>` operator.\n * @api\n */\nol.format.filter.and = function(conditionA, conditionB) {\n  return new ol.format.filter.And(conditionA, conditionB);\n};\n\n\n/**\n * Create a logical `<Or>` operator between two filter conditions.\n *\n * @param {!ol.format.filter.Filter} conditionA First filter condition.\n * @param {!ol.format.filter.Filter} conditionB Second filter condition.\n * @returns {!ol.format.filter.Or} `<Or>` operator.\n * @api\n */\nol.format.filter.or = function(conditionA, conditionB) {\n  return new ol.format.filter.Or(conditionA, conditionB);\n};\n\n\n/**\n * Represents a logical `<Not>` operator for a filter condition.\n *\n * @param {!ol.format.filter.Filter} condition Filter condition.\n * @returns {!ol.format.filter.Not} `<Not>` operator.\n * @api\n */\nol.format.filter.not = function(condition) {\n  return new ol.format.filter.Not(condition);\n};\n\n\n/**\n * Create a `<BBOX>` operator to test whether a geometry-valued property\n * intersects a fixed bounding box\n *\n * @param {!string} geometryName Geometry name to use.\n * @param {!ol.Extent} extent Extent.\n * @param {string=} opt_srsName SRS name. No srsName attribute will be\n *    set on geometries when this is not provided.\n * @returns {!ol.format.filter.Bbox} `<BBOX>` operator.\n * @api\n */\nol.format.filter.bbox = function(geometryName, extent, opt_srsName) {\n  return new ol.format.filter.Bbox(geometryName, extent, opt_srsName);\n};\n\n/**\n * Create a `<Intersects>` operator to test whether a geometry-valued property\n * intersects a given geometry.\n *\n * @param {!string} geometryName Geometry name to use.\n * @param {!ol.geom.Geometry} geometry Geometry.\n * @param {string=} opt_srsName SRS name. No srsName attribute will be\n *    set on geometries when this is not provided.\n * @returns {!ol.format.filter.Intersects} `<Intersects>` operator.\n * @api\n */\nol.format.filter.intersects = function(geometryName, geometry, opt_srsName) {\n  return new ol.format.filter.Intersects(geometryName, geometry, opt_srsName);\n};\n\n/**\n * Create a `<Within>` operator to test whether a geometry-valued property\n * is within a given geometry.\n *\n * @param {!string} geometryName Geometry name to use.\n * @param {!ol.geom.Geometry} geometry Geometry.\n * @param {string=} opt_srsName SRS name. No srsName attribute will be\n *    set on geometries when this is not provided.\n * @returns {!ol.format.filter.Within} `<Within>` operator.\n * @api\n */\nol.format.filter.within = function(geometryName, geometry, opt_srsName) {\n  return new ol.format.filter.Within(geometryName, geometry, opt_srsName);\n};\n\n\n/**\n * Creates a `<PropertyIsEqualTo>` comparison operator.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!(string|number)} expression The value to compare.\n * @param {boolean=} opt_matchCase Case-sensitive?\n * @returns {!ol.format.filter.EqualTo} `<PropertyIsEqualTo>` operator.\n * @api\n */\nol.format.filter.equalTo = function(propertyName, expression, opt_matchCase) {\n  return new ol.format.filter.EqualTo(propertyName, expression, opt_matchCase);\n};\n\n\n/**\n * Creates a `<PropertyIsNotEqualTo>` comparison operator.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!(string|number)} expression The value to compare.\n * @param {boolean=} opt_matchCase Case-sensitive?\n * @returns {!ol.format.filter.NotEqualTo} `<PropertyIsNotEqualTo>` operator.\n * @api\n */\nol.format.filter.notEqualTo = function(propertyName, expression, opt_matchCase) {\n  return new ol.format.filter.NotEqualTo(propertyName, expression, opt_matchCase);\n};\n\n\n/**\n * Creates a `<PropertyIsLessThan>` comparison operator.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @returns {!ol.format.filter.LessThan} `<PropertyIsLessThan>` operator.\n * @api\n */\nol.format.filter.lessThan = function(propertyName, expression) {\n  return new ol.format.filter.LessThan(propertyName, expression);\n};\n\n\n/**\n * Creates a `<PropertyIsLessThanOrEqualTo>` comparison operator.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @returns {!ol.format.filter.LessThanOrEqualTo} `<PropertyIsLessThanOrEqualTo>` operator.\n * @api\n */\nol.format.filter.lessThanOrEqualTo = function(propertyName, expression) {\n  return new ol.format.filter.LessThanOrEqualTo(propertyName, expression);\n};\n\n\n/**\n * Creates a `<PropertyIsGreaterThan>` comparison operator.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @returns {!ol.format.filter.GreaterThan} `<PropertyIsGreaterThan>` operator.\n * @api\n */\nol.format.filter.greaterThan = function(propertyName, expression) {\n  return new ol.format.filter.GreaterThan(propertyName, expression);\n};\n\n\n/**\n * Creates a `<PropertyIsGreaterThanOrEqualTo>` comparison operator.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} expression The value to compare.\n * @returns {!ol.format.filter.GreaterThanOrEqualTo} `<PropertyIsGreaterThanOrEqualTo>` operator.\n * @api\n */\nol.format.filter.greaterThanOrEqualTo = function(propertyName, expression) {\n  return new ol.format.filter.GreaterThanOrEqualTo(propertyName, expression);\n};\n\n\n/**\n * Creates a `<PropertyIsNull>` comparison operator to test whether a property value\n * is null.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @returns {!ol.format.filter.IsNull} `<PropertyIsNull>` operator.\n * @api\n */\nol.format.filter.isNull = function(propertyName) {\n  return new ol.format.filter.IsNull(propertyName);\n};\n\n\n/**\n * Creates a `<PropertyIsBetween>` comparison operator to test whether an expression\n * value lies within a range given by a lower and upper bound (inclusive).\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!number} lowerBoundary The lower bound of the range.\n * @param {!number} upperBoundary The upper bound of the range.\n * @returns {!ol.format.filter.IsBetween} `<PropertyIsBetween>` operator.\n * @api\n */\nol.format.filter.between = function(propertyName, lowerBoundary, upperBoundary) {\n  return new ol.format.filter.IsBetween(propertyName, lowerBoundary, upperBoundary);\n};\n\n\n/**\n * Represents a `<PropertyIsLike>` comparison operator that matches a string property\n * value against a text pattern.\n *\n * @param {!string} propertyName Name of the context property to compare.\n * @param {!string} pattern Text pattern.\n * @param {string=} opt_wildCard Pattern character which matches any sequence of\n *    zero or more string characters. Default is '*'.\n * @param {string=} opt_singleChar pattern character which matches any single\n *    string character. Default is '.'.\n * @param {string=} opt_escapeChar Escape character which can be used to escape\n *    the pattern characters. Default is '!'.\n * @param {boolean=} opt_matchCase Case-sensitive?\n * @returns {!ol.format.filter.IsLike} `<PropertyIsLike>` operator.\n * @api\n */\nol.format.filter.like = function(propertyName, pattern,\n    opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {\n  return new ol.format.filter.IsLike(propertyName, pattern,\n    opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase);\n};\n\ngoog.provide('ol.geom.GeometryCollection');\n\ngoog.require('ol');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.geom.Geometry');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.obj');\n\n\n/**\n * @classdesc\n * An array of {@link ol.geom.Geometry} objects.\n *\n * @constructor\n * @extends {ol.geom.Geometry}\n * @param {Array.<ol.geom.Geometry>=} opt_geometries Geometries.\n * @api stable\n */\nol.geom.GeometryCollection = function(opt_geometries) {\n\n  ol.geom.Geometry.call(this);\n\n  /**\n   * @private\n   * @type {Array.<ol.geom.Geometry>}\n   */\n  this.geometries_ = opt_geometries ? opt_geometries : null;\n\n  this.listenGeometriesChange_();\n};\nol.inherits(ol.geom.GeometryCollection, ol.geom.Geometry);\n\n\n/**\n * @param {Array.<ol.geom.Geometry>} geometries Geometries.\n * @private\n * @return {Array.<ol.geom.Geometry>} Cloned geometries.\n */\nol.geom.GeometryCollection.cloneGeometries_ = function(geometries) {\n  var clonedGeometries = [];\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    clonedGeometries.push(geometries[i].clone());\n  }\n  return clonedGeometries;\n};\n\n\n/**\n * @private\n */\nol.geom.GeometryCollection.prototype.unlistenGeometriesChange_ = function() {\n  var i, ii;\n  if (!this.geometries_) {\n    return;\n  }\n  for (i = 0, ii = this.geometries_.length; i < ii; ++i) {\n    ol.events.unlisten(\n        this.geometries_[i], ol.events.EventType.CHANGE,\n        this.changed, this);\n  }\n};\n\n\n/**\n * @private\n */\nol.geom.GeometryCollection.prototype.listenGeometriesChange_ = function() {\n  var i, ii;\n  if (!this.geometries_) {\n    return;\n  }\n  for (i = 0, ii = this.geometries_.length; i < ii; ++i) {\n    ol.events.listen(\n        this.geometries_[i], ol.events.EventType.CHANGE,\n        this.changed, this);\n  }\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.GeometryCollection} Clone.\n * @api stable\n */\nol.geom.GeometryCollection.prototype.clone = function() {\n  var geometryCollection = new ol.geom.GeometryCollection(null);\n  geometryCollection.setGeometries(this.geometries_);\n  return geometryCollection;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.GeometryCollection.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  if (minSquaredDistance <\n      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {\n    return minSquaredDistance;\n  }\n  var geometries = this.geometries_;\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    minSquaredDistance = geometries[i].closestPointXY(\n        x, y, closestPoint, minSquaredDistance);\n  }\n  return minSquaredDistance;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.GeometryCollection.prototype.containsXY = function(x, y) {\n  var geometries = this.geometries_;\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    if (geometries[i].containsXY(x, y)) {\n      return true;\n    }\n  }\n  return false;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.GeometryCollection.prototype.computeExtent = function(extent) {\n  ol.extent.createOrUpdateEmpty(extent);\n  var geometries = this.geometries_;\n  for (var i = 0, ii = geometries.length; i < ii; ++i) {\n    ol.extent.extend(extent, geometries[i].getExtent());\n  }\n  return extent;\n};\n\n\n/**\n * Return the geometries that make up this geometry collection.\n * @return {Array.<ol.geom.Geometry>} Geometries.\n * @api stable\n */\nol.geom.GeometryCollection.prototype.getGeometries = function() {\n  return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_);\n};\n\n\n/**\n * @return {Array.<ol.geom.Geometry>} Geometries.\n */\nol.geom.GeometryCollection.prototype.getGeometriesArray = function() {\n  return this.geometries_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.GeometryCollection.prototype.getSimplifiedGeometry = function(squaredTolerance) {\n  if (this.simplifiedGeometryRevision != this.getRevision()) {\n    ol.obj.clear(this.simplifiedGeometryCache);\n    this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n    this.simplifiedGeometryRevision = this.getRevision();\n  }\n  if (squaredTolerance < 0 ||\n      (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&\n       squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) {\n    return this;\n  }\n  var key = squaredTolerance.toString();\n  if (this.simplifiedGeometryCache.hasOwnProperty(key)) {\n    return this.simplifiedGeometryCache[key];\n  } else {\n    var simplifiedGeometries = [];\n    var geometries = this.geometries_;\n    var simplified = false;\n    var i, ii;\n    for (i = 0, ii = geometries.length; i < ii; ++i) {\n      var geometry = geometries[i];\n      var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);\n      simplifiedGeometries.push(simplifiedGeometry);\n      if (simplifiedGeometry !== geometry) {\n        simplified = true;\n      }\n    }\n    if (simplified) {\n      var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null);\n      simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries);\n      this.simplifiedGeometryCache[key] = simplifiedGeometryCollection;\n      return simplifiedGeometryCollection;\n    } else {\n      this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;\n      return this;\n    }\n  }\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.GeometryCollection.prototype.getType = function() {\n  return ol.geom.GeometryType.GEOMETRY_COLLECTION;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) {\n  var geometries = this.geometries_;\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    if (geometries[i].intersectsExtent(extent)) {\n      return true;\n    }\n  }\n  return false;\n};\n\n\n/**\n * @return {boolean} Is empty.\n */\nol.geom.GeometryCollection.prototype.isEmpty = function() {\n  return this.geometries_.length === 0;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.geom.GeometryCollection.prototype.rotate = function(angle, anchor) {\n  var geometries = this.geometries_;\n  for (var i = 0, ii = geometries.length; i < ii; ++i) {\n    geometries[i].rotate(angle, anchor);\n  }\n  this.changed();\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.geom.GeometryCollection.prototype.scale = function(sx, opt_sy, opt_anchor) {\n  var anchor = opt_anchor;\n  if (!anchor) {\n    anchor = ol.extent.getCenter(this.getExtent());\n  }\n  var geometries = this.geometries_;\n  for (var i = 0, ii = geometries.length; i < ii; ++i) {\n    geometries[i].scale(sx, opt_sy, anchor);\n  }\n  this.changed();\n};\n\n\n/**\n * Set the geometries that make up this geometry collection.\n * @param {Array.<ol.geom.Geometry>} geometries Geometries.\n * @api stable\n */\nol.geom.GeometryCollection.prototype.setGeometries = function(geometries) {\n  this.setGeometriesArray(\n      ol.geom.GeometryCollection.cloneGeometries_(geometries));\n};\n\n\n/**\n * @param {Array.<ol.geom.Geometry>} geometries Geometries.\n */\nol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) {\n  this.unlistenGeometriesChange_();\n  this.geometries_ = geometries;\n  this.listenGeometriesChange_();\n  this.changed();\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) {\n  var geometries = this.geometries_;\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    geometries[i].applyTransform(transformFn);\n  }\n  this.changed();\n};\n\n\n/**\n * Translate the geometry.\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @api\n */\nol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) {\n  var geometries = this.geometries_;\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    geometries[i].translate(deltaX, deltaY);\n  }\n  this.changed();\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.GeometryCollection.prototype.disposeInternal = function() {\n  this.unlistenGeometriesChange_();\n  ol.geom.Geometry.prototype.disposeInternal.call(this);\n};\n\n// TODO: serialize dataProjection as crs member when writing\n// see https://github.com/openlayers/ol3/issues/2078\n\ngoog.provide('ol.format.GeoJSON');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.Feature');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.JSONFeature');\ngoog.require('ol.geom.GeometryCollection');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the GeoJSON format.\n *\n * @constructor\n * @extends {ol.format.JSONFeature}\n * @param {olx.format.GeoJSONOptions=} opt_options Options.\n * @api stable\n */\nol.format.GeoJSON = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.JSONFeature.call(this);\n\n  /**\n   * @inheritDoc\n   */\n  this.defaultDataProjection = ol.proj.get(\n      options.defaultDataProjection ?\n          options.defaultDataProjection : 'EPSG:4326');\n\n\n  if (options.featureProjection) {\n    this.defaultFeatureProjection = ol.proj.get(options.featureProjection);\n  }\n\n  /**\n   * Name of the geometry attribute for features.\n   * @type {string|undefined}\n   * @private\n   */\n  this.geometryName_ = options.geometryName;\n\n};\nol.inherits(ol.format.GeoJSON, ol.format.JSONFeature);\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.GeoJSON.EXTENSIONS_ = ['.geojson'];\n\n\n/**\n * @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @private\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.GeoJSON.readGeometry_ = function(object, opt_options) {\n  if (!object) {\n    return null;\n  }\n  var geometryReader = ol.format.GeoJSON.GEOMETRY_READERS_[object.type];\n  return /** @type {ol.geom.Geometry} */ (\n      ol.format.Feature.transformWithOptions(\n          geometryReader(object), false, opt_options));\n};\n\n\n/**\n * @param {GeoJSONGeometryCollection} object Object.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @private\n * @return {ol.geom.GeometryCollection} Geometry collection.\n */\nol.format.GeoJSON.readGeometryCollectionGeometry_ = function(\n    object, opt_options) {\n  ol.DEBUG && console.assert(object.type == 'GeometryCollection',\n      'object.type should be GeometryCollection');\n  var geometries = object.geometries.map(\n      /**\n       * @param {GeoJSONGeometry} geometry Geometry.\n       * @return {ol.geom.Geometry} geometry Geometry.\n       */\n      function(geometry) {\n        return ol.format.GeoJSON.readGeometry_(geometry, opt_options);\n      });\n  return new ol.geom.GeometryCollection(geometries);\n};\n\n\n/**\n * @param {GeoJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Point} Point.\n */\nol.format.GeoJSON.readPointGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.type == 'Point',\n      'object.type should be Point');\n  return new ol.geom.Point(object.coordinates);\n};\n\n\n/**\n * @param {GeoJSONGeometry} object Object.\n * @private\n * @return {ol.geom.LineString} LineString.\n */\nol.format.GeoJSON.readLineStringGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.type == 'LineString',\n      'object.type should be LineString');\n  return new ol.geom.LineString(object.coordinates);\n};\n\n\n/**\n * @param {GeoJSONGeometry} object Object.\n * @private\n * @return {ol.geom.MultiLineString} MultiLineString.\n */\nol.format.GeoJSON.readMultiLineStringGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.type == 'MultiLineString',\n      'object.type should be MultiLineString');\n  return new ol.geom.MultiLineString(object.coordinates);\n};\n\n\n/**\n * @param {GeoJSONGeometry} object Object.\n * @private\n * @return {ol.geom.MultiPoint} MultiPoint.\n */\nol.format.GeoJSON.readMultiPointGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.type == 'MultiPoint',\n      'object.type should be MultiPoint');\n  return new ol.geom.MultiPoint(object.coordinates);\n};\n\n\n/**\n * @param {GeoJSONGeometry} object Object.\n * @private\n * @return {ol.geom.MultiPolygon} MultiPolygon.\n */\nol.format.GeoJSON.readMultiPolygonGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.type == 'MultiPolygon',\n      'object.type should be MultiPolygon');\n  return new ol.geom.MultiPolygon(object.coordinates);\n};\n\n\n/**\n * @param {GeoJSONGeometry} object Object.\n * @private\n * @return {ol.geom.Polygon} Polygon.\n */\nol.format.GeoJSON.readPolygonGeometry_ = function(object) {\n  ol.DEBUG && console.assert(object.type == 'Polygon',\n      'object.type should be Polygon');\n  return new ol.geom.Polygon(object.coordinates);\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometry|GeoJSONGeometryCollection} GeoJSON geometry.\n */\nol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) {\n  var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()];\n  return geometryWriter(/** @type {ol.geom.Geometry} */ (\n      ol.format.Feature.transformWithOptions(geometry, true, opt_options)),\n      opt_options);\n};\n\n\n/**\n * @param {ol.geom.Geometry} geometry Geometry.\n * @private\n * @return {GeoJSONGeometryCollection} Empty GeoJSON geometry collection.\n */\nol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) {\n  return /** @type {GeoJSONGeometryCollection} */ ({\n    type: 'GeometryCollection',\n    geometries: []\n  });\n};\n\n\n/**\n * @param {ol.geom.GeometryCollection} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometryCollection} GeoJSON geometry collection.\n */\nol.format.GeoJSON.writeGeometryCollectionGeometry_ = function(\n    geometry, opt_options) {\n  var geometries = geometry.getGeometriesArray().map(function(geometry) {\n    var options = ol.obj.assign({}, opt_options);\n    delete options.featureProjection;\n    return ol.format.GeoJSON.writeGeometry_(geometry, options);\n  });\n  return /** @type {GeoJSONGeometryCollection} */ ({\n    type: 'GeometryCollection',\n    geometries: geometries\n  });\n};\n\n\n/**\n * @param {ol.geom.LineString} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometry} GeoJSON geometry.\n */\nol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) {\n  return /** @type {GeoJSONGeometry} */ ({\n    type: 'LineString',\n    coordinates: geometry.getCoordinates()\n  });\n};\n\n\n/**\n * @param {ol.geom.MultiLineString} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometry} GeoJSON geometry.\n */\nol.format.GeoJSON.writeMultiLineStringGeometry_ = function(geometry, opt_options) {\n  return /** @type {GeoJSONGeometry} */ ({\n    type: 'MultiLineString',\n    coordinates: geometry.getCoordinates()\n  });\n};\n\n\n/**\n * @param {ol.geom.MultiPoint} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometry} GeoJSON geometry.\n */\nol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {\n  return /** @type {GeoJSONGeometry} */ ({\n    type: 'MultiPoint',\n    coordinates: geometry.getCoordinates()\n  });\n};\n\n\n/**\n * @param {ol.geom.MultiPolygon} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometry} GeoJSON geometry.\n */\nol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) {\n  var right;\n  if (opt_options) {\n    right = opt_options.rightHanded;\n  }\n  return /** @type {GeoJSONGeometry} */ ({\n    type: 'MultiPolygon',\n    coordinates: geometry.getCoordinates(right)\n  });\n};\n\n\n/**\n * @param {ol.geom.Point} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometry} GeoJSON geometry.\n */\nol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) {\n  return /** @type {GeoJSONGeometry} */ ({\n    type: 'Point',\n    coordinates: geometry.getCoordinates()\n  });\n};\n\n\n/**\n * @param {ol.geom.Polygon} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @private\n * @return {GeoJSONGeometry} GeoJSON geometry.\n */\nol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) {\n  var right;\n  if (opt_options) {\n    right = opt_options.rightHanded;\n  }\n  return /** @type {GeoJSONGeometry} */ ({\n    type: 'Polygon',\n    coordinates: geometry.getCoordinates(right)\n  });\n};\n\n\n/**\n * @const\n * @private\n * @type {Object.<string, function(GeoJSONObject): ol.geom.Geometry>}\n */\nol.format.GeoJSON.GEOMETRY_READERS_ = {\n  'Point': ol.format.GeoJSON.readPointGeometry_,\n  'LineString': ol.format.GeoJSON.readLineStringGeometry_,\n  'Polygon': ol.format.GeoJSON.readPolygonGeometry_,\n  'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_,\n  'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_,\n  'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_,\n  'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_\n};\n\n\n/**\n * @const\n * @private\n * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (GeoJSONGeometry|GeoJSONGeometryCollection)>}\n */\nol.format.GeoJSON.GEOMETRY_WRITERS_ = {\n  'Point': ol.format.GeoJSON.writePointGeometry_,\n  'LineString': ol.format.GeoJSON.writeLineStringGeometry_,\n  'Polygon': ol.format.GeoJSON.writePolygonGeometry_,\n  'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_,\n  'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_,\n  'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_,\n  'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_,\n  'Circle': ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.GeoJSON.prototype.getExtensions = function() {\n  return ol.format.GeoJSON.EXTENSIONS_;\n};\n\n\n/**\n * Read a feature from a GeoJSON Feature source.  Only works for Feature or\n * geometry types.  Use {@link ol.format.GeoJSON#readFeatures} to read\n * FeatureCollection source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @api stable\n */\nol.format.GeoJSON.prototype.readFeature;\n\n\n/**\n * Read all features from a GeoJSON source.  Works for all GeoJSON types.\n * If the source includes only geometries, features will be created with those\n * geometries.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.GeoJSON.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.GeoJSON.prototype.readFeatureFromObject = function(\n    object, opt_options) {\n\n  ol.DEBUG && console.assert(object.type !== 'FeatureCollection', 'Expected a Feature or geometry');\n\n  /**\n   * @type {GeoJSONFeature}\n   */\n  var geoJSONFeature = null;\n  if (object.type === 'Feature') {\n    geoJSONFeature = /** @type {GeoJSONFeature} */ (object);\n  } else {\n    geoJSONFeature = /** @type {GeoJSONFeature} */ ({\n      type: 'Feature',\n      geometry: /** @type {GeoJSONGeometry|GeoJSONGeometryCollection} */ (object)\n    });\n  }\n\n  var geometry = ol.format.GeoJSON.readGeometry_(geoJSONFeature.geometry, opt_options);\n  var feature = new ol.Feature();\n  if (this.geometryName_) {\n    feature.setGeometryName(this.geometryName_);\n  }\n  feature.setGeometry(geometry);\n  if (geoJSONFeature.id !== undefined) {\n    feature.setId(geoJSONFeature.id);\n  }\n  if (geoJSONFeature.properties) {\n    feature.setProperties(geoJSONFeature.properties);\n  }\n  return feature;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.GeoJSON.prototype.readFeaturesFromObject = function(\n    object, opt_options) {\n  var geoJSONObject = /** @type {GeoJSONObject} */ (object);\n  /** @type {Array.<ol.Feature>} */\n  var features = null;\n  if (geoJSONObject.type === 'FeatureCollection') {\n    var geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */\n        (object);\n    features = [];\n    var geoJSONFeatures = geoJSONFeatureCollection.features;\n    var i, ii;\n    for (i = 0, ii = geoJSONFeatures.length; i < ii; ++i) {\n      features.push(this.readFeatureFromObject(geoJSONFeatures[i],\n          opt_options));\n    }\n  } else {\n    features = [this.readFeatureFromObject(object, opt_options)];\n  }\n  return features;\n};\n\n\n/**\n * Read a geometry from a GeoJSON source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.geom.Geometry} Geometry.\n * @api stable\n */\nol.format.GeoJSON.prototype.readGeometry;\n\n\n/**\n * @inheritDoc\n */\nol.format.GeoJSON.prototype.readGeometryFromObject = function(\n    object, opt_options) {\n  return ol.format.GeoJSON.readGeometry_(\n      /** @type {GeoJSONGeometry} */ (object), opt_options);\n};\n\n\n/**\n * Read the projection from a GeoJSON source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n * @api stable\n */\nol.format.GeoJSON.prototype.readProjection;\n\n\n/**\n * @inheritDoc\n */\nol.format.GeoJSON.prototype.readProjectionFromObject = function(object) {\n  var geoJSONObject = /** @type {GeoJSONObject} */ (object);\n  var crs = geoJSONObject.crs;\n  var projection;\n  if (crs) {\n    if (crs.type == 'name') {\n      projection = ol.proj.get(crs.properties.name);\n    } else if (crs.type == 'EPSG') {\n      // 'EPSG' is not part of the GeoJSON specification, but is generated by\n      // GeoServer.\n      // TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996\n      // is fixed and widely deployed.\n      projection = ol.proj.get('EPSG:' + crs.properties.code);\n    } else {\n      ol.asserts.assert(false, 36); // Unknown SRS type\n    }\n  } else {\n    projection = this.defaultDataProjection;\n  }\n  return /** @type {ol.proj.Projection} */ (projection);\n};\n\n\n/**\n * Encode a feature as a GeoJSON Feature string.\n *\n * @function\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} GeoJSON.\n * @api stable\n */\nol.format.GeoJSON.prototype.writeFeature;\n\n\n/**\n * Encode a feature as a GeoJSON Feature object.\n *\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {GeoJSONFeature} Object.\n * @api stable\n */\nol.format.GeoJSON.prototype.writeFeatureObject = function(feature, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n\n  var object = /** @type {GeoJSONFeature} */ ({\n    'type': 'Feature'\n  });\n  var id = feature.getId();\n  if (id !== undefined) {\n    object.id = id;\n  }\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    object.geometry =\n        ol.format.GeoJSON.writeGeometry_(geometry, opt_options);\n  } else {\n    object.geometry = null;\n  }\n  var properties = feature.getProperties();\n  delete properties[feature.getGeometryName()];\n  if (!ol.obj.isEmpty(properties)) {\n    object.properties = properties;\n  } else {\n    object.properties = null;\n  }\n  return object;\n};\n\n\n/**\n * Encode an array of features as GeoJSON.\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} GeoJSON.\n * @api stable\n */\nol.format.GeoJSON.prototype.writeFeatures;\n\n\n/**\n * Encode an array of features as a GeoJSON object.\n *\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {GeoJSONFeatureCollection} GeoJSON Object.\n * @api stable\n */\nol.format.GeoJSON.prototype.writeFeaturesObject = function(features, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n  var objects = [];\n  var i, ii;\n  for (i = 0, ii = features.length; i < ii; ++i) {\n    objects.push(this.writeFeatureObject(features[i], opt_options));\n  }\n  return /** @type {GeoJSONFeatureCollection} */ ({\n    type: 'FeatureCollection',\n    features: objects\n  });\n};\n\n\n/**\n * Encode a geometry as a GeoJSON string.\n *\n * @function\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} GeoJSON.\n * @api stable\n */\nol.format.GeoJSON.prototype.writeGeometry;\n\n\n/**\n * Encode a geometry as a GeoJSON object.\n *\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object.\n * @api stable\n */\nol.format.GeoJSON.prototype.writeGeometryObject = function(geometry,\n    opt_options) {\n  return ol.format.GeoJSON.writeGeometry_(geometry,\n      this.adaptOptions(opt_options));\n};\n\ngoog.provide('ol.format.XMLFeature');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.FormatType');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for XML feature formats.\n *\n * @constructor\n * @extends {ol.format.Feature}\n */\nol.format.XMLFeature = function() {\n\n  /**\n   * @type {XMLSerializer}\n   * @private\n   */\n  this.xmlSerializer_ = new XMLSerializer();\n\n  ol.format.Feature.call(this);\n};\nol.inherits(ol.format.XMLFeature, ol.format.Feature);\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.getType = function() {\n  return ol.format.FormatType.XML;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.readFeature = function(source, opt_options) {\n  if (ol.xml.isDocument(source)) {\n    return this.readFeatureFromDocument(\n        /** @type {Document} */ (source), opt_options);\n  } else if (ol.xml.isNode(source)) {\n    return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options);\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readFeatureFromDocument(doc, opt_options);\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @param {Document} doc Document.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @return {ol.Feature} Feature.\n */\nol.format.XMLFeature.prototype.readFeatureFromDocument = function(\n    doc, opt_options) {\n  var features = this.readFeaturesFromDocument(doc, opt_options);\n  if (features.length > 0) {\n    return features[0];\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @abstract\n * @param {Node} node Node.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @return {ol.Feature} Feature.\n */\nol.format.XMLFeature.prototype.readFeatureFromNode = function(node, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.readFeatures = function(source, opt_options) {\n  if (ol.xml.isDocument(source)) {\n    return this.readFeaturesFromDocument(\n        /** @type {Document} */ (source), opt_options);\n  } else if (ol.xml.isNode(source)) {\n    return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options);\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readFeaturesFromDocument(doc, opt_options);\n  } else {\n    return [];\n  }\n};\n\n\n/**\n * @param {Document} doc Document.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @protected\n * @return {Array.<ol.Feature>} Features.\n */\nol.format.XMLFeature.prototype.readFeaturesFromDocument = function(\n    doc, opt_options) {\n  /** @type {Array.<ol.Feature>} */\n  var features = [];\n  var n;\n  for (n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      ol.array.extend(features, this.readFeaturesFromNode(n, opt_options));\n    }\n  }\n  return features;\n};\n\n\n/**\n * @abstract\n * @param {Node} node Node.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @protected\n * @return {Array.<ol.Feature>} Features.\n */\nol.format.XMLFeature.prototype.readFeaturesFromNode = function(node, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.readGeometry = function(source, opt_options) {\n  if (ol.xml.isDocument(source)) {\n    return this.readGeometryFromDocument(\n        /** @type {Document} */ (source), opt_options);\n  } else if (ol.xml.isNode(source)) {\n    return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options);\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readGeometryFromDocument(doc, opt_options);\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @abstract\n * @param {Document} doc Document.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @protected\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.XMLFeature.prototype.readGeometryFromDocument = function(doc, opt_options) {};\n\n\n/**\n * @abstract\n * @param {Node} node Node.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @protected\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.XMLFeature.prototype.readGeometryFromNode = function(node, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.readProjection = function(source) {\n  if (ol.xml.isDocument(source)) {\n    return this.readProjectionFromDocument(/** @type {Document} */ (source));\n  } else if (ol.xml.isNode(source)) {\n    return this.readProjectionFromNode(/** @type {Node} */ (source));\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readProjectionFromDocument(doc);\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @param {Document} doc Document.\n * @protected\n * @return {ol.proj.Projection} Projection.\n */\nol.format.XMLFeature.prototype.readProjectionFromDocument = function(doc) {\n  return this.defaultDataProjection;\n};\n\n\n/**\n * @param {Node} node Node.\n * @protected\n * @return {ol.proj.Projection} Projection.\n */\nol.format.XMLFeature.prototype.readProjectionFromNode = function(node) {\n  return this.defaultDataProjection;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) {\n  var node = this.writeFeatureNode(feature, opt_options);\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  return this.xmlSerializer_.serializeToString(node);\n};\n\n\n/**\n * @abstract\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @protected\n * @return {Node} Node.\n */\nol.format.XMLFeature.prototype.writeFeatureNode = function(feature, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) {\n  var node = this.writeFeaturesNode(features, opt_options);\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  return this.xmlSerializer_.serializeToString(node);\n};\n\n\n/**\n * @abstract\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {Node} Node.\n */\nol.format.XMLFeature.prototype.writeFeaturesNode = function(features, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) {\n  var node = this.writeGeometryNode(geometry, opt_options);\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  return this.xmlSerializer_.serializeToString(node);\n};\n\n\n/**\n * @abstract\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {Node} Node.\n */\nol.format.XMLFeature.prototype.writeGeometryNode = function(geometry, opt_options) {};\n\n// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part\n// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect\n// envelopes/extents, only geometries!\ngoog.provide('ol.format.GMLBase');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.Feature');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.XMLFeature');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.LinearRing');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Feature base format for reading and writing data in the GML format.\n * This class cannot be instantiated, it contains only base content that\n * is shared with versioned format classes ol.format.GML2 and\n * ol.format.GML3.\n *\n * @constructor\n * @param {olx.format.GMLOptions=} opt_options\n *     Optional configuration object.\n * @extends {ol.format.XMLFeature}\n */\nol.format.GMLBase = function(opt_options) {\n  var options = /** @type {olx.format.GMLOptions} */\n      (opt_options ? opt_options : {});\n\n  /**\n   * @protected\n   * @type {Array.<string>|string|undefined}\n   */\n  this.featureType = options.featureType;\n\n  /**\n   * @protected\n   * @type {Object.<string, string>|string|undefined}\n   */\n  this.featureNS = options.featureNS;\n\n  /**\n   * @protected\n   * @type {string}\n   */\n  this.srsName = options.srsName;\n\n  /**\n   * @protected\n   * @type {string}\n   */\n  this.schemaLocation = '';\n\n  /**\n   * @type {Object.<string, Object.<string, Object>>}\n   */\n  this.FEATURE_COLLECTION_PARSERS = {};\n  this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS] = {\n    'featureMember': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readFeaturesInternal),\n    'featureMembers': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readFeaturesInternal)\n  };\n\n  ol.format.XMLFeature.call(this);\n};\nol.inherits(ol.format.GMLBase, ol.format.XMLFeature);\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.GMLBase.GMLNS = 'http://www.opengis.net/gml';\n\n\n/**\n * A regular expression that matches if a string only contains whitespace\n * characters. It will e.g. match `''`, `' '`, `'\\n'` etc. The non-breaking\n * space (0xa0) is explicitly included as IE doesn't include it in its\n * definition of `\\s`.\n *\n * Information from `goog.string.isEmptyOrWhitespace`: https://github.com/google/closure-library/blob/e877b1e/closure/goog/string/string.js#L156-L160\n *\n * @const\n * @type {RegExp}\n * @private\n */\nol.format.GMLBase.ONLY_WHITESPACE_RE_ = /^[\\s\\xa0]*$/;\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Array.<ol.Feature> | undefined} Features.\n */\nol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  var localName = node.localName;\n  var features = null;\n  if (localName == 'FeatureCollection') {\n    if (node.namespaceURI === 'http://www.opengis.net/wfs') {\n      features = ol.xml.pushParseAndPop([],\n          this.FEATURE_COLLECTION_PARSERS, node,\n          objectStack, this);\n    } else {\n      features = ol.xml.pushParseAndPop(null,\n          this.FEATURE_COLLECTION_PARSERS, node,\n          objectStack, this);\n    }\n  } else if (localName == 'featureMembers' || localName == 'featureMember') {\n    var context = objectStack[0];\n    var featureType = context['featureType'];\n    var featureNS = context['featureNS'];\n    var i, ii, prefix = 'p', defaultPrefix = 'p0';\n    if (!featureType && node.childNodes) {\n      featureType = [], featureNS = {};\n      for (i = 0, ii = node.childNodes.length; i < ii; ++i) {\n        var child = node.childNodes[i];\n        if (child.nodeType === 1) {\n          var ft = child.nodeName.split(':').pop();\n          if (featureType.indexOf(ft) === -1) {\n            var key = '';\n            var count = 0;\n            var uri = child.namespaceURI;\n            for (var candidate in featureNS) {\n              if (featureNS[candidate] === uri) {\n                key = candidate;\n                break;\n              }\n              ++count;\n            }\n            if (!key) {\n              key = prefix + count;\n              featureNS[key] = uri;\n            }\n            featureType.push(key + ':' + ft);\n          }\n        }\n      }\n      if (localName != 'featureMember') {\n        // recheck featureType for each featureMember\n        context['featureType'] = featureType;\n        context['featureNS'] = featureNS;\n      }\n    }\n    if (typeof featureNS === 'string') {\n      var ns = featureNS;\n      featureNS = {};\n      featureNS[defaultPrefix] = ns;\n    }\n    var parsersNS = {};\n    var featureTypes = Array.isArray(featureType) ? featureType : [featureType];\n    for (var p in featureNS) {\n      var parsers = {};\n      for (i = 0, ii = featureTypes.length; i < ii; ++i) {\n        var featurePrefix = featureTypes[i].indexOf(':') === -1 ?\n            defaultPrefix : featureTypes[i].split(':')[0];\n        if (featurePrefix === p) {\n          parsers[featureTypes[i].split(':').pop()] =\n              (localName == 'featureMembers') ?\n              ol.xml.makeArrayPusher(this.readFeatureElement, this) :\n              ol.xml.makeReplacer(this.readFeatureElement, this);\n        }\n      }\n      parsersNS[featureNS[p]] = parsers;\n    }\n    if (localName == 'featureMember') {\n      features = ol.xml.pushParseAndPop(undefined, parsersNS, node, objectStack);\n    } else {\n      features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack);\n    }\n  }\n  if (features === null) {\n    features = [];\n  }\n  return features;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.Geometry|undefined} Geometry.\n */\nol.format.GMLBase.prototype.readGeometryElement = function(node, objectStack) {\n  var context = /** @type {Object} */ (objectStack[0]);\n  context['srsName'] = node.firstElementChild.getAttribute('srsName');\n  /** @type {ol.geom.Geometry} */\n  var geometry = ol.xml.pushParseAndPop(null,\n      this.GEOMETRY_PARSERS_, node, objectStack, this);\n  if (geometry) {\n    return /** @type {ol.geom.Geometry} */ (\n        ol.format.Feature.transformWithOptions(geometry, false, context));\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.Feature} Feature.\n */\nol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) {\n  var n;\n  var fid = node.getAttribute('fid') ||\n      ol.xml.getAttributeNS(node, ol.format.GMLBase.GMLNS, 'id');\n  var values = {}, geometryName;\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    var localName = n.localName;\n    // Assume attribute elements have one child node and that the child\n    // is a text or CDATA node (to be treated as text).\n    // Otherwise assume it is a geometry node.\n    if (n.childNodes.length === 0 ||\n        (n.childNodes.length === 1 &&\n        (n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {\n      var value = ol.xml.getAllTextContent(n, false);\n      if (ol.format.GMLBase.ONLY_WHITESPACE_RE_.test(value)) {\n        value = undefined;\n      }\n      values[localName] = value;\n    } else {\n      // boundedBy is an extent and must not be considered as a geometry\n      if (localName !== 'boundedBy') {\n        geometryName = localName;\n      }\n      values[localName] = this.readGeometryElement(n, objectStack);\n    }\n  }\n  var feature = new ol.Feature(values);\n  if (geometryName) {\n    feature.setGeometryName(geometryName);\n  }\n  if (fid) {\n    feature.setId(fid);\n  }\n  return feature;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.Point|undefined} Point.\n */\nol.format.GMLBase.prototype.readPoint = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Point', 'localName should be Point');\n  var flatCoordinates =\n      this.readFlatCoordinatesFromNode_(node, objectStack);\n  if (flatCoordinates) {\n    var point = new ol.geom.Point(null);\n    ol.DEBUG && console.assert(flatCoordinates.length == 3,\n        'flatCoordinates should have a length of 3');\n    point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);\n    return point;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.MultiPoint|undefined} MultiPoint.\n */\nol.format.GMLBase.prototype.readMultiPoint = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'MultiPoint',\n      'localName should be MultiPoint');\n  /** @type {Array.<Array.<number>>} */\n  var coordinates = ol.xml.pushParseAndPop([],\n      this.MULTIPOINT_PARSERS_, node, objectStack, this);\n  if (coordinates) {\n    return new ol.geom.MultiPoint(coordinates);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.MultiLineString|undefined} MultiLineString.\n */\nol.format.GMLBase.prototype.readMultiLineString = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'MultiLineString',\n      'localName should be MultiLineString');\n  /** @type {Array.<ol.geom.LineString>} */\n  var lineStrings = ol.xml.pushParseAndPop([],\n      this.MULTILINESTRING_PARSERS_, node, objectStack, this);\n  if (lineStrings) {\n    var multiLineString = new ol.geom.MultiLineString(null);\n    multiLineString.setLineStrings(lineStrings);\n    return multiLineString;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.MultiPolygon|undefined} MultiPolygon.\n */\nol.format.GMLBase.prototype.readMultiPolygon = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'MultiPolygon',\n      'localName should be MultiPolygon');\n  /** @type {Array.<ol.geom.Polygon>} */\n  var polygons = ol.xml.pushParseAndPop([],\n      this.MULTIPOLYGON_PARSERS_, node, objectStack, this);\n  if (polygons) {\n    var multiPolygon = new ol.geom.MultiPolygon(null);\n    multiPolygon.setPolygons(polygons);\n    return multiPolygon;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GMLBase.prototype.pointMemberParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'pointMember' ||\n      node.localName == 'pointMembers',\n      'localName should be pointMember or pointMembers');\n  ol.xml.parseNode(this.POINTMEMBER_PARSERS_,\n      node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GMLBase.prototype.lineStringMemberParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'lineStringMember' ||\n      node.localName == 'lineStringMembers',\n      'localName should be LineStringMember or LineStringMembers');\n  ol.xml.parseNode(this.LINESTRINGMEMBER_PARSERS_,\n      node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GMLBase.prototype.polygonMemberParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'polygonMember' ||\n      node.localName == 'polygonMembers',\n      'localName should be polygonMember or polygonMembers');\n  ol.xml.parseNode(this.POLYGONMEMBER_PARSERS_, node,\n      objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.LineString|undefined} LineString.\n */\nol.format.GMLBase.prototype.readLineString = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LineString',\n      'localName should be LineString');\n  var flatCoordinates =\n      this.readFlatCoordinatesFromNode_(node, objectStack);\n  if (flatCoordinates) {\n    var lineString = new ol.geom.LineString(null);\n    lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);\n    return lineString;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>|undefined} LinearRing flat coordinates.\n */\nol.format.GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LinearRing',\n      'localName should be LinearRing');\n  var ring = ol.xml.pushParseAndPop(null,\n      this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,\n      objectStack, this);\n  if (ring) {\n    return ring;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.LinearRing|undefined} LinearRing.\n */\nol.format.GMLBase.prototype.readLinearRing = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LinearRing',\n      'localName should be LinearRing');\n  var flatCoordinates =\n      this.readFlatCoordinatesFromNode_(node, objectStack);\n  if (flatCoordinates) {\n    var ring = new ol.geom.LinearRing(null);\n    ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);\n    return ring;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.geom.Polygon|undefined} Polygon.\n */\nol.format.GMLBase.prototype.readPolygon = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Polygon',\n      'localName should be Polygon');\n  /** @type {Array.<Array.<number>>} */\n  var flatLinearRings = ol.xml.pushParseAndPop([null],\n      this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);\n  if (flatLinearRings && flatLinearRings[0]) {\n    var polygon = new ol.geom.Polygon(null);\n    var flatCoordinates = flatLinearRings[0];\n    var ends = [flatCoordinates.length];\n    var i, ii;\n    for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {\n      ol.array.extend(flatCoordinates, flatLinearRings[i]);\n      ends.push(flatCoordinates.length);\n    }\n    polygon.setFlatCoordinates(\n        ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);\n    return polygon;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>} Flat coordinates.\n */\nol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  return ol.xml.pushParseAndPop(null,\n      this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,\n      objectStack, this);\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GMLBase.prototype.MULTIPOINT_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'pointMember': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.pointMemberParser_),\n    'pointMembers': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.pointMemberParser_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'lineStringMember': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.lineStringMemberParser_),\n    'lineStringMembers': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.lineStringMemberParser_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GMLBase.prototype.MULTIPOLYGON_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'polygonMember': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.polygonMemberParser_),\n    'polygonMembers': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.polygonMemberParser_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'Point': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GMLBase.prototype.LINESTRINGMEMBER_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'LineString': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.readLineString)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GMLBase.prototype.POLYGONMEMBER_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'Polygon': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.readPolygon)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @protected\n */\nol.format.GMLBase.prototype.RING_PARSERS = {\n  'http://www.opengis.net/gml' : {\n    'LinearRing': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readFlatLinearRing_)\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.GMLBase.prototype.readGeometryFromNode = function(node, opt_options) {\n  var geometry = this.readGeometryElement(node,\n      [this.getReadOptions(node, opt_options ? opt_options : {})]);\n  return geometry ? geometry : null;\n};\n\n\n/**\n * Read all features from a GML FeatureCollection.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.GMLBase.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.GMLBase.prototype.readFeaturesFromNode = function(node, opt_options) {\n  var options = {\n    featureType: this.featureType,\n    featureNS: this.featureNS\n  };\n  if (opt_options) {\n    ol.obj.assign(options, this.getReadOptions(node, opt_options));\n  }\n  var features = this.readFeaturesInternal(node, [options]);\n  return features || [];\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.GMLBase.prototype.readProjectionFromNode = function(node) {\n  return ol.proj.get(this.srsName ? this.srsName :\n      node.firstElementChild.getAttribute('srsName'));\n};\n\ngoog.provide('ol.format.XSD');\n\ngoog.require('ol');\ngoog.require('ol.xml');\ngoog.require('ol.string');\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema';\n\n\n/**\n * @param {Node} node Node.\n * @return {boolean|undefined} Boolean.\n */\nol.format.XSD.readBoolean = function(node) {\n  var s = ol.xml.getAllTextContent(node, false);\n  return ol.format.XSD.readBooleanString(s);\n};\n\n\n/**\n * @param {string} string String.\n * @return {boolean|undefined} Boolean.\n */\nol.format.XSD.readBooleanString = function(string) {\n  var m = /^\\s*(true|1)|(false|0)\\s*$/.exec(string);\n  if (m) {\n    return m[1] !== undefined || false;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {number|undefined} DateTime in seconds.\n */\nol.format.XSD.readDateTime = function(node) {\n  var s = ol.xml.getAllTextContent(node, false);\n  var dateTime = Date.parse(s);\n  return isNaN(dateTime) ? undefined : dateTime / 1000;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {number|undefined} Decimal.\n */\nol.format.XSD.readDecimal = function(node) {\n  var s = ol.xml.getAllTextContent(node, false);\n  return ol.format.XSD.readDecimalString(s);\n};\n\n\n/**\n * @param {string} string String.\n * @return {number|undefined} Decimal.\n */\nol.format.XSD.readDecimalString = function(string) {\n  // FIXME check spec\n  var m = /^\\s*([+\\-]?\\d*\\.?\\d+(?:e[+\\-]?\\d+)?)\\s*$/i.exec(string);\n  if (m) {\n    return parseFloat(m[1]);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {number|undefined} Non negative integer.\n */\nol.format.XSD.readNonNegativeInteger = function(node) {\n  var s = ol.xml.getAllTextContent(node, false);\n  return ol.format.XSD.readNonNegativeIntegerString(s);\n};\n\n\n/**\n * @param {string} string String.\n * @return {number|undefined} Non negative integer.\n */\nol.format.XSD.readNonNegativeIntegerString = function(string) {\n  var m = /^\\s*(\\d+)\\s*$/.exec(string);\n  if (m) {\n    return parseInt(m[1], 10);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {string|undefined} String.\n */\nol.format.XSD.readString = function(node) {\n  return ol.xml.getAllTextContent(node, false).trim();\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the boolean to.\n * @param {boolean} bool Boolean.\n */\nol.format.XSD.writeBooleanTextNode = function(node, bool) {\n  ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0');\n};\n\n\n/**\n * @param {Node} node Node to append a CDATA Section with the string to.\n * @param {string} string String.\n */\nol.format.XSD.writeCDATASection = function(node, string) {\n  node.appendChild(ol.xml.DOCUMENT.createCDATASection(string));\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the dateTime to.\n * @param {number} dateTime DateTime in seconds.\n */\nol.format.XSD.writeDateTimeTextNode = function(node, dateTime) {\n  var date = new Date(dateTime * 1000);\n  var string = date.getUTCFullYear() + '-' +\n      ol.string.padNumber(date.getUTCMonth() + 1, 2) + '-' +\n      ol.string.padNumber(date.getUTCDate(), 2) + 'T' +\n      ol.string.padNumber(date.getUTCHours(), 2) + ':' +\n      ol.string.padNumber(date.getUTCMinutes(), 2) + ':' +\n      ol.string.padNumber(date.getUTCSeconds(), 2) + 'Z';\n  node.appendChild(ol.xml.DOCUMENT.createTextNode(string));\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the decimal to.\n * @param {number} decimal Decimal.\n */\nol.format.XSD.writeDecimalTextNode = function(node, decimal) {\n  var string = decimal.toPrecision();\n  node.appendChild(ol.xml.DOCUMENT.createTextNode(string));\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the decimal to.\n * @param {number} nonNegativeInteger Non negative integer.\n */\nol.format.XSD.writeNonNegativeIntegerTextNode = function(node, nonNegativeInteger) {\n  ol.DEBUG && console.assert(nonNegativeInteger >= 0, 'value should be more than 0');\n  ol.DEBUG && console.assert(nonNegativeInteger == (nonNegativeInteger | 0),\n      'value should be an integer value');\n  var string = nonNegativeInteger.toString();\n  node.appendChild(ol.xml.DOCUMENT.createTextNode(string));\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the string to.\n * @param {string} string String.\n */\nol.format.XSD.writeStringTextNode = function(node, string) {\n  node.appendChild(ol.xml.DOCUMENT.createTextNode(string));\n};\n\ngoog.provide('ol.format.GML3');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.GMLBase');\ngoog.require('ol.format.XSD');\ngoog.require('ol.geom.Geometry');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the GML format\n * version 3.1.1.\n * Currently only supports GML 3.1.1 Simple Features profile.\n *\n * @constructor\n * @param {olx.format.GMLOptions=} opt_options\n *     Optional configuration object.\n * @extends {ol.format.GMLBase}\n * @api\n */\nol.format.GML3 = function(opt_options) {\n  var options = /** @type {olx.format.GMLOptions} */\n      (opt_options ? opt_options : {});\n\n  ol.format.GMLBase.call(this, options);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.surface_ = options.surface !== undefined ? options.surface : false;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.curve_ = options.curve !== undefined ? options.curve : false;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.multiCurve_ = options.multiCurve !== undefined ?\n      options.multiCurve : true;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.multiSurface_ = options.multiSurface !== undefined ?\n      options.multiSurface : true;\n\n  /**\n   * @inheritDoc\n   */\n  this.schemaLocation = options.schemaLocation ?\n      options.schemaLocation : ol.format.GML3.schemaLocation_;\n\n};\nol.inherits(ol.format.GML3, ol.format.GMLBase);\n\n\n/**\n * @const\n * @type {string}\n * @private\n */\nol.format.GML3.schemaLocation_ = ol.format.GMLBase.GMLNS +\n    ' http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' +\n    '1.0.0/gmlsf.xsd';\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.MultiLineString|undefined} MultiLineString.\n */\nol.format.GML3.prototype.readMultiCurve_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'MultiCurve',\n      'localName should be MultiCurve');\n  /** @type {Array.<ol.geom.LineString>} */\n  var lineStrings = ol.xml.pushParseAndPop([],\n      this.MULTICURVE_PARSERS_, node, objectStack, this);\n  if (lineStrings) {\n    var multiLineString = new ol.geom.MultiLineString(null);\n    multiLineString.setLineStrings(lineStrings);\n    return multiLineString;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.MultiPolygon|undefined} MultiPolygon.\n */\nol.format.GML3.prototype.readMultiSurface_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'MultiSurface',\n      'localName should be MultiSurface');\n  /** @type {Array.<ol.geom.Polygon>} */\n  var polygons = ol.xml.pushParseAndPop([],\n      this.MULTISURFACE_PARSERS_, node, objectStack, this);\n  if (polygons) {\n    var multiPolygon = new ol.geom.MultiPolygon(null);\n    multiPolygon.setPolygons(polygons);\n    return multiPolygon;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GML3.prototype.curveMemberParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'curveMember' ||\n      node.localName == 'curveMembers',\n      'localName should be curveMember or curveMembers');\n  ol.xml.parseNode(this.CURVEMEMBER_PARSERS_, node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GML3.prototype.surfaceMemberParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'surfaceMember' ||\n      node.localName == 'surfaceMembers',\n      'localName should be surfaceMember or surfaceMembers');\n  ol.xml.parseNode(this.SURFACEMEMBER_PARSERS_,\n      node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<(Array.<number>)>|undefined} flat coordinates.\n */\nol.format.GML3.prototype.readPatch_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'patches',\n      'localName should be patches');\n  return ol.xml.pushParseAndPop([null],\n      this.PATCHES_PARSERS_, node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>|undefined} flat coordinates.\n */\nol.format.GML3.prototype.readSegment_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'segments',\n      'localName should be segments');\n  return ol.xml.pushParseAndPop([null],\n      this.SEGMENTS_PARSERS_, node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<(Array.<number>)>|undefined} flat coordinates.\n */\nol.format.GML3.prototype.readPolygonPatch_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'npde.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'PolygonPatch',\n      'localName should be PolygonPatch');\n  return ol.xml.pushParseAndPop([null],\n      this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>|undefined} flat coordinates.\n */\nol.format.GML3.prototype.readLineStringSegment_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LineStringSegment',\n      'localName should be LineStringSegment');\n  return ol.xml.pushParseAndPop([null],\n      this.GEOMETRY_FLAT_COORDINATES_PARSERS_,\n      node, objectStack, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GML3.prototype.interiorParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'interior',\n      'localName should be interior');\n  /** @type {Array.<number>|undefined} */\n  var flatLinearRing = ol.xml.pushParseAndPop(undefined,\n      this.RING_PARSERS, node, objectStack, this);\n  if (flatLinearRing) {\n    var flatLinearRings = /** @type {Array.<Array.<number>>} */\n        (objectStack[objectStack.length - 1]);\n    ol.DEBUG && console.assert(Array.isArray(flatLinearRings),\n        'flatLinearRings should be an array');\n    ol.DEBUG && console.assert(flatLinearRings.length > 0,\n        'flatLinearRings should have an array length of 1 or more');\n    flatLinearRings.push(flatLinearRing);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GML3.prototype.exteriorParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'exterior',\n      'localName should be exterior');\n   /** @type {Array.<number>|undefined} */\n  var flatLinearRing = ol.xml.pushParseAndPop(undefined,\n      this.RING_PARSERS, node, objectStack, this);\n  if (flatLinearRing) {\n    var flatLinearRings = /** @type {Array.<Array.<number>>} */\n        (objectStack[objectStack.length - 1]);\n    ol.DEBUG && console.assert(Array.isArray(flatLinearRings),\n        'flatLinearRings should be an array');\n    ol.DEBUG && console.assert(flatLinearRings.length > 0,\n        'flatLinearRings should have an array length of 1 or more');\n    flatLinearRings[0] = flatLinearRing;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.Polygon|undefined} Polygon.\n */\nol.format.GML3.prototype.readSurface_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Surface',\n      'localName should be Surface');\n  /** @type {Array.<Array.<number>>} */\n  var flatLinearRings = ol.xml.pushParseAndPop([null],\n      this.SURFACE_PARSERS_, node, objectStack, this);\n  if (flatLinearRings && flatLinearRings[0]) {\n    var polygon = new ol.geom.Polygon(null);\n    var flatCoordinates = flatLinearRings[0];\n    var ends = [flatCoordinates.length];\n    var i, ii;\n    for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {\n      ol.array.extend(flatCoordinates, flatLinearRings[i]);\n      ends.push(flatCoordinates.length);\n    }\n    polygon.setFlatCoordinates(\n        ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);\n    return polygon;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.LineString|undefined} LineString.\n */\nol.format.GML3.prototype.readCurve_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Curve', 'localName should be Curve');\n  /** @type {Array.<number>} */\n  var flatCoordinates = ol.xml.pushParseAndPop([null],\n      this.CURVE_PARSERS_, node, objectStack, this);\n  if (flatCoordinates) {\n    var lineString = new ol.geom.LineString(null);\n    lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);\n    return lineString;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.Extent|undefined} Envelope.\n */\nol.format.GML3.prototype.readEnvelope_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Envelope',\n      'localName should be Envelope');\n  /** @type {Array.<number>} */\n  var flatCoordinates = ol.xml.pushParseAndPop([null],\n      this.ENVELOPE_PARSERS_, node, objectStack, this);\n  return ol.extent.createOrUpdate(flatCoordinates[1][0],\n      flatCoordinates[1][1], flatCoordinates[2][0],\n      flatCoordinates[2][1]);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>|undefined} Flat coordinates.\n */\nol.format.GML3.prototype.readFlatPos_ = function(node, objectStack) {\n  var s = ol.xml.getAllTextContent(node, false);\n  var re = /^\\s*([+\\-]?\\d*\\.?\\d+(?:[eE][+\\-]?\\d+)?)\\s*/;\n  /** @type {Array.<number>} */\n  var flatCoordinates = [];\n  var m;\n  while ((m = re.exec(s))) {\n    flatCoordinates.push(parseFloat(m[1]));\n    s = s.substr(m[0].length);\n  }\n  if (s !== '') {\n    return undefined;\n  }\n  var context = objectStack[0];\n  var containerSrs = context['srsName'];\n  var axisOrientation = 'enu';\n  if (containerSrs) {\n    var proj = ol.proj.get(containerSrs);\n    axisOrientation = proj.getAxisOrientation();\n  }\n  if (axisOrientation === 'neu') {\n    var i, ii;\n    for (i = 0, ii = flatCoordinates.length; i < ii; i += 3) {\n      var y = flatCoordinates[i];\n      var x = flatCoordinates[i + 1];\n      flatCoordinates[i] = x;\n      flatCoordinates[i + 1] = y;\n    }\n  }\n  var len = flatCoordinates.length;\n  if (len == 2) {\n    flatCoordinates.push(0);\n  }\n  if (len === 0) {\n    return undefined;\n  }\n  return flatCoordinates;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>|undefined} Flat coordinates.\n */\nol.format.GML3.prototype.readFlatPosList_ = function(node, objectStack) {\n  var s = ol.xml.getAllTextContent(node, false).replace(/^\\s*|\\s*$/g, '');\n  var context = objectStack[0];\n  var containerSrs = context['srsName'];\n  var containerDimension = node.parentNode.getAttribute('srsDimension');\n  var axisOrientation = 'enu';\n  if (containerSrs) {\n    var proj = ol.proj.get(containerSrs);\n    axisOrientation = proj.getAxisOrientation();\n  }\n  var coords = s.split(/\\s+/);\n  // The \"dimension\" attribute is from the GML 3.0.1 spec.\n  var dim = 2;\n  if (node.getAttribute('srsDimension')) {\n    dim = ol.format.XSD.readNonNegativeIntegerString(\n        node.getAttribute('srsDimension'));\n  } else if (node.getAttribute('dimension')) {\n    dim = ol.format.XSD.readNonNegativeIntegerString(\n        node.getAttribute('dimension'));\n  } else if (containerDimension) {\n    dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension);\n  }\n  var x, y, z;\n  var flatCoordinates = [];\n  for (var i = 0, ii = coords.length; i < ii; i += dim) {\n    x = parseFloat(coords[i]);\n    y = parseFloat(coords[i + 1]);\n    z = (dim === 3) ? parseFloat(coords[i + 2]) : 0;\n    if (axisOrientation.substr(0, 2) === 'en') {\n      flatCoordinates.push(x, y, z);\n    } else {\n      flatCoordinates.push(y, x, z);\n    }\n  }\n  return flatCoordinates;\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'pos': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPos_),\n    'posList': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPosList_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.FLAT_LINEAR_RINGS_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'interior': ol.format.GML3.prototype.interiorParser_,\n    'exterior': ol.format.GML3.prototype.exteriorParser_\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.GEOMETRY_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint),\n    'MultiPoint': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readMultiPoint),\n    'LineString': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readLineString),\n    'MultiLineString': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readMultiLineString),\n    'LinearRing' : ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readLinearRing),\n    'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon),\n    'MultiPolygon': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readMultiPolygon),\n    'Surface': ol.xml.makeReplacer(ol.format.GML3.prototype.readSurface_),\n    'MultiSurface': ol.xml.makeReplacer(\n        ol.format.GML3.prototype.readMultiSurface_),\n    'Curve': ol.xml.makeReplacer(ol.format.GML3.prototype.readCurve_),\n    'MultiCurve': ol.xml.makeReplacer(\n        ol.format.GML3.prototype.readMultiCurve_),\n    'Envelope': ol.xml.makeReplacer(ol.format.GML3.prototype.readEnvelope_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.MULTICURVE_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'curveMember': ol.xml.makeArrayPusher(\n        ol.format.GML3.prototype.curveMemberParser_),\n    'curveMembers': ol.xml.makeArrayPusher(\n        ol.format.GML3.prototype.curveMemberParser_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.MULTISURFACE_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'surfaceMember': ol.xml.makeArrayPusher(\n        ol.format.GML3.prototype.surfaceMemberParser_),\n    'surfaceMembers': ol.xml.makeArrayPusher(\n        ol.format.GML3.prototype.surfaceMemberParser_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.CURVEMEMBER_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'LineString': ol.xml.makeArrayPusher(\n        ol.format.GMLBase.prototype.readLineString),\n    'Curve': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readCurve_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.SURFACEMEMBER_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'Polygon': ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readPolygon),\n    'Surface': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readSurface_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.SURFACE_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'patches': ol.xml.makeReplacer(ol.format.GML3.prototype.readPatch_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.CURVE_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'segments': ol.xml.makeReplacer(ol.format.GML3.prototype.readSegment_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.ENVELOPE_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'lowerCorner': ol.xml.makeArrayPusher(\n        ol.format.GML3.prototype.readFlatPosList_),\n    'upperCorner': ol.xml.makeArrayPusher(\n        ol.format.GML3.prototype.readFlatPosList_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.PATCHES_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'PolygonPatch': ol.xml.makeReplacer(\n        ol.format.GML3.prototype.readPolygonPatch_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML3.prototype.SEGMENTS_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'LineStringSegment': ol.xml.makeReplacer(\n        ol.format.GML3.prototype.readLineStringSegment_)\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Point} value Point geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writePos_ = function(node, value, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  var axisOrientation = 'enu';\n  if (srsName) {\n    axisOrientation = ol.proj.get(srsName).getAxisOrientation();\n  }\n  var point = value.getCoordinates();\n  var coords;\n  // only 2d for simple features profile\n  if (axisOrientation.substr(0, 2) === 'en') {\n    coords = (point[0] + ' ' + point[1]);\n  } else {\n    coords = (point[1] + ' ' + point[0]);\n  }\n  ol.format.XSD.writeStringTextNode(node, coords);\n};\n\n\n/**\n * @param {Array.<number>} point Point geometry.\n * @param {string=} opt_srsName Optional srsName\n * @return {string} The coords string.\n * @private\n */\nol.format.GML3.prototype.getCoords_ = function(point, opt_srsName) {\n  var axisOrientation = 'enu';\n  if (opt_srsName) {\n    axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation();\n  }\n  return ((axisOrientation.substr(0, 2) === 'en') ?\n      point[0] + ' ' + point[1] :\n      point[1] + ' ' + point[0]);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writePosList_ = function(node, value, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  // only 2d for simple features profile\n  var points = value.getCoordinates();\n  var len = points.length;\n  var parts = new Array(len);\n  var point;\n  for (var i = 0; i < len; ++i) {\n    point = points[i];\n    parts[i] = this.getCoords_(point, srsName);\n  }\n  ol.format.XSD.writeStringTextNode(node, parts.join(' '));\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Point} geometry Point geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writePoint_ = function(node, geometry, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  if (srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  var pos = ol.xml.createElementNS(node.namespaceURI, 'pos');\n  node.appendChild(pos);\n  this.writePos_(pos, geometry, objectStack);\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GML3.ENVELOPE_SERIALIZERS_ = {\n  'http://www.opengis.net/gml': {\n    'lowerCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n    'upperCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Extent} extent Extent.\n * @param {Array.<*>} objectStack Node stack.\n */\nol.format.GML3.prototype.writeEnvelope = function(node, extent, objectStack) {\n  ol.DEBUG && console.assert(extent.length == 4, 'extent should have 4 items');\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  if (srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  var keys = ['lowerCorner', 'upperCorner'];\n  var values = [extent[0] + ' ' + extent[1], extent[2] + ' ' + extent[3]];\n  ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */\n      ({node: node}), ol.format.GML3.ENVELOPE_SERIALIZERS_,\n      ol.xml.OBJECT_PROPERTY_NODE_FACTORY,\n      values,\n      objectStack, keys, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LinearRing} geometry LinearRing geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeLinearRing_ = function(node, geometry, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  if (srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  var posList = ol.xml.createElementNS(node.namespaceURI, 'posList');\n  node.appendChild(posList);\n  this.writePosList_(posList, geometry, objectStack);\n};\n\n\n/**\n * @param {*} value Value.\n * @param {Array.<*>} objectStack Object stack.\n * @param {string=} opt_nodeName Node name.\n * @return {Node} Node.\n * @private\n */\nol.format.GML3.prototype.RING_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {\n  var context = objectStack[objectStack.length - 1];\n  var parentNode = context.node;\n  var exteriorWritten = context['exteriorWritten'];\n  if (exteriorWritten === undefined) {\n    context['exteriorWritten'] = true;\n  }\n  return ol.xml.createElementNS(parentNode.namespaceURI,\n      exteriorWritten !== undefined ? 'interior' : 'exterior');\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Polygon} geometry Polygon geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeSurfaceOrPolygon_ = function(node, geometry, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  if (node.nodeName !== 'PolygonPatch' && srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') {\n    var rings = geometry.getLinearRings();\n    ol.xml.pushSerializeAndPop(\n        {node: node, srsName: srsName},\n        ol.format.GML3.RING_SERIALIZERS_,\n        this.RING_NODE_FACTORY_,\n        rings, objectStack, undefined, this);\n  } else if (node.nodeName === 'Surface') {\n    var patches = ol.xml.createElementNS(node.namespaceURI, 'patches');\n    node.appendChild(patches);\n    this.writeSurfacePatches_(\n        patches, geometry, objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LineString} geometry LineString geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeCurveOrLineString_ = function(node, geometry, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  if (node.nodeName !== 'LineStringSegment' && srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  if (node.nodeName === 'LineString' ||\n      node.nodeName === 'LineStringSegment') {\n    var posList = ol.xml.createElementNS(node.namespaceURI, 'posList');\n    node.appendChild(posList);\n    this.writePosList_(posList, geometry, objectStack);\n  } else if (node.nodeName === 'Curve') {\n    var segments = ol.xml.createElementNS(node.namespaceURI, 'segments');\n    node.appendChild(segments);\n    this.writeCurveSegments_(segments,\n        geometry, objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeMultiSurfaceOrPolygon_ = function(node, geometry, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  var surface = context['surface'];\n  if (srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  var polygons = geometry.getPolygons();\n  ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface},\n      ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_,\n      this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons,\n      objectStack, undefined, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.MultiPoint} geometry MultiPoint geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeMultiPoint_ = function(node, geometry,\n    objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  if (srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  var points = geometry.getPoints();\n  ol.xml.pushSerializeAndPop({node: node, srsName: srsName},\n      ol.format.GML3.POINTMEMBER_SERIALIZERS_,\n      ol.xml.makeSimpleNodeFactory('pointMember'), points,\n      objectStack, undefined, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.MultiLineString} geometry MultiLineString geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeMultiCurveOrLineString_ = function(node, geometry, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var srsName = context['srsName'];\n  var curve = context['curve'];\n  if (srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  var lines = geometry.getLineStrings();\n  ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve},\n      ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_,\n      this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines,\n      objectStack, undefined, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LinearRing} ring LinearRing geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeRing_ = function(node, ring, objectStack) {\n  var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing');\n  node.appendChild(linearRing);\n  this.writeLinearRing_(linearRing, ring, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Polygon} polygon Polygon geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeSurfaceOrPolygonMember_ = function(node, polygon, objectStack) {\n  var child = this.GEOMETRY_NODE_FACTORY_(\n      polygon, objectStack);\n  if (child) {\n    node.appendChild(child);\n    this.writeSurfaceOrPolygon_(child, polygon, objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Point} point Point geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writePointMember_ = function(node, point, objectStack) {\n  var child = ol.xml.createElementNS(node.namespaceURI, 'Point');\n  node.appendChild(child);\n  this.writePoint_(child, point, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LineString} line LineString geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeLineStringOrCurveMember_ = function(node, line, objectStack) {\n  var child = this.GEOMETRY_NODE_FACTORY_(line, objectStack);\n  if (child) {\n    node.appendChild(child);\n    this.writeCurveOrLineString_(child, line, objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Polygon} polygon Polygon geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeSurfacePatches_ = function(node, polygon, objectStack) {\n  var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch');\n  node.appendChild(child);\n  this.writeSurfaceOrPolygon_(child, polygon, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LineString} line LineString geometry.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeCurveSegments_ = function(node, line, objectStack) {\n  var child = ol.xml.createElementNS(node.namespaceURI,\n      'LineStringSegment');\n  node.appendChild(child);\n  this.writeCurveOrLineString_(child, line, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Geometry|ol.Extent} geometry Geometry.\n * @param {Array.<*>} objectStack Node stack.\n */\nol.format.GML3.prototype.writeGeometryElement = function(node, geometry, objectStack) {\n  var context = /** @type {olx.format.WriteOptions} */ (objectStack[objectStack.length - 1]);\n  var item = ol.obj.assign({}, context);\n  item.node = node;\n  var value;\n  if (Array.isArray(geometry)) {\n    if (context.dataProjection) {\n      value = ol.proj.transformExtent(\n          geometry, context.featureProjection, context.dataProjection);\n    } else {\n      value = geometry;\n    }\n  } else {\n    value =\n        ol.format.Feature.transformWithOptions(/** @type {ol.geom.Geometry} */ (geometry), true, context);\n  }\n  ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */\n      (item), ol.format.GML3.GEOMETRY_SERIALIZERS_,\n      this.GEOMETRY_NODE_FACTORY_, [value],\n      objectStack, undefined, this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Node stack.\n */\nol.format.GML3.prototype.writeFeatureElement = function(node, feature, objectStack) {\n  var fid = feature.getId();\n  if (fid) {\n    node.setAttribute('fid', fid);\n  }\n  var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var featureNS = context['featureNS'];\n  var geometryName = feature.getGeometryName();\n  if (!context.serializers) {\n    context.serializers = {};\n    context.serializers[featureNS] = {};\n  }\n  var properties = feature.getProperties();\n  var keys = [], values = [];\n  for (var key in properties) {\n    var value = properties[key];\n    if (value !== null) {\n      keys.push(key);\n      values.push(value);\n      if (key == geometryName || value instanceof ol.geom.Geometry) {\n        if (!(key in context.serializers[featureNS])) {\n          context.serializers[featureNS][key] = ol.xml.makeChildAppender(\n              this.writeGeometryElement, this);\n        }\n      } else {\n        if (!(key in context.serializers[featureNS])) {\n          context.serializers[featureNS][key] = ol.xml.makeChildAppender(\n              ol.format.XSD.writeStringTextNode);\n        }\n      }\n    }\n  }\n  var item = ol.obj.assign({}, context);\n  item.node = node;\n  ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */\n      (item), context.serializers,\n      ol.xml.makeSimpleNodeFactory(undefined, featureNS),\n      values,\n      objectStack, keys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<ol.Feature>} features Features.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GML3.prototype.writeFeatureMembers_ = function(node, features, objectStack) {\n  var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var featureType = context['featureType'];\n  var featureNS = context['featureNS'];\n  var serializers = {};\n  serializers[featureNS] = {};\n  serializers[featureNS][featureType] = ol.xml.makeChildAppender(\n      this.writeFeatureElement, this);\n  var item = ol.obj.assign({}, context);\n  item.node = node;\n  ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */\n      (item),\n      serializers,\n      ol.xml.makeSimpleNodeFactory(featureType, featureNS), features,\n      objectStack);\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = {\n  'http://www.opengis.net/gml': {\n    'surfaceMember': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeSurfaceOrPolygonMember_),\n    'polygonMember': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeSurfaceOrPolygonMember_)\n  }\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GML3.POINTMEMBER_SERIALIZERS_ = {\n  'http://www.opengis.net/gml': {\n    'pointMember': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writePointMember_)\n  }\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = {\n  'http://www.opengis.net/gml': {\n    'lineStringMember': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeLineStringOrCurveMember_),\n    'curveMember': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeLineStringOrCurveMember_)\n  }\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GML3.RING_SERIALIZERS_ = {\n  'http://www.opengis.net/gml': {\n    'exterior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_),\n    'interior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_)\n  }\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GML3.GEOMETRY_SERIALIZERS_ = {\n  'http://www.opengis.net/gml': {\n    'Curve': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeCurveOrLineString_),\n    'MultiCurve': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeMultiCurveOrLineString_),\n    'Point': ol.xml.makeChildAppender(ol.format.GML3.prototype.writePoint_),\n    'MultiPoint': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeMultiPoint_),\n    'LineString': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeCurveOrLineString_),\n    'MultiLineString': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeMultiCurveOrLineString_),\n    'LinearRing': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeLinearRing_),\n    'Polygon': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeSurfaceOrPolygon_),\n    'MultiPolygon': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_),\n    'Surface': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeSurfaceOrPolygon_),\n    'MultiSurface': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_),\n    'Envelope': ol.xml.makeChildAppender(\n        ol.format.GML3.prototype.writeEnvelope)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, string>}\n * @private\n */\nol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = {\n  'MultiLineString': 'lineStringMember',\n  'MultiCurve': 'curveMember',\n  'MultiPolygon': 'polygonMember',\n  'MultiSurface': 'surfaceMember'\n};\n\n\n/**\n * @const\n * @param {*} value Value.\n * @param {Array.<*>} objectStack Object stack.\n * @param {string=} opt_nodeName Node name.\n * @return {Node|undefined} Node.\n * @private\n */\nol.format.GML3.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {\n  var parentNode = objectStack[objectStack.length - 1].node;\n  ol.DEBUG && console.assert(ol.xml.isNode(parentNode),\n      'parentNode should be a node');\n  return ol.xml.createElementNS('http://www.opengis.net/gml',\n      ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]);\n};\n\n\n/**\n * @const\n * @param {*} value Value.\n * @param {Array.<*>} objectStack Object stack.\n * @param {string=} opt_nodeName Node name.\n * @return {Node|undefined} Node.\n * @private\n */\nol.format.GML3.prototype.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {\n  var context = objectStack[objectStack.length - 1];\n  var multiSurface = context['multiSurface'];\n  var surface = context['surface'];\n  var curve = context['curve'];\n  var multiCurve = context['multiCurve'];\n  var parentNode = objectStack[objectStack.length - 1].node;\n  ol.DEBUG && console.assert(ol.xml.isNode(parentNode),\n      'parentNode should be a node');\n  var nodeName;\n  if (!Array.isArray(value)) {\n    nodeName = /** @type {ol.geom.Geometry} */ (value).getType();\n    if (nodeName === 'MultiPolygon' && multiSurface === true) {\n      nodeName = 'MultiSurface';\n    } else if (nodeName === 'Polygon' && surface === true) {\n      nodeName = 'Surface';\n    } else if (nodeName === 'LineString' && curve === true) {\n      nodeName = 'Curve';\n    } else if (nodeName === 'MultiLineString' && multiCurve === true) {\n      nodeName = 'MultiCurve';\n    }\n  } else {\n    nodeName = 'Envelope';\n  }\n  return ol.xml.createElementNS('http://www.opengis.net/gml',\n      nodeName);\n};\n\n\n/**\n * Encode a geometry in GML 3.1.1 Simple Features.\n *\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {Node} Node.\n * @api\n */\nol.format.GML3.prototype.writeGeometryNode = function(geometry, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n  var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom');\n  var context = {node: geom, srsName: this.srsName,\n    curve: this.curve_, surface: this.surface_,\n    multiSurface: this.multiSurface_, multiCurve: this.multiCurve_};\n  if (opt_options) {\n    ol.obj.assign(context, opt_options);\n  }\n  this.writeGeometryElement(geom, geometry, [context]);\n  return geom;\n};\n\n\n/**\n * Encode an array of features in GML 3.1.1 Simple Features.\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {string} Result.\n * @api stable\n */\nol.format.GML3.prototype.writeFeatures;\n\n\n/**\n * Encode an array of features in the GML 3.1.1 format as an XML node.\n *\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {Node} Node.\n * @api\n */\nol.format.GML3.prototype.writeFeaturesNode = function(features, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n  var node = ol.xml.createElementNS('http://www.opengis.net/gml',\n      'featureMembers');\n  ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',\n      'xsi:schemaLocation', this.schemaLocation);\n  var context = {\n    srsName: this.srsName,\n    curve: this.curve_,\n    surface: this.surface_,\n    multiSurface: this.multiSurface_,\n    multiCurve: this.multiCurve_,\n    featureNS: this.featureNS,\n    featureType: this.featureType\n  };\n  if (opt_options) {\n    ol.obj.assign(context, opt_options);\n  }\n  this.writeFeatureMembers_(node, features, [context]);\n  return node;\n};\n\ngoog.provide('ol.format.GML');\n\ngoog.require('ol.format.GML3');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the GML format\n * version 3.1.1.\n * Currently only supports GML 3.1.1 Simple Features profile.\n *\n * @constructor\n * @param {olx.format.GMLOptions=} opt_options\n *     Optional configuration object.\n * @extends {ol.format.GMLBase}\n * @api stable\n */\nol.format.GML = ol.format.GML3;\n\n\n/**\n * Encode an array of features in GML 3.1.1 Simple Features.\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {string} Result.\n * @api stable\n */\nol.format.GML.prototype.writeFeatures;\n\n\n/**\n * Encode an array of features in the GML 3.1.1 format as an XML node.\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {Node} Node.\n * @api\n */\nol.format.GML.prototype.writeFeaturesNode;\n\ngoog.provide('ol.format.GML2');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.format.GMLBase');\ngoog.require('ol.format.XSD');\ngoog.require('ol.proj');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the GML format,\n * version 2.1.2.\n *\n * @constructor\n * @param {olx.format.GMLOptions=} opt_options Optional configuration object.\n * @extends {ol.format.GMLBase}\n * @api\n */\nol.format.GML2 = function(opt_options) {\n  var options = /** @type {olx.format.GMLOptions} */\n      (opt_options ? opt_options : {});\n\n  ol.format.GMLBase.call(this, options);\n\n  this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][\n      'featureMember'] =\n      ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal);\n\n  /**\n   * @inheritDoc\n   */\n  this.schemaLocation = options.schemaLocation ?\n      options.schemaLocation : ol.format.GML2.schemaLocation_;\n\n};\nol.inherits(ol.format.GML2, ol.format.GMLBase);\n\n\n/**\n * @const\n * @type {string}\n * @private\n */\nol.format.GML2.schemaLocation_ = ol.format.GMLBase.GMLNS +\n    ' http://schemas.opengis.net/gml/2.1.2/feature.xsd';\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>|undefined} Flat coordinates.\n */\nol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {\n  var s = ol.xml.getAllTextContent(node, false).replace(/^\\s*|\\s*$/g, '');\n  var context = /** @type {ol.XmlNodeStackItem} */ (objectStack[0]);\n  var containerSrs = context['srsName'];\n  var containerDimension = node.parentNode.getAttribute('srsDimension');\n  var axisOrientation = 'enu';\n  if (containerSrs) {\n    var proj = ol.proj.get(containerSrs);\n    if (proj) {\n      axisOrientation = proj.getAxisOrientation();\n    }\n  }\n  var coords = s.split(/[\\s,]+/);\n  // The \"dimension\" attribute is from the GML 3.0.1 spec.\n  var dim = 2;\n  if (node.getAttribute('srsDimension')) {\n    dim = ol.format.XSD.readNonNegativeIntegerString(\n        node.getAttribute('srsDimension'));\n  } else if (node.getAttribute('dimension')) {\n    dim = ol.format.XSD.readNonNegativeIntegerString(\n        node.getAttribute('dimension'));\n  } else if (containerDimension) {\n    dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension);\n  }\n  var x, y, z;\n  var flatCoordinates = [];\n  for (var i = 0, ii = coords.length; i < ii; i += dim) {\n    x = parseFloat(coords[i]);\n    y = parseFloat(coords[i + 1]);\n    z = (dim === 3) ? parseFloat(coords[i + 2]) : 0;\n    if (axisOrientation.substr(0, 2) === 'en') {\n      flatCoordinates.push(x, y, z);\n    } else {\n      flatCoordinates.push(y, x, z);\n    }\n  }\n  return flatCoordinates;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.Extent|undefined} Envelope.\n */\nol.format.GML2.prototype.readBox_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Box', 'localName should be Box');\n  /** @type {Array.<number>} */\n  var flatCoordinates = ol.xml.pushParseAndPop([null],\n      this.BOX_PARSERS_, node, objectStack, this);\n  return ol.extent.createOrUpdate(flatCoordinates[1][0],\n      flatCoordinates[1][1], flatCoordinates[1][3],\n      flatCoordinates[1][4]);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GML2.prototype.innerBoundaryIsParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'innerBoundaryIs',\n      'localName should be innerBoundaryIs');\n  /** @type {Array.<number>|undefined} */\n  var flatLinearRing = ol.xml.pushParseAndPop(undefined,\n      this.RING_PARSERS, node, objectStack, this);\n  if (flatLinearRing) {\n    var flatLinearRings = /** @type {Array.<Array.<number>>} */\n        (objectStack[objectStack.length - 1]);\n    ol.DEBUG && console.assert(Array.isArray(flatLinearRings),\n        'flatLinearRings should be an array');\n    ol.DEBUG && console.assert(flatLinearRings.length > 0,\n        'flatLinearRings should have an array length larger than 0');\n    flatLinearRings.push(flatLinearRing);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GML2.prototype.outerBoundaryIsParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'outerBoundaryIs',\n      'localName should be outerBoundaryIs');\n  /** @type {Array.<number>|undefined} */\n  var flatLinearRing = ol.xml.pushParseAndPop(undefined,\n      this.RING_PARSERS, node, objectStack, this);\n  if (flatLinearRing) {\n    var flatLinearRings = /** @type {Array.<Array.<number>>} */\n        (objectStack[objectStack.length - 1]);\n    ol.DEBUG && console.assert(Array.isArray(flatLinearRings),\n        'flatLinearRings should be an array');\n    ol.DEBUG && console.assert(flatLinearRings.length > 0,\n        'flatLinearRings should have an array length larger than 0');\n    flatLinearRings[0] = flatLinearRing;\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML2.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'coordinates': ol.xml.makeReplacer(\n        ol.format.GML2.prototype.readFlatCoordinates_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML2.prototype.FLAT_LINEAR_RINGS_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'innerBoundaryIs': ol.format.GML2.prototype.innerBoundaryIsParser_,\n    'outerBoundaryIs': ol.format.GML2.prototype.outerBoundaryIsParser_\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML2.prototype.BOX_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'coordinates': ol.xml.makeArrayPusher(\n        ol.format.GML2.prototype.readFlatCoordinates_)\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GML2.prototype.GEOMETRY_PARSERS_ = {\n  'http://www.opengis.net/gml' : {\n    'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint),\n    'MultiPoint': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readMultiPoint),\n    'LineString': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readLineString),\n    'MultiLineString': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readMultiLineString),\n    'LinearRing' : ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readLinearRing),\n    'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon),\n    'MultiPolygon': ol.xml.makeReplacer(\n        ol.format.GMLBase.prototype.readMultiPolygon),\n    'Box': ol.xml.makeReplacer(ol.format.GML2.prototype.readBox_)\n  }\n};\n\ngoog.provide('ol.format.GPX');\n\ngoog.require('ol');\ngoog.require('ol.Feature');\ngoog.require('ol.array');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.XMLFeature');\ngoog.require('ol.format.XSD');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.Point');\ngoog.require('ol.proj');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the GPX format.\n *\n * @constructor\n * @extends {ol.format.XMLFeature}\n * @param {olx.format.GPXOptions=} opt_options Options.\n * @api stable\n */\nol.format.GPX = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.XMLFeature.call(this);\n\n  /**\n   * @inheritDoc\n   */\n  this.defaultDataProjection = ol.proj.get('EPSG:4326');\n\n  /**\n   * @type {function(ol.Feature, Node)|undefined}\n   * @private\n   */\n  this.readExtensions_ = options.readExtensions;\n};\nol.inherits(ol.format.GPX, ol.format.XMLFeature);\n\n\n/**\n * @const\n * @private\n * @type {Array.<string>}\n */\nol.format.GPX.NAMESPACE_URIS_ = [\n  null,\n  'http://www.topografix.com/GPX/1/0',\n  'http://www.topografix.com/GPX/1/1'\n];\n\n\n/**\n * @const\n * @type {string}\n * @private\n */\nol.format.GPX.SCHEMA_LOCATION_ = 'http://www.topografix.com/GPX/1/1 ' +\n    'http://www.topografix.com/GPX/1/1/gpx.xsd';\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {ol.LayoutOptions} layoutOptions Layout options.\n * @param {Node} node Node.\n * @param {Object} values Values.\n * @private\n * @return {Array.<number>} Flat coordinates.\n */\nol.format.GPX.appendCoordinate_ = function(flatCoordinates, layoutOptions, node, values) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  flatCoordinates.push(\n      parseFloat(node.getAttribute('lon')),\n      parseFloat(node.getAttribute('lat')));\n  if ('ele' in values) {\n    flatCoordinates.push(/** @type {number} */ (values['ele']));\n    delete values['ele'];\n    layoutOptions.hasZ = true;\n  } else {\n    flatCoordinates.push(0);\n  }\n  if ('time' in values) {\n    flatCoordinates.push(/** @type {number} */ (values['time']));\n    delete values['time'];\n    layoutOptions.hasM = true;\n  } else {\n    flatCoordinates.push(0);\n  }\n  return flatCoordinates;\n};\n\n\n/**\n * Choose GeometryLayout based on flags in layoutOptions and adjust flatCoordinates\n * and ends arrays by shrinking them accordingly (removing unused zero entries).\n *\n * @param {ol.LayoutOptions} layoutOptions Layout options.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {Array.<number>=} ends Ends.\n * @return {ol.geom.GeometryLayout} Layout.\n */\nol.format.GPX.applyLayoutOptions_ = function(layoutOptions, flatCoordinates, ends) {\n  var layout = ol.geom.GeometryLayout.XY;\n  var stride = 2;\n  if (layoutOptions.hasZ && layoutOptions.hasM) {\n    layout = ol.geom.GeometryLayout.XYZM;\n    stride = 4;\n  } else if (layoutOptions.hasZ) {\n    layout = ol.geom.GeometryLayout.XYZ;\n    stride = 3;\n  } else if (layoutOptions.hasM) {\n    layout = ol.geom.GeometryLayout.XYM;\n    stride = 3;\n  }\n  if (stride !== 4) {\n    var i, ii;\n    for (i = 0, ii = flatCoordinates.length / 4; i < ii; i++) {\n      flatCoordinates[i * stride] = flatCoordinates[i * 4];\n      flatCoordinates[i * stride + 1] = flatCoordinates[i * 4 + 1];\n      if (layoutOptions.hasZ) {\n        flatCoordinates[i * stride + 2] = flatCoordinates[i * 4 + 2];\n      }\n      if (layoutOptions.hasM) {\n        flatCoordinates[i * stride + 2] = flatCoordinates[i * 4 + 3];\n      }\n    }\n    flatCoordinates.length = flatCoordinates.length / 4 * stride;\n    if (ends) {\n      for (i = 0, ii = ends.length; i < ii; i++) {\n        ends[i] = ends[i] / 4 * stride;\n      }\n    }\n  }\n  return layout;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.parseLink_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'link', 'localName should be link');\n  var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var href = node.getAttribute('href');\n  if (href !== null) {\n    values['link'] = href;\n  }\n  ol.xml.parseNode(ol.format.GPX.LINK_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.parseExtensions_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'extensions',\n      'localName should be extensions');\n  var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  values['extensionsNode_'] = node;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.parseRtePt_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'rtept', 'localName should be rtept');\n  var values = ol.xml.pushParseAndPop(\n      {}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack);\n  if (values) {\n    var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n    var flatCoordinates = /** @type {Array.<number>} */\n        (rteValues['flatCoordinates']);\n    var layoutOptions = /** @type {ol.LayoutOptions} */\n        (rteValues['layoutOptions']);\n    ol.format.GPX.appendCoordinate_(flatCoordinates, layoutOptions, node, values);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.parseTrkPt_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'trkpt', 'localName should be trkpt');\n  var values = ol.xml.pushParseAndPop(\n      {}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack);\n  if (values) {\n    var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n    var flatCoordinates = /** @type {Array.<number>} */\n        (trkValues['flatCoordinates']);\n    var layoutOptions = /** @type {ol.LayoutOptions} */\n        (trkValues['layoutOptions']);\n    ol.format.GPX.appendCoordinate_(flatCoordinates, layoutOptions, node, values);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.parseTrkSeg_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'trkseg',\n      'localName should be trkseg');\n  var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  ol.xml.parseNode(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack);\n  var flatCoordinates = /** @type {Array.<number>} */\n      (values['flatCoordinates']);\n  var ends = /** @type {Array.<number>} */ (values['ends']);\n  ends.push(flatCoordinates.length);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.Feature|undefined} Track.\n */\nol.format.GPX.readRte_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'rte', 'localName should be rte');\n  var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);\n  var values = ol.xml.pushParseAndPop({\n    'flatCoordinates': [],\n    'layoutOptions': {}\n  }, ol.format.GPX.RTE_PARSERS_, node, objectStack);\n  if (!values) {\n    return undefined;\n  }\n  var flatCoordinates = /** @type {Array.<number>} */\n      (values['flatCoordinates']);\n  delete values['flatCoordinates'];\n  var layoutOptions = /** @type {ol.LayoutOptions} */ (values['layoutOptions']);\n  delete values['layoutOptions'];\n  var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, flatCoordinates);\n  var geometry = new ol.geom.LineString(null);\n  geometry.setFlatCoordinates(layout, flatCoordinates);\n  ol.format.Feature.transformWithOptions(geometry, false, options);\n  var feature = new ol.Feature(geometry);\n  feature.setProperties(values);\n  return feature;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.Feature|undefined} Track.\n */\nol.format.GPX.readTrk_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'trk', 'localName should be trk');\n  var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);\n  var values = ol.xml.pushParseAndPop({\n    'flatCoordinates': [],\n    'ends': [],\n    'layoutOptions': {}\n  }, ol.format.GPX.TRK_PARSERS_, node, objectStack);\n  if (!values) {\n    return undefined;\n  }\n  var flatCoordinates = /** @type {Array.<number>} */\n      (values['flatCoordinates']);\n  delete values['flatCoordinates'];\n  var ends = /** @type {Array.<number>} */ (values['ends']);\n  delete values['ends'];\n  var layoutOptions = /** @type {ol.LayoutOptions} */ (values['layoutOptions']);\n  delete values['layoutOptions'];\n  var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, flatCoordinates, ends);\n  var geometry = new ol.geom.MultiLineString(null);\n  geometry.setFlatCoordinates(layout, flatCoordinates, ends);\n  ol.format.Feature.transformWithOptions(geometry, false, options);\n  var feature = new ol.Feature(geometry);\n  feature.setProperties(values);\n  return feature;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.Feature|undefined} Waypoint.\n */\nol.format.GPX.readWpt_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'wpt', 'localName should be wpt');\n  var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);\n  var values = ol.xml.pushParseAndPop(\n      {}, ol.format.GPX.WPT_PARSERS_, node, objectStack);\n  if (!values) {\n    return undefined;\n  }\n  var layoutOptions = /** @type {ol.LayoutOptions} */ ({});\n  var coordinates = ol.format.GPX.appendCoordinate_([], layoutOptions, node, values);\n  var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, coordinates);\n  var geometry = new ol.geom.Point(coordinates, layout);\n  ol.format.Feature.transformWithOptions(geometry, false, options);\n  var feature = new ol.Feature(geometry);\n  feature.setProperties(values);\n  return feature;\n};\n\n\n/**\n * @const\n * @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>}\n * @private\n */\nol.format.GPX.FEATURE_READER_ = {\n  'rte': ol.format.GPX.readRte_,\n  'trk': ol.format.GPX.readTrk_,\n  'wpt': ol.format.GPX.readWpt_\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.GPX_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_),\n      'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_),\n      'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.LINK_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'text':\n          ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'),\n      'type':\n          ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType')\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.RTE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'link': ol.format.GPX.parseLink_,\n      'number':\n          ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),\n      'extensions': ol.format.GPX.parseExtensions_,\n      'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'rtept': ol.format.GPX.parseRtePt_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.TRK_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'link': ol.format.GPX.parseLink_,\n      'number':\n          ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),\n      'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'extensions': ol.format.GPX.parseExtensions_,\n      'trkseg': ol.format.GPX.parseTrkSeg_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'trkpt': ol.format.GPX.parseTrkPt_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.GPX.WPT_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime),\n      'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'link': ol.format.GPX.parseLink_,\n      'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'sat': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'ageofdgpsdata':\n          ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'dgpsid':\n          ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),\n      'extensions': ol.format.GPX.parseExtensions_\n    });\n\n\n/**\n * @param {Array.<ol.Feature>} features List of features.\n * @private\n */\nol.format.GPX.prototype.handleReadExtensions_ = function(features) {\n  if (!features) {\n    features = [];\n  }\n  for (var i = 0, ii = features.length; i < ii; ++i) {\n    var feature = features[i];\n    if (this.readExtensions_) {\n      var extensionsNode = feature.get('extensionsNode_') || null;\n      this.readExtensions_(feature, extensionsNode);\n    }\n    feature.set('extensionsNode_', undefined);\n  }\n};\n\n\n/**\n * Read the first feature from a GPX source.\n * Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)\n * into MultiLineString. Any properties on route and track waypoints are ignored.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @api stable\n */\nol.format.GPX.prototype.readFeature;\n\n\n/**\n * @inheritDoc\n */\nol.format.GPX.prototype.readFeatureFromNode = function(node, opt_options) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {\n    return null;\n  }\n  var featureReader = ol.format.GPX.FEATURE_READER_[node.localName];\n  if (!featureReader) {\n    return null;\n  }\n  var feature = featureReader(node, [this.getReadOptions(node, opt_options)]);\n  if (!feature) {\n    return null;\n  }\n  this.handleReadExtensions_([feature]);\n  return feature;\n};\n\n\n/**\n * Read all features from a GPX source.\n * Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)\n * into MultiLineString. Any properties on route and track waypoints are ignored.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.GPX.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.GPX.prototype.readFeaturesFromNode = function(node, opt_options) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {\n    return [];\n  }\n  if (node.localName == 'gpx') {\n    /** @type {Array.<ol.Feature>} */\n    var features = ol.xml.pushParseAndPop([], ol.format.GPX.GPX_PARSERS_,\n        node, [this.getReadOptions(node, opt_options)]);\n    if (features) {\n      this.handleReadExtensions_(features);\n      return features;\n    } else {\n      return [];\n    }\n  }\n  return [];\n};\n\n\n/**\n * Read the projection from a GPX source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n * @api stable\n */\nol.format.GPX.prototype.readProjection;\n\n\n/**\n * @param {Node} node Node.\n * @param {string} value Value for the link's `href` attribute.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.GPX.writeLink_ = function(node, value, objectStack) {\n  node.setAttribute('href', value);\n  var context = objectStack[objectStack.length - 1];\n  var properties = context['properties'];\n  var link = [\n    properties['linkText'],\n    properties['linkType']\n  ];\n  ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */ ({node: node}),\n      ol.format.GPX.LINK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,\n      link, objectStack, ol.format.GPX.LINK_SEQUENCE_);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.writeWptType_ = function(node, coordinate, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var parentNode = context.node;\n  ol.DEBUG && console.assert(ol.xml.isNode(parentNode),\n      'parentNode should be an XML node');\n  var namespaceURI = parentNode.namespaceURI;\n  var properties = context['properties'];\n  //FIXME Projection handling\n  ol.xml.setAttributeNS(node, null, 'lat', coordinate[1]);\n  ol.xml.setAttributeNS(node, null, 'lon', coordinate[0]);\n  var geometryLayout = context['geometryLayout'];\n  switch (geometryLayout) {\n    case ol.geom.GeometryLayout.XYZM:\n      if (coordinate[3] !== 0) {\n        properties['time'] = coordinate[3];\n      }\n      // fall through\n    case ol.geom.GeometryLayout.XYZ:\n      if (coordinate[2] !== 0) {\n        properties['ele'] = coordinate[2];\n      }\n      break;\n    case ol.geom.GeometryLayout.XYM:\n      if (coordinate[2] !== 0) {\n        properties['time'] = coordinate[2];\n      }\n      break;\n    default:\n      // pass\n  }\n  var orderedKeys = (node.nodeName == 'rtept') ?\n      ol.format.GPX.RTEPT_TYPE_SEQUENCE_[namespaceURI] :\n      ol.format.GPX.WPT_TYPE_SEQUENCE_[namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */\n      ({node: node, 'properties': properties}),\n      ol.format.GPX.WPT_TYPE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,\n      values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.writeRte_ = function(node, feature, objectStack) {\n  var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);\n  var properties = feature.getProperties();\n  var context = {node: node, 'properties': properties};\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    geometry = /** @type {ol.geom.LineString} */\n        (ol.format.Feature.transformWithOptions(geometry, true, options));\n    context['geometryLayout'] = geometry.getLayout();\n    properties['rtept'] = geometry.getCoordinates();\n  }\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys = ol.format.GPX.RTE_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.GPX.RTE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,\n      values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.writeTrk_ = function(node, feature, objectStack) {\n  var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);\n  var properties = feature.getProperties();\n  /** @type {ol.XmlNodeStackItem} */\n  var context = {node: node, 'properties': properties};\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    geometry = /** @type {ol.geom.MultiLineString} */\n        (ol.format.Feature.transformWithOptions(geometry, true, options));\n    properties['trkseg'] = geometry.getLineStrings();\n  }\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys = ol.format.GPX.TRK_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.GPX.TRK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,\n      values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LineString} lineString LineString.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.writeTrkSeg_ = function(node, lineString, objectStack) {\n  /** @type {ol.XmlNodeStackItem} */\n  var context = {node: node, 'geometryLayout': lineString.getLayout(),\n    'properties': {}};\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.GPX.TRKSEG_SERIALIZERS_, ol.format.GPX.TRKSEG_NODE_FACTORY_,\n      lineString.getCoordinates(), objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.GPX.writeWpt_ = function(node, feature, objectStack) {\n  var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);\n  var context = objectStack[objectStack.length - 1];\n  context['properties'] = feature.getProperties();\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    geometry = /** @type {ol.geom.Point} */\n        (ol.format.Feature.transformWithOptions(geometry, true, options));\n    context['geometryLayout'] = geometry.getLayout();\n    ol.format.GPX.writeWptType_(node, geometry.getCoordinates(), objectStack);\n  }\n};\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.GPX.LINK_SEQUENCE_ = ['text', 'type'];\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GPX.LINK_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'text': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.GPX.RTE_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, [\n      'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'rtept'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GPX.RTE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),\n      'number': ol.xml.makeChildAppender(\n          ol.format.XSD.writeNonNegativeIntegerTextNode),\n      'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'rtept': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(\n          ol.format.GPX.writeWptType_))\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.GPX.RTEPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, [\n      'ele', 'time'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.GPX.TRK_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, [\n      'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'trkseg'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GPX.TRK_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),\n      'number': ol.xml.makeChildAppender(\n          ol.format.XSD.writeNonNegativeIntegerTextNode),\n      'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'trkseg': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(\n          ol.format.GPX.writeTrkSeg_))\n    });\n\n\n/**\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.GPX.TRKSEG_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('trkpt');\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GPX.TRKSEG_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'trkpt': ol.xml.makeChildAppender(ol.format.GPX.writeWptType_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.GPX.WPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, [\n      'ele', 'time', 'magvar', 'geoidheight', 'name', 'cmt', 'desc', 'src',\n      'link', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop', 'pdop',\n      'ageofdgpsdata', 'dgpsid'\n    ]);\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GPX.WPT_TYPE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'ele': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n      'time': ol.xml.makeChildAppender(ol.format.XSD.writeDateTimeTextNode),\n      'magvar': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n      'geoidheight': ol.xml.makeChildAppender(\n          ol.format.XSD.writeDecimalTextNode),\n      'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),\n      'sym': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'fix': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'sat': ol.xml.makeChildAppender(\n          ol.format.XSD.writeNonNegativeIntegerTextNode),\n      'hdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n      'vdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n      'pdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n      'ageofdgpsdata': ol.xml.makeChildAppender(\n          ol.format.XSD.writeDecimalTextNode),\n      'dgpsid': ol.xml.makeChildAppender(\n          ol.format.XSD.writeNonNegativeIntegerTextNode)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, string>}\n * @private\n */\nol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_ = {\n  'Point': 'wpt',\n  'LineString': 'rte',\n  'MultiLineString': 'trk'\n};\n\n\n/**\n * @const\n * @param {*} value Value.\n * @param {Array.<*>} objectStack Object stack.\n * @param {string=} opt_nodeName Node name.\n * @return {Node|undefined} Node.\n * @private\n */\nol.format.GPX.GPX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {\n  var geometry = /** @type {ol.Feature} */ (value).getGeometry();\n  if (geometry) {\n    var nodeName = ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_[geometry.getType()];\n    if (nodeName) {\n      var parentNode = objectStack[objectStack.length - 1].node;\n      ol.DEBUG && console.assert(ol.xml.isNode(parentNode),\n          'parentNode should be an XML node');\n      return ol.xml.createElementNS(parentNode.namespaceURI, nodeName);\n    }\n  }\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.GPX.GPX_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.GPX.NAMESPACE_URIS_, {\n      'rte': ol.xml.makeChildAppender(ol.format.GPX.writeRte_),\n      'trk': ol.xml.makeChildAppender(ol.format.GPX.writeTrk_),\n      'wpt': ol.xml.makeChildAppender(ol.format.GPX.writeWpt_)\n    });\n\n\n/**\n * Encode an array of features in the GPX format.\n * LineString geometries are output as routes (`<rte>`), and MultiLineString\n * as tracks (`<trk>`).\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} Result.\n * @api stable\n */\nol.format.GPX.prototype.writeFeatures;\n\n\n/**\n * Encode an array of features in the GPX format as an XML node.\n * LineString geometries are output as routes (`<rte>`), and MultiLineString\n * as tracks (`<trk>`).\n *\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {Node} Node.\n * @api\n */\nol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n  //FIXME Serialize metadata\n  var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx');\n  var xmlnsUri = 'http://www.w3.org/2000/xmlns/';\n  var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance';\n  ol.xml.setAttributeNS(gpx, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri);\n  ol.xml.setAttributeNS(gpx, xmlSchemaInstanceUri, 'xsi:schemaLocation',\n      ol.format.GPX.SCHEMA_LOCATION_);\n  gpx.setAttribute('version', '1.1');\n  gpx.setAttribute('creator', 'OpenLayers 3');\n\n  ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */\n      ({node: gpx}), ol.format.GPX.GPX_SERIALIZERS_,\n      ol.format.GPX.GPX_NODE_FACTORY_, features, [opt_options]);\n  return gpx;\n};\n\ngoog.provide('ol.format.TextFeature');\n\ngoog.require('ol');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.FormatType');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for text feature formats.\n *\n * @constructor\n * @extends {ol.format.Feature}\n */\nol.format.TextFeature = function() {\n  ol.format.Feature.call(this);\n};\nol.inherits(ol.format.TextFeature, ol.format.Feature);\n\n\n/**\n * @param {Document|Node|Object|string} source Source.\n * @private\n * @return {string} Text.\n */\nol.format.TextFeature.prototype.getText_ = function(source) {\n  if (typeof source === 'string') {\n    return source;\n  } else {\n    return '';\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.getType = function() {\n  return ol.format.FormatType.TEXT;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.readFeature = function(source, opt_options) {\n  return this.readFeatureFromText(\n      this.getText_(source), this.adaptOptions(opt_options));\n};\n\n\n/**\n * @abstract\n * @param {string} text Text.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @protected\n * @return {ol.Feature} Feature.\n */\nol.format.TextFeature.prototype.readFeatureFromText = function(text, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.readFeatures = function(source, opt_options) {\n  return this.readFeaturesFromText(\n      this.getText_(source), this.adaptOptions(opt_options));\n};\n\n\n/**\n * @abstract\n * @param {string} text Text.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @protected\n * @return {Array.<ol.Feature>} Features.\n */\nol.format.TextFeature.prototype.readFeaturesFromText = function(text, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.readGeometry = function(source, opt_options) {\n  return this.readGeometryFromText(\n      this.getText_(source), this.adaptOptions(opt_options));\n};\n\n\n/**\n * @abstract\n * @param {string} text Text.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @protected\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.TextFeature.prototype.readGeometryFromText = function(text, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.readProjection = function(source) {\n  return this.readProjectionFromText(this.getText_(source));\n};\n\n\n/**\n * @param {string} text Text.\n * @protected\n * @return {ol.proj.Projection} Projection.\n */\nol.format.TextFeature.prototype.readProjectionFromText = function(text) {\n  return this.defaultDataProjection;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) {\n  return this.writeFeatureText(feature, this.adaptOptions(opt_options));\n};\n\n\n/**\n * @abstract\n * @param {ol.Feature} feature Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @protected\n * @return {string} Text.\n */\nol.format.TextFeature.prototype.writeFeatureText = function(feature, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.writeFeatures = function(\n    features, opt_options) {\n  return this.writeFeaturesText(features, this.adaptOptions(opt_options));\n};\n\n\n/**\n * @abstract\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @protected\n * @return {string} Text.\n */\nol.format.TextFeature.prototype.writeFeaturesText = function(features, opt_options) {};\n\n\n/**\n * @inheritDoc\n */\nol.format.TextFeature.prototype.writeGeometry = function(\n    geometry, opt_options) {\n  return this.writeGeometryText(geometry, this.adaptOptions(opt_options));\n};\n\n\n/**\n * @abstract\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @protected\n * @return {string} Text.\n */\nol.format.TextFeature.prototype.writeGeometryText = function(geometry, opt_options) {};\n\ngoog.provide('ol.format.IGC');\n\ngoog.require('ol');\ngoog.require('ol.Feature');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.TextFeature');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Feature format for `*.igc` flight recording files.\n *\n * @constructor\n * @extends {ol.format.TextFeature}\n * @param {olx.format.IGCOptions=} opt_options Options.\n * @api\n */\nol.format.IGC = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.TextFeature.call(this);\n\n  /**\n   * @inheritDoc\n   */\n  this.defaultDataProjection = ol.proj.get('EPSG:4326');\n\n  /**\n   * @private\n   * @type {ol.format.IGC.Z}\n   */\n  this.altitudeMode_ = options.altitudeMode ?\n      options.altitudeMode : ol.format.IGC.Z.NONE;\n\n};\nol.inherits(ol.format.IGC, ol.format.TextFeature);\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.IGC.EXTENSIONS_ = ['.igc'];\n\n\n/**\n * @const\n * @type {RegExp}\n * @private\n */\nol.format.IGC.B_RECORD_RE_ =\n    /^B(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{5})([NS])(\\d{3})(\\d{5})([EW])([AV])(\\d{5})(\\d{5})/;\n\n\n/**\n * @const\n * @type {RegExp}\n * @private\n */\nol.format.IGC.H_RECORD_RE_ = /^H.([A-Z]{3}).*?:(.*)/;\n\n\n/**\n * @const\n * @type {RegExp}\n * @private\n */\nol.format.IGC.HFDTE_RECORD_RE_ = /^HFDTE(\\d{2})(\\d{2})(\\d{2})/;\n\n\n/**\n * A regular expression matching the newline characters `\\r\\n`, `\\r` and `\\n`.\n *\n * @const\n * @type {RegExp}\n * @private\n */\nol.format.IGC.NEWLINE_RE_ = /\\r\\n|\\r|\\n/;\n\n\n/**\n * @inheritDoc\n */\nol.format.IGC.prototype.getExtensions = function() {\n  return ol.format.IGC.EXTENSIONS_;\n};\n\n\n/**\n * Read the feature from the IGC source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @api\n */\nol.format.IGC.prototype.readFeature;\n\n\n/**\n * @inheritDoc\n */\nol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) {\n  var altitudeMode = this.altitudeMode_;\n  var lines = text.split(ol.format.IGC.NEWLINE_RE_);\n  /** @type {Object.<string, string>} */\n  var properties = {};\n  var flatCoordinates = [];\n  var year = 2000;\n  var month = 0;\n  var day = 1;\n  var lastDateTime = -1;\n  var i, ii;\n  for (i = 0, ii = lines.length; i < ii; ++i) {\n    var line = lines[i];\n    var m;\n    if (line.charAt(0) == 'B') {\n      m = ol.format.IGC.B_RECORD_RE_.exec(line);\n      if (m) {\n        var hour = parseInt(m[1], 10);\n        var minute = parseInt(m[2], 10);\n        var second = parseInt(m[3], 10);\n        var y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000;\n        if (m[6] == 'S') {\n          y = -y;\n        }\n        var x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000;\n        if (m[9] == 'W') {\n          x = -x;\n        }\n        flatCoordinates.push(x, y);\n        if (altitudeMode != ol.format.IGC.Z.NONE) {\n          var z;\n          if (altitudeMode == ol.format.IGC.Z.GPS) {\n            z = parseInt(m[11], 10);\n          } else if (altitudeMode == ol.format.IGC.Z.BAROMETRIC) {\n            z = parseInt(m[12], 10);\n          } else {\n            ol.DEBUG && console.assert(false, 'Unknown altitude mode.');\n            z = 0;\n          }\n          flatCoordinates.push(z);\n        }\n        var dateTime = Date.UTC(year, month, day, hour, minute, second);\n        // Detect UTC midnight wrap around.\n        if (dateTime < lastDateTime) {\n          dateTime = Date.UTC(year, month, day + 1, hour, minute, second);\n        }\n        flatCoordinates.push(dateTime / 1000);\n        lastDateTime = dateTime;\n      }\n    } else if (line.charAt(0) == 'H') {\n      m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line);\n      if (m) {\n        day = parseInt(m[1], 10);\n        month = parseInt(m[2], 10) - 1;\n        year = 2000 + parseInt(m[3], 10);\n      } else {\n        m = ol.format.IGC.H_RECORD_RE_.exec(line);\n        if (m) {\n          properties[m[1]] = m[2].trim();\n        }\n      }\n    }\n  }\n  if (flatCoordinates.length === 0) {\n    return null;\n  }\n  var lineString = new ol.geom.LineString(null);\n  var layout = altitudeMode == ol.format.IGC.Z.NONE ?\n      ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM;\n  lineString.setFlatCoordinates(layout, flatCoordinates);\n  var feature = new ol.Feature(ol.format.Feature.transformWithOptions(\n      lineString, false, opt_options));\n  feature.setProperties(properties);\n  return feature;\n};\n\n\n/**\n * Read the feature from the source. As IGC sources contain a single\n * feature, this will return the feature in an array.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api\n */\nol.format.IGC.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) {\n  var feature = this.readFeatureFromText(text, opt_options);\n  if (feature) {\n    return [feature];\n  } else {\n    return [];\n  }\n};\n\n\n/**\n * Read the projection from the IGC source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n * @api\n */\nol.format.IGC.prototype.readProjection;\n\n\n/**\n * IGC altitude/z. One of 'barometric', 'gps', 'none'.\n * @enum {string}\n */\nol.format.IGC.Z = {\n  BAROMETRIC: 'barometric',\n  GPS: 'gps',\n  NONE: 'none'\n};\n\ngoog.provide('ol.style.IconImage');\n\ngoog.require('ol');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.events.EventTarget');\ngoog.require('ol.events.EventType');\ngoog.require('ol.Image');\ngoog.require('ol.style');\n\n\n/**\n * @constructor\n * @param {Image|HTMLCanvasElement} image Image.\n * @param {string|undefined} src Src.\n * @param {ol.Size} size Size.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.Image.State} imageState Image state.\n * @param {ol.Color} color Color.\n * @extends {ol.events.EventTarget}\n */\nol.style.IconImage = function(image, src, size, crossOrigin, imageState,\n                               color) {\n\n  ol.events.EventTarget.call(this);\n\n  /**\n   * @private\n   * @type {Image|HTMLCanvasElement}\n   */\n  this.hitDetectionImage_ = null;\n\n  /**\n   * @private\n   * @type {Image|HTMLCanvasElement}\n   */\n  this.image_ = !image ? new Image() : image;\n\n  if (crossOrigin !== null) {\n    this.image_.crossOrigin = crossOrigin;\n  }\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = color ?\n      /** @type {HTMLCanvasElement} */ (document.createElement('CANVAS')) :\n      null;\n\n  /**\n   * @private\n   * @type {ol.Color}\n   */\n  this.color_ = color;\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.imageListenerKeys_ = null;\n\n  /**\n   * @private\n   * @type {ol.Image.State}\n   */\n  this.imageState_ = imageState;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.size_ = size;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.src_ = src;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.tainting_ = false;\n  if (this.imageState_ == ol.Image.State.LOADED) {\n    this.determineTainting_();\n  }\n\n};\nol.inherits(ol.style.IconImage, ol.events.EventTarget);\n\n\n/**\n * @param {Image|HTMLCanvasElement} image Image.\n * @param {string} src Src.\n * @param {ol.Size} size Size.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.Image.State} imageState Image state.\n * @param {ol.Color} color Color.\n * @return {ol.style.IconImage} Icon image.\n */\nol.style.IconImage.get = function(image, src, size, crossOrigin, imageState,\n                                   color) {\n  var iconImageCache = ol.style.iconImageCache;\n  var iconImage = iconImageCache.get(src, crossOrigin, color);\n  if (!iconImage) {\n    iconImage = new ol.style.IconImage(\n        image, src, size, crossOrigin, imageState, color);\n    iconImageCache.set(src, crossOrigin, color, iconImage);\n  }\n  return iconImage;\n};\n\n\n/**\n * @private\n */\nol.style.IconImage.prototype.determineTainting_ = function() {\n  var context = ol.dom.createCanvasContext2D(1, 1);\n  try {\n    context.drawImage(this.image_, 0, 0);\n    context.getImageData(0, 0, 1, 1);\n  } catch (e) {\n    this.tainting_ = true;\n  }\n};\n\n\n/**\n * @private\n */\nol.style.IconImage.prototype.dispatchChangeEvent_ = function() {\n  this.dispatchEvent(ol.events.EventType.CHANGE);\n};\n\n\n/**\n * @private\n */\nol.style.IconImage.prototype.handleImageError_ = function() {\n  this.imageState_ = ol.Image.State.ERROR;\n  this.unlistenImage_();\n  this.dispatchChangeEvent_();\n};\n\n\n/**\n * @private\n */\nol.style.IconImage.prototype.handleImageLoad_ = function() {\n  this.imageState_ = ol.Image.State.LOADED;\n  if (this.size_) {\n    this.image_.width = this.size_[0];\n    this.image_.height = this.size_[1];\n  }\n  this.size_ = [this.image_.width, this.image_.height];\n  this.unlistenImage_();\n  this.determineTainting_();\n  this.replaceColor_();\n  this.dispatchChangeEvent_();\n};\n\n\n/**\n * @param {number} pixelRatio Pixel ratio.\n * @return {Image|HTMLCanvasElement} Image or Canvas element.\n */\nol.style.IconImage.prototype.getImage = function(pixelRatio) {\n  return this.canvas_ ? this.canvas_ : this.image_;\n};\n\n\n/**\n * @return {ol.Image.State} Image state.\n */\nol.style.IconImage.prototype.getImageState = function() {\n  return this.imageState_;\n};\n\n\n/**\n * @param {number} pixelRatio Pixel ratio.\n * @return {Image|HTMLCanvasElement} Image element.\n */\nol.style.IconImage.prototype.getHitDetectionImage = function(pixelRatio) {\n  if (!this.hitDetectionImage_) {\n    if (this.tainting_) {\n      var width = this.size_[0];\n      var height = this.size_[1];\n      var context = ol.dom.createCanvasContext2D(width, height);\n      context.fillRect(0, 0, width, height);\n      this.hitDetectionImage_ = context.canvas;\n    } else {\n      this.hitDetectionImage_ = this.image_;\n    }\n  }\n  return this.hitDetectionImage_;\n};\n\n\n/**\n * @return {ol.Size} Image size.\n */\nol.style.IconImage.prototype.getSize = function() {\n  return this.size_;\n};\n\n\n/**\n * @return {string|undefined} Image src.\n */\nol.style.IconImage.prototype.getSrc = function() {\n  return this.src_;\n};\n\n\n/**\n * Load not yet loaded URI.\n */\nol.style.IconImage.prototype.load = function() {\n  if (this.imageState_ == ol.Image.State.IDLE) {\n    ol.DEBUG && console.assert(this.src_ !== undefined,\n        'this.src_ must not be undefined');\n    ol.DEBUG && console.assert(!this.imageListenerKeys_,\n        'no listener keys existing');\n    this.imageState_ = ol.Image.State.LOADING;\n    this.imageListenerKeys_ = [\n      ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,\n          this.handleImageError_, this),\n      ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,\n          this.handleImageLoad_, this)\n    ];\n    try {\n      this.image_.src = this.src_;\n    } catch (e) {\n      this.handleImageError_();\n    }\n  }\n};\n\n\n/**\n * @private\n */\nol.style.IconImage.prototype.replaceColor_ = function() {\n  if (this.tainting_ || this.color_ === null) {\n    return;\n  }\n\n  this.canvas_.width = this.image_.width;\n  this.canvas_.height = this.image_.height;\n\n  var ctx = this.canvas_.getContext('2d');\n  ctx.drawImage(this.image_, 0, 0);\n\n  var imgData = ctx.getImageData(0, 0, this.image_.width, this.image_.height);\n  var data = imgData.data;\n  var r = this.color_[0] / 255.0;\n  var g = this.color_[1] / 255.0;\n  var b = this.color_[2] / 255.0;\n\n  for (var i = 0, ii = data.length; i < ii; i += 4) {\n    data[i] *= r;\n    data[i + 1] *= g;\n    data[i + 2] *= b;\n  }\n  ctx.putImageData(imgData, 0, 0);\n};\n\n\n/**\n * Discards event handlers which listen for load completion or errors.\n *\n * @private\n */\nol.style.IconImage.prototype.unlistenImage_ = function() {\n  this.imageListenerKeys_.forEach(ol.events.unlistenByKey);\n  this.imageListenerKeys_ = null;\n};\n\ngoog.provide('ol.style.Icon');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.color');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.Image');\ngoog.require('ol.style.IconImage');\ngoog.require('ol.style.Image');\n\n\n/**\n * @classdesc\n * Set icon style for vector features.\n *\n * @constructor\n * @param {olx.style.IconOptions=} opt_options Options.\n * @extends {ol.style.Image}\n * @api\n */\nol.style.Icon = function(opt_options) {\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5];\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.normalizedAnchor_ = null;\n\n  /**\n   * @private\n   * @type {ol.style.Icon.Origin}\n   */\n  this.anchorOrigin_ = options.anchorOrigin !== undefined ?\n      options.anchorOrigin : ol.style.Icon.Origin.TOP_LEFT;\n\n  /**\n   * @private\n   * @type {ol.style.Icon.AnchorUnits}\n   */\n  this.anchorXUnits_ = options.anchorXUnits !== undefined ?\n      options.anchorXUnits : ol.style.Icon.AnchorUnits.FRACTION;\n\n  /**\n   * @private\n   * @type {ol.style.Icon.AnchorUnits}\n   */\n  this.anchorYUnits_ = options.anchorYUnits !== undefined ?\n      options.anchorYUnits : ol.style.Icon.AnchorUnits.FRACTION;\n\n  /**\n   * @private\n   * @type {?string}\n   */\n  this.crossOrigin_ =\n      options.crossOrigin !== undefined ? options.crossOrigin : null;\n\n  /**\n   * @type {Image|HTMLCanvasElement}\n   */\n  var image = options.img !== undefined ? options.img : null;\n\n  /**\n   * @type {ol.Size}\n   */\n  var imgSize = options.imgSize !== undefined ? options.imgSize : null;\n\n  /**\n   * @type {string|undefined}\n   */\n  var src = options.src;\n\n  ol.asserts.assert(!(src !== undefined && image),\n      4); // `image` and `src` cannot be provided at the same time\n  ol.asserts.assert(!image || (image && imgSize),\n      5); // `imgSize` must be set when `image` is provided\n\n  if ((src === undefined || src.length === 0) && image) {\n    src = image.src || ol.getUid(image).toString();\n  }\n  ol.asserts.assert(src !== undefined && src.length > 0,\n      6); // A defined and non-empty `src` or `image` must be provided\n\n  /**\n   * @type {ol.Image.State}\n   */\n  var imageState = options.src !== undefined ?\n      ol.Image.State.IDLE : ol.Image.State.LOADED;\n\n  /**\n   * @private\n   * @type {ol.Color}\n   */\n  this.color_ = options.color !== undefined ? ol.color.asArray(options.color) :\n      null;\n\n  /**\n   * @private\n   * @type {ol.style.IconImage}\n   */\n  this.iconImage_ = ol.style.IconImage.get(\n      image, /** @type {string} */ (src), imgSize, this.crossOrigin_, imageState, this.color_);\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.offset_ = options.offset !== undefined ? options.offset : [0, 0];\n\n  /**\n   * @private\n   * @type {ol.style.Icon.Origin}\n   */\n  this.offsetOrigin_ = options.offsetOrigin !== undefined ?\n      options.offsetOrigin : ol.style.Icon.Origin.TOP_LEFT;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.origin_ = null;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.size_ = options.size !== undefined ? options.size : null;\n\n  /**\n   * @type {number}\n   */\n  var opacity = options.opacity !== undefined ? options.opacity : 1;\n\n  /**\n   * @type {boolean}\n   */\n  var rotateWithView = options.rotateWithView !== undefined ?\n      options.rotateWithView : false;\n\n  /**\n   * @type {number}\n   */\n  var rotation = options.rotation !== undefined ? options.rotation : 0;\n\n  /**\n   * @type {number}\n   */\n  var scale = options.scale !== undefined ? options.scale : 1;\n\n  /**\n   * @type {boolean}\n   */\n  var snapToPixel = options.snapToPixel !== undefined ?\n      options.snapToPixel : true;\n\n  ol.style.Image.call(this, {\n    opacity: opacity,\n    rotation: rotation,\n    scale: scale,\n    snapToPixel: snapToPixel,\n    rotateWithView: rotateWithView\n  });\n\n};\nol.inherits(ol.style.Icon, ol.style.Image);\n\n\n/**\n * Clones the style.\n * @return {ol.style.Icon} The cloned style.\n * @api\n */\nol.style.Icon.prototype.clone = function() {\n  var oldImage = this.getImage(1);\n  var newImage;\n  if (this.iconImage_.getImageState() === ol.Image.State.LOADED) {\n    if (oldImage.tagName.toUpperCase() === 'IMG') {\n      newImage = /** @type {Image} */ (oldImage.cloneNode(true));\n    } else {\n      newImage = /** @type {HTMLCanvasElement} */ (document.createElement('canvas'));\n      var context = newImage.getContext('2d');\n      newImage.width = oldImage.width;\n      newImage.height = oldImage.height;\n      context.drawImage(oldImage, 0, 0);\n    }\n  }\n  return new ol.style.Icon({\n    anchor: this.anchor_.slice(),\n    anchorOrigin: this.anchorOrigin_,\n    anchorXUnits: this.anchorXUnits_,\n    anchorYUnits: this.anchorYUnits_,\n    crossOrigin: this.crossOrigin_,\n    color: (this.color_ && this.color_.slice) ? this.color_.slice() : this.color_ || undefined,\n    img: newImage ? newImage : undefined,\n    imgSize: newImage ? this.iconImage_.getSize().slice() : undefined,\n    src: newImage ? undefined : this.getSrc(),\n    offset: this.offset_.slice(),\n    offsetOrigin: this.offsetOrigin_,\n    size: this.size_ !== null ? this.size_.slice() : undefined,\n    opacity: this.getOpacity(),\n    scale: this.getScale(),\n    snapToPixel: this.getSnapToPixel(),\n    rotation: this.getRotation(),\n    rotateWithView: this.getRotateWithView()\n  });\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.style.Icon.prototype.getAnchor = function() {\n  if (this.normalizedAnchor_) {\n    return this.normalizedAnchor_;\n  }\n  var anchor = this.anchor_;\n  var size = this.getSize();\n  if (this.anchorXUnits_ == ol.style.Icon.AnchorUnits.FRACTION ||\n      this.anchorYUnits_ == ol.style.Icon.AnchorUnits.FRACTION) {\n    if (!size) {\n      return null;\n    }\n    anchor = this.anchor_.slice();\n    if (this.anchorXUnits_ == ol.style.Icon.AnchorUnits.FRACTION) {\n      anchor[0] *= size[0];\n    }\n    if (this.anchorYUnits_ == ol.style.Icon.AnchorUnits.FRACTION) {\n      anchor[1] *= size[1];\n    }\n  }\n\n  if (this.anchorOrigin_ != ol.style.Icon.Origin.TOP_LEFT) {\n    if (!size) {\n      return null;\n    }\n    if (anchor === this.anchor_) {\n      anchor = this.anchor_.slice();\n    }\n    if (this.anchorOrigin_ == ol.style.Icon.Origin.TOP_RIGHT ||\n        this.anchorOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) {\n      anchor[0] = -anchor[0] + size[0];\n    }\n    if (this.anchorOrigin_ == ol.style.Icon.Origin.BOTTOM_LEFT ||\n        this.anchorOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) {\n      anchor[1] = -anchor[1] + size[1];\n    }\n  }\n  this.normalizedAnchor_ = anchor;\n  return this.normalizedAnchor_;\n};\n\n\n/**\n * Get the icon color.\n * @return {ol.Color} Color.\n * @api\n */\nol.style.Icon.prototype.getColor = function() {\n  return this.color_;\n};\n\n\n/**\n * Get the image icon.\n * @param {number} pixelRatio Pixel ratio.\n * @return {Image|HTMLCanvasElement} Image or Canvas element.\n * @api\n */\nol.style.Icon.prototype.getImage = function(pixelRatio) {\n  return this.iconImage_.getImage(pixelRatio);\n};\n\n\n/**\n * Real Image size used.\n * @return {ol.Size} Size.\n */\nol.style.Icon.prototype.getImageSize = function() {\n  return this.iconImage_.getSize();\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.Icon.prototype.getHitDetectionImageSize = function() {\n  return this.getImageSize();\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.Icon.prototype.getImageState = function() {\n  return this.iconImage_.getImageState();\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.Icon.prototype.getHitDetectionImage = function(pixelRatio) {\n  return this.iconImage_.getHitDetectionImage(pixelRatio);\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.style.Icon.prototype.getOrigin = function() {\n  if (this.origin_) {\n    return this.origin_;\n  }\n  var offset = this.offset_;\n\n  if (this.offsetOrigin_ != ol.style.Icon.Origin.TOP_LEFT) {\n    var size = this.getSize();\n    var iconImageSize = this.iconImage_.getSize();\n    if (!size || !iconImageSize) {\n      return null;\n    }\n    offset = offset.slice();\n    if (this.offsetOrigin_ == ol.style.Icon.Origin.TOP_RIGHT ||\n        this.offsetOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) {\n      offset[0] = iconImageSize[0] - size[0] - offset[0];\n    }\n    if (this.offsetOrigin_ == ol.style.Icon.Origin.BOTTOM_LEFT ||\n        this.offsetOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) {\n      offset[1] = iconImageSize[1] - size[1] - offset[1];\n    }\n  }\n  this.origin_ = offset;\n  return this.origin_;\n};\n\n\n/**\n * Get the image URL.\n * @return {string|undefined} Image src.\n * @api\n */\nol.style.Icon.prototype.getSrc = function() {\n  return this.iconImage_.getSrc();\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.style.Icon.prototype.getSize = function() {\n  return !this.size_ ? this.iconImage_.getSize() : this.size_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.Icon.prototype.listenImageChange = function(listener, thisArg) {\n  return ol.events.listen(this.iconImage_, ol.events.EventType.CHANGE,\n      listener, thisArg);\n};\n\n\n/**\n * Load not yet loaded URI.\n * When rendering a feature with an icon style, the vector renderer will\n * automatically call this method. However, you might want to call this\n * method yourself for preloading or other purposes.\n * @api\n */\nol.style.Icon.prototype.load = function() {\n  this.iconImage_.load();\n};\n\n\n/**\n * @inheritDoc\n */\nol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) {\n  ol.events.unlisten(this.iconImage_, ol.events.EventType.CHANGE,\n      listener, thisArg);\n};\n\n\n/**\n * Icon anchor units. One of 'fraction', 'pixels'.\n * @enum {string}\n */\nol.style.Icon.AnchorUnits = {\n  FRACTION: 'fraction',\n  PIXELS: 'pixels'\n};\n\n\n/**\n * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'.\n * @enum {string}\n */\nol.style.Icon.Origin = {\n  BOTTOM_LEFT: 'bottom-left',\n  BOTTOM_RIGHT: 'bottom-right',\n  TOP_LEFT: 'top-left',\n  TOP_RIGHT: 'top-right'\n};\n\ngoog.provide('ol.style.Text');\n\n\ngoog.require('ol.style.Fill');\n\n\n/**\n * @classdesc\n * Set text style for vector features.\n *\n * @constructor\n * @param {olx.style.TextOptions=} opt_options Options.\n * @api\n */\nol.style.Text = function(opt_options) {\n\n  var options = opt_options || {};\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.font_ = options.font;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.rotation_ = options.rotation;\n\n  /**\n   * @private\n   * @type {boolean|undefined}\n   */\n  this.rotateWithView_ = options.rotateWithView;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.scale_ = options.scale;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.text_ = options.text;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.textAlign_ = options.textAlign;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.textBaseline_ = options.textBaseline;\n\n  /**\n   * @private\n   * @type {ol.style.Fill}\n   */\n  this.fill_ = options.fill !== undefined ? options.fill :\n      new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_});\n\n  /**\n   * @private\n   * @type {ol.style.Stroke}\n   */\n  this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0;\n};\n\n\n/**\n * The default fill color to use if no fill was set at construction time; a\n * blackish `#333`.\n *\n * @const {string}\n * @private\n */\nol.style.Text.DEFAULT_FILL_COLOR_ = '#333';\n\n\n/**\n * Clones the style.\n * @return {ol.style.Text} The cloned style.\n * @api\n */\nol.style.Text.prototype.clone = function() {\n  return new ol.style.Text({\n    font: this.getFont(),\n    rotation: this.getRotation(),\n    rotateWithView: this.getRotateWithView(),\n    scale: this.getScale(),\n    text: this.getText(),\n    textAlign: this.getTextAlign(),\n    textBaseline: this.getTextBaseline(),\n    fill: this.getFill() ? this.getFill().clone() : undefined,\n    stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n    offsetX: this.getOffsetX(),\n    offsetY: this.getOffsetY()\n  });\n};\n\n\n/**\n * Get the font name.\n * @return {string|undefined} Font.\n * @api\n */\nol.style.Text.prototype.getFont = function() {\n  return this.font_;\n};\n\n\n/**\n * Get the x-offset for the text.\n * @return {number} Horizontal text offset.\n * @api\n */\nol.style.Text.prototype.getOffsetX = function() {\n  return this.offsetX_;\n};\n\n\n/**\n * Get the y-offset for the text.\n * @return {number} Vertical text offset.\n * @api\n */\nol.style.Text.prototype.getOffsetY = function() {\n  return this.offsetY_;\n};\n\n\n/**\n * Get the fill style for the text.\n * @return {ol.style.Fill} Fill style.\n * @api\n */\nol.style.Text.prototype.getFill = function() {\n  return this.fill_;\n};\n\n\n/**\n * Determine whether the text rotates with the map.\n * @return {boolean|undefined} Rotate with map.\n * @api\n */\nol.style.Text.prototype.getRotateWithView = function() {\n  return this.rotateWithView_;\n};\n\n\n/**\n * Get the text rotation.\n * @return {number|undefined} Rotation.\n * @api\n */\nol.style.Text.prototype.getRotation = function() {\n  return this.rotation_;\n};\n\n\n/**\n * Get the text scale.\n * @return {number|undefined} Scale.\n * @api\n */\nol.style.Text.prototype.getScale = function() {\n  return this.scale_;\n};\n\n\n/**\n * Get the stroke style for the text.\n * @return {ol.style.Stroke} Stroke style.\n * @api\n */\nol.style.Text.prototype.getStroke = function() {\n  return this.stroke_;\n};\n\n\n/**\n * Get the text to be rendered.\n * @return {string|undefined} Text.\n * @api\n */\nol.style.Text.prototype.getText = function() {\n  return this.text_;\n};\n\n\n/**\n * Get the text alignment.\n * @return {string|undefined} Text align.\n * @api\n */\nol.style.Text.prototype.getTextAlign = function() {\n  return this.textAlign_;\n};\n\n\n/**\n * Get the text baseline.\n * @return {string|undefined} Text baseline.\n * @api\n */\nol.style.Text.prototype.getTextBaseline = function() {\n  return this.textBaseline_;\n};\n\n\n/**\n * Set the font.\n *\n * @param {string|undefined} font Font.\n * @api\n */\nol.style.Text.prototype.setFont = function(font) {\n  this.font_ = font;\n};\n\n\n/**\n * Set the x offset.\n *\n * @param {number} offsetX Horizontal text offset.\n * @api\n */\nol.style.Text.prototype.setOffsetX = function(offsetX) {\n  this.offsetX_ = offsetX;\n};\n\n\n/**\n * Set the y offset.\n *\n * @param {number} offsetY Vertical text offset.\n * @api\n */\nol.style.Text.prototype.setOffsetY = function(offsetY) {\n  this.offsetY_ = offsetY;\n};\n\n\n/**\n * Set the fill.\n *\n * @param {ol.style.Fill} fill Fill style.\n * @api\n */\nol.style.Text.prototype.setFill = function(fill) {\n  this.fill_ = fill;\n};\n\n\n/**\n * Set the rotation.\n *\n * @param {number|undefined} rotation Rotation.\n * @api\n */\nol.style.Text.prototype.setRotation = function(rotation) {\n  this.rotation_ = rotation;\n};\n\n\n/**\n * Set the scale.\n *\n * @param {number|undefined} scale Scale.\n * @api\n */\nol.style.Text.prototype.setScale = function(scale) {\n  this.scale_ = scale;\n};\n\n\n/**\n * Set the stroke.\n *\n * @param {ol.style.Stroke} stroke Stroke style.\n * @api\n */\nol.style.Text.prototype.setStroke = function(stroke) {\n  this.stroke_ = stroke;\n};\n\n\n/**\n * Set the text.\n *\n * @param {string|undefined} text Text.\n * @api\n */\nol.style.Text.prototype.setText = function(text) {\n  this.text_ = text;\n};\n\n\n/**\n * Set the text alignment.\n *\n * @param {string|undefined} textAlign Text align.\n * @api\n */\nol.style.Text.prototype.setTextAlign = function(textAlign) {\n  this.textAlign_ = textAlign;\n};\n\n\n/**\n * Set the text baseline.\n *\n * @param {string|undefined} textBaseline Text baseline.\n * @api\n */\nol.style.Text.prototype.setTextBaseline = function(textBaseline) {\n  this.textBaseline_ = textBaseline;\n};\n\n// FIXME http://earth.google.com/kml/1.0 namespace?\n// FIXME why does node.getAttribute return an unknown type?\n// FIXME serialize arbitrary feature properties\n// FIXME don't parse style if extractStyles is false\n\ngoog.provide('ol.format.KML');\n\ngoog.require('ol');\ngoog.require('ol.Feature');\ngoog.require('ol.array');\ngoog.require('ol.asserts');\ngoog.require('ol.color');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.XMLFeature');\ngoog.require('ol.format.XSD');\ngoog.require('ol.geom.GeometryCollection');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.LinearRing');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.math');\ngoog.require('ol.proj');\ngoog.require('ol.style.Fill');\ngoog.require('ol.style.Icon');\ngoog.require('ol.style.Stroke');\ngoog.require('ol.style.Style');\ngoog.require('ol.style.Text');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the KML format.\n *\n * Note that the KML format uses the URL() constructor. Older browsers such as IE\n * which do not support this will need a URL polyfill to be loaded before use.\n *\n * @constructor\n * @extends {ol.format.XMLFeature}\n * @param {olx.format.KMLOptions=} opt_options Options.\n * @api stable\n */\nol.format.KML = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.XMLFeature.call(this);\n\n  if (!ol.format.KML.DEFAULT_STYLE_ARRAY_) {\n    ol.format.KML.createStyleDefaults_();\n  }\n\n  /**\n   * @inheritDoc\n   */\n  this.defaultDataProjection = ol.proj.get('EPSG:4326');\n\n  /**\n   * @private\n   * @type {Array.<ol.style.Style>}\n   */\n  this.defaultStyle_ = options.defaultStyle ?\n      options.defaultStyle : ol.format.KML.DEFAULT_STYLE_ARRAY_;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.extractStyles_ = options.extractStyles !== undefined ?\n      options.extractStyles : true;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.writeStyles_ = options.writeStyles !== undefined ?\n      options.writeStyles : true;\n\n  /**\n   * @private\n   * @type {Object.<string, (Array.<ol.style.Style>|string)>}\n   */\n  this.sharedStyles_ = {};\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.showPointNames_ = options.showPointNames !== undefined ?\n      options.showPointNames : true;\n\n};\nol.inherits(ol.format.KML, ol.format.XMLFeature);\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.KML.EXTENSIONS_ = ['.kml'];\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.KML.GX_NAMESPACE_URIS_ = [\n  'http://www.google.com/kml/ext/2.2'\n];\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.KML.NAMESPACE_URIS_ = [\n  null,\n  'http://earth.google.com/kml/2.0',\n  'http://earth.google.com/kml/2.1',\n  'http://earth.google.com/kml/2.2',\n  'http://www.opengis.net/kml/2.2'\n];\n\n\n/**\n * @const\n * @type {string}\n * @private\n */\nol.format.KML.SCHEMA_LOCATION_ = 'http://www.opengis.net/kml/2.2 ' +\n    'https://developers.google.com/kml/schema/kml22gx.xsd';\n\n\n/**\n * @return {Array.<ol.style.Style>} Default style.\n * @private\n */\nol.format.KML.createStyleDefaults_ = function() {\n  /**\n   * @const\n   * @type {ol.Color}\n   * @private\n   */\n  ol.format.KML.DEFAULT_COLOR_ = [255, 255, 255, 1];\n\n  /**\n   * @const\n   * @type {ol.style.Fill}\n   * @private\n   */\n  ol.format.KML.DEFAULT_FILL_STYLE_ = new ol.style.Fill({\n    color: ol.format.KML.DEFAULT_COLOR_\n  });\n\n  /**\n   * @const\n   * @type {ol.Size}\n   * @private\n   */\n  ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_ = [20, 2]; // FIXME maybe [8, 32] ?\n\n  /**\n   * @const\n   * @type {ol.style.Icon.AnchorUnits}\n   * @private\n   */\n  ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_ =\n      ol.style.Icon.AnchorUnits.PIXELS;\n\n  /**\n   * @const\n   * @type {ol.style.Icon.AnchorUnits}\n   * @private\n   */\n  ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_ =\n      ol.style.Icon.AnchorUnits.PIXELS;\n\n  /**\n   * @const\n   * @type {ol.Size}\n   * @private\n   */\n  ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_ = [64, 64];\n\n  /**\n   * @const\n   * @type {string}\n   * @private\n   */\n  ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ =\n      'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png';\n\n  /**\n   * @const\n   * @type {number}\n   * @private\n   */\n  ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_ = 0.5;\n\n  /**\n   * @const\n   * @type {ol.style.Image}\n   * @private\n   */\n  ol.format.KML.DEFAULT_IMAGE_STYLE_ = new ol.style.Icon({\n    anchor: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_,\n    anchorOrigin: ol.style.Icon.Origin.BOTTOM_LEFT,\n    anchorXUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_,\n    anchorYUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_,\n    crossOrigin: 'anonymous',\n    rotation: 0,\n    scale: ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_,\n    size: ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_,\n    src: ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_\n  });\n\n  /**\n   * @const\n   * @type {string}\n   * @private\n   */\n  ol.format.KML.DEFAULT_NO_IMAGE_STYLE_ = 'NO_IMAGE';\n\n  /**\n   * @const\n   * @type {ol.style.Stroke}\n   * @private\n   */\n  ol.format.KML.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({\n    color: ol.format.KML.DEFAULT_COLOR_,\n    width: 1\n  });\n\n  /**\n   * @const\n   * @type {ol.style.Stroke}\n   * @private\n   */\n  ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_ = new ol.style.Stroke({\n    color: [51, 51, 51, 1],\n    width: 2\n  });\n\n  /**\n   * @const\n   * @type {ol.style.Text}\n   * @private\n   */\n  ol.format.KML.DEFAULT_TEXT_STYLE_ = new ol.style.Text({\n    font: 'bold 16px Helvetica',\n    fill: ol.format.KML.DEFAULT_FILL_STYLE_,\n    stroke: ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_,\n    scale: 0.8\n  });\n\n  /**\n   * @const\n   * @type {ol.style.Style}\n   * @private\n   */\n  ol.format.KML.DEFAULT_STYLE_ = new ol.style.Style({\n    fill: ol.format.KML.DEFAULT_FILL_STYLE_,\n    image: ol.format.KML.DEFAULT_IMAGE_STYLE_,\n    text: ol.format.KML.DEFAULT_TEXT_STYLE_,\n    stroke: ol.format.KML.DEFAULT_STROKE_STYLE_,\n    zIndex: 0\n  });\n\n  /**\n   * @const\n   * @type {Array.<ol.style.Style>}\n   * @private\n   */\n  ol.format.KML.DEFAULT_STYLE_ARRAY_ = [ol.format.KML.DEFAULT_STYLE_];\n\n  return ol.format.KML.DEFAULT_STYLE_ARRAY_;\n};\n\n\n/**\n * @const\n * @type {Object.<string, ol.style.Icon.AnchorUnits>}\n * @private\n */\nol.format.KML.ICON_ANCHOR_UNITS_MAP_ = {\n  'fraction': ol.style.Icon.AnchorUnits.FRACTION,\n  'pixels': ol.style.Icon.AnchorUnits.PIXELS\n};\n\n\n/**\n * @param {ol.style.Style|undefined} foundStyle Style.\n * @param {string} name Name.\n * @return {ol.style.Style} style Style.\n * @private\n */\nol.format.KML.createNameStyleFunction_ = function(foundStyle, name) {\n  var textStyle = null;\n  var textOffset = [0, 0];\n  var textAlign = 'start';\n  if (foundStyle.getImage()) {\n    var imageSize = foundStyle.getImage().getImageSize();\n    if (imageSize === null) {\n      imageSize = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_;\n    }\n    if (imageSize.length == 2) {\n      var imageScale = foundStyle.getImage().getScale();\n      // Offset the label to be centered to the right of the icon, if there is\n      // one.\n      textOffset[0] = imageScale * imageSize[0] / 2;\n      textOffset[1] = -imageScale * imageSize[1] / 2;\n      textAlign = 'left';\n    }\n  }\n  if (foundStyle.getText() !== null) {\n    // clone the text style, customizing it with name, alignments and offset.\n    // Note that kml does not support many text options that OpenLayers does (rotation, textBaseline).\n    var foundText = foundStyle.getText();\n    textStyle = foundText.clone();\n    textStyle.setFont(foundText.getFont() || ol.format.KML.DEFAULT_TEXT_STYLE_.getFont());\n    textStyle.setScale(foundText.getScale() || ol.format.KML.DEFAULT_TEXT_STYLE_.getScale());\n    textStyle.setFill(foundText.getFill() || ol.format.KML.DEFAULT_TEXT_STYLE_.getFill());\n    textStyle.setStroke(foundText.getStroke() || ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_);\n  } else {\n    textStyle = ol.format.KML.DEFAULT_TEXT_STYLE_.clone();\n  }\n  textStyle.setText(name);\n  textStyle.setOffsetX(textOffset[0]);\n  textStyle.setOffsetY(textOffset[1]);\n  textStyle.setTextAlign(textAlign);\n\n  var nameStyle = new ol.style.Style({\n    text: textStyle\n  });\n  return nameStyle;\n};\n\n\n/**\n * @param {Array.<ol.style.Style>|undefined} style Style.\n * @param {string} styleUrl Style URL.\n * @param {Array.<ol.style.Style>} defaultStyle Default style.\n * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles Shared\n *          styles.\n * @param {boolean|undefined} showPointNames true to show names for point\n *          placemarks.\n * @return {ol.FeatureStyleFunction} Feature style function.\n * @private\n */\nol.format.KML.createFeatureStyleFunction_ = function(style, styleUrl,\n    defaultStyle, sharedStyles, showPointNames) {\n\n  return (\n      /**\n       * @param {number} resolution Resolution.\n       * @return {Array.<ol.style.Style>} Style.\n       * @this {ol.Feature}\n       */\n      function(resolution) {\n        var drawName = showPointNames;\n        /** @type {ol.style.Style|undefined} */\n        var nameStyle;\n        var name = '';\n        if (drawName) {\n          if (this.getGeometry()) {\n            drawName = (this.getGeometry().getType() ===\n                        ol.geom.GeometryType.POINT);\n          }\n        }\n\n        if (drawName) {\n          name = /** @type {string} */ (this.get('name'));\n          drawName = drawName && name;\n        }\n\n        if (style) {\n          if (drawName) {\n            nameStyle = ol.format.KML.createNameStyleFunction_(style[0],\n                name);\n            return style.concat(nameStyle);\n          }\n          return style;\n        }\n        if (styleUrl) {\n          var foundStyle = ol.format.KML.findStyle_(styleUrl, defaultStyle,\n              sharedStyles);\n          if (drawName) {\n            nameStyle = ol.format.KML.createNameStyleFunction_(foundStyle[0],\n                name);\n            return foundStyle.concat(nameStyle);\n          }\n          return foundStyle;\n        }\n        if (drawName) {\n          nameStyle = ol.format.KML.createNameStyleFunction_(defaultStyle[0],\n              name);\n          return defaultStyle.concat(nameStyle);\n        }\n        return defaultStyle;\n      });\n};\n\n\n/**\n * @param {Array.<ol.style.Style>|string|undefined} styleValue Style value.\n * @param {Array.<ol.style.Style>} defaultStyle Default style.\n * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles\n * Shared styles.\n * @return {Array.<ol.style.Style>} Style.\n * @private\n */\nol.format.KML.findStyle_ = function(styleValue, defaultStyle, sharedStyles) {\n  if (Array.isArray(styleValue)) {\n    return styleValue;\n  } else if (typeof styleValue === 'string') {\n    // KML files in the wild occasionally forget the leading `#` on styleUrls\n    // defined in the same document.  Add a leading `#` if it enables to find\n    // a style.\n    if (!(styleValue in sharedStyles) && ('#' + styleValue in sharedStyles)) {\n      styleValue = '#' + styleValue;\n    }\n    return ol.format.KML.findStyle_(\n        sharedStyles[styleValue], defaultStyle, sharedStyles);\n  } else {\n    return defaultStyle;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @private\n * @return {ol.Color|undefined} Color.\n */\nol.format.KML.readColor_ = function(node) {\n  var s = ol.xml.getAllTextContent(node, false);\n  // The KML specification states that colors should not include a leading `#`\n  // but we tolerate them.\n  var m = /^\\s*#?\\s*([0-9A-Fa-f]{8})\\s*$/.exec(s);\n  if (m) {\n    var hexColor = m[1];\n    return [\n      parseInt(hexColor.substr(6, 2), 16),\n      parseInt(hexColor.substr(4, 2), 16),\n      parseInt(hexColor.substr(2, 2), 16),\n      parseInt(hexColor.substr(0, 2), 16) / 255\n    ];\n\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @private\n * @return {Array.<number>|undefined} Flat coordinates.\n */\nol.format.KML.readFlatCoordinates_ = function(node) {\n  var s = ol.xml.getAllTextContent(node, false);\n  var flatCoordinates = [];\n  // The KML specification states that coordinate tuples should not include\n  // spaces, but we tolerate them.\n  var re =\n      /^\\s*([+\\-]?\\d*\\.?\\d+(?:e[+\\-]?\\d+)?)\\s*,\\s*([+\\-]?\\d*\\.?\\d+(?:e[+\\-]?\\d+)?)(?:\\s*,\\s*([+\\-]?\\d*\\.?\\d+(?:e[+\\-]?\\d+)?))?\\s*/i;\n  var m;\n  while ((m = re.exec(s))) {\n    var x = parseFloat(m[1]);\n    var y = parseFloat(m[2]);\n    var z = m[3] ? parseFloat(m[3]) : 0;\n    flatCoordinates.push(x, y, z);\n    s = s.substr(m[0].length);\n  }\n  if (s !== '') {\n    return undefined;\n  }\n  return flatCoordinates;\n};\n\n\n/**\n * @param {Node} node Node.\n * @private\n * @return {string} URI.\n */\nol.format.KML.readURI_ = function(node) {\n  var s = ol.xml.getAllTextContent(node, false).trim();\n  if (node.baseURI) {\n    var url = new URL(s, node.baseURI);\n    return url.href;\n  } else {\n    return s;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @private\n * @return {ol.KMLVec2_} Vec2.\n */\nol.format.KML.readVec2_ = function(node) {\n  var xunits = node.getAttribute('xunits');\n  var yunits = node.getAttribute('yunits');\n  return {\n    x: parseFloat(node.getAttribute('x')),\n    xunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[xunits],\n    y: parseFloat(node.getAttribute('y')),\n    yunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[yunits]\n  };\n};\n\n\n/**\n * @param {Node} node Node.\n * @private\n * @return {number|undefined} Scale.\n */\nol.format.KML.readScale_ = function(node) {\n  return ol.format.XSD.readDecimal(node);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<ol.style.Style>|string|undefined} StyleMap.\n */\nol.format.KML.readStyleMapValue_ = function(node, objectStack) {\n  return ol.xml.pushParseAndPop(undefined,\n      ol.format.KML.STYLE_MAP_PARSERS_, node, objectStack);\n};\n /**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.IconStyleParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be an ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'IconStyle',\n      'localName should be IconStyle');\n  // FIXME refreshMode\n  // FIXME refreshInterval\n  // FIXME viewRefreshTime\n  // FIXME viewBoundScale\n  // FIXME viewFormat\n  // FIXME httpQuery\n  var object = ol.xml.pushParseAndPop(\n      {}, ol.format.KML.ICON_STYLE_PARSERS_, node, objectStack);\n  if (!object) {\n    return;\n  }\n  var styleObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var IconObject = 'Icon' in object ? object['Icon'] : {};\n  var drawIcon = (!('Icon' in object) || Object.keys(IconObject).length > 0);\n  var src;\n  var href = /** @type {string|undefined} */\n      (IconObject['href']);\n  if (href) {\n    src = href;\n  } else if (drawIcon) {\n    src = ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_;\n  }\n  var anchor, anchorXUnits, anchorYUnits;\n  var hotSpot = /** @type {ol.KMLVec2_|undefined} */\n      (object['hotSpot']);\n  if (hotSpot) {\n    anchor = [hotSpot.x, hotSpot.y];\n    anchorXUnits = hotSpot.xunits;\n    anchorYUnits = hotSpot.yunits;\n  } else if (src === ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) {\n    anchor = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_;\n    anchorXUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_;\n    anchorYUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_;\n  } else if (/^http:\\/\\/maps\\.(?:google|gstatic)\\.com\\//.test(src)) {\n    anchor = [0.5, 0];\n    anchorXUnits = ol.style.Icon.AnchorUnits.FRACTION;\n    anchorYUnits = ol.style.Icon.AnchorUnits.FRACTION;\n  }\n\n  var offset;\n  var x = /** @type {number|undefined} */\n      (IconObject['x']);\n  var y = /** @type {number|undefined} */\n      (IconObject['y']);\n  if (x !== undefined && y !== undefined) {\n    offset = [x, y];\n  }\n\n  var size;\n  var w = /** @type {number|undefined} */\n      (IconObject['w']);\n  var h = /** @type {number|undefined} */\n      (IconObject['h']);\n  if (w !== undefined && h !== undefined) {\n    size = [w, h];\n  }\n\n  var rotation;\n  var heading = /** @type {number} */\n      (object['heading']);\n  if (heading !== undefined) {\n    rotation = ol.math.toRadians(heading);\n  }\n\n  var scale = /** @type {number|undefined} */\n      (object['scale']);\n\n  if (drawIcon) {\n    if (src == ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) {\n      size = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_;\n      if (scale === undefined) {\n        scale = ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_;\n      }\n    }\n\n    var imageStyle = new ol.style.Icon({\n      anchor: anchor,\n      anchorOrigin: ol.style.Icon.Origin.BOTTOM_LEFT,\n      anchorXUnits: anchorXUnits,\n      anchorYUnits: anchorYUnits,\n      crossOrigin: 'anonymous', // FIXME should this be configurable?\n      offset: offset,\n      offsetOrigin: ol.style.Icon.Origin.BOTTOM_LEFT,\n      rotation: rotation,\n      scale: scale,\n      size: size,\n      src: src\n    });\n    styleObject['imageStyle'] = imageStyle;\n  } else {\n    // handle the case when we explicitly want to draw no icon.\n    styleObject['imageStyle'] = ol.format.KML.DEFAULT_NO_IMAGE_STYLE_;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.LabelStyleParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LabelStyle',\n      'localName should be LabelStyle');\n  // FIXME colorMode\n  var object = ol.xml.pushParseAndPop(\n      {}, ol.format.KML.LABEL_STYLE_PARSERS_, node, objectStack);\n  if (!object) {\n    return;\n  }\n  var styleObject = objectStack[objectStack.length - 1];\n  var textStyle = new ol.style.Text({\n    fill: new ol.style.Fill({\n      color: /** @type {ol.Color} */\n          ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_)\n    }),\n    scale: /** @type {number|undefined} */\n        (object['scale'])\n  });\n  styleObject['textStyle'] = textStyle;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.LineStyleParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LineStyle',\n      'localName should be LineStyle');\n  // FIXME colorMode\n  // FIXME gx:outerColor\n  // FIXME gx:outerWidth\n  // FIXME gx:physicalWidth\n  // FIXME gx:labelVisibility\n  var object = ol.xml.pushParseAndPop(\n      {}, ol.format.KML.LINE_STYLE_PARSERS_, node, objectStack);\n  if (!object) {\n    return;\n  }\n  var styleObject = objectStack[objectStack.length - 1];\n  var strokeStyle = new ol.style.Stroke({\n    color: /** @type {ol.Color} */\n        ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_),\n    width: /** @type {number} */ ('width' in object ? object['width'] : 1)\n  });\n  styleObject['strokeStyle'] = strokeStyle;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.PolyStyleParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'PolyStyle',\n      'localName should be PolyStyle');\n  // FIXME colorMode\n  var object = ol.xml.pushParseAndPop(\n      {}, ol.format.KML.POLY_STYLE_PARSERS_, node, objectStack);\n  if (!object) {\n    return;\n  }\n  var styleObject = objectStack[objectStack.length - 1];\n  var fillStyle = new ol.style.Fill({\n    color: /** @type {ol.Color} */\n        ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_)\n  });\n  styleObject['fillStyle'] = fillStyle;\n  var fill = /** @type {boolean|undefined} */ (object['fill']);\n  if (fill !== undefined) {\n    styleObject['fill'] = fill;\n  }\n  var outline =\n      /** @type {boolean|undefined} */ (object['outline']);\n  if (outline !== undefined) {\n    styleObject['outline'] = outline;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>} LinearRing flat coordinates.\n */\nol.format.KML.readFlatLinearRing_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LinearRing',\n      'localName should be LinearRing');\n  return ol.xml.pushParseAndPop(null,\n      ol.format.KML.FLAT_LINEAR_RING_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.gxCoordParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(ol.array.includes(\n      ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI),\n      'namespaceURI of the node should be known to the KML parser');\n  ol.DEBUG && console.assert(node.localName == 'coord', 'localName should be coord');\n  var gxTrackObject = /** @type {ol.KMLGxTrackObject_} */\n      (objectStack[objectStack.length - 1]);\n  var flatCoordinates = gxTrackObject.flatCoordinates;\n  var s = ol.xml.getAllTextContent(node, false);\n  var re =\n      /^\\s*([+\\-]?\\d+(?:\\.\\d*)?(?:e[+\\-]?\\d*)?)\\s+([+\\-]?\\d+(?:\\.\\d*)?(?:e[+\\-]?\\d*)?)\\s+([+\\-]?\\d+(?:\\.\\d*)?(?:e[+\\-]?\\d*)?)\\s*$/i;\n  var m = re.exec(s);\n  if (m) {\n    var x = parseFloat(m[1]);\n    var y = parseFloat(m[2]);\n    var z = parseFloat(m[3]);\n    flatCoordinates.push(x, y, z, 0);\n  } else {\n    flatCoordinates.push(0, 0, 0, 0);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.MultiLineString|undefined} MultiLineString.\n */\nol.format.KML.readGxMultiTrack_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(ol.array.includes(\n      ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI),\n      'namespaceURI of the node should be known to the KML parser');\n  ol.DEBUG && console.assert(node.localName == 'MultiTrack',\n      'localName should be MultiTrack');\n  var lineStrings = ol.xml.pushParseAndPop([],\n      ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_, node, objectStack);\n  if (!lineStrings) {\n    return undefined;\n  }\n  var multiLineString = new ol.geom.MultiLineString(null);\n  multiLineString.setLineStrings(lineStrings);\n  return multiLineString;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.LineString|undefined} LineString.\n */\nol.format.KML.readGxTrack_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(ol.array.includes(\n      ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI),\n      'namespaceURI of the node should be known to the KML parser');\n  ol.DEBUG && console.assert(node.localName == 'Track', 'localName should be Track');\n  var gxTrackObject = ol.xml.pushParseAndPop(\n      /** @type {ol.KMLGxTrackObject_} */ ({\n        flatCoordinates: [],\n        whens: []\n      }), ol.format.KML.GX_TRACK_PARSERS_, node, objectStack);\n  if (!gxTrackObject) {\n    return undefined;\n  }\n  var flatCoordinates = gxTrackObject.flatCoordinates;\n  var whens = gxTrackObject.whens;\n  ol.DEBUG && console.assert(flatCoordinates.length / 4 == whens.length,\n      'the length of the flatCoordinates array divided by 4 should be the ' +\n      'length of the whens array');\n  var i, ii;\n  for (i = 0, ii = Math.min(flatCoordinates.length, whens.length); i < ii;\n       ++i) {\n    flatCoordinates[4 * i + 3] = whens[i];\n  }\n  var lineString = new ol.geom.LineString(null);\n  lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates);\n  return lineString;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object} Icon object.\n */\nol.format.KML.readIcon_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Icon', 'localName should be Icon');\n  var iconObject = ol.xml.pushParseAndPop(\n      {}, ol.format.KML.ICON_PARSERS_, node, objectStack);\n  if (iconObject) {\n    return iconObject;\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<number>} Flat coordinates.\n */\nol.format.KML.readFlatCoordinatesFromNode_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  return ol.xml.pushParseAndPop(null,\n      ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.LineString|undefined} LineString.\n */\nol.format.KML.readLineString_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LineString',\n      'localName should be LineString');\n  var properties = ol.xml.pushParseAndPop({},\n      ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,\n      objectStack);\n  var flatCoordinates =\n      ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);\n  if (flatCoordinates) {\n    var lineString = new ol.geom.LineString(null);\n    lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);\n    lineString.setProperties(properties);\n    return lineString;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.Polygon|undefined} Polygon.\n */\nol.format.KML.readLinearRing_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LinearRing',\n      'localName should be LinearRing');\n  var properties = ol.xml.pushParseAndPop({},\n      ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,\n      objectStack);\n  var flatCoordinates =\n      ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);\n  if (flatCoordinates) {\n    var polygon = new ol.geom.Polygon(null);\n    polygon.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates,\n        [flatCoordinates.length]);\n    polygon.setProperties(properties);\n    return polygon;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.KML.readMultiGeometry_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'MultiGeometry',\n      'localName should be MultiGeometry');\n  var geometries = ol.xml.pushParseAndPop([],\n      ol.format.KML.MULTI_GEOMETRY_PARSERS_, node, objectStack);\n  if (!geometries) {\n    return null;\n  }\n  if (geometries.length === 0) {\n    return new ol.geom.GeometryCollection(geometries);\n  }\n  /** @type {ol.geom.Geometry} */\n  var multiGeometry;\n  var homogeneous = true;\n  var type = geometries[0].getType();\n  var geometry, i, ii;\n  for (i = 1, ii = geometries.length; i < ii; ++i) {\n    geometry = geometries[i];\n    if (geometry.getType() != type) {\n      homogeneous = false;\n      break;\n    }\n  }\n  if (homogeneous) {\n    var layout;\n    var flatCoordinates;\n    if (type == ol.geom.GeometryType.POINT) {\n      var point = geometries[0];\n      layout = point.getLayout();\n      flatCoordinates = point.getFlatCoordinates();\n      for (i = 1, ii = geometries.length; i < ii; ++i) {\n        geometry = geometries[i];\n        ol.DEBUG && console.assert(geometry.getLayout() == layout,\n            'geometry layout should be consistent');\n        ol.array.extend(flatCoordinates, geometry.getFlatCoordinates());\n      }\n      multiGeometry = new ol.geom.MultiPoint(null);\n      multiGeometry.setFlatCoordinates(layout, flatCoordinates);\n      ol.format.KML.setCommonGeometryProperties_(multiGeometry, geometries);\n    } else if (type == ol.geom.GeometryType.LINE_STRING) {\n      multiGeometry = new ol.geom.MultiLineString(null);\n      multiGeometry.setLineStrings(geometries);\n      ol.format.KML.setCommonGeometryProperties_(multiGeometry, geometries);\n    } else if (type == ol.geom.GeometryType.POLYGON) {\n      multiGeometry = new ol.geom.MultiPolygon(null);\n      multiGeometry.setPolygons(geometries);\n      ol.format.KML.setCommonGeometryProperties_(multiGeometry, geometries);\n    } else if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) {\n      multiGeometry = new ol.geom.GeometryCollection(geometries);\n    } else {\n      ol.asserts.assert(false, 37); // Unknown geometry type found\n    }\n  } else {\n    multiGeometry = new ol.geom.GeometryCollection(geometries);\n  }\n  return /** @type {ol.geom.Geometry} */ (multiGeometry);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.Point|undefined} Point.\n */\nol.format.KML.readPoint_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Point', 'localName should be Point');\n  var properties = ol.xml.pushParseAndPop({},\n      ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,\n      objectStack);\n  var flatCoordinates =\n      ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);\n  if (flatCoordinates) {\n    var point = new ol.geom.Point(null);\n    ol.DEBUG && console.assert(flatCoordinates.length == 3,\n        'flatCoordinates should have a length of 3');\n    point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);\n    point.setProperties(properties);\n    return point;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.geom.Polygon|undefined} Polygon.\n */\nol.format.KML.readPolygon_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Polygon',\n      'localName should be Polygon');\n  var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}),\n      ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,\n      objectStack);\n  var flatLinearRings = ol.xml.pushParseAndPop([null],\n      ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack);\n  if (flatLinearRings && flatLinearRings[0]) {\n    var polygon = new ol.geom.Polygon(null);\n    var flatCoordinates = flatLinearRings[0];\n    var ends = [flatCoordinates.length];\n    var i, ii;\n    for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {\n      ol.array.extend(flatCoordinates, flatLinearRings[i]);\n      ends.push(flatCoordinates.length);\n    }\n    polygon.setFlatCoordinates(\n        ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);\n    polygon.setProperties(properties);\n    return polygon;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<ol.style.Style>} Style.\n */\nol.format.KML.readStyle_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Style', 'localName should be Style');\n  var styleObject = ol.xml.pushParseAndPop(\n      {}, ol.format.KML.STYLE_PARSERS_, node, objectStack);\n  if (!styleObject) {\n    return null;\n  }\n  var fillStyle = /** @type {ol.style.Fill} */\n      ('fillStyle' in styleObject ?\n          styleObject['fillStyle'] : ol.format.KML.DEFAULT_FILL_STYLE_);\n  var fill = /** @type {boolean|undefined} */ (styleObject['fill']);\n  if (fill !== undefined && !fill) {\n    fillStyle = null;\n  }\n  var imageStyle = /** @type {ol.style.Image} */\n      ('imageStyle' in styleObject ?\n          styleObject['imageStyle'] : ol.format.KML.DEFAULT_IMAGE_STYLE_);\n  if (imageStyle == ol.format.KML.DEFAULT_NO_IMAGE_STYLE_) {\n    imageStyle = undefined;\n  }\n  var textStyle = /** @type {ol.style.Text} */\n      ('textStyle' in styleObject ?\n          styleObject['textStyle'] : ol.format.KML.DEFAULT_TEXT_STYLE_);\n  var strokeStyle = /** @type {ol.style.Stroke} */\n      ('strokeStyle' in styleObject ?\n          styleObject['strokeStyle'] : ol.format.KML.DEFAULT_STROKE_STYLE_);\n  var outline = /** @type {boolean|undefined} */\n      (styleObject['outline']);\n  if (outline !== undefined && !outline) {\n    strokeStyle = null;\n  }\n  return [new ol.style.Style({\n    fill: fillStyle,\n    image: imageStyle,\n    stroke: strokeStyle,\n    text: textStyle,\n    zIndex: undefined // FIXME\n  })];\n};\n\n\n/**\n * Reads an array of geometries and creates arrays for common geometry\n * properties. Then sets them to the multi geometry.\n * @param {ol.geom.MultiPoint|ol.geom.MultiLineString|ol.geom.MultiPolygon}\n *     multiGeometry A multi-geometry.\n * @param {Array.<ol.geom.Geometry>} geometries List of geometries.\n * @private\n */\nol.format.KML.setCommonGeometryProperties_ = function(multiGeometry,\n    geometries) {\n  var ii = geometries.length;\n  var extrudes = new Array(geometries.length);\n  var altitudeModes = new Array(geometries.length);\n  var geometry, i, hasExtrude, hasAltitudeMode;\n  hasExtrude = hasAltitudeMode = false;\n  for (i = 0; i < ii; ++i) {\n    geometry = geometries[i];\n    extrudes[i] = geometry.get('extrude');\n    altitudeModes[i] = geometry.get('altitudeMode');\n    hasExtrude = hasExtrude || extrudes[i] !== undefined;\n    hasAltitudeMode = hasAltitudeMode || altitudeModes[i];\n  }\n  if (hasExtrude) {\n    multiGeometry.set('extrude', extrudes);\n  }\n  if (hasAltitudeMode) {\n    multiGeometry.set('altitudeMode', altitudeModes);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.DataParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Data', 'localName should be Data');\n  var name = node.getAttribute('name');\n  ol.xml.parseNode(ol.format.KML.DATA_PARSERS_, node, objectStack);\n  var featureObject =\n    /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  if (name !== null) {\n    featureObject[name] = featureObject.value;\n  } else if (featureObject.displayName !== null) {\n    featureObject[featureObject.displayName] = featureObject.value;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.ExtendedDataParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ExtendedData',\n      'localName should be ExtendedData');\n  ol.xml.parseNode(ol.format.KML.EXTENDED_DATA_PARSERS_, node, objectStack);\n};\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.RegionParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Region',\n      'localName should be Region');\n  ol.xml.parseNode(ol.format.KML.REGION_PARSERS_, node, objectStack);\n};\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.PairDataParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Pair', 'localName should be Pair');\n  var pairObject = ol.xml.pushParseAndPop(\n      {}, ol.format.KML.PAIR_PARSERS_, node, objectStack);\n  if (!pairObject) {\n    return;\n  }\n  var key = /** @type {string|undefined} */\n      (pairObject['key']);\n  if (key && key == 'normal') {\n    var styleUrl = /** @type {string|undefined} */\n        (pairObject['styleUrl']);\n    if (styleUrl) {\n      objectStack[objectStack.length - 1] = styleUrl;\n    }\n    var Style = /** @type {ol.style.Style} */\n        (pairObject['Style']);\n    if (Style) {\n      objectStack[objectStack.length - 1] = Style;\n    }\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.PlacemarkStyleMapParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'StyleMap',\n      'localName should be StyleMap');\n  var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack);\n  if (!styleMapValue) {\n    return;\n  }\n  var placemarkObject = objectStack[objectStack.length - 1];\n  if (Array.isArray(styleMapValue)) {\n    placemarkObject['Style'] = styleMapValue;\n  } else if (typeof styleMapValue === 'string') {\n    placemarkObject['styleUrl'] = styleMapValue;\n  } else {\n    ol.asserts.assert(false, 38); // `styleMapValue` has an unknown type\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.SchemaDataParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'SchemaData',\n      'localName should be SchemaData');\n  ol.xml.parseNode(ol.format.KML.SCHEMA_DATA_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.SimpleDataParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'SimpleData',\n      'localName should be SimpleData');\n  var name = node.getAttribute('name');\n  if (name !== null) {\n    var data = ol.format.XSD.readString(node);\n    var featureObject =\n        /** @type {Object} */ (objectStack[objectStack.length - 1]);\n    featureObject[name] = data;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.LatLonAltBoxParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'LatLonAltBox',\n      'localName should be LatLonAltBox');\n  var object = ol.xml.pushParseAndPop({}, ol.format.KML.LAT_LON_ALT_BOX_PARSERS_, node, objectStack);\n  if (!object) {\n    return;\n  }\n  var regionObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var extent = [\n    parseFloat(object['west']),\n    parseFloat(object['south']),\n    parseFloat(object['east']),\n    parseFloat(object['north'])\n  ];\n  regionObject['extent'] = extent;\n  regionObject['altitudeMode'] = object['altitudeMode'];\n  regionObject['minAltitude'] = parseFloat(object['minAltitude']);\n  regionObject['maxAltitude'] = parseFloat(object['maxAltitude']);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.LodParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Lod',\n      'localName should be Lod');\n  var object = ol.xml.pushParseAndPop({}, ol.format.KML.LOD_PARSERS_, node, objectStack);\n  if (!object) {\n    return;\n  }\n  var lodObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  lodObject['minLodPixels'] = parseFloat(object['minLodPixels']);\n  lodObject['maxLodPixels'] = parseFloat(object['maxLodPixels']);\n  lodObject['minFadeExtent'] = parseFloat(object['minFadeExtent']);\n  lodObject['maxFadeExtent'] = parseFloat(object['maxFadeExtent']);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.innerBoundaryIsParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'innerBoundaryIs',\n      'localName should be innerBoundaryIs');\n  /** @type {Array.<number>|undefined} */\n  var flatLinearRing = ol.xml.pushParseAndPop(undefined,\n      ol.format.KML.INNER_BOUNDARY_IS_PARSERS_, node, objectStack);\n  if (flatLinearRing) {\n    var flatLinearRings = /** @type {Array.<Array.<number>>} */\n        (objectStack[objectStack.length - 1]);\n    ol.DEBUG && console.assert(Array.isArray(flatLinearRings),\n        'flatLinearRings should be an array');\n    ol.DEBUG && console.assert(flatLinearRings.length > 0,\n        'flatLinearRings array should not be empty');\n    flatLinearRings.push(flatLinearRing);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.outerBoundaryIsParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'outerBoundaryIs',\n      'localName should be outerBoundaryIs');\n  /** @type {Array.<number>|undefined} */\n  var flatLinearRing = ol.xml.pushParseAndPop(undefined,\n      ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_, node, objectStack);\n  if (flatLinearRing) {\n    var flatLinearRings = /** @type {Array.<Array.<number>>} */\n        (objectStack[objectStack.length - 1]);\n    ol.DEBUG && console.assert(Array.isArray(flatLinearRings),\n        'flatLinearRings should be an array');\n    ol.DEBUG && console.assert(flatLinearRings.length > 0,\n        'flatLinearRings array should not be empty');\n    flatLinearRings[0] = flatLinearRing;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.LinkParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Link', 'localName should be Link');\n  ol.xml.parseNode(ol.format.KML.LINK_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.whenParser_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'when', 'localName should be when');\n  var gxTrackObject = /** @type {ol.KMLGxTrackObject_} */\n      (objectStack[objectStack.length - 1]);\n  var whens = gxTrackObject.whens;\n  var s = ol.xml.getAllTextContent(node, false);\n  var when = Date.parse(s);\n  whens.push(isNaN(when) ? 0 : when);\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.DATA_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'displayName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'value': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.EXTENDED_DATA_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Data': ol.format.KML.DataParser_,\n      'SchemaData': ol.format.KML.SchemaDataParser_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.REGION_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'LatLonAltBox': ol.format.KML.LatLonAltBoxParser_,\n      'Lod': ol.format.KML.LodParser_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.LAT_LON_ALT_BOX_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'minAltitude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'maxAltitude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'north': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'south': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'east': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'west': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.LOD_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'minLodPixels': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'maxLodPixels': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'minFadeExtent': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'maxFadeExtent': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'extrude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),\n      'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.FLAT_LINEAR_RING_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.FLAT_LINEAR_RINGS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'innerBoundaryIs': ol.format.KML.innerBoundaryIsParser_,\n      'outerBoundaryIs': ol.format.KML.outerBoundaryIsParser_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.GX_TRACK_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'when': ol.format.KML.whenParser_\n    }, ol.xml.makeStructureNS(\n        ol.format.KML.GX_NAMESPACE_URIS_, {\n          'coord': ol.format.KML.gxCoordParser_\n        }));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.ICON_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)\n    }, ol.xml.makeStructureNS(\n        ol.format.KML.GX_NAMESPACE_URIS_, {\n          'x': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n          'y': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n          'w': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n          'h': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)\n        }));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.ICON_STYLE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Icon': ol.xml.makeObjectPropertySetter(ol.format.KML.readIcon_),\n      'heading': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),\n      'hotSpot': ol.xml.makeObjectPropertySetter(ol.format.KML.readVec2_),\n      'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.INNER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.LABEL_STYLE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),\n      'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.LINE_STYLE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),\n      'width': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.MULTI_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'LineString': ol.xml.makeArrayPusher(ol.format.KML.readLineString_),\n      'LinearRing': ol.xml.makeArrayPusher(ol.format.KML.readLinearRing_),\n      'MultiGeometry': ol.xml.makeArrayPusher(ol.format.KML.readMultiGeometry_),\n      'Point': ol.xml.makeArrayPusher(ol.format.KML.readPoint_),\n      'Polygon': ol.xml.makeArrayPusher(ol.format.KML.readPolygon_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.GX_NAMESPACE_URIS_, {\n      'Track': ol.xml.makeArrayPusher(ol.format.KML.readGxTrack_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.NETWORK_LINK_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'ExtendedData': ol.format.KML.ExtendedDataParser_,\n      'Region': ol.format.KML.RegionParser_,\n      'Link': ol.format.KML.LinkParser_,\n      'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),\n      'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.LINK_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.OUTER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.PAIR_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_),\n      'key': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.PLACEMARK_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'ExtendedData': ol.format.KML.ExtendedDataParser_,\n      'Region': ol.format.KML.RegionParser_,\n      'MultiGeometry': ol.xml.makeObjectPropertySetter(\n          ol.format.KML.readMultiGeometry_, 'geometry'),\n      'LineString': ol.xml.makeObjectPropertySetter(\n          ol.format.KML.readLineString_, 'geometry'),\n      'LinearRing': ol.xml.makeObjectPropertySetter(\n          ol.format.KML.readLinearRing_, 'geometry'),\n      'Point': ol.xml.makeObjectPropertySetter(\n          ol.format.KML.readPoint_, 'geometry'),\n      'Polygon': ol.xml.makeObjectPropertySetter(\n          ol.format.KML.readPolygon_, 'geometry'),\n      'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_),\n      'StyleMap': ol.format.KML.PlacemarkStyleMapParser_,\n      'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),\n      'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_),\n      'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)\n    }, ol.xml.makeStructureNS(\n        ol.format.KML.GX_NAMESPACE_URIS_, {\n          'MultiTrack': ol.xml.makeObjectPropertySetter(\n              ol.format.KML.readGxMultiTrack_, 'geometry'),\n          'Track': ol.xml.makeObjectPropertySetter(\n              ol.format.KML.readGxTrack_, 'geometry')\n        }\n    ));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.POLY_STYLE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),\n      'fill': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),\n      'outline': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.SCHEMA_DATA_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'SimpleData': ol.format.KML.SimpleDataParser_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.STYLE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'IconStyle': ol.format.KML.IconStyleParser_,\n      'LabelStyle': ol.format.KML.LabelStyleParser_,\n      'LineStyle': ol.format.KML.LineStyleParser_,\n      'PolyStyle': ol.format.KML.PolyStyleParser_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.KML.STYLE_MAP_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Pair': ol.format.KML.PairDataParser_\n    });\n\n\n/**\n * @inheritDoc\n */\nol.format.KML.prototype.getExtensions = function() {\n  return ol.format.KML.EXTENSIONS_;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<ol.Feature>|undefined} Features.\n */\nol.format.KML.prototype.readDocumentOrFolder_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  var localName = node.localName;\n  ol.DEBUG && console.assert(localName == 'Document' || localName == 'Folder',\n      'localName should be Document or Folder');\n  // FIXME use scope somehow\n  var parsersNS = ol.xml.makeStructureNS(\n      ol.format.KML.NAMESPACE_URIS_, {\n        'Document': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this),\n        'Folder': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this),\n        'Placemark': ol.xml.makeArrayPusher(this.readPlacemark_, this),\n        'Style': this.readSharedStyle_.bind(this),\n        'StyleMap': this.readSharedStyleMap_.bind(this)\n      });\n  /** @type {Array.<ol.Feature>} */\n  var features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack, this);\n  if (features) {\n    return features;\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {ol.Feature|undefined} Feature.\n */\nol.format.KML.prototype.readPlacemark_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Placemark',\n      'localName should be Placemark');\n  var object = ol.xml.pushParseAndPop({'geometry': null},\n      ol.format.KML.PLACEMARK_PARSERS_, node, objectStack);\n  if (!object) {\n    return undefined;\n  }\n  var feature = new ol.Feature();\n  var id = node.getAttribute('id');\n  if (id !== null) {\n    feature.setId(id);\n  }\n  var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);\n\n  var geometry = object['geometry'];\n  if (geometry) {\n    ol.format.Feature.transformWithOptions(geometry, false, options);\n  }\n  feature.setGeometry(geometry);\n  delete object['geometry'];\n\n  if (this.extractStyles_) {\n    var style = object['Style'];\n    var styleUrl = object['styleUrl'];\n    var styleFunction = ol.format.KML.createFeatureStyleFunction_(\n        style, styleUrl, this.defaultStyle_, this.sharedStyles_,\n        this.showPointNames_);\n    feature.setStyle(styleFunction);\n  }\n  delete object['Style'];\n  // we do not remove the styleUrl property from the object, so it\n  // gets stored on feature when setProperties is called\n\n  feature.setProperties(object);\n\n  return feature;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.prototype.readSharedStyle_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Style', 'localName should be Style');\n  var id = node.getAttribute('id');\n  if (id !== null) {\n    var style = ol.format.KML.readStyle_(node, objectStack);\n    if (style) {\n      var styleUri;\n      if (node.baseURI) {\n        var url = new URL('#' + id, node.baseURI);\n        styleUri = url.href;\n      } else {\n        styleUri = '#' + id;\n      }\n      this.sharedStyles_[styleUri] = style;\n    }\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.prototype.readSharedStyleMap_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'StyleMap',\n      'localName should be StyleMap');\n  var id = node.getAttribute('id');\n  if (id === null) {\n    return;\n  }\n  var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack);\n  if (!styleMapValue) {\n    return;\n  }\n  var styleUri;\n  if (node.baseURI) {\n    var url = new URL('#' + id, node.baseURI);\n    styleUri = url.href;\n  } else {\n    styleUri = '#' + id;\n  }\n  this.sharedStyles_[styleUri] = styleMapValue;\n};\n\n\n/**\n * Read the first feature from a KML source. MultiGeometries are converted into\n * GeometryCollections if they are a mix of geometry types, and into MultiPoint/\n * MultiLineString/MultiPolygon if they are all of the same type.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @api stable\n */\nol.format.KML.prototype.readFeature;\n\n\n/**\n * @inheritDoc\n */\nol.format.KML.prototype.readFeatureFromNode = function(node, opt_options) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) {\n    return null;\n  }\n  ol.DEBUG && console.assert(node.localName == 'Placemark',\n      'localName should be Placemark');\n  var feature = this.readPlacemark_(\n      node, [this.getReadOptions(node, opt_options)]);\n  if (feature) {\n    return feature;\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * Read all features from a KML source. MultiGeometries are converted into\n * GeometryCollections if they are a mix of geometry types, and into MultiPoint/\n * MultiLineString/MultiPolygon if they are all of the same type.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.KML.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.KML.prototype.readFeaturesFromNode = function(node, opt_options) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) {\n    return [];\n  }\n  var features;\n  var localName = node.localName;\n  if (localName == 'Document' || localName == 'Folder') {\n    features = this.readDocumentOrFolder_(\n        node, [this.getReadOptions(node, opt_options)]);\n    if (features) {\n      return features;\n    } else {\n      return [];\n    }\n  } else if (localName == 'Placemark') {\n    var feature = this.readPlacemark_(\n        node, [this.getReadOptions(node, opt_options)]);\n    if (feature) {\n      return [feature];\n    } else {\n      return [];\n    }\n  } else if (localName == 'kml') {\n    features = [];\n    var n;\n    for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n      var fs = this.readFeaturesFromNode(n, opt_options);\n      if (fs) {\n        ol.array.extend(features, fs);\n      }\n    }\n    return features;\n  } else {\n    return [];\n  }\n};\n\n\n/**\n * Read the name of the KML.\n *\n * @param {Document|Node|string} source Souce.\n * @return {string|undefined} Name.\n * @api stable\n */\nol.format.KML.prototype.readName = function(source) {\n  if (ol.xml.isDocument(source)) {\n    return this.readNameFromDocument(/** @type {Document} */ (source));\n  } else if (ol.xml.isNode(source)) {\n    return this.readNameFromNode(/** @type {Node} */ (source));\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readNameFromDocument(doc);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Document} doc Document.\n * @return {string|undefined} Name.\n */\nol.format.KML.prototype.readNameFromDocument = function(doc) {\n  var n;\n  for (n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      var name = this.readNameFromNode(n);\n      if (name) {\n        return name;\n      }\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {string|undefined} Name.\n */\nol.format.KML.prototype.readNameFromNode = function(node) {\n  var n;\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&\n        n.localName == 'name') {\n      return ol.format.XSD.readString(n);\n    }\n  }\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    var localName = n.localName;\n    if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&\n        (localName == 'Document' ||\n         localName == 'Folder' ||\n         localName == 'Placemark' ||\n         localName == 'kml')) {\n      var name = this.readNameFromNode(n);\n      if (name) {\n        return name;\n      }\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * Read the network links of the KML.\n *\n * @param {Document|Node|string} source Source.\n * @return {Array.<Object>} Network links.\n * @api\n */\nol.format.KML.prototype.readNetworkLinks = function(source) {\n  var networkLinks = [];\n  if (ol.xml.isDocument(source)) {\n    ol.array.extend(networkLinks, this.readNetworkLinksFromDocument(\n        /** @type {Document} */ (source)));\n  } else if (ol.xml.isNode(source)) {\n    ol.array.extend(networkLinks, this.readNetworkLinksFromNode(\n        /** @type {Node} */ (source)));\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    ol.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc));\n  }\n  return networkLinks;\n};\n\n\n/**\n * @param {Document} doc Document.\n * @return {Array.<Object>} Network links.\n */\nol.format.KML.prototype.readNetworkLinksFromDocument = function(doc) {\n  var n, networkLinks = [];\n  for (n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n));\n    }\n  }\n  return networkLinks;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {Array.<Object>} Network links.\n */\nol.format.KML.prototype.readNetworkLinksFromNode = function(node) {\n  var n, networkLinks = [];\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&\n        n.localName == 'NetworkLink') {\n      var obj = ol.xml.pushParseAndPop({}, ol.format.KML.NETWORK_LINK_PARSERS_,\n          n, []);\n      networkLinks.push(obj);\n    }\n  }\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    var localName = n.localName;\n    if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&\n        (localName == 'Document' ||\n         localName == 'Folder' ||\n         localName == 'kml')) {\n      ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n));\n    }\n  }\n  return networkLinks;\n};\n\n\n/**\n * Read the regions of the KML.\n *\n * @param {Document|Node|string} source Source.\n * @return {Array.<Object>} Regions.\n * @api\n */\nol.format.KML.prototype.readRegion = function(source) {\n  var regions = [];\n  if (ol.xml.isDocument(source)) {\n    ol.array.extend(regions, this.readRegionFromDocument(\n        /** @type {Document} */ (source)));\n  } else if (ol.xml.isNode(source)) {\n    ol.array.extend(regions, this.readRegionFromNode(\n        /** @type {Node} */ (source)));\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    ol.array.extend(regions, this.readRegionFromDocument(doc));\n  }\n  return regions;\n};\n\n\n/**\n * @param {Document} doc Document.\n * @return {Array.<Object>} Region.\n */\nol.format.KML.prototype.readRegionFromDocument = function(doc) {\n  var n, regions = [];\n  for (n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      ol.array.extend(regions, this.readRegionFromNode(n));\n    }\n  }\n  return regions;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {Array.<Object>} Region.\n * @api\n */\nol.format.KML.prototype.readRegionFromNode = function(node) {\n  var n, regions = [];\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&\n        n.localName == 'Region') {\n      var obj = ol.xml.pushParseAndPop({}, ol.format.KML.REGION_PARSERS_,\n          n, []);\n      regions.push(obj);\n    }\n  }\n  for (n = node.firstElementChild; n; n = n.nextElementSibling) {\n    var localName = n.localName;\n    if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&\n        (localName == 'Document' ||\n         localName == 'Folder' ||\n         localName == 'kml')) {\n      ol.array.extend(regions, this.readRegionFromNode(n));\n    }\n  }\n  return regions;\n};\n\n\n/**\n * Read the projection from a KML source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n * @api stable\n */\nol.format.KML.prototype.readProjection;\n\n\n/**\n * @param {Node} node Node to append a TextNode with the color to.\n * @param {ol.Color|string} color Color.\n * @private\n */\nol.format.KML.writeColorTextNode_ = function(node, color) {\n  var rgba = ol.color.asArray(color);\n  var opacity = (rgba.length == 4) ? rgba[3] : 1;\n  var abgr = [opacity * 255, rgba[2], rgba[1], rgba[0]];\n  var i;\n  for (i = 0; i < 4; ++i) {\n    var hex = parseInt(abgr[i], 10).toString(16);\n    abgr[i] = (hex.length == 1) ? '0' + hex : hex;\n  }\n  ol.format.XSD.writeStringTextNode(node, abgr.join(''));\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the coordinates to.\n * @param {Array.<number>} coordinates Coordinates.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeCoordinatesTextNode_ = function(node, coordinates, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n\n  var layout = context['layout'];\n  var stride = context['stride'];\n\n  var dimension;\n  if (layout == ol.geom.GeometryLayout.XY ||\n      layout == ol.geom.GeometryLayout.XYM) {\n    dimension = 2;\n  } else if (layout == ol.geom.GeometryLayout.XYZ ||\n      layout == ol.geom.GeometryLayout.XYZM) {\n    dimension = 3;\n  } else {\n    ol.asserts.assert(false, 34); // Invalid geometry layout\n  }\n\n  var d, i;\n  var ii = coordinates.length;\n  var text = '';\n  if (ii > 0) {\n    text += coordinates[0];\n    for (d = 1; d < dimension; ++d) {\n      text += ',' + coordinates[d];\n    }\n    for (i = stride; i < ii; i += stride) {\n      text += ' ' + coordinates[i];\n      for (d = 1; d < dimension; ++d) {\n        text += ',' + coordinates[i + d];\n      }\n    }\n  }\n  ol.format.XSD.writeStringTextNode(node, text);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {{name: *, value: *}} pair Name value pair.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeDataNode_ = function(node, pair, objectStack) {\n  node.setAttribute('name', pair.name);\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  var value = pair.value;\n\n  if (typeof value == 'object') {\n    if (value !== null && value.displayName) {\n      ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,\n        ol.xml.OBJECT_PROPERTY_NODE_FACTORY, [value.displayName], objectStack, ['displayName']);\n    }\n\n    if (value !== null && value.value) {\n      ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,\n        ol.xml.OBJECT_PROPERTY_NODE_FACTORY, [value.value], objectStack, ['value']);\n    }\n  } else {\n    ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,\n     ol.xml.OBJECT_PROPERTY_NODE_FACTORY, [value], objectStack, ['value']);\n  }\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the name to.\n * @param {string} name DisplayName.\n * @private\n */\nol.format.KML.writeDataNodeName_ = function(node, name) {\n  ol.format.XSD.writeCDATASection(node, name);\n};\n\n\n/**\n * @param {Node} node Node to append a CDATA Section with the value to.\n * @param {string} value Value.\n * @private\n */\nol.format.KML.writeDataNodeValue_ = function(node, value) {\n  ol.format.XSD.writeStringTextNode(node, value);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<ol.Feature>} features Features.\n * @param {Array.<*>} objectStack Object stack.\n * @this {ol.format.KML}\n * @private\n */\nol.format.KML.writeDocument_ = function(node, features, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.DOCUMENT_SERIALIZERS_,\n      ol.format.KML.DOCUMENT_NODE_FACTORY_, features, objectStack, undefined,\n      this);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {{names: Array<string>, values: (Array<*>)}} namesAndValues Names and values.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeExtendedData_ = function(node, namesAndValues, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  var names = namesAndValues.names, values = namesAndValues.values;\n  var length = names.length;\n\n  for (var i = 0; i < length; i++) {\n    ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,\n      ol.format.KML.DATA_NODE_FACTORY_, [{name: names[i], value: values[i]}], objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Object} icon Icon object.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeIcon_ = function(node, icon, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys = ol.format.KML.ICON_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(icon, orderedKeys);\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.KML.ICON_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,\n      values, objectStack, orderedKeys);\n  orderedKeys =\n      ol.format.KML.ICON_SEQUENCE_[ol.format.KML.GX_NAMESPACE_URIS_[0]];\n  values = ol.xml.makeSequence(icon, orderedKeys);\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_SERIALIZERS_,\n      ol.format.KML.GX_NODE_FACTORY_, values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.style.Icon} style Icon style.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeIconStyle_ = function(node, style, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  var properties = {};\n  var src = style.getSrc();\n  var size = style.getSize();\n  var iconImageSize = style.getImageSize();\n  var iconProperties = {\n    'href': src\n  };\n\n  if (size) {\n    iconProperties['w'] = size[0];\n    iconProperties['h'] = size[1];\n    var anchor = style.getAnchor(); // top-left\n    var origin = style.getOrigin(); // top-left\n\n    if (origin && iconImageSize && origin[0] !== 0 && origin[1] !== size[1]) {\n      iconProperties['x'] = origin[0];\n      iconProperties['y'] = iconImageSize[1] - (origin[1] + size[1]);\n    }\n\n    if (anchor && anchor[0] !== 0 && anchor[1] !== size[1]) {\n      var /** @type {ol.KMLVec2_} */ hotSpot = {\n        x: anchor[0],\n        xunits: ol.style.Icon.AnchorUnits.PIXELS,\n        y: size[1] - anchor[1],\n        yunits: ol.style.Icon.AnchorUnits.PIXELS\n      };\n      properties['hotSpot'] = hotSpot;\n    }\n  }\n\n  properties['Icon'] = iconProperties;\n\n  var scale = style.getScale();\n  if (scale !== 1) {\n    properties['scale'] = scale;\n  }\n\n  var rotation = style.getRotation();\n  if (rotation !== 0) {\n    properties['heading'] = rotation; // 0-360\n  }\n\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys = ol.format.KML.ICON_STYLE_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_STYLE_SERIALIZERS_,\n      ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.style.Text} style style.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeLabelStyle_ = function(node, style, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  var properties = {};\n  var fill = style.getFill();\n  if (fill) {\n    properties['color'] = fill.getColor();\n  }\n  var scale = style.getScale();\n  if (scale && scale !== 1) {\n    properties['scale'] = scale;\n  }\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys =\n      ol.format.KML.LABEL_STYLE_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.LABEL_STYLE_SERIALIZERS_,\n      ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.style.Stroke} style style.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeLineStyle_ = function(node, style, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  var properties = {\n    'color': style.getColor(),\n    'width': style.getWidth()\n  };\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys = ol.format.KML.LINE_STYLE_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.LINE_STYLE_SERIALIZERS_,\n      ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeMultiGeometry_ = function(node, geometry, objectStack) {\n  /** @type {ol.XmlNodeStackItem} */\n  var context = {node: node};\n  var type = geometry.getType();\n  /** @type {Array.<ol.geom.Geometry>} */\n  var geometries;\n  /** @type {function(*, Array.<*>, string=): (Node|undefined)} */\n  var factory;\n  if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) {\n    geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries();\n    factory = ol.format.KML.GEOMETRY_NODE_FACTORY_;\n  } else if (type == ol.geom.GeometryType.MULTI_POINT) {\n    geometries = /** @type {ol.geom.MultiPoint} */ (geometry).getPoints();\n    factory = ol.format.KML.POINT_NODE_FACTORY_;\n  } else if (type == ol.geom.GeometryType.MULTI_LINE_STRING) {\n    geometries =\n        (/** @type {ol.geom.MultiLineString} */ (geometry)).getLineStrings();\n    factory = ol.format.KML.LINE_STRING_NODE_FACTORY_;\n  } else if (type == ol.geom.GeometryType.MULTI_POLYGON) {\n    geometries =\n        (/** @type {ol.geom.MultiPolygon} */ (geometry)).getPolygons();\n    factory = ol.format.KML.POLYGON_NODE_FACTORY_;\n  } else {\n    ol.asserts.assert(false, 39); // Unknown geometry type\n  }\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_, factory,\n      geometries, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.LinearRing} linearRing Linear ring.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeBoundaryIs_ = function(node, linearRing, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.KML.BOUNDARY_IS_SERIALIZERS_,\n      ol.format.KML.LINEAR_RING_NODE_FACTORY_, [linearRing], objectStack);\n};\n\n\n/**\n * FIXME currently we do serialize arbitrary/custom feature properties\n * (ExtendedData).\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Object stack.\n * @this {ol.format.KML}\n * @private\n */\nol.format.KML.writePlacemark_ = function(node, feature, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n\n  // set id\n  if (feature.getId()) {\n    node.setAttribute('id', feature.getId());\n  }\n\n  // serialize properties (properties unknown to KML are not serialized)\n  var properties = feature.getProperties();\n\n  // don't export these to ExtendedData\n  var filter = {'address': 1, 'description': 1, 'name': 1, 'open': 1,\n    'phoneNumber': 1, 'styleUrl': 1, 'visibility': 1};\n  filter[feature.getGeometryName()] = 1;\n  var keys = Object.keys(properties || {}).sort().filter(function(v) {\n    return !filter[v];\n  });\n\n  if (keys.length > 0) {\n    var sequence = ol.xml.makeSequence(properties, keys);\n    var namesAndValues = {names: keys, values: sequence};\n    ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,\n      ol.format.KML.EXTENDEDDATA_NODE_FACTORY_, [namesAndValues], objectStack);\n  }\n\n  var styleFunction = feature.getStyleFunction();\n  if (styleFunction) {\n    // FIXME the styles returned by the style function are supposed to be\n    // resolution-independent here\n    var styles = styleFunction.call(feature, 0);\n    if (styles) {\n      var style = Array.isArray(styles) ? styles[0] : styles;\n      if (this.writeStyles_) {\n        properties['Style'] = style;\n      }\n      var textStyle = style.getText();\n      if (textStyle) {\n        properties['name'] = textStyle.getText();\n      }\n    }\n  }\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys = ol.format.KML.PLACEMARK_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,\n      ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);\n\n  // serialize geometry\n  var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    geometry =\n        ol.format.Feature.transformWithOptions(geometry, true, options);\n  }\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,\n      ol.format.KML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.SimpleGeometry} geometry Geometry.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writePrimitiveGeometry_ = function(node, geometry, objectStack) {\n  ol.DEBUG && console.assert(\n      (geometry instanceof ol.geom.Point) ||\n      (geometry instanceof ol.geom.LineString) ||\n      (geometry instanceof ol.geom.LinearRing),\n      'geometry should be one of ol.geom.Point, ol.geom.LineString ' +\n      'or ol.geom.LinearRing');\n  var flatCoordinates = geometry.getFlatCoordinates();\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  context['layout'] = geometry.getLayout();\n  context['stride'] = geometry.getStride();\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_,\n      ol.format.KML.COORDINATES_NODE_FACTORY_,\n      [flatCoordinates], objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.geom.Polygon} polygon Polygon.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writePolygon_ = function(node, polygon, objectStack) {\n  var linearRings = polygon.getLinearRings();\n  ol.DEBUG && console.assert(linearRings.length > 0,\n      'linearRings should not be empty');\n  var outerRing = linearRings.shift();\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  // inner rings\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.KML.POLYGON_SERIALIZERS_,\n      ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_,\n      linearRings, objectStack);\n  // outer ring\n  ol.xml.pushSerializeAndPop(context,\n      ol.format.KML.POLYGON_SERIALIZERS_,\n      ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_,\n      [outerRing], objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.style.Fill} style Style.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writePolyStyle_ = function(node, style, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.POLY_STYLE_SERIALIZERS_,\n      ol.format.KML.COLOR_NODE_FACTORY_, [style.getColor()], objectStack);\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the scale to.\n * @param {number|undefined} scale Scale.\n * @private\n */\nol.format.KML.writeScaleTextNode_ = function(node, scale) {\n  // the Math is to remove any excess decimals created by float arithmetic\n  ol.format.XSD.writeDecimalTextNode(node,\n      Math.round(scale * 1e6) / 1e6);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.style.Style} style Style.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.KML.writeStyle_ = function(node, style, objectStack) {\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: node};\n  var properties = {};\n  var fillStyle = style.getFill();\n  var strokeStyle = style.getStroke();\n  var imageStyle = style.getImage();\n  var textStyle = style.getText();\n  if (imageStyle instanceof ol.style.Icon) {\n    properties['IconStyle'] = imageStyle;\n  }\n  if (textStyle) {\n    properties['LabelStyle'] = textStyle;\n  }\n  if (strokeStyle) {\n    properties['LineStyle'] = strokeStyle;\n  }\n  if (fillStyle) {\n    properties['PolyStyle'] = fillStyle;\n  }\n  var parentNode = objectStack[objectStack.length - 1].node;\n  var orderedKeys = ol.format.KML.STYLE_SEQUENCE_[parentNode.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.STYLE_SERIALIZERS_,\n      ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);\n};\n\n\n/**\n * @param {Node} node Node to append a TextNode with the Vec2 to.\n * @param {ol.KMLVec2_} vec2 Vec2.\n * @private\n */\nol.format.KML.writeVec2_ = function(node, vec2) {\n  node.setAttribute('x', vec2.x);\n  node.setAttribute('y', vec2.y);\n  node.setAttribute('xunits', vec2.xunits);\n  node.setAttribute('yunits', vec2.yunits);\n};\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.KML.KML_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, [\n      'Document', 'Placemark'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.KML_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Document': ol.xml.makeChildAppender(ol.format.KML.writeDocument_),\n      'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.DOCUMENT_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Data': ol.xml.makeChildAppender(ol.format.KML.writeDataNode_),\n      'value': ol.xml.makeChildAppender(ol.format.KML.writeDataNodeValue_),\n      'displayName': ol.xml.makeChildAppender(ol.format.KML.writeDataNodeName_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, string>}\n * @private\n */\nol.format.KML.GEOMETRY_TYPE_TO_NODENAME_ = {\n  'Point': 'Point',\n  'LineString': 'LineString',\n  'LinearRing': 'LinearRing',\n  'Polygon': 'Polygon',\n  'MultiPoint': 'MultiGeometry',\n  'MultiLineString': 'MultiGeometry',\n  'MultiPolygon': 'MultiGeometry',\n  'GeometryCollection': 'MultiGeometry'\n};\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.KML.ICON_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, [\n      'href'\n    ],\n    ol.xml.makeStructureNS(ol.format.KML.GX_NAMESPACE_URIS_, [\n      'x', 'y', 'w', 'h'\n    ]));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.ICON_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'href': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)\n    }, ol.xml.makeStructureNS(\n        ol.format.KML.GX_NAMESPACE_URIS_, {\n          'x': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n          'y': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n          'w': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n          'h': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)\n        }));\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.KML.ICON_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, [\n      'scale', 'heading', 'Icon', 'hotSpot'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.ICON_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'Icon': ol.xml.makeChildAppender(ol.format.KML.writeIcon_),\n      'heading': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),\n      'hotSpot': ol.xml.makeChildAppender(ol.format.KML.writeVec2_),\n      'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.KML.LABEL_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, [\n      'color', 'scale'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.LABEL_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),\n      'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.KML.LINE_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, [\n      'color', 'width'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.LINE_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),\n      'width': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.BOUNDARY_IS_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'LinearRing': ol.xml.makeChildAppender(\n          ol.format.KML.writePrimitiveGeometry_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.MULTI_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'LineString': ol.xml.makeChildAppender(\n          ol.format.KML.writePrimitiveGeometry_),\n      'Point': ol.xml.makeChildAppender(\n          ol.format.KML.writePrimitiveGeometry_),\n      'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_),\n      'GeometryCollection': ol.xml.makeChildAppender(\n          ol.format.KML.writeMultiGeometry_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.KML.PLACEMARK_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, [\n      'name', 'open', 'visibility', 'address', 'phoneNumber', 'description',\n      'styleUrl', 'Style'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.PLACEMARK_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'ExtendedData': ol.xml.makeChildAppender(\n          ol.format.KML.writeExtendedData_),\n      'MultiGeometry': ol.xml.makeChildAppender(\n          ol.format.KML.writeMultiGeometry_),\n      'LineString': ol.xml.makeChildAppender(\n          ol.format.KML.writePrimitiveGeometry_),\n      'LinearRing': ol.xml.makeChildAppender(\n          ol.format.KML.writePrimitiveGeometry_),\n      'Point': ol.xml.makeChildAppender(\n          ol.format.KML.writePrimitiveGeometry_),\n      'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_),\n      'Style': ol.xml.makeChildAppender(ol.format.KML.writeStyle_),\n      'address': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'description': ol.xml.makeChildAppender(\n          ol.format.XSD.writeStringTextNode),\n      'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'open': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode),\n      'phoneNumber': ol.xml.makeChildAppender(\n          ol.format.XSD.writeStringTextNode),\n      'styleUrl': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),\n      'visibility': ol.xml.makeChildAppender(\n          ol.format.XSD.writeBooleanTextNode)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'coordinates': ol.xml.makeChildAppender(\n          ol.format.KML.writeCoordinatesTextNode_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.POLYGON_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'outerBoundaryIs': ol.xml.makeChildAppender(\n          ol.format.KML.writeBoundaryIs_),\n      'innerBoundaryIs': ol.xml.makeChildAppender(\n          ol.format.KML.writeBoundaryIs_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.POLY_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Array.<string>>}\n * @private\n */\nol.format.KML.STYLE_SEQUENCE_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, [\n      'IconStyle', 'LabelStyle', 'LineStyle', 'PolyStyle'\n    ]);\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.KML.STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(\n    ol.format.KML.NAMESPACE_URIS_, {\n      'IconStyle': ol.xml.makeChildAppender(ol.format.KML.writeIconStyle_),\n      'LabelStyle': ol.xml.makeChildAppender(ol.format.KML.writeLabelStyle_),\n      'LineStyle': ol.xml.makeChildAppender(ol.format.KML.writeLineStyle_),\n      'PolyStyle': ol.xml.makeChildAppender(ol.format.KML.writePolyStyle_)\n    });\n\n\n/**\n * @const\n * @param {*} value Value.\n * @param {Array.<*>} objectStack Object stack.\n * @param {string=} opt_nodeName Node name.\n * @return {Node|undefined} Node.\n * @private\n */\nol.format.KML.GX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {\n  return ol.xml.createElementNS(ol.format.KML.GX_NAMESPACE_URIS_[0],\n      'gx:' + opt_nodeName);\n};\n\n\n/**\n * @const\n * @param {*} value Value.\n * @param {Array.<*>} objectStack Object stack.\n * @param {string=} opt_nodeName Node name.\n * @return {Node|undefined} Node.\n * @private\n */\nol.format.KML.DOCUMENT_NODE_FACTORY_ = function(value, objectStack,\n    opt_nodeName) {\n  var parentNode = objectStack[objectStack.length - 1].node;\n  ol.DEBUG && console.assert(ol.xml.isNode(parentNode),\n      'parentNode should be an XML node');\n  return ol.xml.createElementNS(parentNode.namespaceURI, 'Placemark');\n};\n\n\n/**\n * @const\n * @param {*} value Value.\n * @param {Array.<*>} objectStack Object stack.\n * @param {string=} opt_nodeName Node name.\n * @return {Node|undefined} Node.\n * @private\n */\nol.format.KML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack,\n    opt_nodeName) {\n  if (value) {\n    var parentNode = objectStack[objectStack.length - 1].node;\n    ol.DEBUG && console.assert(ol.xml.isNode(parentNode),\n        'parentNode should be an XML node');\n    return ol.xml.createElementNS(parentNode.namespaceURI,\n        ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_[/** @type {ol.geom.Geometry} */ (value).getType()]);\n  }\n};\n\n\n/**\n * A factory for creating coordinates nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.COLOR_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('color');\n\n\n/**\n * A factory for creating coordinates nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.COORDINATES_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('coordinates');\n\n\n/**\n * A factory for creating Data nodes.\n * @const\n * @type {function(*, Array.<*>): (Node|undefined)}\n * @private\n */\nol.format.KML.DATA_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('Data');\n\n\n/**\n * A factory for creating ExtendedData nodes.\n * @const\n * @type {function(*, Array.<*>): (Node|undefined)}\n * @private\n */\nol.format.KML.EXTENDEDDATA_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('ExtendedData');\n\n\n/**\n * A factory for creating innerBoundaryIs nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.INNER_BOUNDARY_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('innerBoundaryIs');\n\n\n/**\n * A factory for creating Point nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.POINT_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('Point');\n\n\n/**\n * A factory for creating LineString nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.LINE_STRING_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('LineString');\n\n\n/**\n * A factory for creating LinearRing nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.LINEAR_RING_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('LinearRing');\n\n\n/**\n * A factory for creating Polygon nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.POLYGON_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('Polygon');\n\n\n/**\n * A factory for creating outerBoundaryIs nodes.\n * @const\n * @type {function(*, Array.<*>, string=): (Node|undefined)}\n * @private\n */\nol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_ =\n    ol.xml.makeSimpleNodeFactory('outerBoundaryIs');\n\n\n/**\n * Encode an array of features in the KML format. GeometryCollections, MultiPoints,\n * MultiLineStrings, and MultiPolygons are output as MultiGeometries.\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {string} Result.\n * @api stable\n */\nol.format.KML.prototype.writeFeatures;\n\n\n/**\n * Encode an array of features in the KML format as an XML node. GeometryCollections,\n * MultiPoints, MultiLineStrings, and MultiPolygons are output as MultiGeometries.\n *\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Options.\n * @return {Node} Node.\n * @api\n */\nol.format.KML.prototype.writeFeaturesNode = function(features, opt_options) {\n  opt_options = this.adaptOptions(opt_options);\n  var kml = ol.xml.createElementNS(ol.format.KML.NAMESPACE_URIS_[4], 'kml');\n  var xmlnsUri = 'http://www.w3.org/2000/xmlns/';\n  var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance';\n  ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:gx',\n      ol.format.KML.GX_NAMESPACE_URIS_[0]);\n  ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri);\n  ol.xml.setAttributeNS(kml, xmlSchemaInstanceUri, 'xsi:schemaLocation',\n      ol.format.KML.SCHEMA_LOCATION_);\n\n  var /** @type {ol.XmlNodeStackItem} */ context = {node: kml};\n  var properties = {};\n  if (features.length > 1) {\n    properties['Document'] = features;\n  } else if (features.length == 1) {\n    properties['Placemark'] = features[0];\n  }\n  var orderedKeys = ol.format.KML.KML_SEQUENCE_[kml.namespaceURI];\n  var values = ol.xml.makeSequence(properties, orderedKeys);\n  ol.xml.pushSerializeAndPop(context, ol.format.KML.KML_SERIALIZERS_,\n      ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, [opt_options], orderedKeys,\n      this);\n  return kml;\n};\n\ngoog.provide('ol.ext.pbf');\n/** @typedef {function(*)} */\nol.ext.pbf;\n(function() {\nvar exports = {};\nvar module = {exports: exports};\nvar define;\n/**\n * @fileoverview\n * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}\n */\n(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){\nexports.read = function (buffer, offset, isLE, mLen, nBytes) {\n  var e, m\n  var eLen = nBytes * 8 - mLen - 1\n  var eMax = (1 << eLen) - 1\n  var eBias = eMax >> 1\n  var nBits = -7\n  var i = isLE ? (nBytes - 1) : 0\n  var d = isLE ? -1 : 1\n  var s = buffer[offset + i]\n\n  i += d\n\n  e = s & ((1 << (-nBits)) - 1)\n  s >>= (-nBits)\n  nBits += eLen\n  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n  m = e & ((1 << (-nBits)) - 1)\n  e >>= (-nBits)\n  nBits += mLen\n  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n  if (e === 0) {\n    e = 1 - eBias\n  } else if (e === eMax) {\n    return m ? NaN : ((s ? -1 : 1) * Infinity)\n  } else {\n    m = m + Math.pow(2, mLen)\n    e = e - eBias\n  }\n  return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n  var e, m, c\n  var eLen = nBytes * 8 - mLen - 1\n  var eMax = (1 << eLen) - 1\n  var eBias = eMax >> 1\n  var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n  var i = isLE ? 0 : (nBytes - 1)\n  var d = isLE ? 1 : -1\n  var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n  value = Math.abs(value)\n\n  if (isNaN(value) || value === Infinity) {\n    m = isNaN(value) ? 1 : 0\n    e = eMax\n  } else {\n    e = Math.floor(Math.log(value) / Math.LN2)\n    if (value * (c = Math.pow(2, -e)) < 1) {\n      e--\n      c *= 2\n    }\n    if (e + eBias >= 1) {\n      value += rt / c\n    } else {\n      value += rt * Math.pow(2, 1 - eBias)\n    }\n    if (value * c >= 2) {\n      e++\n      c /= 2\n    }\n\n    if (e + eBias >= eMax) {\n      m = 0\n      e = eMax\n    } else if (e + eBias >= 1) {\n      m = (value * c - 1) * Math.pow(2, mLen)\n      e = e + eBias\n    } else {\n      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n      e = 0\n    }\n  }\n\n  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n  e = (e << mLen) | m\n  eLen += mLen\n  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n  buffer[offset + i - d] |= s * 128\n}\n\n},{}],2:[function(_dereq_,module,exports){\n'use strict';\n\nmodule.exports = Pbf;\n\nvar ieee754 = _dereq_('ieee754');\n\nfunction Pbf(buf) {\n    this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);\n    this.pos = 0;\n    this.type = 0;\n    this.length = this.buf.length;\n}\n\nPbf.Varint  = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum\nPbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64\nPbf.Bytes   = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields\nPbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32\n\nvar SHIFT_LEFT_32 = (1 << 16) * (1 << 16),\n    SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;\n\nPbf.prototype = {\n\n    destroy: function() {\n        this.buf = null;\n    },\n\n    // === READING =================================================================\n\n    readFields: function(readField, result, end) {\n        end = end || this.length;\n\n        while (this.pos < end) {\n            var val = this.readVarint(),\n                tag = val >> 3,\n                startPos = this.pos;\n\n            this.type = val & 0x7;\n            readField(tag, result, this);\n\n            if (this.pos === startPos) this.skip(val);\n        }\n        return result;\n    },\n\n    readMessage: function(readField, result) {\n        return this.readFields(readField, result, this.readVarint() + this.pos);\n    },\n\n    readFixed32: function() {\n        var val = readUInt32(this.buf, this.pos);\n        this.pos += 4;\n        return val;\n    },\n\n    readSFixed32: function() {\n        var val = readInt32(this.buf, this.pos);\n        this.pos += 4;\n        return val;\n    },\n\n    // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)\n\n    readFixed64: function() {\n        var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;\n        this.pos += 8;\n        return val;\n    },\n\n    readSFixed64: function() {\n        var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;\n        this.pos += 8;\n        return val;\n    },\n\n    readFloat: function() {\n        var val = ieee754.read(this.buf, this.pos, true, 23, 4);\n        this.pos += 4;\n        return val;\n    },\n\n    readDouble: function() {\n        var val = ieee754.read(this.buf, this.pos, true, 52, 8);\n        this.pos += 8;\n        return val;\n    },\n\n    readVarint: function(isSigned) {\n        var buf = this.buf,\n            val, b;\n\n        b = buf[this.pos++]; val  =  b & 0x7f;        if (b < 0x80) return val;\n        b = buf[this.pos++]; val |= (b & 0x7f) << 7;  if (b < 0x80) return val;\n        b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val;\n        b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val;\n        b = buf[this.pos];   val |= (b & 0x0f) << 28;\n\n        return readVarintRemainder(val, isSigned, this);\n    },\n\n    readVarint64: function() { // for compatibility with v2.0.1\n        return this.readVarint(true);\n    },\n\n    readSVarint: function() {\n        var num = this.readVarint();\n        return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding\n    },\n\n    readBoolean: function() {\n        return Boolean(this.readVarint());\n    },\n\n    readString: function() {\n        var end = this.readVarint() + this.pos,\n            str = readUtf8(this.buf, this.pos, end);\n        this.pos = end;\n        return str;\n    },\n\n    readBytes: function() {\n        var end = this.readVarint() + this.pos,\n            buffer = this.buf.subarray(this.pos, end);\n        this.pos = end;\n        return buffer;\n    },\n\n    // verbose for performance reasons; doesn't affect gzipped size\n\n    readPackedVarint: function(arr, isSigned) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readVarint(isSigned));\n        return arr;\n    },\n    readPackedSVarint: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readSVarint());\n        return arr;\n    },\n    readPackedBoolean: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readBoolean());\n        return arr;\n    },\n    readPackedFloat: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readFloat());\n        return arr;\n    },\n    readPackedDouble: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readDouble());\n        return arr;\n    },\n    readPackedFixed32: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readFixed32());\n        return arr;\n    },\n    readPackedSFixed32: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readSFixed32());\n        return arr;\n    },\n    readPackedFixed64: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readFixed64());\n        return arr;\n    },\n    readPackedSFixed64: function(arr) {\n        var end = readPackedEnd(this);\n        arr = arr || [];\n        while (this.pos < end) arr.push(this.readSFixed64());\n        return arr;\n    },\n\n    skip: function(val) {\n        var type = val & 0x7;\n        if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {}\n        else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos;\n        else if (type === Pbf.Fixed32) this.pos += 4;\n        else if (type === Pbf.Fixed64) this.pos += 8;\n        else throw new Error('Unimplemented type: ' + type);\n    },\n\n    // === WRITING =================================================================\n\n    writeTag: function(tag, type) {\n        this.writeVarint((tag << 3) | type);\n    },\n\n    realloc: function(min) {\n        var length = this.length || 16;\n\n        while (length < this.pos + min) length *= 2;\n\n        if (length !== this.length) {\n            var buf = new Uint8Array(length);\n            buf.set(this.buf);\n            this.buf = buf;\n            this.length = length;\n        }\n    },\n\n    finish: function() {\n        this.length = this.pos;\n        this.pos = 0;\n        return this.buf.subarray(0, this.length);\n    },\n\n    writeFixed32: function(val) {\n        this.realloc(4);\n        writeInt32(this.buf, val, this.pos);\n        this.pos += 4;\n    },\n\n    writeSFixed32: function(val) {\n        this.realloc(4);\n        writeInt32(this.buf, val, this.pos);\n        this.pos += 4;\n    },\n\n    writeFixed64: function(val) {\n        this.realloc(8);\n        writeInt32(this.buf, val & -1, this.pos);\n        writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);\n        this.pos += 8;\n    },\n\n    writeSFixed64: function(val) {\n        this.realloc(8);\n        writeInt32(this.buf, val & -1, this.pos);\n        writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);\n        this.pos += 8;\n    },\n\n    writeVarint: function(val) {\n        val = +val || 0;\n\n        if (val > 0xfffffff || val < 0) {\n            writeBigVarint(val, this);\n            return;\n        }\n\n        this.realloc(4);\n\n        this.buf[this.pos++] =           val & 0x7f  | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;\n        this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;\n        this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;\n        this.buf[this.pos++] =   (val >>> 7) & 0x7f;\n    },\n\n    writeSVarint: function(val) {\n        this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);\n    },\n\n    writeBoolean: function(val) {\n        this.writeVarint(Boolean(val));\n    },\n\n    writeString: function(str) {\n        str = String(str);\n        this.realloc(str.length * 4);\n\n        this.pos++; // reserve 1 byte for short string length\n\n        var startPos = this.pos;\n        // write the string directly to the buffer and see how much was written\n        this.pos = writeUtf8(this.buf, str, this.pos);\n        var len = this.pos - startPos;\n\n        if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);\n\n        // finally, write the message length in the reserved place and restore the position\n        this.pos = startPos - 1;\n        this.writeVarint(len);\n        this.pos += len;\n    },\n\n    writeFloat: function(val) {\n        this.realloc(4);\n        ieee754.write(this.buf, val, this.pos, true, 23, 4);\n        this.pos += 4;\n    },\n\n    writeDouble: function(val) {\n        this.realloc(8);\n        ieee754.write(this.buf, val, this.pos, true, 52, 8);\n        this.pos += 8;\n    },\n\n    writeBytes: function(buffer) {\n        var len = buffer.length;\n        this.writeVarint(len);\n        this.realloc(len);\n        for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i];\n    },\n\n    writeRawMessage: function(fn, obj) {\n        this.pos++; // reserve 1 byte for short message length\n\n        // write the message directly to the buffer and see how much was written\n        var startPos = this.pos;\n        fn(obj, this);\n        var len = this.pos - startPos;\n\n        if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);\n\n        // finally, write the message length in the reserved place and restore the position\n        this.pos = startPos - 1;\n        this.writeVarint(len);\n        this.pos += len;\n    },\n\n    writeMessage: function(tag, fn, obj) {\n        this.writeTag(tag, Pbf.Bytes);\n        this.writeRawMessage(fn, obj);\n    },\n\n    writePackedVarint:   function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr);   },\n    writePackedSVarint:  function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr);  },\n    writePackedBoolean:  function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr);  },\n    writePackedFloat:    function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr);    },\n    writePackedDouble:   function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr);   },\n    writePackedFixed32:  function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr);  },\n    writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); },\n    writePackedFixed64:  function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr);  },\n    writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); },\n\n    writeBytesField: function(tag, buffer) {\n        this.writeTag(tag, Pbf.Bytes);\n        this.writeBytes(buffer);\n    },\n    writeFixed32Field: function(tag, val) {\n        this.writeTag(tag, Pbf.Fixed32);\n        this.writeFixed32(val);\n    },\n    writeSFixed32Field: function(tag, val) {\n        this.writeTag(tag, Pbf.Fixed32);\n        this.writeSFixed32(val);\n    },\n    writeFixed64Field: function(tag, val) {\n        this.writeTag(tag, Pbf.Fixed64);\n        this.writeFixed64(val);\n    },\n    writeSFixed64Field: function(tag, val) {\n        this.writeTag(tag, Pbf.Fixed64);\n        this.writeSFixed64(val);\n    },\n    writeVarintField: function(tag, val) {\n        this.writeTag(tag, Pbf.Varint);\n        this.writeVarint(val);\n    },\n    writeSVarintField: function(tag, val) {\n        this.writeTag(tag, Pbf.Varint);\n        this.writeSVarint(val);\n    },\n    writeStringField: function(tag, str) {\n        this.writeTag(tag, Pbf.Bytes);\n        this.writeString(str);\n    },\n    writeFloatField: function(tag, val) {\n        this.writeTag(tag, Pbf.Fixed32);\n        this.writeFloat(val);\n    },\n    writeDoubleField: function(tag, val) {\n        this.writeTag(tag, Pbf.Fixed64);\n        this.writeDouble(val);\n    },\n    writeBooleanField: function(tag, val) {\n        this.writeVarintField(tag, Boolean(val));\n    }\n};\n\nfunction readVarintRemainder(l, s, p) {\n    var buf = p.buf,\n        h, b;\n\n    b = buf[p.pos++]; h  = (b & 0x70) >> 4;  if (b < 0x80) return toNum(l, h, s);\n    b = buf[p.pos++]; h |= (b & 0x7f) << 3;  if (b < 0x80) return toNum(l, h, s);\n    b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s);\n    b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s);\n    b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s);\n    b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s);\n\n    throw new Error('Expected varint not more than 10 bytes');\n}\n\nfunction readPackedEnd(pbf) {\n    return pbf.type === Pbf.Bytes ?\n        pbf.readVarint() + pbf.pos : pbf.pos + 1;\n}\n\nfunction toNum(low, high, isSigned) {\n    if (isSigned) {\n        return high * 0x100000000 + (low >>> 0);\n    }\n\n    return ((high >>> 0) * 0x100000000) + (low >>> 0);\n}\n\nfunction writeBigVarint(val, pbf) {\n    var low, high;\n\n    if (val >= 0) {\n        low  = (val % 0x100000000) | 0;\n        high = (val / 0x100000000) | 0;\n    } else {\n        low  = ~(-val % 0x100000000);\n        high = ~(-val / 0x100000000);\n\n        if (low ^ 0xffffffff) {\n            low = (low + 1) | 0;\n        } else {\n            low = 0;\n            high = (high + 1) | 0;\n        }\n    }\n\n    if (val >= 0x10000000000000000 || val < -0x10000000000000000) {\n        throw new Error('Given varint doesn\\'t fit into 10 bytes');\n    }\n\n    pbf.realloc(10);\n\n    writeBigVarintLow(low, high, pbf);\n    writeBigVarintHigh(high, pbf);\n}\n\nfunction writeBigVarintLow(low, high, pbf) {\n    pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;\n    pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;\n    pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;\n    pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;\n    pbf.buf[pbf.pos]   = low & 0x7f;\n}\n\nfunction writeBigVarintHigh(high, pbf) {\n    var lsb = (high & 0x07) << 4;\n\n    pbf.buf[pbf.pos++] |= lsb         | ((high >>>= 3) ? 0x80 : 0); if (!high) return;\n    pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;\n    pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;\n    pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;\n    pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;\n    pbf.buf[pbf.pos++]  = high & 0x7f;\n}\n\nfunction makeRoomForExtraLength(startPos, len, pbf) {\n    var extraLen =\n        len <= 0x3fff ? 1 :\n        len <= 0x1fffff ? 2 :\n        len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7));\n\n    // if 1 byte isn't enough for encoding message length, shift the data to the right\n    pbf.realloc(extraLen);\n    for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i];\n}\n\nfunction writePackedVarint(arr, pbf)   { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]);   }\nfunction writePackedSVarint(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]);  }\nfunction writePackedFloat(arr, pbf)    { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]);    }\nfunction writePackedDouble(arr, pbf)   { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]);   }\nfunction writePackedBoolean(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]);  }\nfunction writePackedFixed32(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]);  }\nfunction writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); }\nfunction writePackedFixed64(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]);  }\nfunction writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); }\n\n// Buffer code below from https://github.com/feross/buffer, MIT-licensed\n\nfunction readUInt32(buf, pos) {\n    return ((buf[pos]) |\n        (buf[pos + 1] << 8) |\n        (buf[pos + 2] << 16)) +\n        (buf[pos + 3] * 0x1000000);\n}\n\nfunction writeInt32(buf, val, pos) {\n    buf[pos] = val;\n    buf[pos + 1] = (val >>> 8);\n    buf[pos + 2] = (val >>> 16);\n    buf[pos + 3] = (val >>> 24);\n}\n\nfunction readInt32(buf, pos) {\n    return ((buf[pos]) |\n        (buf[pos + 1] << 8) |\n        (buf[pos + 2] << 16)) +\n        (buf[pos + 3] << 24);\n}\n\nfunction readUtf8(buf, pos, end) {\n    var str = '';\n    var i = pos;\n\n    while (i < end) {\n        var b0 = buf[i];\n        var c = null; // codepoint\n        var bytesPerSequence =\n            b0 > 0xEF ? 4 :\n            b0 > 0xDF ? 3 :\n            b0 > 0xBF ? 2 : 1;\n\n        if (i + bytesPerSequence > end) break;\n\n        var b1, b2, b3;\n\n        if (bytesPerSequence === 1) {\n            if (b0 < 0x80) {\n                c = b0;\n            }\n        } else if (bytesPerSequence === 2) {\n            b1 = buf[i + 1];\n            if ((b1 & 0xC0) === 0x80) {\n                c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F);\n                if (c <= 0x7F) {\n                    c = null;\n                }\n            }\n        } else if (bytesPerSequence === 3) {\n            b1 = buf[i + 1];\n            b2 = buf[i + 2];\n            if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {\n                c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F);\n                if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) {\n                    c = null;\n                }\n            }\n        } else if (bytesPerSequence === 4) {\n            b1 = buf[i + 1];\n            b2 = buf[i + 2];\n            b3 = buf[i + 3];\n            if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {\n                c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F);\n                if (c <= 0xFFFF || c >= 0x110000) {\n                    c = null;\n                }\n            }\n        }\n\n        if (c === null) {\n            c = 0xFFFD;\n            bytesPerSequence = 1;\n\n        } else if (c > 0xFFFF) {\n            c -= 0x10000;\n            str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);\n            c = 0xDC00 | c & 0x3FF;\n        }\n\n        str += String.fromCharCode(c);\n        i += bytesPerSequence;\n    }\n\n    return str;\n}\n\nfunction writeUtf8(buf, str, pos) {\n    for (var i = 0, c, lead; i < str.length; i++) {\n        c = str.charCodeAt(i); // code point\n\n        if (c > 0xD7FF && c < 0xE000) {\n            if (lead) {\n                if (c < 0xDC00) {\n                    buf[pos++] = 0xEF;\n                    buf[pos++] = 0xBF;\n                    buf[pos++] = 0xBD;\n                    lead = c;\n                    continue;\n                } else {\n                    c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;\n                    lead = null;\n                }\n            } else {\n                if (c > 0xDBFF || (i + 1 === str.length)) {\n                    buf[pos++] = 0xEF;\n                    buf[pos++] = 0xBF;\n                    buf[pos++] = 0xBD;\n                } else {\n                    lead = c;\n                }\n                continue;\n            }\n        } else if (lead) {\n            buf[pos++] = 0xEF;\n            buf[pos++] = 0xBF;\n            buf[pos++] = 0xBD;\n            lead = null;\n        }\n\n        if (c < 0x80) {\n            buf[pos++] = c;\n        } else {\n            if (c < 0x800) {\n                buf[pos++] = c >> 0x6 | 0xC0;\n            } else {\n                if (c < 0x10000) {\n                    buf[pos++] = c >> 0xC | 0xE0;\n                } else {\n                    buf[pos++] = c >> 0x12 | 0xF0;\n                    buf[pos++] = c >> 0xC & 0x3F | 0x80;\n                }\n                buf[pos++] = c >> 0x6 & 0x3F | 0x80;\n            }\n            buf[pos++] = c & 0x3F | 0x80;\n        }\n    }\n    return pos;\n}\n\n},{\"ieee754\":1}]},{},[2])(2)\n});\nol.ext.pbf = module.exports;\n})();\n\ngoog.provide('ol.ext.vectortile');\n/** @typedef {function(*)} */\nol.ext.vectortile;\n(function() {\nvar exports = {};\nvar module = {exports: exports};\nvar define;\n/**\n * @fileoverview\n * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}\n */\n(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){\n'use strict';\n\nmodule.exports = Point;\n\nfunction Point(x, y) {\n    this.x = x;\n    this.y = y;\n}\n\nPoint.prototype = {\n    clone: function() { return new Point(this.x, this.y); },\n\n    add:     function(p) { return this.clone()._add(p);     },\n    sub:     function(p) { return this.clone()._sub(p);     },\n    mult:    function(k) { return this.clone()._mult(k);    },\n    div:     function(k) { return this.clone()._div(k);     },\n    rotate:  function(a) { return this.clone()._rotate(a);  },\n    matMult: function(m) { return this.clone()._matMult(m); },\n    unit:    function() { return this.clone()._unit(); },\n    perp:    function() { return this.clone()._perp(); },\n    round:   function() { return this.clone()._round(); },\n\n    mag: function() {\n        return Math.sqrt(this.x * this.x + this.y * this.y);\n    },\n\n    equals: function(p) {\n        return this.x === p.x &&\n               this.y === p.y;\n    },\n\n    dist: function(p) {\n        return Math.sqrt(this.distSqr(p));\n    },\n\n    distSqr: function(p) {\n        var dx = p.x - this.x,\n            dy = p.y - this.y;\n        return dx * dx + dy * dy;\n    },\n\n    angle: function() {\n        return Math.atan2(this.y, this.x);\n    },\n\n    angleTo: function(b) {\n        return Math.atan2(this.y - b.y, this.x - b.x);\n    },\n\n    angleWith: function(b) {\n        return this.angleWithSep(b.x, b.y);\n    },\n\n    // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ.\n    angleWithSep: function(x, y) {\n        return Math.atan2(\n            this.x * y - this.y * x,\n            this.x * x + this.y * y);\n    },\n\n    _matMult: function(m) {\n        var x = m[0] * this.x + m[1] * this.y,\n            y = m[2] * this.x + m[3] * this.y;\n        this.x = x;\n        this.y = y;\n        return this;\n    },\n\n    _add: function(p) {\n        this.x += p.x;\n        this.y += p.y;\n        return this;\n    },\n\n    _sub: function(p) {\n        this.x -= p.x;\n        this.y -= p.y;\n        return this;\n    },\n\n    _mult: function(k) {\n        this.x *= k;\n        this.y *= k;\n        return this;\n    },\n\n    _div: function(k) {\n        this.x /= k;\n        this.y /= k;\n        return this;\n    },\n\n    _unit: function() {\n        this._div(this.mag());\n        return this;\n    },\n\n    _perp: function() {\n        var y = this.y;\n        this.y = this.x;\n        this.x = -y;\n        return this;\n    },\n\n    _rotate: function(angle) {\n        var cos = Math.cos(angle),\n            sin = Math.sin(angle),\n            x = cos * this.x - sin * this.y,\n            y = sin * this.x + cos * this.y;\n        this.x = x;\n        this.y = y;\n        return this;\n    },\n\n    _round: function() {\n        this.x = Math.round(this.x);\n        this.y = Math.round(this.y);\n        return this;\n    }\n};\n\n// constructs Point from an array if necessary\nPoint.convert = function (a) {\n    if (a instanceof Point) {\n        return a;\n    }\n    if (Array.isArray(a)) {\n        return new Point(a[0], a[1]);\n    }\n    return a;\n};\n\n},{}],2:[function(_dereq_,module,exports){\nmodule.exports.VectorTile = _dereq_('./lib/vectortile.js');\nmodule.exports.VectorTileFeature = _dereq_('./lib/vectortilefeature.js');\nmodule.exports.VectorTileLayer = _dereq_('./lib/vectortilelayer.js');\n\n},{\"./lib/vectortile.js\":3,\"./lib/vectortilefeature.js\":4,\"./lib/vectortilelayer.js\":5}],3:[function(_dereq_,module,exports){\n'use strict';\n\nvar VectorTileLayer = _dereq_('./vectortilelayer');\n\nmodule.exports = VectorTile;\n\nfunction VectorTile(pbf, end) {\n    this.layers = pbf.readFields(readTile, {}, end);\n}\n\nfunction readTile(tag, layers, pbf) {\n    if (tag === 3) {\n        var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);\n        if (layer.length) layers[layer.name] = layer;\n    }\n}\n\n\n},{\"./vectortilelayer\":5}],4:[function(_dereq_,module,exports){\n'use strict';\n\nvar Point = _dereq_('point-geometry');\n\nmodule.exports = VectorTileFeature;\n\nfunction VectorTileFeature(pbf, end, extent, keys, values) {\n    // Public\n    this.properties = {};\n    this.extent = extent;\n    this.type = 0;\n\n    // Private\n    this._pbf = pbf;\n    this._geometry = -1;\n    this._keys = keys;\n    this._values = values;\n\n    pbf.readFields(readFeature, this, end);\n}\n\nfunction readFeature(tag, feature, pbf) {\n    if (tag == 1) feature.id = pbf.readVarint();\n    else if (tag == 2) readTag(pbf, feature);\n    else if (tag == 3) feature.type = pbf.readVarint();\n    else if (tag == 4) feature._geometry = pbf.pos;\n}\n\nfunction readTag(pbf, feature) {\n    var end = pbf.readVarint() + pbf.pos;\n\n    while (pbf.pos < end) {\n        var key = feature._keys[pbf.readVarint()],\n            value = feature._values[pbf.readVarint()];\n        feature.properties[key] = value;\n    }\n}\n\nVectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];\n\nVectorTileFeature.prototype.loadGeometry = function() {\n    var pbf = this._pbf;\n    pbf.pos = this._geometry;\n\n    var end = pbf.readVarint() + pbf.pos,\n        cmd = 1,\n        length = 0,\n        x = 0,\n        y = 0,\n        lines = [],\n        line;\n\n    while (pbf.pos < end) {\n        if (!length) {\n            var cmdLen = pbf.readVarint();\n            cmd = cmdLen & 0x7;\n            length = cmdLen >> 3;\n        }\n\n        length--;\n\n        if (cmd === 1 || cmd === 2) {\n            x += pbf.readSVarint();\n            y += pbf.readSVarint();\n\n            if (cmd === 1) { // moveTo\n                if (line) lines.push(line);\n                line = [];\n            }\n\n            line.push(new Point(x, y));\n\n        } else if (cmd === 7) {\n\n            // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90\n            if (line) {\n                line.push(line[0].clone()); // closePolygon\n            }\n\n        } else {\n            throw new Error('unknown command ' + cmd);\n        }\n    }\n\n    if (line) lines.push(line);\n\n    return lines;\n};\n\nVectorTileFeature.prototype.bbox = function() {\n    var pbf = this._pbf;\n    pbf.pos = this._geometry;\n\n    var end = pbf.readVarint() + pbf.pos,\n        cmd = 1,\n        length = 0,\n        x = 0,\n        y = 0,\n        x1 = Infinity,\n        x2 = -Infinity,\n        y1 = Infinity,\n        y2 = -Infinity;\n\n    while (pbf.pos < end) {\n        if (!length) {\n            var cmdLen = pbf.readVarint();\n            cmd = cmdLen & 0x7;\n            length = cmdLen >> 3;\n        }\n\n        length--;\n\n        if (cmd === 1 || cmd === 2) {\n            x += pbf.readSVarint();\n            y += pbf.readSVarint();\n            if (x < x1) x1 = x;\n            if (x > x2) x2 = x;\n            if (y < y1) y1 = y;\n            if (y > y2) y2 = y;\n\n        } else if (cmd !== 7) {\n            throw new Error('unknown command ' + cmd);\n        }\n    }\n\n    return [x1, y1, x2, y2];\n};\n\nVectorTileFeature.prototype.toGeoJSON = function(x, y, z) {\n    var size = this.extent * Math.pow(2, z),\n        x0 = this.extent * x,\n        y0 = this.extent * y,\n        coords = this.loadGeometry(),\n        type = VectorTileFeature.types[this.type],\n        i, j;\n\n    function project(line) {\n        for (var j = 0; j < line.length; j++) {\n            var p = line[j], y2 = 180 - (p.y + y0) * 360 / size;\n            line[j] = [\n                (p.x + x0) * 360 / size - 180,\n                360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90\n            ];\n        }\n    }\n\n    switch (this.type) {\n    case 1:\n        var points = [];\n        for (i = 0; i < coords.length; i++) {\n            points[i] = coords[i][0];\n        }\n        coords = points;\n        project(coords);\n        break;\n\n    case 2:\n        for (i = 0; i < coords.length; i++) {\n            project(coords[i]);\n        }\n        break;\n\n    case 3:\n        coords = classifyRings(coords);\n        for (i = 0; i < coords.length; i++) {\n            for (j = 0; j < coords[i].length; j++) {\n                project(coords[i][j]);\n            }\n        }\n        break;\n    }\n\n    if (coords.length === 1) {\n        coords = coords[0];\n    } else {\n        type = 'Multi' + type;\n    }\n\n    var result = {\n        type: \"Feature\",\n        geometry: {\n            type: type,\n            coordinates: coords\n        },\n        properties: this.properties\n    };\n\n    if ('id' in this) {\n        result.id = this.id;\n    }\n\n    return result;\n};\n\n// classifies an array of rings into polygons with outer rings and holes\n\nfunction classifyRings(rings) {\n    var len = rings.length;\n\n    if (len <= 1) return [rings];\n\n    var polygons = [],\n        polygon,\n        ccw;\n\n    for (var i = 0; i < len; i++) {\n        var area = signedArea(rings[i]);\n        if (area === 0) continue;\n\n        if (ccw === undefined) ccw = area < 0;\n\n        if (ccw === area < 0) {\n            if (polygon) polygons.push(polygon);\n            polygon = [rings[i]];\n\n        } else {\n            polygon.push(rings[i]);\n        }\n    }\n    if (polygon) polygons.push(polygon);\n\n    return polygons;\n}\n\nfunction signedArea(ring) {\n    var sum = 0;\n    for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {\n        p1 = ring[i];\n        p2 = ring[j];\n        sum += (p2.x - p1.x) * (p1.y + p2.y);\n    }\n    return sum;\n}\n\n},{\"point-geometry\":1}],5:[function(_dereq_,module,exports){\n'use strict';\n\nvar VectorTileFeature = _dereq_('./vectortilefeature.js');\n\nmodule.exports = VectorTileLayer;\n\nfunction VectorTileLayer(pbf, end) {\n    // Public\n    this.version = 1;\n    this.name = null;\n    this.extent = 4096;\n    this.length = 0;\n\n    // Private\n    this._pbf = pbf;\n    this._keys = [];\n    this._values = [];\n    this._features = [];\n\n    pbf.readFields(readLayer, this, end);\n\n    this.length = this._features.length;\n}\n\nfunction readLayer(tag, layer, pbf) {\n    if (tag === 15) layer.version = pbf.readVarint();\n    else if (tag === 1) layer.name = pbf.readString();\n    else if (tag === 5) layer.extent = pbf.readVarint();\n    else if (tag === 2) layer._features.push(pbf.pos);\n    else if (tag === 3) layer._keys.push(pbf.readString());\n    else if (tag === 4) layer._values.push(readValueMessage(pbf));\n}\n\nfunction readValueMessage(pbf) {\n    var value = null,\n        end = pbf.readVarint() + pbf.pos;\n\n    while (pbf.pos < end) {\n        var tag = pbf.readVarint() >> 3;\n\n        value = tag === 1 ? pbf.readString() :\n            tag === 2 ? pbf.readFloat() :\n            tag === 3 ? pbf.readDouble() :\n            tag === 4 ? pbf.readVarint64() :\n            tag === 5 ? pbf.readVarint() :\n            tag === 6 ? pbf.readSVarint() :\n            tag === 7 ? pbf.readBoolean() : null;\n    }\n\n    return value;\n}\n\n// return feature `i` from this layer as a `VectorTileFeature`\nVectorTileLayer.prototype.feature = function(i) {\n    if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');\n\n    this._pbf.pos = this._features[i];\n\n    var end = this._pbf.readVarint() + this._pbf.pos;\n    return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);\n};\n\n},{\"./vectortilefeature.js\":4}]},{},[2])(2)\n});\nol.ext.vectortile = module.exports;\n})();\n\ngoog.provide('ol.render.Feature');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryType');\n\n\n/**\n * Lightweight, read-only, {@link ol.Feature} and {@link ol.geom.Geometry} like\n * structure, optimized for rendering and styling. Geometry access through the\n * API is limited to getting the type and extent of the geometry.\n *\n * @constructor\n * @param {ol.geom.GeometryType} type Geometry type.\n * @param {Array.<number>} flatCoordinates Flat coordinates. These always need\n *     to be right-handed for polygons.\n * @param {Array.<number>|Array.<Array.<number>>} ends Ends or Endss.\n * @param {Object.<string, *>} properties Properties.\n */\nol.render.Feature = function(type, flatCoordinates, ends, properties) {\n\n  /**\n   * @private\n   * @type {ol.Extent|undefined}\n   */\n  this.extent_;\n\n  ol.DEBUG && console.assert(type === ol.geom.GeometryType.POINT ||\n      type === ol.geom.GeometryType.MULTI_POINT ||\n      type === ol.geom.GeometryType.LINE_STRING ||\n      type === ol.geom.GeometryType.MULTI_LINE_STRING ||\n      type === ol.geom.GeometryType.POLYGON,\n      'Need a Point, MultiPoint, LineString, MultiLineString or Polygon type');\n\n  /**\n   * @private\n   * @type {ol.geom.GeometryType}\n   */\n  this.type_ = type;\n\n  /**\n   * @private\n   * @type {Array.<number>}\n   */\n  this.flatCoordinates_ = flatCoordinates;\n\n  /**\n   * @private\n   * @type {Array.<number>|Array.<Array.<number>>}\n   */\n  this.ends_ = ends;\n\n  /**\n   * @private\n   * @type {Object.<string, *>}\n   */\n  this.properties_ = properties;\n\n};\n\n\n/**\n * Get a feature property by its key.\n * @param {string} key Key\n * @return {*} Value for the requested key.\n * @api\n */\nol.render.Feature.prototype.get = function(key) {\n  return this.properties_[key];\n};\n\n\n/**\n * @return {Array.<number>|Array.<Array.<number>>} Ends or endss.\n */\nol.render.Feature.prototype.getEnds = function() {\n  return this.ends_;\n};\n\n\n/**\n * Get the extent of this feature's geometry.\n * @return {ol.Extent} Extent.\n * @api\n */\nol.render.Feature.prototype.getExtent = function() {\n  if (!this.extent_) {\n    this.extent_ = this.type_ === ol.geom.GeometryType.POINT ?\n        ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates_) :\n        ol.extent.createOrUpdateFromFlatCoordinates(\n            this.flatCoordinates_, 0, this.flatCoordinates_.length, 2);\n\n  }\n  return this.extent_;\n};\n\n\n/**\n * @return {Array.<number>} Flat coordinates.\n */\nol.render.Feature.prototype.getOrientedFlatCoordinates = function() {\n  return this.flatCoordinates_;\n};\n\n\n/**\n * @return {Array.<number>} Flat coordinates.\n */\nol.render.Feature.prototype.getFlatCoordinates =\n    ol.render.Feature.prototype.getOrientedFlatCoordinates;\n\n\n/**\n * Get the feature for working with its geometry.\n * @return {ol.render.Feature} Feature.\n * @api\n */\nol.render.Feature.prototype.getGeometry = function() {\n  return this;\n};\n\n\n/**\n * Get the feature properties.\n * @return {Object.<string, *>} Feature properties.\n * @api\n */\nol.render.Feature.prototype.getProperties = function() {\n  return this.properties_;\n};\n\n\n/**\n * Get the feature for working with its geometry.\n * @return {ol.render.Feature} Feature.\n */\nol.render.Feature.prototype.getSimplifiedGeometry =\n    ol.render.Feature.prototype.getGeometry;\n\n\n/**\n * @return {number} Stride.\n */\nol.render.Feature.prototype.getStride = function() {\n  return 2;\n};\n\n\n/**\n * @return {undefined}\n */\nol.render.Feature.prototype.getStyleFunction = ol.nullFunction;\n\n\n/**\n * Get the type of this feature's geometry.\n * @return {ol.geom.GeometryType} Geometry type.\n * @api\n */\nol.render.Feature.prototype.getType = function() {\n  return this.type_;\n};\n\n//FIXME Implement projection handling\n\ngoog.provide('ol.format.MVT');\n\ngoog.require('ol');\ngoog.require('ol.ext.pbf');\ngoog.require('ol.ext.vectortile');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.FormatType');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.proj.Projection');\ngoog.require('ol.proj.Units');\ngoog.require('ol.render.Feature');\n\n\n/**\n * @classdesc\n * Feature format for reading data in the Mapbox MVT format.\n *\n * @constructor\n * @extends {ol.format.Feature}\n * @param {olx.format.MVTOptions=} opt_options Options.\n * @api\n */\nol.format.MVT = function(opt_options) {\n\n  ol.format.Feature.call(this);\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @type {ol.proj.Projection}\n   */\n  this.defaultDataProjection = new ol.proj.Projection({\n    code: '',\n    units: ol.proj.Units.TILE_PIXELS\n  });\n\n  /**\n   * @private\n   * @type {function((ol.geom.Geometry|Object.<string, *>)=)|\n   *     function(ol.geom.GeometryType,Array.<number>,\n   *         (Array.<number>|Array.<Array.<number>>),Object.<string, *>)}\n   */\n  this.featureClass_ = options.featureClass ?\n      options.featureClass : ol.render.Feature;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.geometryName_ = options.geometryName ?\n      options.geometryName : 'geometry';\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.layerName_ = options.layerName ? options.layerName : 'layer';\n\n  /**\n   * @private\n   * @type {Array.<string>}\n   */\n  this.layers_ = options.layers ? options.layers : null;\n\n};\nol.inherits(ol.format.MVT, ol.format.Feature);\n\n\n/**\n * @inheritDoc\n */\nol.format.MVT.prototype.getType = function() {\n  return ol.format.FormatType.ARRAY_BUFFER;\n};\n\n\n/**\n * @private\n * @param {Object} rawFeature Raw Mapbox feature.\n * @param {string} layer Layer.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n */\nol.format.MVT.prototype.readFeature_ = function(\n    rawFeature, layer, opt_options) {\n  var feature = new this.featureClass_();\n  var id = rawFeature.id;\n  var values = rawFeature.properties;\n  values[this.layerName_] = layer;\n  var geometry = ol.format.Feature.transformWithOptions(\n      ol.format.MVT.readGeometry_(rawFeature), false,\n      this.adaptOptions(opt_options));\n  if (geometry) {\n    values[this.geometryName_] = geometry;\n  }\n  feature.setId(id);\n  feature.setProperties(values);\n  feature.setGeometryName(this.geometryName_);\n  return feature;\n};\n\n\n/**\n * @private\n * @param {Object} rawFeature Raw Mapbox feature.\n * @param {string} layer Layer.\n * @return {ol.render.Feature} Feature.\n */\nol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) {\n  var coords = rawFeature.loadGeometry();\n  var ends = [];\n  var flatCoordinates = [];\n  ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends);\n\n  var type = rawFeature.type;\n  /** @type {ol.geom.GeometryType} */\n  var geometryType;\n  if (type === 1) {\n    geometryType = coords.length === 1 ?\n        ol.geom.GeometryType.POINT : ol.geom.GeometryType.MULTI_POINT;\n  } else if (type === 2) {\n    if (coords.length === 1) {\n      geometryType = ol.geom.GeometryType.LINE_STRING;\n    } else {\n      geometryType = ol.geom.GeometryType.MULTI_LINE_STRING;\n    }\n  } else if (type === 3) {\n    geometryType = ol.geom.GeometryType.POLYGON;\n  }\n\n  var values = rawFeature.properties;\n  values[this.layerName_] = layer;\n\n  return new this.featureClass_(geometryType, flatCoordinates, ends, values);\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.format.MVT.prototype.readFeatures = function(source, opt_options) {\n  var layers = this.layers_;\n\n  var pbf = new ol.ext.pbf(/** @type {ArrayBuffer} */ (source));\n  var tile = new ol.ext.vectortile.VectorTile(pbf);\n  var features = [];\n  var featureClass = this.featureClass_;\n  var layer, feature;\n  for (var name in tile.layers) {\n    if (layers && layers.indexOf(name) == -1) {\n      continue;\n    }\n    layer = tile.layers[name];\n\n    for (var i = 0, ii = layer.length; i < ii; ++i) {\n      if (featureClass === ol.render.Feature) {\n        feature = this.readRenderFeature_(layer.feature(i), name);\n      } else {\n        feature = this.readFeature_(layer.feature(i), name, opt_options);\n      }\n      features.push(feature);\n    }\n  }\n\n  return features;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.format.MVT.prototype.readProjection = function(source) {\n  return this.defaultDataProjection;\n};\n\n\n/**\n * Sets the layers that features will be read from.\n * @param {Array.<string>} layers Layers.\n * @api\n */\nol.format.MVT.prototype.setLayers = function(layers) {\n  this.layers_ = layers;\n};\n\n\n/**\n * @private\n * @param {Object} coords Raw feature coordinates.\n * @param {Array.<number>} flatCoordinates Flat coordinates to be populated by\n *     this function.\n * @param {Array.<number>} ends Ends to be populated by this function.\n */\nol.format.MVT.calculateFlatCoordinates_ = function(\n    coords, flatCoordinates, ends) {\n  var end = 0;\n  for (var i = 0, ii = coords.length; i < ii; ++i) {\n    var line = coords[i];\n    var j, jj;\n    for (j = 0, jj = line.length; j < jj; ++j) {\n      var coord = line[j];\n      // Non-tilespace coords can be calculated here when a TileGrid and\n      // TileCoord are known.\n      flatCoordinates.push(coord.x, coord.y);\n    }\n    end += 2 * j;\n    ends.push(end);\n  }\n};\n\n\n/**\n * @private\n * @param {Object} rawFeature Raw Mapbox feature.\n * @return {ol.geom.Geometry} Geometry.\n */\nol.format.MVT.readGeometry_ = function(rawFeature) {\n  var type = rawFeature.type;\n  if (type === 0) {\n    return null;\n  }\n\n  var coords = rawFeature.loadGeometry();\n  var ends = [];\n  var flatCoordinates = [];\n  ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends);\n\n  var geom;\n  if (type === 1) {\n    geom = coords.length === 1 ?\n        new ol.geom.Point(null) : new ol.geom.MultiPoint(null);\n  } else if (type === 2) {\n    if (coords.length === 1) {\n      geom = new ol.geom.LineString(null);\n    } else {\n      geom = new ol.geom.MultiLineString(null);\n    }\n  } else if (type === 3) {\n    geom = new ol.geom.Polygon(null);\n  }\n\n  geom.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,\n      ends);\n\n  return geom;\n};\n\n// FIXME add typedef for stack state objects\ngoog.provide('ol.format.OSMXML');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.Feature');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.XMLFeature');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Feature format for reading data in the\n * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML).\n *\n * @constructor\n * @extends {ol.format.XMLFeature}\n * @api stable\n */\nol.format.OSMXML = function() {\n  ol.format.XMLFeature.call(this);\n\n  /**\n   * @inheritDoc\n   */\n  this.defaultDataProjection = ol.proj.get('EPSG:4326');\n};\nol.inherits(ol.format.OSMXML, ol.format.XMLFeature);\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.OSMXML.EXTENSIONS_ = ['.osm'];\n\n\n/**\n * @inheritDoc\n */\nol.format.OSMXML.prototype.getExtensions = function() {\n  return ol.format.OSMXML.EXTENSIONS_;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.OSMXML.readNode_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'node', 'localName should be node');\n  var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);\n  var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var id = node.getAttribute('id');\n  /** @type {ol.Coordinate} */\n  var coordinates = [\n    parseFloat(node.getAttribute('lon')),\n    parseFloat(node.getAttribute('lat'))\n  ];\n  state.nodes[id] = coordinates;\n\n  var values = ol.xml.pushParseAndPop({\n    tags: {}\n  }, ol.format.OSMXML.NODE_PARSERS_, node, objectStack);\n  if (!ol.obj.isEmpty(values.tags)) {\n    var geometry = new ol.geom.Point(coordinates);\n    ol.format.Feature.transformWithOptions(geometry, false, options);\n    var feature = new ol.Feature(geometry);\n    feature.setId(id);\n    feature.setProperties(values.tags);\n    state.features.push(feature);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.OSMXML.readWay_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'way', 'localName should be way');\n  var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);\n  var id = node.getAttribute('id');\n  var values = ol.xml.pushParseAndPop({\n    ndrefs: [],\n    tags: {}\n  }, ol.format.OSMXML.WAY_PARSERS_, node, objectStack);\n  var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  /** @type {Array.<number>} */\n  var flatCoordinates = [];\n  for (var i = 0, ii = values.ndrefs.length; i < ii; i++) {\n    var point = state.nodes[values.ndrefs[i]];\n    ol.array.extend(flatCoordinates, point);\n  }\n  var geometry;\n  if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) {\n    // closed way\n    geometry = new ol.geom.Polygon(null);\n    geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,\n        [flatCoordinates.length]);\n  } else {\n    geometry = new ol.geom.LineString(null);\n    geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);\n  }\n  ol.format.Feature.transformWithOptions(geometry, false, options);\n  var feature = new ol.Feature(geometry);\n  feature.setId(id);\n  feature.setProperties(values.tags);\n  state.features.push(feature);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.OSMXML.readNd_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'nd', 'localName should be nd');\n  var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  values.ndrefs.push(node.getAttribute('ref'));\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.OSMXML.readTag_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'tag', 'localName should be tag');\n  var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  values.tags[node.getAttribute('k')] = node.getAttribute('v');\n};\n\n\n/**\n * @const\n * @private\n * @type {Array.<string>}\n */\nol.format.OSMXML.NAMESPACE_URIS_ = [\n  null\n];\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OSMXML.NAMESPACE_URIS_, {\n      'nd': ol.format.OSMXML.readNd_,\n      'tag': ol.format.OSMXML.readTag_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OSMXML.PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OSMXML.NAMESPACE_URIS_, {\n      'node': ol.format.OSMXML.readNode_,\n      'way': ol.format.OSMXML.readWay_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OSMXML.NAMESPACE_URIS_, {\n      'tag': ol.format.OSMXML.readTag_\n    });\n\n\n/**\n * Read all features from an OSM source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.OSMXML.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  var options = this.getReadOptions(node, opt_options);\n  if (node.localName == 'osm') {\n    var state = ol.xml.pushParseAndPop({\n      nodes: {},\n      features: []\n    }, ol.format.OSMXML.PARSERS_, node, [options]);\n    if (state.features) {\n      return state.features;\n    }\n  }\n  return [];\n};\n\n\n/**\n * Read the projection from an OSM source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n * @api stable\n */\nol.format.OSMXML.prototype.readProjection;\n\ngoog.provide('ol.format.XLink');\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.XLink.NAMESPACE_URI = 'http://www.w3.org/1999/xlink';\n\n\n/**\n * @param {Node} node Node.\n * @return {boolean|undefined} Boolean.\n */\nol.format.XLink.readHref = function(node) {\n  return node.getAttributeNS(ol.format.XLink.NAMESPACE_URI, 'href');\n};\n\ngoog.provide('ol.format.XML');\n\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Generic format for reading non-feature XML data\n *\n * @constructor\n * @struct\n */\nol.format.XML = function() {\n};\n\n\n/**\n * @param {Document|Node|string} source Source.\n * @return {Object} The parsed result.\n */\nol.format.XML.prototype.read = function(source) {\n  if (ol.xml.isDocument(source)) {\n    return this.readFromDocument(/** @type {Document} */ (source));\n  } else if (ol.xml.isNode(source)) {\n    return this.readFromNode(/** @type {Node} */ (source));\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readFromDocument(doc);\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * @abstract\n * @param {Document} doc Document.\n * @return {Object} Object\n */\nol.format.XML.prototype.readFromDocument = function(doc) {};\n\n\n/**\n * @abstract\n * @param {Node} node Node.\n * @return {Object} Object\n */\nol.format.XML.prototype.readFromNode = function(node) {};\n\ngoog.provide('ol.format.OWS');\n\ngoog.require('ol');\ngoog.require('ol.format.XLink');\ngoog.require('ol.format.XML');\ngoog.require('ol.format.XSD');\ngoog.require('ol.xml');\n\n\n/**\n * @constructor\n * @extends {ol.format.XML}\n */\nol.format.OWS = function() {\n  ol.format.XML.call(this);\n};\nol.inherits(ol.format.OWS, ol.format.XML);\n\n\n/**\n * @param {Document} doc Document.\n * @return {Object} OWS object.\n */\nol.format.OWS.prototype.readFromDocument = function(doc) {\n  ol.DEBUG && console.assert(doc.nodeType == Node.DOCUMENT_NODE,\n      'doc.nodeType should be DOCUMENT');\n  for (var n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      return this.readFromNode(n);\n    }\n  }\n  return null;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {Object} OWS object.\n */\nol.format.OWS.prototype.readFromNode = function(node) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  var owsObject = ol.xml.pushParseAndPop({},\n      ol.format.OWS.PARSERS_, node, []);\n  return owsObject ? owsObject : null;\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The address.\n */\nol.format.OWS.readAddress_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Address',\n      'localName should be Address');\n  return ol.xml.pushParseAndPop({},\n      ol.format.OWS.ADDRESS_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The values.\n */\nol.format.OWS.readAllowedValues_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'AllowedValues',\n      'localName should be AllowedValues');\n  return ol.xml.pushParseAndPop({},\n      ol.format.OWS.ALLOWED_VALUES_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The constraint.\n */\nol.format.OWS.readConstraint_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Constraint',\n      'localName should be Constraint');\n  var name = node.getAttribute('name');\n  if (!name) {\n    return undefined;\n  }\n  return ol.xml.pushParseAndPop({'name': name},\n      ol.format.OWS.CONSTRAINT_PARSERS_, node,\n      objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The contact info.\n */\nol.format.OWS.readContactInfo_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ContactInfo',\n      'localName should be ContactInfo');\n  return ol.xml.pushParseAndPop({},\n      ol.format.OWS.CONTACT_INFO_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The DCP.\n */\nol.format.OWS.readDcp_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'DCP', 'localName should be DCP');\n  return ol.xml.pushParseAndPop({},\n      ol.format.OWS.DCP_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The GET object.\n */\nol.format.OWS.readGet_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Get', 'localName should be Get');\n  var href = ol.format.XLink.readHref(node);\n  if (!href) {\n    return undefined;\n  }\n  return ol.xml.pushParseAndPop({'href': href},\n      ol.format.OWS.REQUEST_METHOD_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The HTTP object.\n */\nol.format.OWS.readHttp_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'HTTP', 'localName should be HTTP');\n  return ol.xml.pushParseAndPop({}, ol.format.OWS.HTTP_PARSERS_,\n      node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The operation.\n */\nol.format.OWS.readOperation_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Operation',\n      'localName should be Operation');\n  var name = node.getAttribute('name');\n  var value = ol.xml.pushParseAndPop({},\n      ol.format.OWS.OPERATION_PARSERS_, node, objectStack);\n  if (!value) {\n    return undefined;\n  }\n  var object = /** @type {Object} */\n      (objectStack[objectStack.length - 1]);\n  object[name] = value;\n\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The operations metadata.\n */\nol.format.OWS.readOperationsMetadata_ = function(node,\n    objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'OperationsMetadata',\n      'localName should be OperationsMetadata');\n  return ol.xml.pushParseAndPop({},\n      ol.format.OWS.OPERATIONS_METADATA_PARSERS_, node,\n      objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The phone.\n */\nol.format.OWS.readPhone_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Phone', 'localName should be Phone');\n  return ol.xml.pushParseAndPop({},\n      ol.format.OWS.PHONE_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The service identification.\n */\nol.format.OWS.readServiceIdentification_ = function(node,\n    objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ServiceIdentification',\n      'localName should be ServiceIdentification');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_, node,\n      objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The service contact.\n */\nol.format.OWS.readServiceContact_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ServiceContact',\n      'localName should be ServiceContact');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.OWS.SERVICE_CONTACT_PARSERS_, node,\n      objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} The service provider.\n */\nol.format.OWS.readServiceProvider_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ServiceProvider',\n      'localName should be ServiceProvider');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.OWS.SERVICE_PROVIDER_PARSERS_, node,\n      objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {string|undefined} The value.\n */\nol.format.OWS.readValue_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Value', 'localName should be Value');\n  return ol.format.XSD.readString(node);\n};\n\n\n/**\n * @const\n * @type {Array.<string>}\n * @private\n */\nol.format.OWS.NAMESPACE_URIS_ = [\n  null,\n  'http://www.opengis.net/ows/1.1'\n];\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'ServiceIdentification': ol.xml.makeObjectPropertySetter(\n          ol.format.OWS.readServiceIdentification_),\n      'ServiceProvider': ol.xml.makeObjectPropertySetter(\n          ol.format.OWS.readServiceProvider_),\n      'OperationsMetadata': ol.xml.makeObjectPropertySetter(\n          ol.format.OWS.readOperationsMetadata_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.ADDRESS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'DeliveryPoint': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'AdministrativeArea': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'PostalCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'ElectronicMailAddress': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.ALLOWED_VALUES_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'Value': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readValue_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.CONSTRAINT_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'AllowedValues': ol.xml.makeObjectPropertySetter(\n          ol.format.OWS.readAllowedValues_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.CONTACT_INFO_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'Phone': ol.xml.makeObjectPropertySetter(ol.format.OWS.readPhone_),\n      'Address': ol.xml.makeObjectPropertySetter(ol.format.OWS.readAddress_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.DCP_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'HTTP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readHttp_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.HTTP_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'Get': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readGet_),\n      'Post': undefined // TODO\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.OPERATION_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'DCP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readDcp_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.OPERATIONS_METADATA_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'Operation': ol.format.OWS.readOperation_\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.PHONE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'Voice': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Facsimile': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.REQUEST_METHOD_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'Constraint': ol.xml.makeObjectPropertyPusher(\n          ol.format.OWS.readConstraint_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.SERVICE_CONTACT_PARSERS_ =\n    ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'IndividualName': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'PositionName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'ContactInfo': ol.xml.makeObjectPropertySetter(\n          ol.format.OWS.readContactInfo_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ =\n    ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'ServiceTypeVersion': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'ServiceType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.OWS.SERVICE_PROVIDER_PARSERS_ =\n    ol.xml.makeStructureNS(\n    ol.format.OWS.NAMESPACE_URIS_, {\n      'ProviderName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'ProviderSite': ol.xml.makeObjectPropertySetter(ol.format.XLink.readHref),\n      'ServiceContact': ol.xml.makeObjectPropertySetter(\n          ol.format.OWS.readServiceContact_)\n    });\n\ngoog.provide('ol.geom.flat.flip');\n\n\n/**\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {Array.<number>=} opt_dest Destination.\n * @param {number=} opt_destOffset Destination offset.\n * @return {Array.<number>} Flat coordinates.\n */\nol.geom.flat.flip.flipXY = function(flatCoordinates, offset, end, stride, opt_dest, opt_destOffset) {\n  var dest, destOffset;\n  if (opt_dest !== undefined) {\n    dest = opt_dest;\n    destOffset = opt_destOffset !== undefined ? opt_destOffset : 0;\n  } else {\n    dest = [];\n    destOffset = 0;\n  }\n  var j = offset;\n  while (j < end) {\n    var x = flatCoordinates[j++];\n    dest[destOffset++] = flatCoordinates[j++];\n    dest[destOffset++] = x;\n    for (var k = 2; k < stride; ++k) {\n      dest[destOffset++] = flatCoordinates[j++];\n    }\n  }\n  dest.length = destOffset;\n  return dest;\n};\n\ngoog.provide('ol.format.Polyline');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.Feature');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.TextFeature');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.flip');\ngoog.require('ol.geom.flat.inflate');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the Encoded\n * Polyline Algorithm Format.\n *\n * @constructor\n * @extends {ol.format.TextFeature}\n * @param {olx.format.PolylineOptions=} opt_options\n *     Optional configuration object.\n * @api stable\n */\nol.format.Polyline = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.TextFeature.call(this);\n\n  /**\n   * @inheritDoc\n   */\n  this.defaultDataProjection = ol.proj.get('EPSG:4326');\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.factor_ = options.factor ? options.factor : 1e5;\n\n  /**\n   * @private\n   * @type {ol.geom.GeometryLayout}\n   */\n  this.geometryLayout_ = options.geometryLayout ?\n      options.geometryLayout : ol.geom.GeometryLayout.XY;\n};\nol.inherits(ol.format.Polyline, ol.format.TextFeature);\n\n\n/**\n * Encode a list of n-dimensional points and return an encoded string\n *\n * Attention: This function will modify the passed array!\n *\n * @param {Array.<number>} numbers A list of n-dimensional points.\n * @param {number} stride The number of dimension of the points in the list.\n * @param {number=} opt_factor The factor by which the numbers will be\n *     multiplied. The remaining decimal places will get rounded away.\n *     Default is `1e5`.\n * @return {string} The encoded string.\n * @api\n */\nol.format.Polyline.encodeDeltas = function(numbers, stride, opt_factor) {\n  var factor = opt_factor ? opt_factor : 1e5;\n  var d;\n\n  var lastNumbers = new Array(stride);\n  for (d = 0; d < stride; ++d) {\n    lastNumbers[d] = 0;\n  }\n\n  var i, ii;\n  for (i = 0, ii = numbers.length; i < ii;) {\n    for (d = 0; d < stride; ++d, ++i) {\n      var num = numbers[i];\n      var delta = num - lastNumbers[d];\n      lastNumbers[d] = num;\n\n      numbers[i] = delta;\n    }\n  }\n\n  return ol.format.Polyline.encodeFloats(numbers, factor);\n};\n\n\n/**\n * Decode a list of n-dimensional points from an encoded string\n *\n * @param {string} encoded An encoded string.\n * @param {number} stride The number of dimension of the points in the\n *     encoded string.\n * @param {number=} opt_factor The factor by which the resulting numbers will\n *     be divided. Default is `1e5`.\n * @return {Array.<number>} A list of n-dimensional points.\n * @api\n */\nol.format.Polyline.decodeDeltas = function(encoded, stride, opt_factor) {\n  var factor = opt_factor ? opt_factor : 1e5;\n  var d;\n\n  /** @type {Array.<number>} */\n  var lastNumbers = new Array(stride);\n  for (d = 0; d < stride; ++d) {\n    lastNumbers[d] = 0;\n  }\n\n  var numbers = ol.format.Polyline.decodeFloats(encoded, factor);\n\n  var i, ii;\n  for (i = 0, ii = numbers.length; i < ii;) {\n    for (d = 0; d < stride; ++d, ++i) {\n      lastNumbers[d] += numbers[i];\n\n      numbers[i] = lastNumbers[d];\n    }\n  }\n\n  return numbers;\n};\n\n\n/**\n * Encode a list of floating point numbers and return an encoded string\n *\n * Attention: This function will modify the passed array!\n *\n * @param {Array.<number>} numbers A list of floating point numbers.\n * @param {number=} opt_factor The factor by which the numbers will be\n *     multiplied. The remaining decimal places will get rounded away.\n *     Default is `1e5`.\n * @return {string} The encoded string.\n * @api\n */\nol.format.Polyline.encodeFloats = function(numbers, opt_factor) {\n  var factor = opt_factor ? opt_factor : 1e5;\n  var i, ii;\n  for (i = 0, ii = numbers.length; i < ii; ++i) {\n    numbers[i] = Math.round(numbers[i] * factor);\n  }\n\n  return ol.format.Polyline.encodeSignedIntegers(numbers);\n};\n\n\n/**\n * Decode a list of floating point numbers from an encoded string\n *\n * @param {string} encoded An encoded string.\n * @param {number=} opt_factor The factor by which the result will be divided.\n *     Default is `1e5`.\n * @return {Array.<number>} A list of floating point numbers.\n * @api\n */\nol.format.Polyline.decodeFloats = function(encoded, opt_factor) {\n  var factor = opt_factor ? opt_factor : 1e5;\n  var numbers = ol.format.Polyline.decodeSignedIntegers(encoded);\n  var i, ii;\n  for (i = 0, ii = numbers.length; i < ii; ++i) {\n    numbers[i] /= factor;\n  }\n  return numbers;\n};\n\n\n/**\n * Encode a list of signed integers and return an encoded string\n *\n * Attention: This function will modify the passed array!\n *\n * @param {Array.<number>} numbers A list of signed integers.\n * @return {string} The encoded string.\n */\nol.format.Polyline.encodeSignedIntegers = function(numbers) {\n  var i, ii;\n  for (i = 0, ii = numbers.length; i < ii; ++i) {\n    var num = numbers[i];\n    numbers[i] = (num < 0) ? ~(num << 1) : (num << 1);\n  }\n  return ol.format.Polyline.encodeUnsignedIntegers(numbers);\n};\n\n\n/**\n * Decode a list of signed integers from an encoded string\n *\n * @param {string} encoded An encoded string.\n * @return {Array.<number>} A list of signed integers.\n */\nol.format.Polyline.decodeSignedIntegers = function(encoded) {\n  var numbers = ol.format.Polyline.decodeUnsignedIntegers(encoded);\n  var i, ii;\n  for (i = 0, ii = numbers.length; i < ii; ++i) {\n    var num = numbers[i];\n    numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);\n  }\n  return numbers;\n};\n\n\n/**\n * Encode a list of unsigned integers and return an encoded string\n *\n * @param {Array.<number>} numbers A list of unsigned integers.\n * @return {string} The encoded string.\n */\nol.format.Polyline.encodeUnsignedIntegers = function(numbers) {\n  var encoded = '';\n  var i, ii;\n  for (i = 0, ii = numbers.length; i < ii; ++i) {\n    encoded += ol.format.Polyline.encodeUnsignedInteger(numbers[i]);\n  }\n  return encoded;\n};\n\n\n/**\n * Decode a list of unsigned integers from an encoded string\n *\n * @param {string} encoded An encoded string.\n * @return {Array.<number>} A list of unsigned integers.\n */\nol.format.Polyline.decodeUnsignedIntegers = function(encoded) {\n  var numbers = [];\n  var current = 0;\n  var shift = 0;\n  var i, ii;\n  for (i = 0, ii = encoded.length; i < ii; ++i) {\n    var b = encoded.charCodeAt(i) - 63;\n    current |= (b & 0x1f) << shift;\n    if (b < 0x20) {\n      numbers.push(current);\n      current = 0;\n      shift = 0;\n    } else {\n      shift += 5;\n    }\n  }\n  return numbers;\n};\n\n\n/**\n * Encode one single unsigned integer and return an encoded string\n *\n * @param {number} num Unsigned integer that should be encoded.\n * @return {string} The encoded string.\n */\nol.format.Polyline.encodeUnsignedInteger = function(num) {\n  var value, encoded = '';\n  while (num >= 0x20) {\n    value = (0x20 | (num & 0x1f)) + 63;\n    encoded += String.fromCharCode(value);\n    num >>= 5;\n  }\n  value = num + 63;\n  encoded += String.fromCharCode(value);\n  return encoded;\n};\n\n\n/**\n * Read the feature from the Polyline source. The coordinates are assumed to be\n * in two dimensions and in latitude, longitude order.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @api stable\n */\nol.format.Polyline.prototype.readFeature;\n\n\n/**\n * @inheritDoc\n */\nol.format.Polyline.prototype.readFeatureFromText = function(text, opt_options) {\n  var geometry = this.readGeometryFromText(text, opt_options);\n  return new ol.Feature(geometry);\n};\n\n\n/**\n * Read the feature from the source. As Polyline sources contain a single\n * feature, this will return the feature in an array.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.Polyline.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.Polyline.prototype.readFeaturesFromText = function(text, opt_options) {\n  var feature = this.readFeatureFromText(text, opt_options);\n  return [feature];\n};\n\n\n/**\n * Read the geometry from the source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.geom.Geometry} Geometry.\n * @api stable\n */\nol.format.Polyline.prototype.readGeometry;\n\n\n/**\n * @inheritDoc\n */\nol.format.Polyline.prototype.readGeometryFromText = function(text, opt_options) {\n  var stride = ol.geom.SimpleGeometry.getStrideForLayout(this.geometryLayout_);\n  var flatCoordinates = ol.format.Polyline.decodeDeltas(\n      text, stride, this.factor_);\n  ol.geom.flat.flip.flipXY(\n      flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);\n  var coordinates = ol.geom.flat.inflate.coordinates(\n      flatCoordinates, 0, flatCoordinates.length, stride);\n\n  return /** @type {ol.geom.Geometry} */ (\n      ol.format.Feature.transformWithOptions(\n          new ol.geom.LineString(coordinates, this.geometryLayout_), false,\n          this.adaptOptions(opt_options)));\n};\n\n\n/**\n * Read the projection from a Polyline source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.proj.Projection} Projection.\n * @api stable\n */\nol.format.Polyline.prototype.readProjection;\n\n\n/**\n * @inheritDoc\n */\nol.format.Polyline.prototype.writeFeatureText = function(feature, opt_options) {\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    return this.writeGeometryText(geometry, opt_options);\n  } else {\n    ol.asserts.assert(false, 40); // Expected `feature` to have a geometry\n    return '';\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.Polyline.prototype.writeFeaturesText = function(features, opt_options) {\n  ol.DEBUG && console.assert(features.length == 1,\n      'features array should have 1 item');\n  return this.writeFeatureText(features[0], opt_options);\n};\n\n\n/**\n * Write a single geometry in Polyline format.\n *\n * @function\n * @param {ol.geom.Geometry} geometry Geometry.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} Geometry.\n * @api stable\n */\nol.format.Polyline.prototype.writeGeometry;\n\n\n/**\n * @inheritDoc\n */\nol.format.Polyline.prototype.writeGeometryText = function(geometry, opt_options) {\n  geometry = /** @type {ol.geom.LineString} */\n      (ol.format.Feature.transformWithOptions(\n          geometry, true, this.adaptOptions(opt_options)));\n  var flatCoordinates = geometry.getFlatCoordinates();\n  var stride = geometry.getStride();\n  ol.geom.flat.flip.flipXY(\n      flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);\n  return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_);\n};\n\ngoog.provide('ol.format.TopoJSON');\n\ngoog.require('ol');\ngoog.require('ol.Feature');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.JSONFeature');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Feature format for reading data in the TopoJSON format.\n *\n * @constructor\n * @extends {ol.format.JSONFeature}\n * @param {olx.format.TopoJSONOptions=} opt_options Options.\n * @api stable\n */\nol.format.TopoJSON = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.JSONFeature.call(this);\n\n  /**\n   * @inheritDoc\n   */\n  this.defaultDataProjection = ol.proj.get(\n      options.defaultDataProjection ?\n          options.defaultDataProjection : 'EPSG:4326');\n\n};\nol.inherits(ol.format.TopoJSON, ol.format.JSONFeature);\n\n\n/**\n * @const {Array.<string>}\n * @private\n */\nol.format.TopoJSON.EXTENSIONS_ = ['.topojson'];\n\n\n/**\n * Concatenate arcs into a coordinate array.\n * @param {Array.<number>} indices Indices of arcs to concatenate.  Negative\n *     values indicate arcs need to be reversed.\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs (already\n *     transformed).\n * @return {Array.<ol.Coordinate>} Coordinates array.\n * @private\n */\nol.format.TopoJSON.concatenateArcs_ = function(indices, arcs) {\n  /** @type {Array.<ol.Coordinate>} */\n  var coordinates = [];\n  var index, arc;\n  var i, ii;\n  var j, jj;\n  for (i = 0, ii = indices.length; i < ii; ++i) {\n    index = indices[i];\n    if (i > 0) {\n      // splicing together arcs, discard last point\n      coordinates.pop();\n    }\n    if (index >= 0) {\n      // forward arc\n      arc = arcs[index];\n    } else {\n      // reverse arc\n      arc = arcs[~index].slice().reverse();\n    }\n    coordinates.push.apply(coordinates, arc);\n  }\n  // provide fresh copies of coordinate arrays\n  for (j = 0, jj = coordinates.length; j < jj; ++j) {\n    coordinates[j] = coordinates[j].slice();\n  }\n  return coordinates;\n};\n\n\n/**\n * Create a point from a TopoJSON geometry object.\n *\n * @param {TopoJSONGeometry} object TopoJSON object.\n * @param {Array.<number>} scale Scale for each dimension.\n * @param {Array.<number>} translate Translation for each dimension.\n * @return {ol.geom.Point} Geometry.\n * @private\n */\nol.format.TopoJSON.readPointGeometry_ = function(object, scale, translate) {\n  var coordinates = object.coordinates;\n  if (scale && translate) {\n    ol.format.TopoJSON.transformVertex_(coordinates, scale, translate);\n  }\n  return new ol.geom.Point(coordinates);\n};\n\n\n/**\n * Create a multi-point from a TopoJSON geometry object.\n *\n * @param {TopoJSONGeometry} object TopoJSON object.\n * @param {Array.<number>} scale Scale for each dimension.\n * @param {Array.<number>} translate Translation for each dimension.\n * @return {ol.geom.MultiPoint} Geometry.\n * @private\n */\nol.format.TopoJSON.readMultiPointGeometry_ = function(object, scale,\n    translate) {\n  var coordinates = object.coordinates;\n  var i, ii;\n  if (scale && translate) {\n    for (i = 0, ii = coordinates.length; i < ii; ++i) {\n      ol.format.TopoJSON.transformVertex_(coordinates[i], scale, translate);\n    }\n  }\n  return new ol.geom.MultiPoint(coordinates);\n};\n\n\n/**\n * Create a linestring from a TopoJSON geometry object.\n *\n * @param {TopoJSONGeometry} object TopoJSON object.\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.\n * @return {ol.geom.LineString} Geometry.\n * @private\n */\nol.format.TopoJSON.readLineStringGeometry_ = function(object, arcs) {\n  var coordinates = ol.format.TopoJSON.concatenateArcs_(object.arcs, arcs);\n  return new ol.geom.LineString(coordinates);\n};\n\n\n/**\n * Create a multi-linestring from a TopoJSON geometry object.\n *\n * @param {TopoJSONGeometry} object TopoJSON object.\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.\n * @return {ol.geom.MultiLineString} Geometry.\n * @private\n */\nol.format.TopoJSON.readMultiLineStringGeometry_ = function(object, arcs) {\n  var coordinates = [];\n  var i, ii;\n  for (i = 0, ii = object.arcs.length; i < ii; ++i) {\n    coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);\n  }\n  return new ol.geom.MultiLineString(coordinates);\n};\n\n\n/**\n * Create a polygon from a TopoJSON geometry object.\n *\n * @param {TopoJSONGeometry} object TopoJSON object.\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.\n * @return {ol.geom.Polygon} Geometry.\n * @private\n */\nol.format.TopoJSON.readPolygonGeometry_ = function(object, arcs) {\n  var coordinates = [];\n  var i, ii;\n  for (i = 0, ii = object.arcs.length; i < ii; ++i) {\n    coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);\n  }\n  return new ol.geom.Polygon(coordinates);\n};\n\n\n/**\n * Create a multi-polygon from a TopoJSON geometry object.\n *\n * @param {TopoJSONGeometry} object TopoJSON object.\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.\n * @return {ol.geom.MultiPolygon} Geometry.\n * @private\n */\nol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) {\n  var coordinates = [];\n  var polyArray, ringCoords, j, jj;\n  var i, ii;\n  for (i = 0, ii = object.arcs.length; i < ii; ++i) {\n    // for each polygon\n    polyArray = object.arcs[i];\n    ringCoords = [];\n    for (j = 0, jj = polyArray.length; j < jj; ++j) {\n      // for each ring\n      ringCoords[j] = ol.format.TopoJSON.concatenateArcs_(polyArray[j], arcs);\n    }\n    coordinates[i] = ringCoords;\n  }\n  return new ol.geom.MultiPolygon(coordinates);\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.TopoJSON.prototype.getExtensions = function() {\n  return ol.format.TopoJSON.EXTENSIONS_;\n};\n\n\n/**\n * Create features from a TopoJSON GeometryCollection object.\n *\n * @param {TopoJSONGeometryCollection} collection TopoJSON Geometry\n *     object.\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.\n * @param {Array.<number>} scale Scale for each dimension.\n * @param {Array.<number>} translate Translation for each dimension.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Array of features.\n * @private\n */\nol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function(\n    collection, arcs, scale, translate, opt_options) {\n  var geometries = collection.geometries;\n  var features = [];\n  var i, ii;\n  for (i = 0, ii = geometries.length; i < ii; ++i) {\n    features[i] = ol.format.TopoJSON.readFeatureFromGeometry_(\n        geometries[i], arcs, scale, translate, opt_options);\n  }\n  return features;\n};\n\n\n/**\n * Create a feature from a TopoJSON geometry object.\n *\n * @param {TopoJSONGeometry} object TopoJSON geometry object.\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.\n * @param {Array.<number>} scale Scale for each dimension.\n * @param {Array.<number>} translate Translation for each dimension.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @private\n */\nol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs,\n    scale, translate, opt_options) {\n  var geometry;\n  var type = object.type;\n  var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type];\n  if ((type === 'Point') || (type === 'MultiPoint')) {\n    geometry = geometryReader(object, scale, translate);\n  } else {\n    geometry = geometryReader(object, arcs);\n  }\n  var feature = new ol.Feature();\n  feature.setGeometry(/** @type {ol.geom.Geometry} */ (\n      ol.format.Feature.transformWithOptions(geometry, false, opt_options)));\n  if (object.id !== undefined) {\n    feature.setId(object.id);\n  }\n  if (object.properties) {\n    feature.setProperties(object.properties);\n  }\n  return feature;\n};\n\n\n/**\n * Read all features from a TopoJSON source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.TopoJSON.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.TopoJSON.prototype.readFeaturesFromObject = function(\n    object, opt_options) {\n  if (object.type == 'Topology') {\n    var topoJSONTopology = /** @type {TopoJSONTopology} */ (object);\n    var transform, scale = null, translate = null;\n    if (topoJSONTopology.transform) {\n      transform = topoJSONTopology.transform;\n      scale = transform.scale;\n      translate = transform.translate;\n    }\n    var arcs = topoJSONTopology.arcs;\n    if (transform) {\n      ol.format.TopoJSON.transformArcs_(arcs, scale, translate);\n    }\n    /** @type {Array.<ol.Feature>} */\n    var features = [];\n    var topoJSONFeatures = ol.obj.getValues(topoJSONTopology.objects);\n    var i, ii;\n    var feature;\n    for (i = 0, ii = topoJSONFeatures.length; i < ii; ++i) {\n      if (topoJSONFeatures[i].type === 'GeometryCollection') {\n        feature = /** @type {TopoJSONGeometryCollection} */\n            (topoJSONFeatures[i]);\n        features.push.apply(features,\n            ol.format.TopoJSON.readFeaturesFromGeometryCollection_(\n                feature, arcs, scale, translate, opt_options));\n      } else {\n        feature = /** @type {TopoJSONGeometry} */\n            (topoJSONFeatures[i]);\n        features.push(ol.format.TopoJSON.readFeatureFromGeometry_(\n            feature, arcs, scale, translate, opt_options));\n      }\n    }\n    return features;\n  } else {\n    return [];\n  }\n};\n\n\n/**\n * Apply a linear transform to array of arcs.  The provided array of arcs is\n * modified in place.\n *\n * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.\n * @param {Array.<number>} scale Scale for each dimension.\n * @param {Array.<number>} translate Translation for each dimension.\n * @private\n */\nol.format.TopoJSON.transformArcs_ = function(arcs, scale, translate) {\n  var i, ii;\n  for (i = 0, ii = arcs.length; i < ii; ++i) {\n    ol.format.TopoJSON.transformArc_(arcs[i], scale, translate);\n  }\n};\n\n\n/**\n * Apply a linear transform to an arc.  The provided arc is modified in place.\n *\n * @param {Array.<ol.Coordinate>} arc Arc.\n * @param {Array.<number>} scale Scale for each dimension.\n * @param {Array.<number>} translate Translation for each dimension.\n * @private\n */\nol.format.TopoJSON.transformArc_ = function(arc, scale, translate) {\n  var x = 0;\n  var y = 0;\n  var vertex;\n  var i, ii;\n  for (i = 0, ii = arc.length; i < ii; ++i) {\n    vertex = arc[i];\n    x += vertex[0];\n    y += vertex[1];\n    vertex[0] = x;\n    vertex[1] = y;\n    ol.format.TopoJSON.transformVertex_(vertex, scale, translate);\n  }\n};\n\n\n/**\n * Apply a linear transform to a vertex.  The provided vertex is modified in\n * place.\n *\n * @param {ol.Coordinate} vertex Vertex.\n * @param {Array.<number>} scale Scale for each dimension.\n * @param {Array.<number>} translate Translation for each dimension.\n * @private\n */\nol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) {\n  vertex[0] = vertex[0] * scale[0] + translate[0];\n  vertex[1] = vertex[1] * scale[1] + translate[1];\n};\n\n\n/**\n * Read the projection from a TopoJSON source.\n *\n * @function\n * @param {Document|Node|Object|string} object Source.\n * @return {ol.proj.Projection} Projection.\n * @api stable\n */\nol.format.TopoJSON.prototype.readProjection = function(object) {\n  return this.defaultDataProjection;\n};\n\n\n/**\n * @const\n * @private\n * @type {Object.<string, function(TopoJSONGeometry, Array, ...Array): ol.geom.Geometry>}\n */\nol.format.TopoJSON.GEOMETRY_READERS_ = {\n  'Point': ol.format.TopoJSON.readPointGeometry_,\n  'LineString': ol.format.TopoJSON.readLineStringGeometry_,\n  'Polygon': ol.format.TopoJSON.readPolygonGeometry_,\n  'MultiPoint': ol.format.TopoJSON.readMultiPointGeometry_,\n  'MultiLineString': ol.format.TopoJSON.readMultiLineStringGeometry_,\n  'MultiPolygon': ol.format.TopoJSON.readMultiPolygonGeometry_\n};\n\ngoog.provide('ol.format.WFS');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.format.GML3');\ngoog.require('ol.format.GMLBase');\ngoog.require('ol.format.filter');\ngoog.require('ol.format.XMLFeature');\ngoog.require('ol.format.XSD');\ngoog.require('ol.geom.Geometry');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Feature format for reading and writing data in the WFS format.\n * By default, supports WFS version 1.1.0. You can pass a GML format\n * as option if you want to read a WFS that contains GML2 (WFS 1.0.0).\n * Also see {@link ol.format.GMLBase} which is used by this format.\n *\n * @constructor\n * @param {olx.format.WFSOptions=} opt_options\n *     Optional configuration object.\n * @extends {ol.format.XMLFeature}\n * @api stable\n */\nol.format.WFS = function(opt_options) {\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {Array.<string>|string|undefined}\n   */\n  this.featureType_ = options.featureType;\n\n  /**\n   * @private\n   * @type {Object.<string, string>|string|undefined}\n   */\n  this.featureNS_ = options.featureNS;\n\n  /**\n   * @private\n   * @type {ol.format.GMLBase}\n   */\n  this.gmlFormat_ = options.gmlFormat ?\n      options.gmlFormat : new ol.format.GML3();\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.schemaLocation_ = options.schemaLocation ?\n      options.schemaLocation : ol.format.WFS.SCHEMA_LOCATION;\n\n  ol.format.XMLFeature.call(this);\n};\nol.inherits(ol.format.WFS, ol.format.XMLFeature);\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WFS.FEATURE_PREFIX = 'feature';\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WFS.XMLNS = 'http://www.w3.org/2000/xmlns/';\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WFS.OGCNS = 'http://www.opengis.net/ogc';\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WFS.WFSNS = 'http://www.opengis.net/wfs';\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WFS.SCHEMA_LOCATION = 'http://www.opengis.net/wfs ' +\n    'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd';\n\n\n/**\n * Read all features from a WFS FeatureCollection.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.WFS.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.WFS.prototype.readFeaturesFromNode = function(node, opt_options) {\n  var context = /** @type {ol.XmlNodeStackItem} */ ({\n    'featureType': this.featureType_,\n    'featureNS': this.featureNS_\n  });\n  ol.obj.assign(context, this.getReadOptions(node,\n      opt_options ? opt_options : {}));\n  var objectStack = [context];\n  this.gmlFormat_.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][\n      'featureMember'] =\n      ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal);\n  var features = ol.xml.pushParseAndPop([],\n      this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,\n      objectStack, this.gmlFormat_);\n  if (!features) {\n    features = [];\n  }\n  return features;\n};\n\n\n/**\n * Read transaction response of the source.\n *\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.WFSTransactionResponse|undefined} Transaction response.\n * @api stable\n */\nol.format.WFS.prototype.readTransactionResponse = function(source) {\n  if (ol.xml.isDocument(source)) {\n    return this.readTransactionResponseFromDocument(\n        /** @type {Document} */ (source));\n  } else if (ol.xml.isNode(source)) {\n    return this.readTransactionResponseFromNode(/** @type {Node} */ (source));\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readTransactionResponseFromDocument(doc);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * Read feature collection metadata of the source.\n *\n * @param {Document|Node|Object|string} source Source.\n * @return {ol.WFSFeatureCollectionMetadata|undefined}\n *     FeatureCollection metadata.\n * @api stable\n */\nol.format.WFS.prototype.readFeatureCollectionMetadata = function(source) {\n  if (ol.xml.isDocument(source)) {\n    return this.readFeatureCollectionMetadataFromDocument(\n        /** @type {Document} */ (source));\n  } else if (ol.xml.isNode(source)) {\n    return this.readFeatureCollectionMetadataFromNode(\n        /** @type {Node} */ (source));\n  } else if (typeof source === 'string') {\n    var doc = ol.xml.parse(source);\n    return this.readFeatureCollectionMetadataFromDocument(doc);\n  } else {\n    return undefined;\n  }\n};\n\n\n/**\n * @param {Document} doc Document.\n * @return {ol.WFSFeatureCollectionMetadata|undefined}\n *     FeatureCollection metadata.\n */\nol.format.WFS.prototype.readFeatureCollectionMetadataFromDocument = function(doc) {\n  ol.DEBUG && console.assert(doc.nodeType == Node.DOCUMENT_NODE,\n      'doc.nodeType should be DOCUMENT');\n  for (var n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      return this.readFeatureCollectionMetadataFromNode(n);\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WFS.FEATURE_COLLECTION_PARSERS_ = {\n  'http://www.opengis.net/gml': {\n    'boundedBy': ol.xml.makeObjectPropertySetter(\n        ol.format.GMLBase.prototype.readGeometryElement, 'bounds')\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {ol.WFSFeatureCollectionMetadata|undefined}\n *     FeatureCollection metadata.\n */\nol.format.WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'FeatureCollection',\n      'localName should be FeatureCollection');\n  var result = {};\n  var value = ol.format.XSD.readNonNegativeIntegerString(\n      node.getAttribute('numberOfFeatures'));\n  result['numberOfFeatures'] = value;\n  return ol.xml.pushParseAndPop(\n      /** @type {ol.WFSFeatureCollectionMetadata} */ (result),\n      ol.format.WFS.FEATURE_COLLECTION_PARSERS_, node, [], this.gmlFormat_);\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WFS.TRANSACTION_SUMMARY_PARSERS_ = {\n  'http://www.opengis.net/wfs': {\n    'totalInserted': ol.xml.makeObjectPropertySetter(\n        ol.format.XSD.readNonNegativeInteger),\n    'totalUpdated': ol.xml.makeObjectPropertySetter(\n        ol.format.XSD.readNonNegativeInteger),\n    'totalDeleted': ol.xml.makeObjectPropertySetter(\n        ol.format.XSD.readNonNegativeInteger)\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Transaction Summary.\n * @private\n */\nol.format.WFS.readTransactionSummary_ = function(node, objectStack) {\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WFS.OGC_FID_PARSERS_ = {\n  'http://www.opengis.net/ogc': {\n    'FeatureId': ol.xml.makeArrayPusher(function(node, objectStack) {\n      return node.getAttribute('fid');\n    })\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n */\nol.format.WFS.fidParser_ = function(node, objectStack) {\n  ol.xml.parseNode(ol.format.WFS.OGC_FID_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WFS.INSERT_RESULTS_PARSERS_ = {\n  'http://www.opengis.net/wfs': {\n    'Feature': ol.format.WFS.fidParser_\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Array.<string>|undefined} Insert results.\n * @private\n */\nol.format.WFS.readInsertResults_ = function(node, objectStack) {\n  return ol.xml.pushParseAndPop(\n      [], ol.format.WFS.INSERT_RESULTS_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WFS.TRANSACTION_RESPONSE_PARSERS_ = {\n  'http://www.opengis.net/wfs': {\n    'TransactionSummary': ol.xml.makeObjectPropertySetter(\n        ol.format.WFS.readTransactionSummary_, 'transactionSummary'),\n    'InsertResults': ol.xml.makeObjectPropertySetter(\n        ol.format.WFS.readInsertResults_, 'insertIds')\n  }\n};\n\n\n/**\n * @param {Document} doc Document.\n * @return {ol.WFSTransactionResponse|undefined} Transaction response.\n */\nol.format.WFS.prototype.readTransactionResponseFromDocument = function(doc) {\n  ol.DEBUG && console.assert(doc.nodeType == Node.DOCUMENT_NODE,\n      'doc.nodeType should be DOCUMENT');\n  for (var n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      return this.readTransactionResponseFromNode(n);\n    }\n  }\n  return undefined;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {ol.WFSTransactionResponse|undefined} Transaction response.\n */\nol.format.WFS.prototype.readTransactionResponseFromNode = function(node) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should  be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'TransactionResponse',\n      'localName should be TransactionResponse');\n  return ol.xml.pushParseAndPop(\n      /** @type {ol.WFSTransactionResponse} */({}),\n      ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_, node, []);\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.WFS.QUERY_SERIALIZERS_ = {\n  'http://www.opengis.net/wfs': {\n    'PropertyName': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeFeature_ = function(node, feature, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  var featureType = context['featureType'];\n  var featureNS = context['featureNS'];\n  var child = ol.xml.createElementNS(featureNS, featureType);\n  node.appendChild(child);\n  ol.format.GML3.prototype.writeFeatureElement(child, feature, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {number|string} fid Feature identifier.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) {\n  var filter = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'Filter');\n  var child = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'FeatureId');\n  filter.appendChild(child);\n  child.setAttribute('fid', fid);\n  node.appendChild(filter);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeDelete_ = function(node, feature, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  ol.asserts.assert(feature.getId() !== undefined, 26); // Features must have an id set\n  var featureType = context['featureType'];\n  var featurePrefix = context['featurePrefix'];\n  featurePrefix = featurePrefix ? featurePrefix :\n      ol.format.WFS.FEATURE_PREFIX;\n  var featureNS = context['featureNS'];\n  node.setAttribute('typeName', featurePrefix + ':' + featureType);\n  ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,\n      featureNS);\n  var fid = feature.getId();\n  if (fid !== undefined) {\n    ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.Feature} feature Feature.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeUpdate_ = function(node, feature, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  ol.asserts.assert(feature.getId() !== undefined, 27); // Features must have an id set\n  var featureType = context['featureType'];\n  var featurePrefix = context['featurePrefix'];\n  featurePrefix = featurePrefix ? featurePrefix :\n      ol.format.WFS.FEATURE_PREFIX;\n  var featureNS = context['featureNS'];\n  node.setAttribute('typeName', featurePrefix + ':' + featureType);\n  ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,\n      featureNS);\n  var fid = feature.getId();\n  if (fid !== undefined) {\n    var keys = feature.getKeys();\n    var values = [];\n    for (var i = 0, ii = keys.length; i < ii; i++) {\n      var value = feature.get(keys[i]);\n      if (value !== undefined) {\n        values.push({name: keys[i], value: value});\n      }\n    }\n    ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */ (\n        {node: node, 'srsName': context['srsName']}),\n        ol.format.WFS.TRANSACTION_SERIALIZERS_,\n        ol.xml.makeSimpleNodeFactory('Property'), values,\n        objectStack);\n    ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Object} pair Property name and value.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeProperty_ = function(node, pair, objectStack) {\n  var name = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'Name');\n  node.appendChild(name);\n  ol.format.XSD.writeStringTextNode(name, pair.name);\n  if (pair.value !== undefined && pair.value !== null) {\n    var value = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'Value');\n    node.appendChild(value);\n    if (pair.value instanceof ol.geom.Geometry) {\n      ol.format.GML3.prototype.writeGeometryElement(value,\n          pair.value, objectStack);\n    } else {\n      ol.format.XSD.writeStringTextNode(value, pair.value);\n    }\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {{vendorId: string, safeToIgnore: boolean, value: string}}\n *     nativeElement The native element.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeNative_ = function(node, nativeElement, objectStack) {\n  if (nativeElement.vendorId) {\n    node.setAttribute('vendorId', nativeElement.vendorId);\n  }\n  if (nativeElement.safeToIgnore !== undefined) {\n    node.setAttribute('safeToIgnore', nativeElement.safeToIgnore);\n  }\n  if (nativeElement.value !== undefined) {\n    ol.format.XSD.writeStringTextNode(node, nativeElement.value);\n  }\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.WFS.TRANSACTION_SERIALIZERS_ = {\n  'http://www.opengis.net/wfs': {\n    'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_),\n    'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_),\n    'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_),\n    'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_),\n    'Native': ol.xml.makeChildAppender(ol.format.WFS.writeNative_)\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {string} featureType Feature type.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeQuery_ = function(node, featureType, objectStack) {\n  var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var featurePrefix = context['featurePrefix'];\n  var featureNS = context['featureNS'];\n  var propertyNames = context['propertyNames'];\n  var srsName = context['srsName'];\n  var prefix = featurePrefix ? featurePrefix + ':' : '';\n  node.setAttribute('typeName', prefix + featureType);\n  if (srsName) {\n    node.setAttribute('srsName', srsName);\n  }\n  if (featureNS) {\n    ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,\n        featureNS);\n  }\n  var item = /** @type {ol.XmlNodeStackItem} */ (ol.obj.assign({}, context));\n  item.node = node;\n  ol.xml.pushSerializeAndPop(item,\n      ol.format.WFS.QUERY_SERIALIZERS_,\n      ol.xml.makeSimpleNodeFactory('PropertyName'), propertyNames,\n      objectStack);\n  var filter = context['filter'];\n  if (filter) {\n    var child = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'Filter');\n    node.appendChild(child);\n    ol.format.WFS.writeFilterCondition_(child, filter, objectStack);\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.Filter} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeFilterCondition_ = function(node, filter, objectStack) {\n  /** @type {ol.XmlNodeStackItem} */\n  var item = {node: node};\n  ol.xml.pushSerializeAndPop(item,\n      ol.format.WFS.GETFEATURE_SERIALIZERS_,\n      ol.xml.makeSimpleNodeFactory(filter.getTagName()),\n      [filter], objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.Bbox} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeBboxFilter_ = function(node, filter, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  context['srsName'] = filter.srsName;\n\n  ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);\n  ol.format.GML3.prototype.writeGeometryElement(node, filter.extent, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.Intersects} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeIntersectsFilter_ = function(node, filter, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  context['srsName'] = filter.srsName;\n\n  ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);\n  ol.format.GML3.prototype.writeGeometryElement(node, filter.geometry, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.Within} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeWithinFilter_ = function(node, filter, objectStack) {\n  var context = objectStack[objectStack.length - 1];\n  context['srsName'] = filter.srsName;\n\n  ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);\n  ol.format.GML3.prototype.writeGeometryElement(node, filter.geometry, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.LogicalBinary} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeLogicalFilter_ = function(node, filter, objectStack) {\n  /** @type {ol.XmlNodeStackItem} */\n  var item = {node: node};\n  var conditionA = filter.conditionA;\n  ol.xml.pushSerializeAndPop(item,\n      ol.format.WFS.GETFEATURE_SERIALIZERS_,\n      ol.xml.makeSimpleNodeFactory(conditionA.getTagName()),\n      [conditionA], objectStack);\n  var conditionB = filter.conditionB;\n  ol.xml.pushSerializeAndPop(item,\n      ol.format.WFS.GETFEATURE_SERIALIZERS_,\n      ol.xml.makeSimpleNodeFactory(conditionB.getTagName()),\n      [conditionB], objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.Not} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeNotFilter_ = function(node, filter, objectStack) {\n  /** @type {ol.XmlNodeStackItem} */\n  var item = {node: node};\n  var condition = filter.condition;\n  ol.xml.pushSerializeAndPop(item,\n      ol.format.WFS.GETFEATURE_SERIALIZERS_,\n      ol.xml.makeSimpleNodeFactory(condition.getTagName()),\n      [condition], objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.ComparisonBinary} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeComparisonFilter_ = function(node, filter, objectStack) {\n  if (filter.matchCase !== undefined) {\n    node.setAttribute('matchCase', filter.matchCase.toString());\n  }\n  ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);\n  ol.format.WFS.writeOgcLiteral_(node, '' + filter.expression);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.IsNull} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeIsNullFilter_ = function(node, filter, objectStack) {\n  ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.IsBetween} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeIsBetweenFilter_ = function(node, filter, objectStack) {\n  ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);\n\n  var lowerBoundary = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'LowerBoundary');\n  node.appendChild(lowerBoundary);\n  ol.format.WFS.writeOgcLiteral_(lowerBoundary, '' + filter.lowerBoundary);\n\n  var upperBoundary = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'UpperBoundary');\n  node.appendChild(upperBoundary);\n  ol.format.WFS.writeOgcLiteral_(upperBoundary, '' + filter.upperBoundary);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {ol.format.filter.IsLike} filter Filter.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeIsLikeFilter_ = function(node, filter, objectStack) {\n  node.setAttribute('wildCard', filter.wildCard);\n  node.setAttribute('singleChar', filter.singleChar);\n  node.setAttribute('escapeChar', filter.escapeChar);\n  if (filter.matchCase !== undefined) {\n    node.setAttribute('matchCase', filter.matchCase.toString());\n  }\n  ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);\n  ol.format.WFS.writeOgcLiteral_(node, '' + filter.pattern);\n};\n\n\n/**\n * @param {string} tagName Tag name.\n * @param {Node} node Node.\n * @param {string} value Value.\n * @private\n */\nol.format.WFS.writeOgcExpression_ = function(tagName, node, value) {\n  var property = ol.xml.createElementNS(ol.format.WFS.OGCNS, tagName);\n  ol.format.XSD.writeStringTextNode(property, value);\n  node.appendChild(property);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {string} value PropertyName value.\n * @private\n */\nol.format.WFS.writeOgcPropertyName_ = function(node, value) {\n  ol.format.WFS.writeOgcExpression_('PropertyName', node, value);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {string} value PropertyName value.\n * @private\n */\nol.format.WFS.writeOgcLiteral_ = function(node, value) {\n  ol.format.WFS.writeOgcExpression_('Literal', node, value);\n};\n\n\n/**\n * @type {Object.<string, Object.<string, ol.XmlSerializer>>}\n * @private\n */\nol.format.WFS.GETFEATURE_SERIALIZERS_ = {\n  'http://www.opengis.net/wfs': {\n    'Query': ol.xml.makeChildAppender(ol.format.WFS.writeQuery_)\n  },\n  'http://www.opengis.net/ogc': {\n    'And': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),\n    'Or': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),\n    'Not': ol.xml.makeChildAppender(ol.format.WFS.writeNotFilter_),\n    'BBOX': ol.xml.makeChildAppender(ol.format.WFS.writeBboxFilter_),\n    'Intersects': ol.xml.makeChildAppender(ol.format.WFS.writeIntersectsFilter_),\n    'Within': ol.xml.makeChildAppender(ol.format.WFS.writeWithinFilter_),\n    'PropertyIsEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),\n    'PropertyIsNotEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),\n    'PropertyIsLessThan': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),\n    'PropertyIsLessThanOrEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),\n    'PropertyIsGreaterThan': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),\n    'PropertyIsGreaterThanOrEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),\n    'PropertyIsNull': ol.xml.makeChildAppender(ol.format.WFS.writeIsNullFilter_),\n    'PropertyIsBetween': ol.xml.makeChildAppender(ol.format.WFS.writeIsBetweenFilter_),\n    'PropertyIsLike': ol.xml.makeChildAppender(ol.format.WFS.writeIsLikeFilter_)\n  }\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<string>} featureTypes Feature types.\n * @param {Array.<*>} objectStack Node stack.\n * @private\n */\nol.format.WFS.writeGetFeature_ = function(node, featureTypes, objectStack) {\n  var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);\n  var item = /** @type {ol.XmlNodeStackItem} */ (ol.obj.assign({}, context));\n  item.node = node;\n  ol.xml.pushSerializeAndPop(item,\n      ol.format.WFS.GETFEATURE_SERIALIZERS_,\n      ol.xml.makeSimpleNodeFactory('Query'), featureTypes,\n      objectStack);\n};\n\n\n/**\n * Encode format as WFS `GetFeature` and return the Node.\n *\n * @param {olx.format.WFSWriteGetFeatureOptions} options Options.\n * @return {Node} Result.\n * @api stable\n */\nol.format.WFS.prototype.writeGetFeature = function(options) {\n  var node = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'GetFeature');\n  node.setAttribute('service', 'WFS');\n  node.setAttribute('version', '1.1.0');\n  var filter;\n  if (options) {\n    if (options.handle) {\n      node.setAttribute('handle', options.handle);\n    }\n    if (options.outputFormat) {\n      node.setAttribute('outputFormat', options.outputFormat);\n    }\n    if (options.maxFeatures !== undefined) {\n      node.setAttribute('maxFeatures', options.maxFeatures);\n    }\n    if (options.resultType) {\n      node.setAttribute('resultType', options.resultType);\n    }\n    if (options.startIndex !== undefined) {\n      node.setAttribute('startIndex', options.startIndex);\n    }\n    if (options.count !== undefined) {\n      node.setAttribute('count', options.count);\n    }\n    filter = options.filter;\n    if (options.bbox) {\n      ol.asserts.assert(options.geometryName,\n          12); // `options.geometryName` must also be provided when `options.bbox` is set\n      var bbox = ol.format.filter.bbox(\n          /** @type {string} */ (options.geometryName), options.bbox, options.srsName);\n      if (filter) {\n        // if bbox and filter are both set, combine the two into a single filter\n        filter = ol.format.filter.and(filter, bbox);\n      } else {\n        filter = bbox;\n      }\n    }\n  }\n  ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',\n      'xsi:schemaLocation', this.schemaLocation_);\n  /** @type {ol.XmlNodeStackItem} */\n  var context = {\n    node: node,\n    'srsName': options.srsName,\n    'featureNS': options.featureNS ? options.featureNS : this.featureNS_,\n    'featurePrefix': options.featurePrefix,\n    'geometryName': options.geometryName,\n    'filter': filter,\n    'propertyNames': options.propertyNames ? options.propertyNames : []\n  };\n  ol.asserts.assert(Array.isArray(options.featureTypes),\n      11); // `options.featureTypes` should be an Array\n  ol.format.WFS.writeGetFeature_(node, /** @type {!Array.<string>} */ (options.featureTypes), [context]);\n  return node;\n};\n\n\n/**\n * Encode format as WFS `Transaction` and return the Node.\n *\n * @param {Array.<ol.Feature>} inserts The features to insert.\n * @param {Array.<ol.Feature>} updates The features to update.\n * @param {Array.<ol.Feature>} deletes The features to delete.\n * @param {olx.format.WFSWriteTransactionOptions} options Write options.\n * @return {Node} Result.\n * @api stable\n */\nol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes,\n    options) {\n  var objectStack = [];\n  var node = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'Transaction');\n  node.setAttribute('service', 'WFS');\n  node.setAttribute('version', '1.1.0');\n  var baseObj;\n  /** @type {ol.XmlNodeStackItem} */\n  var obj;\n  if (options) {\n    baseObj = options.gmlOptions ? options.gmlOptions : {};\n    if (options.handle) {\n      node.setAttribute('handle', options.handle);\n    }\n  }\n  ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',\n      'xsi:schemaLocation', this.schemaLocation_);\n  if (inserts) {\n    obj = {node: node, 'featureNS': options.featureNS,\n      'featureType': options.featureType, 'featurePrefix': options.featurePrefix,\n      'srsName': options.srsName};\n    ol.obj.assign(obj, baseObj);\n    ol.xml.pushSerializeAndPop(obj,\n        ol.format.WFS.TRANSACTION_SERIALIZERS_,\n        ol.xml.makeSimpleNodeFactory('Insert'), inserts,\n        objectStack);\n  }\n  if (updates) {\n    obj = {node: node, 'featureNS': options.featureNS,\n      'featureType': options.featureType, 'featurePrefix': options.featurePrefix,\n      'srsName': options.srsName};\n    ol.obj.assign(obj, baseObj);\n    ol.xml.pushSerializeAndPop(obj,\n        ol.format.WFS.TRANSACTION_SERIALIZERS_,\n        ol.xml.makeSimpleNodeFactory('Update'), updates,\n        objectStack);\n  }\n  if (deletes) {\n    ol.xml.pushSerializeAndPop({node: node, 'featureNS': options.featureNS,\n      'featureType': options.featureType, 'featurePrefix': options.featurePrefix,\n      'srsName': options.srsName},\n    ol.format.WFS.TRANSACTION_SERIALIZERS_,\n    ol.xml.makeSimpleNodeFactory('Delete'), deletes,\n    objectStack);\n  }\n  if (options.nativeElements) {\n    ol.xml.pushSerializeAndPop({node: node, 'featureNS': options.featureNS,\n      'featureType': options.featureType, 'featurePrefix': options.featurePrefix,\n      'srsName': options.srsName},\n    ol.format.WFS.TRANSACTION_SERIALIZERS_,\n    ol.xml.makeSimpleNodeFactory('Native'), options.nativeElements,\n    objectStack);\n  }\n  return node;\n};\n\n\n/**\n * Read the projection from a WFS source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @return {?ol.proj.Projection} Projection.\n * @api stable\n */\nol.format.WFS.prototype.readProjection;\n\n\n/**\n * @inheritDoc\n */\nol.format.WFS.prototype.readProjectionFromDocument = function(doc) {\n  ol.DEBUG && console.assert(doc.nodeType == Node.DOCUMENT_NODE,\n      'doc.nodeType should be a DOCUMENT');\n  for (var n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      return this.readProjectionFromNode(n);\n    }\n  }\n  return null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.format.WFS.prototype.readProjectionFromNode = function(node) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'FeatureCollection',\n      'localName should be FeatureCollection');\n\n  if (node.firstElementChild &&\n      node.firstElementChild.firstElementChild) {\n    node = node.firstElementChild.firstElementChild;\n    for (var n = node.firstElementChild; n; n = n.nextElementSibling) {\n      if (!(n.childNodes.length === 0 ||\n          (n.childNodes.length === 1 &&\n          n.firstChild.nodeType === 3))) {\n        var objectStack = [{}];\n        this.gmlFormat_.readGeometryElement(n, objectStack);\n        return ol.proj.get(objectStack.pop().srsName);\n      }\n    }\n  }\n\n  return null;\n};\n\ngoog.provide('ol.format.WKT');\n\ngoog.require('ol');\ngoog.require('ol.Feature');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.TextFeature');\ngoog.require('ol.geom.GeometryCollection');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.geom.SimpleGeometry');\n\n\n/**\n * @classdesc\n * Geometry format for reading and writing data in the `WellKnownText` (WKT)\n * format.\n *\n * @constructor\n * @extends {ol.format.TextFeature}\n * @param {olx.format.WKTOptions=} opt_options Options.\n * @api stable\n */\nol.format.WKT = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.format.TextFeature.call(this);\n\n  /**\n   * Split GeometryCollection into multiple features.\n   * @type {boolean}\n   * @private\n   */\n  this.splitCollection_ = options.splitCollection !== undefined ?\n      options.splitCollection : false;\n\n};\nol.inherits(ol.format.WKT, ol.format.TextFeature);\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WKT.EMPTY = 'EMPTY';\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WKT.Z = 'Z';\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WKT.M = 'M';\n\n\n/**\n * @const\n * @type {string}\n */\nol.format.WKT.ZM = 'ZM';\n\n\n/**\n * @param {ol.geom.Point} geom Point geometry.\n * @return {string} Coordinates part of Point as WKT.\n * @private\n */\nol.format.WKT.encodePointGeometry_ = function(geom) {\n  var coordinates = geom.getCoordinates();\n  if (coordinates.length === 0) {\n    return '';\n  }\n  return coordinates.join(' ');\n};\n\n\n/**\n * @param {ol.geom.MultiPoint} geom MultiPoint geometry.\n * @return {string} Coordinates part of MultiPoint as WKT.\n * @private\n */\nol.format.WKT.encodeMultiPointGeometry_ = function(geom) {\n  var array = [];\n  var components = geom.getPoints();\n  for (var i = 0, ii = components.length; i < ii; ++i) {\n    array.push('(' + ol.format.WKT.encodePointGeometry_(components[i]) + ')');\n  }\n  return array.join(',');\n};\n\n\n/**\n * @param {ol.geom.GeometryCollection} geom GeometryCollection geometry.\n * @return {string} Coordinates part of GeometryCollection as WKT.\n * @private\n */\nol.format.WKT.encodeGeometryCollectionGeometry_ = function(geom) {\n  var array = [];\n  var geoms = geom.getGeometries();\n  for (var i = 0, ii = geoms.length; i < ii; ++i) {\n    array.push(ol.format.WKT.encode_(geoms[i]));\n  }\n  return array.join(',');\n};\n\n\n/**\n * @param {ol.geom.LineString|ol.geom.LinearRing} geom LineString geometry.\n * @return {string} Coordinates part of LineString as WKT.\n * @private\n */\nol.format.WKT.encodeLineStringGeometry_ = function(geom) {\n  var coordinates = geom.getCoordinates();\n  var array = [];\n  for (var i = 0, ii = coordinates.length; i < ii; ++i) {\n    array.push(coordinates[i].join(' '));\n  }\n  return array.join(',');\n};\n\n\n/**\n * @param {ol.geom.MultiLineString} geom MultiLineString geometry.\n * @return {string} Coordinates part of MultiLineString as WKT.\n * @private\n */\nol.format.WKT.encodeMultiLineStringGeometry_ = function(geom) {\n  var array = [];\n  var components = geom.getLineStrings();\n  for (var i = 0, ii = components.length; i < ii; ++i) {\n    array.push('(' + ol.format.WKT.encodeLineStringGeometry_(\n        components[i]) + ')');\n  }\n  return array.join(',');\n};\n\n\n/**\n * @param {ol.geom.Polygon} geom Polygon geometry.\n * @return {string} Coordinates part of Polygon as WKT.\n * @private\n */\nol.format.WKT.encodePolygonGeometry_ = function(geom) {\n  var array = [];\n  var rings = geom.getLinearRings();\n  for (var i = 0, ii = rings.length; i < ii; ++i) {\n    array.push('(' + ol.format.WKT.encodeLineStringGeometry_(\n        rings[i]) + ')');\n  }\n  return array.join(',');\n};\n\n\n/**\n * @param {ol.geom.MultiPolygon} geom MultiPolygon geometry.\n * @return {string} Coordinates part of MultiPolygon as WKT.\n * @private\n */\nol.format.WKT.encodeMultiPolygonGeometry_ = function(geom) {\n  var array = [];\n  var components = geom.getPolygons();\n  for (var i = 0, ii = components.length; i < ii; ++i) {\n    array.push('(' + ol.format.WKT.encodePolygonGeometry_(\n        components[i]) + ')');\n  }\n  return array.join(',');\n};\n\n/**\n * @param {ol.geom.SimpleGeometry} geom SimpleGeometry geometry.\n * @return {string} Potential dimensional information for WKT type.\n * @private\n */\nol.format.WKT.encodeGeometryLayout_ = function(geom) {\n  var layout = geom.getLayout();\n  var dimInfo = '';\n  if (layout === ol.geom.GeometryLayout.XYZ || layout === ol.geom.GeometryLayout.XYZM) {\n    dimInfo += ol.format.WKT.Z;\n  }\n  if (layout === ol.geom.GeometryLayout.XYM || layout === ol.geom.GeometryLayout.XYZM) {\n    dimInfo += ol.format.WKT.M;\n  }\n  return dimInfo;\n};\n\n\n/**\n * Encode a geometry as WKT.\n * @param {ol.geom.Geometry} geom The geometry to encode.\n * @return {string} WKT string for the geometry.\n * @private\n */\nol.format.WKT.encode_ = function(geom) {\n  var type = geom.getType();\n  var geometryEncoder = ol.format.WKT.GeometryEncoder_[type];\n  ol.DEBUG && console.assert(geometryEncoder, 'geometryEncoder should be defined');\n  var enc = geometryEncoder(geom);\n  type = type.toUpperCase();\n  if (geom instanceof ol.geom.SimpleGeometry) {\n    var dimInfo = ol.format.WKT.encodeGeometryLayout_(geom);\n    if (dimInfo.length > 0) {\n      type += ' ' + dimInfo;\n    }\n  }\n  if (enc.length === 0) {\n    return type + ' ' + ol.format.WKT.EMPTY;\n  }\n  return type + '(' + enc + ')';\n};\n\n\n/**\n * @const\n * @type {Object.<string, function(ol.geom.Geometry): string>}\n * @private\n */\nol.format.WKT.GeometryEncoder_ = {\n  'Point': ol.format.WKT.encodePointGeometry_,\n  'LineString': ol.format.WKT.encodeLineStringGeometry_,\n  'Polygon': ol.format.WKT.encodePolygonGeometry_,\n  'MultiPoint': ol.format.WKT.encodeMultiPointGeometry_,\n  'MultiLineString': ol.format.WKT.encodeMultiLineStringGeometry_,\n  'MultiPolygon': ol.format.WKT.encodeMultiPolygonGeometry_,\n  'GeometryCollection': ol.format.WKT.encodeGeometryCollectionGeometry_\n};\n\n\n/**\n * Parse a WKT string.\n * @param {string} wkt WKT string.\n * @return {ol.geom.Geometry|undefined}\n *     The geometry created.\n * @private\n */\nol.format.WKT.prototype.parse_ = function(wkt) {\n  var lexer = new ol.format.WKT.Lexer(wkt);\n  var parser = new ol.format.WKT.Parser(lexer);\n  return parser.parse();\n};\n\n\n/**\n * Read a feature from a WKT source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.Feature} Feature.\n * @api stable\n */\nol.format.WKT.prototype.readFeature;\n\n\n/**\n * @inheritDoc\n */\nol.format.WKT.prototype.readFeatureFromText = function(text, opt_options) {\n  var geom = this.readGeometryFromText(text, opt_options);\n  if (geom) {\n    var feature = new ol.Feature();\n    feature.setGeometry(geom);\n    return feature;\n  }\n  return null;\n};\n\n\n/**\n * Read all features from a WKT source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.WKT.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.WKT.prototype.readFeaturesFromText = function(text, opt_options) {\n  var geometries = [];\n  var geometry = this.readGeometryFromText(text, opt_options);\n  if (this.splitCollection_ &&\n      geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) {\n    geometries = (/** @type {ol.geom.GeometryCollection} */ (geometry))\n        .getGeometriesArray();\n  } else {\n    geometries = [geometry];\n  }\n  var feature, features = [];\n  for (var i = 0, ii = geometries.length; i < ii; ++i) {\n    feature = new ol.Feature();\n    feature.setGeometry(geometries[i]);\n    features.push(feature);\n  }\n  return features;\n};\n\n\n/**\n * Read a single geometry from a WKT source.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Read options.\n * @return {ol.geom.Geometry} Geometry.\n * @api stable\n */\nol.format.WKT.prototype.readGeometry;\n\n\n/**\n * @inheritDoc\n */\nol.format.WKT.prototype.readGeometryFromText = function(text, opt_options) {\n  var geometry = this.parse_(text);\n  if (geometry) {\n    return /** @type {ol.geom.Geometry} */ (\n        ol.format.Feature.transformWithOptions(geometry, false, opt_options));\n  } else {\n    return null;\n  }\n};\n\n\n/**\n * Encode a feature as a WKT string.\n *\n * @function\n * @param {ol.Feature} feature Feature.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} WKT string.\n * @api stable\n */\nol.format.WKT.prototype.writeFeature;\n\n\n/**\n * @inheritDoc\n */\nol.format.WKT.prototype.writeFeatureText = function(feature, opt_options) {\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    return this.writeGeometryText(geometry, opt_options);\n  }\n  return '';\n};\n\n\n/**\n * Encode an array of features as a WKT string.\n *\n * @function\n * @param {Array.<ol.Feature>} features Features.\n * @param {olx.format.WriteOptions=} opt_options Write options.\n * @return {string} WKT string.\n * @api stable\n */\nol.format.WKT.prototype.writeFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.WKT.prototype.writeFeaturesText = function(features, opt_options) {\n  if (features.length == 1) {\n    return this.writeFeatureText(features[0], opt_options);\n  }\n  var geometries = [];\n  for (var i = 0, ii = features.length; i < ii; ++i) {\n    geometries.push(features[i].getGeometry());\n  }\n  var collection = new ol.geom.GeometryCollection(geometries);\n  return this.writeGeometryText(collection, opt_options);\n};\n\n\n/**\n * Write a single geometry as a WKT string.\n *\n * @function\n * @param {ol.geom.Geometry} geometry Geometry.\n * @return {string} WKT string.\n * @api stable\n */\nol.format.WKT.prototype.writeGeometry;\n\n\n/**\n * @inheritDoc\n */\nol.format.WKT.prototype.writeGeometryText = function(geometry, opt_options) {\n  return ol.format.WKT.encode_(/** @type {ol.geom.Geometry} */ (\n      ol.format.Feature.transformWithOptions(geometry, true, opt_options)));\n};\n\n\n/**\n * @const\n * @enum {number}\n */\nol.format.WKT.TokenType = {\n  TEXT: 1,\n  LEFT_PAREN: 2,\n  RIGHT_PAREN: 3,\n  NUMBER: 4,\n  COMMA: 5,\n  EOF: 6\n};\n\n\n/**\n * Class to tokenize a WKT string.\n * @param {string} wkt WKT string.\n * @constructor\n * @protected\n */\nol.format.WKT.Lexer = function(wkt) {\n\n  /**\n   * @type {string}\n   */\n  this.wkt = wkt;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.index_ = -1;\n};\n\n\n/**\n * @param {string} c Character.\n * @return {boolean} Whether the character is alphabetic.\n * @private\n */\nol.format.WKT.Lexer.prototype.isAlpha_ = function(c) {\n  return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';\n};\n\n\n/**\n * @param {string} c Character.\n * @param {boolean=} opt_decimal Whether the string number\n *     contains a dot, i.e. is a decimal number.\n * @return {boolean} Whether the character is numeric.\n * @private\n */\nol.format.WKT.Lexer.prototype.isNumeric_ = function(c, opt_decimal) {\n  var decimal = opt_decimal !== undefined ? opt_decimal : false;\n  return c >= '0' && c <= '9' || c == '.' && !decimal;\n};\n\n\n/**\n * @param {string} c Character.\n * @return {boolean} Whether the character is whitespace.\n * @private\n */\nol.format.WKT.Lexer.prototype.isWhiteSpace_ = function(c) {\n  return c == ' ' || c == '\\t' || c == '\\r' || c == '\\n';\n};\n\n\n/**\n * @return {string} Next string character.\n * @private\n */\nol.format.WKT.Lexer.prototype.nextChar_ = function() {\n  return this.wkt.charAt(++this.index_);\n};\n\n\n/**\n * Fetch and return the next token.\n * @return {!ol.WKTToken} Next string token.\n */\nol.format.WKT.Lexer.prototype.nextToken = function() {\n  var c = this.nextChar_();\n  var token = {position: this.index_, value: c};\n\n  if (c == '(') {\n    token.type = ol.format.WKT.TokenType.LEFT_PAREN;\n  } else if (c == ',') {\n    token.type = ol.format.WKT.TokenType.COMMA;\n  } else if (c == ')') {\n    token.type = ol.format.WKT.TokenType.RIGHT_PAREN;\n  } else if (this.isNumeric_(c) || c == '-') {\n    token.type = ol.format.WKT.TokenType.NUMBER;\n    token.value = this.readNumber_();\n  } else if (this.isAlpha_(c)) {\n    token.type = ol.format.WKT.TokenType.TEXT;\n    token.value = this.readText_();\n  } else if (this.isWhiteSpace_(c)) {\n    return this.nextToken();\n  } else if (c === '') {\n    token.type = ol.format.WKT.TokenType.EOF;\n  } else {\n    throw new Error('Unexpected character: ' + c);\n  }\n\n  return token;\n};\n\n\n/**\n * @return {number} Numeric token value.\n * @private\n */\nol.format.WKT.Lexer.prototype.readNumber_ = function() {\n  var c, index = this.index_;\n  var decimal = false;\n  var scientificNotation = false;\n  do {\n    if (c == '.') {\n      decimal = true;\n    } else if (c == 'e' || c == 'E') {\n      scientificNotation = true;\n    }\n    c = this.nextChar_();\n  } while (\n      this.isNumeric_(c, decimal) ||\n      // if we haven't detected a scientific number before, 'e' or 'E'\n      // hint that we should continue to read\n      !scientificNotation && (c == 'e' || c == 'E') ||\n      // once we know that we have a scientific number, both '-' and '+'\n      // are allowed\n      scientificNotation && (c == '-' || c == '+')\n  );\n  return parseFloat(this.wkt.substring(index, this.index_--));\n};\n\n\n/**\n * @return {string} String token value.\n * @private\n */\nol.format.WKT.Lexer.prototype.readText_ = function() {\n  var c, index = this.index_;\n  do {\n    c = this.nextChar_();\n  } while (this.isAlpha_(c));\n  return this.wkt.substring(index, this.index_--).toUpperCase();\n};\n\n\n/**\n * Class to parse the tokens from the WKT string.\n * @param {ol.format.WKT.Lexer} lexer The lexer.\n * @constructor\n * @protected\n */\nol.format.WKT.Parser = function(lexer) {\n\n  /**\n   * @type {ol.format.WKT.Lexer}\n   * @private\n   */\n  this.lexer_ = lexer;\n\n  /**\n   * @type {ol.WKTToken}\n   * @private\n   */\n  this.token_;\n\n  /**\n   * @type {ol.geom.GeometryLayout}\n   * @private\n   */\n  this.layout_ = ol.geom.GeometryLayout.XY;\n};\n\n\n/**\n * Fetch the next token form the lexer and replace the active token.\n * @private\n */\nol.format.WKT.Parser.prototype.consume_ = function() {\n  this.token_ = this.lexer_.nextToken();\n};\n\n/**\n * Tests if the given type matches the type of the current token.\n * @param {ol.format.WKT.TokenType} type Token type.\n * @return {boolean} Whether the token matches the given type.\n */\nol.format.WKT.Parser.prototype.isTokenType = function(type) {\n  var isMatch = this.token_.type == type;\n  return isMatch;\n};\n\n\n/**\n * If the given type matches the current token, consume it.\n * @param {ol.format.WKT.TokenType} type Token type.\n * @return {boolean} Whether the token matches the given type.\n */\nol.format.WKT.Parser.prototype.match = function(type) {\n  var isMatch = this.isTokenType(type);\n  if (isMatch) {\n    this.consume_();\n  }\n  return isMatch;\n};\n\n\n/**\n * Try to parse the tokens provided by the lexer.\n * @return {ol.geom.Geometry} The geometry.\n */\nol.format.WKT.Parser.prototype.parse = function() {\n  this.consume_();\n  var geometry = this.parseGeometry_();\n  ol.DEBUG && console.assert(this.token_.type == ol.format.WKT.TokenType.EOF,\n      'token type should be end of file');\n  return geometry;\n};\n\n\n/**\n * Try to parse the dimensional info.\n * @return {ol.geom.GeometryLayout} The layout.\n * @private\n */\nol.format.WKT.Parser.prototype.parseGeometryLayout_ = function() {\n  var layout = ol.geom.GeometryLayout.XY;\n  var dimToken = this.token_;\n  if (this.isTokenType(ol.format.WKT.TokenType.TEXT)) {\n    var dimInfo = dimToken.value;\n    if (dimInfo === ol.format.WKT.Z) {\n      layout = ol.geom.GeometryLayout.XYZ;\n    } else if (dimInfo === ol.format.WKT.M) {\n      layout = ol.geom.GeometryLayout.XYM;\n    } else if (dimInfo === ol.format.WKT.ZM) {\n      layout = ol.geom.GeometryLayout.XYZM;\n    }\n    if (layout !== ol.geom.GeometryLayout.XY) {\n      this.consume_();\n    }\n  }\n  return layout;\n};\n\n\n/**\n * @return {!ol.geom.Geometry} The geometry.\n * @private\n */\nol.format.WKT.Parser.prototype.parseGeometry_ = function() {\n  var token = this.token_;\n  if (this.match(ol.format.WKT.TokenType.TEXT)) {\n    var geomType = token.value;\n    this.layout_ = this.parseGeometryLayout_();\n    if (geomType == ol.geom.GeometryType.GEOMETRY_COLLECTION.toUpperCase()) {\n      var geometries = this.parseGeometryCollectionText_();\n      return new ol.geom.GeometryCollection(geometries);\n    } else {\n      var parser = ol.format.WKT.Parser.GeometryParser_[geomType];\n      var ctor = ol.format.WKT.Parser.GeometryConstructor_[geomType];\n      if (!parser || !ctor) {\n        throw new Error('Invalid geometry type: ' + geomType);\n      }\n      var coordinates = parser.call(this);\n      return new ctor(coordinates, this.layout_);\n    }\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<ol.geom.Geometry>} A collection of geometries.\n * @private\n */\nol.format.WKT.Parser.prototype.parseGeometryCollectionText_ = function() {\n  if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {\n    var geometries = [];\n    do {\n      geometries.push(this.parseGeometry_());\n    } while (this.match(ol.format.WKT.TokenType.COMMA));\n    if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {\n      return geometries;\n    }\n  } else if (this.isEmptyGeometry_()) {\n    return [];\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {Array.<number>} All values in a point.\n * @private\n */\nol.format.WKT.Parser.prototype.parsePointText_ = function() {\n  if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {\n    var coordinates = this.parsePoint_();\n    if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {\n      return coordinates;\n    }\n  } else if (this.isEmptyGeometry_()) {\n    return null;\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} All points in a linestring.\n * @private\n */\nol.format.WKT.Parser.prototype.parseLineStringText_ = function() {\n  if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {\n    var coordinates = this.parsePointList_();\n    if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {\n      return coordinates;\n    }\n  } else if (this.isEmptyGeometry_()) {\n    return [];\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} All points in a polygon.\n * @private\n */\nol.format.WKT.Parser.prototype.parsePolygonText_ = function() {\n  if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {\n    var coordinates = this.parseLineStringTextList_();\n    if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {\n      return coordinates;\n    }\n  } else if (this.isEmptyGeometry_()) {\n    return [];\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} All points in a multipoint.\n * @private\n */\nol.format.WKT.Parser.prototype.parseMultiPointText_ = function() {\n  if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {\n    var coordinates;\n    if (this.token_.type == ol.format.WKT.TokenType.LEFT_PAREN) {\n      coordinates = this.parsePointTextList_();\n    } else {\n      coordinates = this.parsePointList_();\n    }\n    if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {\n      return coordinates;\n    }\n  } else if (this.isEmptyGeometry_()) {\n    return [];\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} All linestring points\n *                                        in a multilinestring.\n * @private\n */\nol.format.WKT.Parser.prototype.parseMultiLineStringText_ = function() {\n  if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {\n    var coordinates = this.parseLineStringTextList_();\n    if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {\n      return coordinates;\n    }\n  } else if (this.isEmptyGeometry_()) {\n    return [];\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} All polygon points in a multipolygon.\n * @private\n */\nol.format.WKT.Parser.prototype.parseMultiPolygonText_ = function() {\n  if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {\n    var coordinates = this.parsePolygonTextList_();\n    if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {\n      return coordinates;\n    }\n  } else if (this.isEmptyGeometry_()) {\n    return [];\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<number>} A point.\n * @private\n */\nol.format.WKT.Parser.prototype.parsePoint_ = function() {\n  var coordinates = [];\n  var dimensions = this.layout_.length;\n  for (var i = 0; i < dimensions; ++i) {\n    var token = this.token_;\n    if (this.match(ol.format.WKT.TokenType.NUMBER)) {\n      coordinates.push(token.value);\n    } else {\n      break;\n    }\n  }\n  if (coordinates.length == dimensions) {\n    return coordinates;\n  }\n  throw new Error(this.formatErrorMessage_());\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} An array of points.\n * @private\n */\nol.format.WKT.Parser.prototype.parsePointList_ = function() {\n  var coordinates = [this.parsePoint_()];\n  while (this.match(ol.format.WKT.TokenType.COMMA)) {\n    coordinates.push(this.parsePoint_());\n  }\n  return coordinates;\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} An array of points.\n * @private\n */\nol.format.WKT.Parser.prototype.parsePointTextList_ = function() {\n  var coordinates = [this.parsePointText_()];\n  while (this.match(ol.format.WKT.TokenType.COMMA)) {\n    coordinates.push(this.parsePointText_());\n  }\n  return coordinates;\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} An array of points.\n * @private\n */\nol.format.WKT.Parser.prototype.parseLineStringTextList_ = function() {\n  var coordinates = [this.parseLineStringText_()];\n  while (this.match(ol.format.WKT.TokenType.COMMA)) {\n    coordinates.push(this.parseLineStringText_());\n  }\n  return coordinates;\n};\n\n\n/**\n * @return {!Array.<!Array.<number>>} An array of points.\n * @private\n */\nol.format.WKT.Parser.prototype.parsePolygonTextList_ = function() {\n  var coordinates = [this.parsePolygonText_()];\n  while (this.match(ol.format.WKT.TokenType.COMMA)) {\n    coordinates.push(this.parsePolygonText_());\n  }\n  return coordinates;\n};\n\n\n/**\n * @return {boolean} Whether the token implies an empty geometry.\n * @private\n */\nol.format.WKT.Parser.prototype.isEmptyGeometry_ = function() {\n  var isEmpty = this.isTokenType(ol.format.WKT.TokenType.TEXT) &&\n      this.token_.value == ol.format.WKT.EMPTY;\n  if (isEmpty) {\n    this.consume_();\n  }\n  return isEmpty;\n};\n\n\n/**\n * Create an error message for an unexpected token error.\n * @return {string} Error message.\n * @private\n */\nol.format.WKT.Parser.prototype.formatErrorMessage_ = function() {\n  return 'Unexpected `' + this.token_.value + '` at position ' +\n      this.token_.position + ' in `' + this.lexer_.wkt + '`';\n};\n\n\n/**\n * @enum {function (new:ol.geom.Geometry, Array, ol.geom.GeometryLayout)}\n * @private\n */\nol.format.WKT.Parser.GeometryConstructor_ = {\n  'POINT': ol.geom.Point,\n  'LINESTRING': ol.geom.LineString,\n  'POLYGON': ol.geom.Polygon,\n  'MULTIPOINT': ol.geom.MultiPoint,\n  'MULTILINESTRING': ol.geom.MultiLineString,\n  'MULTIPOLYGON': ol.geom.MultiPolygon\n};\n\n\n/**\n * @enum {(function(): Array)}\n * @private\n */\nol.format.WKT.Parser.GeometryParser_ = {\n  'POINT': ol.format.WKT.Parser.prototype.parsePointText_,\n  'LINESTRING': ol.format.WKT.Parser.prototype.parseLineStringText_,\n  'POLYGON': ol.format.WKT.Parser.prototype.parsePolygonText_,\n  'MULTIPOINT': ol.format.WKT.Parser.prototype.parseMultiPointText_,\n  'MULTILINESTRING': ol.format.WKT.Parser.prototype.parseMultiLineStringText_,\n  'MULTIPOLYGON': ol.format.WKT.Parser.prototype.parseMultiPolygonText_\n};\n\ngoog.provide('ol.format.WMSCapabilities');\n\ngoog.require('ol');\ngoog.require('ol.format.XLink');\ngoog.require('ol.format.XML');\ngoog.require('ol.format.XSD');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Format for reading WMS capabilities data\n *\n * @constructor\n * @extends {ol.format.XML}\n * @api\n */\nol.format.WMSCapabilities = function() {\n\n  ol.format.XML.call(this);\n\n  /**\n   * @type {string|undefined}\n   */\n  this.version = undefined;\n};\nol.inherits(ol.format.WMSCapabilities, ol.format.XML);\n\n\n/**\n * Read a WMS capabilities document.\n *\n * @function\n * @param {Document|Node|string} source The XML source.\n * @return {Object} An object representing the WMS capabilities.\n * @api\n */\nol.format.WMSCapabilities.prototype.read;\n\n\n/**\n * @param {Document} doc Document.\n * @return {Object} WMS Capability object.\n */\nol.format.WMSCapabilities.prototype.readFromDocument = function(doc) {\n  ol.DEBUG && console.assert(doc.nodeType == Node.DOCUMENT_NODE,\n      'doc.nodeType should be DOCUMENT');\n  for (var n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      return this.readFromNode(n);\n    }\n  }\n  return null;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {Object} WMS Capability object.\n */\nol.format.WMSCapabilities.prototype.readFromNode = function(node) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'WMS_Capabilities' ||\n      node.localName == 'WMT_MS_Capabilities',\n      'localName should be WMS_Capabilities or WMT_MS_Capabilities');\n  this.version = node.getAttribute('version').trim();\n  var wmsCapabilityObject = ol.xml.pushParseAndPop({\n    'version': this.version\n  }, ol.format.WMSCapabilities.PARSERS_, node, []);\n  return wmsCapabilityObject ? wmsCapabilityObject : null;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Attribution object.\n */\nol.format.WMSCapabilities.readAttribution_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Attribution',\n      'localName should be Attribution');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object} Bounding box object.\n */\nol.format.WMSCapabilities.readBoundingBox_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'BoundingBox',\n      'localName should be BoundingBox');\n\n  var extent = [\n    ol.format.XSD.readDecimalString(node.getAttribute('minx')),\n    ol.format.XSD.readDecimalString(node.getAttribute('miny')),\n    ol.format.XSD.readDecimalString(node.getAttribute('maxx')),\n    ol.format.XSD.readDecimalString(node.getAttribute('maxy'))\n  ];\n\n  var resolutions = [\n    ol.format.XSD.readDecimalString(node.getAttribute('resx')),\n    ol.format.XSD.readDecimalString(node.getAttribute('resy'))\n  ];\n\n  return {\n    'crs': node.getAttribute('CRS'),\n    'extent': extent,\n    'res': resolutions\n  };\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {ol.Extent|undefined} Bounding box object.\n */\nol.format.WMSCapabilities.readEXGeographicBoundingBox_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'EX_GeographicBoundingBox',\n      'localName should be EX_GeographicBoundingBox');\n  var geographicBoundingBox = ol.xml.pushParseAndPop(\n      {},\n      ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_,\n      node, objectStack);\n  if (!geographicBoundingBox) {\n    return undefined;\n  }\n  var westBoundLongitude = /** @type {number|undefined} */\n      (geographicBoundingBox['westBoundLongitude']);\n  var southBoundLatitude = /** @type {number|undefined} */\n      (geographicBoundingBox['southBoundLatitude']);\n  var eastBoundLongitude = /** @type {number|undefined} */\n      (geographicBoundingBox['eastBoundLongitude']);\n  var northBoundLatitude = /** @type {number|undefined} */\n      (geographicBoundingBox['northBoundLatitude']);\n  if (westBoundLongitude === undefined || southBoundLatitude === undefined ||\n      eastBoundLongitude === undefined || northBoundLatitude === undefined) {\n    return undefined;\n  }\n  return [\n    westBoundLongitude, southBoundLatitude,\n    eastBoundLongitude, northBoundLatitude\n  ];\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} Capability object.\n */\nol.format.WMSCapabilities.readCapability_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Capability',\n      'localName should be Capability');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.CAPABILITY_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} Service object.\n */\nol.format.WMSCapabilities.readService_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Service',\n      'localName should be Service');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.SERVICE_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} Contact information object.\n */\nol.format.WMSCapabilities.readContactInformation_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType shpuld be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ContactInformation',\n      'localName should be ContactInformation');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_,\n      node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} Contact person object.\n */\nol.format.WMSCapabilities.readContactPersonPrimary_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ContactPersonPrimary',\n      'localName should be ContactPersonPrimary');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_,\n      node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} Contact address object.\n */\nol.format.WMSCapabilities.readContactAddress_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'ContactAddress',\n      'localName should be ContactAddress');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_,\n      node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Array.<string>|undefined} Format array.\n */\nol.format.WMSCapabilities.readException_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Exception',\n      'localName should be Exception');\n  return ol.xml.pushParseAndPop(\n      [], ol.format.WMSCapabilities.EXCEPTION_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @private\n * @return {Object|undefined} Layer object.\n */\nol.format.WMSCapabilities.readCapabilityLayer_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Layer', 'localName should be Layer');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Layer object.\n */\nol.format.WMSCapabilities.readLayer_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Layer', 'localName should be Layer');\n  var parentLayerObject = /**  @type {Object.<string,*>} */\n      (objectStack[objectStack.length - 1]);\n\n  var layerObject = ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack);\n\n  if (!layerObject) {\n    return undefined;\n  }\n  var queryable =\n      ol.format.XSD.readBooleanString(node.getAttribute('queryable'));\n  if (queryable === undefined) {\n    queryable = parentLayerObject['queryable'];\n  }\n  layerObject['queryable'] = queryable !== undefined ? queryable : false;\n\n  var cascaded = ol.format.XSD.readNonNegativeIntegerString(\n      node.getAttribute('cascaded'));\n  if (cascaded === undefined) {\n    cascaded = parentLayerObject['cascaded'];\n  }\n  layerObject['cascaded'] = cascaded;\n\n  var opaque = ol.format.XSD.readBooleanString(node.getAttribute('opaque'));\n  if (opaque === undefined) {\n    opaque = parentLayerObject['opaque'];\n  }\n  layerObject['opaque'] = opaque !== undefined ? opaque : false;\n\n  var noSubsets =\n      ol.format.XSD.readBooleanString(node.getAttribute('noSubsets'));\n  if (noSubsets === undefined) {\n    noSubsets = parentLayerObject['noSubsets'];\n  }\n  layerObject['noSubsets'] = noSubsets !== undefined ? noSubsets : false;\n\n  var fixedWidth =\n      ol.format.XSD.readDecimalString(node.getAttribute('fixedWidth'));\n  if (!fixedWidth) {\n    fixedWidth = parentLayerObject['fixedWidth'];\n  }\n  layerObject['fixedWidth'] = fixedWidth;\n\n  var fixedHeight =\n      ol.format.XSD.readDecimalString(node.getAttribute('fixedHeight'));\n  if (!fixedHeight) {\n    fixedHeight = parentLayerObject['fixedHeight'];\n  }\n  layerObject['fixedHeight'] = fixedHeight;\n\n  // See 7.2.4.8\n  var addKeys = ['Style', 'CRS', 'AuthorityURL'];\n  addKeys.forEach(function(key) {\n    if (key in parentLayerObject) {\n      var childValue = layerObject[key] || [];\n      layerObject[key] = childValue.concat(parentLayerObject[key]);\n    }\n  });\n\n  var replaceKeys = ['EX_GeographicBoundingBox', 'BoundingBox', 'Dimension',\n    'Attribution', 'MinScaleDenominator', 'MaxScaleDenominator'];\n  replaceKeys.forEach(function(key) {\n    if (!(key in layerObject)) {\n      var parentValue = parentLayerObject[key];\n      layerObject[key] = parentValue;\n    }\n  });\n\n  return layerObject;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object} Dimension object.\n */\nol.format.WMSCapabilities.readDimension_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Dimension',\n      'localName should be Dimension');\n  var dimensionObject = {\n    'name': node.getAttribute('name'),\n    'units': node.getAttribute('units'),\n    'unitSymbol': node.getAttribute('unitSymbol'),\n    'default': node.getAttribute('default'),\n    'multipleValues': ol.format.XSD.readBooleanString(\n        node.getAttribute('multipleValues')),\n    'nearestValue': ol.format.XSD.readBooleanString(\n        node.getAttribute('nearestValue')),\n    'current': ol.format.XSD.readBooleanString(node.getAttribute('current')),\n    'values': ol.format.XSD.readString(node)\n  };\n  return dimensionObject;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Online resource object.\n */\nol.format.WMSCapabilities.readFormatOnlineresource_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_,\n      node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Request object.\n */\nol.format.WMSCapabilities.readRequest_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Request',\n      'localName should be Request');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.REQUEST_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} DCP type object.\n */\nol.format.WMSCapabilities.readDCPType_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'DCPType',\n      'localName should be DCPType');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.DCPTYPE_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} HTTP object.\n */\nol.format.WMSCapabilities.readHTTP_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'HTTP', 'localName should be HTTP');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.HTTP_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Operation type object.\n */\nol.format.WMSCapabilities.readOperationType_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Online resource object.\n */\nol.format.WMSCapabilities.readSizedFormatOnlineresource_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  var formatOnlineresource =\n      ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);\n  if (formatOnlineresource) {\n    var size = [\n      ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('width')),\n      ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('height'))\n    ];\n    formatOnlineresource['size'] = size;\n    return formatOnlineresource;\n  }\n  return undefined;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Authority URL object.\n */\nol.format.WMSCapabilities.readAuthorityURL_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'AuthorityURL',\n      'localName should be AuthorityURL');\n  var authorityObject =\n      ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);\n  if (authorityObject) {\n    authorityObject['name'] = node.getAttribute('name');\n    return authorityObject;\n  }\n  return undefined;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Metadata URL object.\n */\nol.format.WMSCapabilities.readMetadataURL_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'MetadataURL',\n      'localName should be MetadataURL');\n  var metadataObject =\n      ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);\n  if (metadataObject) {\n    metadataObject['type'] = node.getAttribute('type');\n    return metadataObject;\n  }\n  return undefined;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Style object.\n */\nol.format.WMSCapabilities.readStyle_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Style', 'localName should be Style');\n  return ol.xml.pushParseAndPop(\n      {}, ol.format.WMSCapabilities.STYLE_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Array.<string>|undefined} Keyword list.\n */\nol.format.WMSCapabilities.readKeywordList_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'KeywordList',\n      'localName should be KeywordList');\n  return ol.xml.pushParseAndPop(\n      [], ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @const\n * @private\n * @type {Array.<string>}\n */\nol.format.WMSCapabilities.NAMESPACE_URIS_ = [\n  null,\n  'http://www.opengis.net/wms'\n];\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Service': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readService_),\n      'Capability': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readCapability_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.CAPABILITY_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Request': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readRequest_),\n      'Exception': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readException_),\n      'Layer': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readCapabilityLayer_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.SERVICE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'KeywordList': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readKeywordList_),\n      'OnlineResource': ol.xml.makeObjectPropertySetter(\n          ol.format.XLink.readHref),\n      'ContactInformation': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readContactInformation_),\n      'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'AccessConstraints': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'LayerLimit': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'MaxWidth': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'MaxHeight': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'ContactPersonPrimary': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readContactPersonPrimary_),\n      'ContactPosition': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'ContactAddress': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readContactAddress_),\n      'ContactVoiceTelephone': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'ContactFacsimileTelephone': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'ContactElectronicMailAddress': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'ContactPerson': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'ContactOrganization': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'AddressType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'StateOrProvince': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'PostCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.EXCEPTION_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Format': ol.xml.makeArrayPusher(ol.format.XSD.readString)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'KeywordList': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readKeywordList_),\n      'CRS': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),\n      'EX_GeographicBoundingBox': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readEXGeographicBoundingBox_),\n      'BoundingBox': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readBoundingBox_),\n      'Dimension': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readDimension_),\n      'Attribution': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readAttribution_),\n      'AuthorityURL': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readAuthorityURL_),\n      'Identifier': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),\n      'MetadataURL': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readMetadataURL_),\n      'DataURL': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readFormatOnlineresource_),\n      'FeatureListURL': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readFormatOnlineresource_),\n      'Style': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readStyle_),\n      'MinScaleDenominator': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readDecimal),\n      'MaxScaleDenominator': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readDecimal),\n      'Layer': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readLayer_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.ATTRIBUTION_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'OnlineResource': ol.xml.makeObjectPropertySetter(\n          ol.format.XLink.readHref),\n      'LogoURL': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readSizedFormatOnlineresource_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_ =\n    ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'westBoundLongitude': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readDecimal),\n      'eastBoundLongitude': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readDecimal),\n      'southBoundLatitude': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readDecimal),\n      'northBoundLatitude': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readDecimal)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.REQUEST_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'GetCapabilities': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readOperationType_),\n      'GetMap': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readOperationType_),\n      'GetFeatureInfo': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readOperationType_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Format': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),\n      'DCPType': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readDCPType_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.DCPTYPE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'HTTP': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readHTTP_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.HTTP_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Get': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readFormatOnlineresource_),\n      'Post': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readFormatOnlineresource_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'LegendURL': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMSCapabilities.readSizedFormatOnlineresource_),\n      'StyleSheetURL': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readFormatOnlineresource_),\n      'StyleURL': ol.xml.makeObjectPropertySetter(\n          ol.format.WMSCapabilities.readFormatOnlineresource_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_ =\n    ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Format': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),\n      'OnlineResource': ol.xml.makeObjectPropertySetter(\n          ol.format.XLink.readHref)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMSCapabilities.KEYWORDLIST_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMSCapabilities.NAMESPACE_URIS_, {\n      'Keyword': ol.xml.makeArrayPusher(ol.format.XSD.readString)\n    });\n\ngoog.provide('ol.format.WMSGetFeatureInfo');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.format.GML2');\ngoog.require('ol.format.XMLFeature');\ngoog.require('ol.obj');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Format for reading WMSGetFeatureInfo format. It uses\n * {@link ol.format.GML2} to read features.\n *\n * @constructor\n * @extends {ol.format.XMLFeature}\n * @param {olx.format.WMSGetFeatureInfoOptions=} opt_options Options.\n * @api\n */\nol.format.WMSGetFeatureInfo = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver';\n\n\n  /**\n   * @private\n   * @type {ol.format.GML2}\n   */\n  this.gmlFormat_ = new ol.format.GML2();\n\n\n  /**\n   * @private\n   * @type {Array.<string>}\n   */\n  this.layers_ = options.layers ? options.layers : null;\n\n  ol.format.XMLFeature.call(this);\n};\nol.inherits(ol.format.WMSGetFeatureInfo, ol.format.XMLFeature);\n\n\n/**\n * @const\n * @type {string}\n * @private\n */\nol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature';\n\n\n/**\n * @const\n * @type {string}\n * @private\n */\nol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer';\n\n\n/**\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Array.<ol.Feature>} Features.\n * @private\n */\nol.format.WMSGetFeatureInfo.prototype.readFeatures_ = function(node, objectStack) {\n\n  node.setAttribute('namespaceURI', this.featureNS_);\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  var localName = node.localName;\n  /** @type {Array.<ol.Feature>} */\n  var features = [];\n  if (node.childNodes.length === 0) {\n    return features;\n  }\n  if (localName == 'msGMLOutput') {\n    for (var i = 0, ii = node.childNodes.length; i < ii; i++) {\n      var layer = node.childNodes[i];\n      if (layer.nodeType !== Node.ELEMENT_NODE) {\n        continue;\n      }\n      var context = objectStack[0];\n\n      ol.DEBUG && console.assert(layer.localName.indexOf(\n          ol.format.WMSGetFeatureInfo.layerIdentifier_) >= 0,\n          'localName of layer node should match layerIdentifier');\n\n      var toRemove = ol.format.WMSGetFeatureInfo.layerIdentifier_;\n      var layerName = layer.localName.replace(toRemove, '');\n\n      if (this.layers_ && !ol.array.includes(this.layers_, layerName)) {\n        continue;\n      }\n\n      var featureType = layerName +\n          ol.format.WMSGetFeatureInfo.featureIdentifier_;\n\n      context['featureType'] = featureType;\n      context['featureNS'] = this.featureNS_;\n\n      var parsers = {};\n      parsers[featureType] = ol.xml.makeArrayPusher(\n          this.gmlFormat_.readFeatureElement, this.gmlFormat_);\n      var parsersNS = ol.xml.makeStructureNS(\n          [context['featureNS'], null], parsers);\n      layer.setAttribute('namespaceURI', this.featureNS_);\n      var layerFeatures = ol.xml.pushParseAndPop(\n          [], parsersNS, layer, objectStack, this.gmlFormat_);\n      if (layerFeatures) {\n        ol.array.extend(features, layerFeatures);\n      }\n    }\n  }\n  if (localName == 'FeatureCollection') {\n    var gmlFeatures = ol.xml.pushParseAndPop([],\n        this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,\n        [{}], this.gmlFormat_);\n    if (gmlFeatures) {\n      features = gmlFeatures;\n    }\n  }\n  return features;\n};\n\n\n/**\n * Read all features from a WMSGetFeatureInfo response.\n *\n * @function\n * @param {Document|Node|Object|string} source Source.\n * @param {olx.format.ReadOptions=} opt_options Options.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.format.WMSGetFeatureInfo.prototype.readFeatures;\n\n\n/**\n * @inheritDoc\n */\nol.format.WMSGetFeatureInfo.prototype.readFeaturesFromNode = function(node, opt_options) {\n  var options = {};\n  if (opt_options) {\n    ol.obj.assign(options, this.getReadOptions(node, opt_options));\n  }\n  return this.readFeatures_(node, [options]);\n};\n\ngoog.provide('ol.format.WMTSCapabilities');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.format.OWS');\ngoog.require('ol.format.XLink');\ngoog.require('ol.format.XML');\ngoog.require('ol.format.XSD');\ngoog.require('ol.xml');\n\n\n/**\n * @classdesc\n * Format for reading WMTS capabilities data.\n *\n * @constructor\n * @extends {ol.format.XML}\n * @api\n */\nol.format.WMTSCapabilities = function() {\n  ol.format.XML.call(this);\n\n  /**\n   * @type {ol.format.OWS}\n   * @private\n   */\n  this.owsParser_ = new ol.format.OWS();\n};\nol.inherits(ol.format.WMTSCapabilities, ol.format.XML);\n\n\n/**\n * Read a WMTS capabilities document.\n *\n * @function\n * @param {Document|Node|string} source The XML source.\n * @return {Object} An object representing the WMTS capabilities.\n * @api\n */\nol.format.WMTSCapabilities.prototype.read;\n\n\n/**\n * @param {Document} doc Document.\n * @return {Object} WMTS Capability object.\n */\nol.format.WMTSCapabilities.prototype.readFromDocument = function(doc) {\n  ol.DEBUG && console.assert(doc.nodeType == Node.DOCUMENT_NODE,\n      'doc.nodeType should be DOCUMENT');\n  for (var n = doc.firstChild; n; n = n.nextSibling) {\n    if (n.nodeType == Node.ELEMENT_NODE) {\n      return this.readFromNode(n);\n    }\n  }\n  return null;\n};\n\n\n/**\n * @param {Node} node Node.\n * @return {Object} WMTS Capability object.\n */\nol.format.WMTSCapabilities.prototype.readFromNode = function(node) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Capabilities',\n      'localName should be Capabilities');\n  var version = node.getAttribute('version').trim();\n  var WMTSCapabilityObject = this.owsParser_.readFromNode(node);\n  if (!WMTSCapabilityObject) {\n    return null;\n  }\n  WMTSCapabilityObject['version'] = version;\n  WMTSCapabilityObject = ol.xml.pushParseAndPop(WMTSCapabilityObject,\n      ol.format.WMTSCapabilities.PARSERS_, node, []);\n  return WMTSCapabilityObject ? WMTSCapabilityObject : null;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Attribution object.\n */\nol.format.WMTSCapabilities.readContents_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Contents',\n      'localName should be Contents');\n\n  return ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.CONTENTS_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Layers object.\n */\nol.format.WMTSCapabilities.readLayer_ = function(node, objectStack) {\n  ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,\n      'node.nodeType should be ELEMENT');\n  ol.DEBUG && console.assert(node.localName == 'Layer', 'localName should be Layer');\n  return ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.LAYER_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Tile Matrix Set object.\n */\nol.format.WMTSCapabilities.readTileMatrixSet_ = function(node, objectStack) {\n  return ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.TMS_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Style object.\n */\nol.format.WMTSCapabilities.readStyle_ = function(node, objectStack) {\n  var style = ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.STYLE_PARSERS_, node, objectStack);\n  if (!style) {\n    return undefined;\n  }\n  var isDefault = node.getAttribute('isDefault') === 'true';\n  style['isDefault'] = isDefault;\n  return style;\n\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Tile Matrix Set Link object.\n */\nol.format.WMTSCapabilities.readTileMatrixSetLink_ = function(node,\n    objectStack) {\n  return ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Dimension object.\n */\nol.format.WMTSCapabilities.readDimensions_ = function(node, objectStack) {\n  return ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.DIMENSION_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Resource URL object.\n */\nol.format.WMTSCapabilities.readResourceUrl_ = function(node, objectStack) {\n  var format = node.getAttribute('format');\n  var template = node.getAttribute('template');\n  var resourceType = node.getAttribute('resourceType');\n  var resource = {};\n  if (format) {\n    resource['format'] = format;\n  }\n  if (template) {\n    resource['template'] = template;\n  }\n  if (resourceType) {\n    resource['resourceType'] = resourceType;\n  }\n  return resource;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} WGS84 BBox object.\n */\nol.format.WMTSCapabilities.readWgs84BoundingBox_ = function(node, objectStack) {\n  var coordinates = ol.xml.pushParseAndPop([],\n      ol.format.WMTSCapabilities.WGS84_BBOX_READERS_, node, objectStack);\n  if (coordinates.length != 2) {\n    return undefined;\n  }\n  return ol.extent.boundingExtent(coordinates);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Legend object.\n */\nol.format.WMTSCapabilities.readLegendUrl_ = function(node, objectStack) {\n  var legend = {};\n  legend['format'] = node.getAttribute('format');\n  legend['href'] = ol.format.XLink.readHref(node);\n  return legend;\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} Coordinates object.\n */\nol.format.WMTSCapabilities.readCoordinates_ = function(node, objectStack) {\n  var coordinates = ol.format.XSD.readString(node).split(' ');\n  if (!coordinates || coordinates.length != 2) {\n    return undefined;\n  }\n  var x = +coordinates[0];\n  var y = +coordinates[1];\n  if (isNaN(x) || isNaN(y)) {\n    return undefined;\n  }\n  return [x, y];\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} TileMatrix object.\n */\nol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) {\n  return ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.TM_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} TileMatrixSetLimits Object.\n */\nol.format.WMTSCapabilities.readTileMatrixLimitsList_ = function(node,\n    objectStack) {\n  return ol.xml.pushParseAndPop([],\n      ol.format.WMTSCapabilities.TMS_LIMITS_LIST_PARSERS_, node,\n      objectStack);\n};\n\n\n/**\n * @private\n * @param {Node} node Node.\n * @param {Array.<*>} objectStack Object stack.\n * @return {Object|undefined} TileMatrixLimits Array.\n */\nol.format.WMTSCapabilities.readTileMatrixLimits_ = function(node, objectStack) {\n  return ol.xml.pushParseAndPop({},\n      ol.format.WMTSCapabilities.TMS_LIMITS_PARSERS_, node, objectStack);\n};\n\n\n/**\n * @const\n * @private\n * @type {Array.<string>}\n */\nol.format.WMTSCapabilities.NAMESPACE_URIS_ = [\n  null,\n  'http://www.opengis.net/wmts/1.0'\n];\n\n\n/**\n * @const\n * @private\n * @type {Array.<string>}\n */\nol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_ = [\n  null,\n  'http://www.opengis.net/ows/1.1'\n];\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'Contents': ol.xml.makeObjectPropertySetter(\n          ol.format.WMTSCapabilities.readContents_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.CONTENTS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'Layer': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readLayer_),\n      'TileMatrixSet': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readTileMatrixSet_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'Style': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readStyle_),\n      'Format': ol.xml.makeObjectPropertyPusher(\n          ol.format.XSD.readString),\n      'TileMatrixSetLink': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readTileMatrixSetLink_),\n      'Dimension': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readDimensions_),\n      'ResourceURL': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readResourceUrl_)\n    }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {\n      'Title': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'Abstract': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'WGS84BoundingBox': ol.xml.makeObjectPropertySetter(\n          ol.format.WMTSCapabilities.readWgs84BoundingBox_),\n      'Identifier': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    }));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'LegendURL': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readLegendUrl_)\n    }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {\n      'Title': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'Identifier': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    }));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'TileMatrixSet': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'TileMatrixSetLimits': ol.xml.makeObjectPropertySetter(\n          ol.format.WMTSCapabilities.readTileMatrixLimitsList_)\n    });\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.TMS_LIMITS_LIST_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'TileMatrixLimits': ol.xml.makeArrayPusher(\n          ol.format.WMTSCapabilities.readTileMatrixLimits_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.TMS_LIMITS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'TileMatrix': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'MinTileRow': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'MaxTileRow': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'MinTileCol': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'MaxTileCol': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.DIMENSION_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'Default': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'Value': ol.xml.makeObjectPropertyPusher(\n          ol.format.XSD.readString)\n    }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {\n      'Identifier': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    }));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.WGS84_BBOX_READERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {\n      'LowerCorner': ol.xml.makeArrayPusher(\n          ol.format.WMTSCapabilities.readCoordinates_),\n      'UpperCorner': ol.xml.makeArrayPusher(\n          ol.format.WMTSCapabilities.readCoordinates_)\n    });\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.TMS_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'WellKnownScaleSet': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'TileMatrix': ol.xml.makeObjectPropertyPusher(\n          ol.format.WMTSCapabilities.readTileMatrix_)\n    }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {\n      'SupportedCRS': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString),\n      'Identifier': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    }));\n\n\n/**\n * @const\n * @type {Object.<string, Object.<string, ol.XmlParser>>}\n * @private\n */\nol.format.WMTSCapabilities.TM_PARSERS_ = ol.xml.makeStructureNS(\n    ol.format.WMTSCapabilities.NAMESPACE_URIS_, {\n      'TopLeftCorner': ol.xml.makeObjectPropertySetter(\n          ol.format.WMTSCapabilities.readCoordinates_),\n      'ScaleDenominator': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readDecimal),\n      'TileWidth': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'TileHeight': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'MatrixWidth': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger),\n      'MatrixHeight': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readNonNegativeInteger)\n    }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {\n      'Identifier': ol.xml.makeObjectPropertySetter(\n          ol.format.XSD.readString)\n    }));\n\n// FIXME handle geolocation not supported\n\ngoog.provide('ol.Geolocation');\n\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.has');\ngoog.require('ol.math');\ngoog.require('ol.proj');\ngoog.require('ol.sphere.WGS84');\n\n\n/**\n * @classdesc\n * Helper class for providing HTML5 Geolocation capabilities.\n * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)\n * is used to locate a user's position.\n *\n * To get notified of position changes, register a listener for the generic\n * `change` event on your instance of `ol.Geolocation`.\n *\n * Example:\n *\n *     var geolocation = new ol.Geolocation({\n *       // take the projection to use from the map's view\n *       projection: view.getProjection()\n *     });\n *     // listen to changes in position\n *     geolocation.on('change', function(evt) {\n *       window.console.log(geolocation.getPosition());\n *     });\n *\n * @fires error\n * @constructor\n * @extends {ol.Object}\n * @param {olx.GeolocationOptions=} opt_options Options.\n * @api stable\n */\nol.Geolocation = function(opt_options) {\n\n  ol.Object.call(this);\n\n  var options = opt_options || {};\n\n  /**\n   * The unprojected (EPSG:4326) device position.\n   * @private\n   * @type {ol.Coordinate}\n   */\n  this.position_ = null;\n\n  /**\n   * @private\n   * @type {ol.TransformFunction}\n   */\n  this.transform_ = ol.proj.identityTransform;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.watchId_ = undefined;\n\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Geolocation.Property.PROJECTION),\n      this.handleProjectionChanged_, this);\n  ol.events.listen(\n      this, ol.Object.getChangeEventType(ol.Geolocation.Property.TRACKING),\n      this.handleTrackingChanged_, this);\n\n  if (options.projection !== undefined) {\n    this.setProjection(ol.proj.get(options.projection));\n  }\n  if (options.trackingOptions !== undefined) {\n    this.setTrackingOptions(options.trackingOptions);\n  }\n\n  this.setTracking(options.tracking !== undefined ? options.tracking : false);\n\n};\nol.inherits(ol.Geolocation, ol.Object);\n\n\n/**\n * @inheritDoc\n */\nol.Geolocation.prototype.disposeInternal = function() {\n  this.setTracking(false);\n  ol.Object.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * @private\n */\nol.Geolocation.prototype.handleProjectionChanged_ = function() {\n  var projection = this.getProjection();\n  if (projection) {\n    this.transform_ = ol.proj.getTransformFromProjections(\n        ol.proj.get('EPSG:4326'), projection);\n    if (this.position_) {\n      this.set(\n          ol.Geolocation.Property.POSITION, this.transform_(this.position_));\n    }\n  }\n};\n\n\n/**\n * @private\n */\nol.Geolocation.prototype.handleTrackingChanged_ = function() {\n  if (ol.has.GEOLOCATION) {\n    var tracking = this.getTracking();\n    if (tracking && this.watchId_ === undefined) {\n      this.watchId_ = navigator.geolocation.watchPosition(\n          this.positionChange_.bind(this),\n          this.positionError_.bind(this),\n          this.getTrackingOptions());\n    } else if (!tracking && this.watchId_ !== undefined) {\n      navigator.geolocation.clearWatch(this.watchId_);\n      this.watchId_ = undefined;\n    }\n  }\n};\n\n\n/**\n * @private\n * @param {GeolocationPosition} position position event.\n */\nol.Geolocation.prototype.positionChange_ = function(position) {\n  var coords = position.coords;\n  this.set(ol.Geolocation.Property.ACCURACY, coords.accuracy);\n  this.set(ol.Geolocation.Property.ALTITUDE,\n      coords.altitude === null ? undefined : coords.altitude);\n  this.set(ol.Geolocation.Property.ALTITUDE_ACCURACY,\n      coords.altitudeAccuracy === null ?\n      undefined : coords.altitudeAccuracy);\n  this.set(ol.Geolocation.Property.HEADING, coords.heading === null ?\n      undefined : ol.math.toRadians(coords.heading));\n  if (!this.position_) {\n    this.position_ = [coords.longitude, coords.latitude];\n  } else {\n    this.position_[0] = coords.longitude;\n    this.position_[1] = coords.latitude;\n  }\n  var projectedPosition = this.transform_(this.position_);\n  this.set(ol.Geolocation.Property.POSITION, projectedPosition);\n  this.set(ol.Geolocation.Property.SPEED,\n      coords.speed === null ? undefined : coords.speed);\n  var geometry = ol.geom.Polygon.circular(\n      ol.sphere.WGS84, this.position_, coords.accuracy);\n  geometry.applyTransform(this.transform_);\n  this.set(ol.Geolocation.Property.ACCURACY_GEOMETRY, geometry);\n  this.changed();\n};\n\n/**\n * Triggered when the Geolocation returns an error.\n * @event error\n * @api\n */\n\n/**\n * @private\n * @param {GeolocationPositionError} error error object.\n */\nol.Geolocation.prototype.positionError_ = function(error) {\n  error.type = ol.events.EventType.ERROR;\n  this.setTracking(false);\n  this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));\n};\n\n\n/**\n * Get the accuracy of the position in meters.\n * @return {number|undefined} The accuracy of the position measurement in\n *     meters.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getAccuracy = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.Geolocation.Property.ACCURACY));\n};\n\n\n/**\n * Get a geometry of the position accuracy.\n * @return {?ol.geom.Geometry} A geometry of the position accuracy.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getAccuracyGeometry = function() {\n  return /** @type {?ol.geom.Geometry} */ (\n      this.get(ol.Geolocation.Property.ACCURACY_GEOMETRY) || null);\n};\n\n\n/**\n * Get the altitude associated with the position.\n * @return {number|undefined} The altitude of the position in meters above mean\n *     sea level.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getAltitude = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.Geolocation.Property.ALTITUDE));\n};\n\n\n/**\n * Get the altitude accuracy of the position.\n * @return {number|undefined} The accuracy of the altitude measurement in\n *     meters.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getAltitudeAccuracy = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.Geolocation.Property.ALTITUDE_ACCURACY));\n};\n\n\n/**\n * Get the heading as radians clockwise from North.\n * @return {number|undefined} The heading of the device in radians from north.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getHeading = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.Geolocation.Property.HEADING));\n};\n\n\n/**\n * Get the position of the device.\n * @return {ol.Coordinate|undefined} The current position of the device reported\n *     in the current projection.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getPosition = function() {\n  return /** @type {ol.Coordinate|undefined} */ (\n      this.get(ol.Geolocation.Property.POSITION));\n};\n\n\n/**\n * Get the projection associated with the position.\n * @return {ol.proj.Projection|undefined} The projection the position is\n *     reported in.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getProjection = function() {\n  return /** @type {ol.proj.Projection|undefined} */ (\n      this.get(ol.Geolocation.Property.PROJECTION));\n};\n\n\n/**\n * Get the speed in meters per second.\n * @return {number|undefined} The instantaneous speed of the device in meters\n *     per second.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getSpeed = function() {\n  return /** @type {number|undefined} */ (\n      this.get(ol.Geolocation.Property.SPEED));\n};\n\n\n/**\n * Determine if the device location is being tracked.\n * @return {boolean} The device location is being tracked.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getTracking = function() {\n  return /** @type {boolean} */ (\n      this.get(ol.Geolocation.Property.TRACKING));\n};\n\n\n/**\n * Get the tracking options.\n * @see http://www.w3.org/TR/geolocation-API/#position-options\n * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by\n *     the [HTML5 Geolocation spec\n *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.getTrackingOptions = function() {\n  return /** @type {GeolocationPositionOptions|undefined} */ (\n      this.get(ol.Geolocation.Property.TRACKING_OPTIONS));\n};\n\n\n/**\n * Set the projection to use for transforming the coordinates.\n * @param {ol.proj.Projection} projection The projection the position is\n *     reported in.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.setProjection = function(projection) {\n  this.set(ol.Geolocation.Property.PROJECTION, projection);\n};\n\n\n/**\n * Enable or disable tracking.\n * @param {boolean} tracking Enable tracking.\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.setTracking = function(tracking) {\n  this.set(ol.Geolocation.Property.TRACKING, tracking);\n};\n\n\n/**\n * Set the tracking options.\n * @see http://www.w3.org/TR/geolocation-API/#position-options\n * @param {GeolocationPositionOptions} options PositionOptions as defined by the\n *     [HTML5 Geolocation spec\n *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).\n * @observable\n * @api stable\n */\nol.Geolocation.prototype.setTrackingOptions = function(options) {\n  this.set(ol.Geolocation.Property.TRACKING_OPTIONS, options);\n};\n\n\n/**\n * @enum {string}\n */\nol.Geolocation.Property = {\n  ACCURACY: 'accuracy',\n  ACCURACY_GEOMETRY: 'accuracyGeometry',\n  ALTITUDE: 'altitude',\n  ALTITUDE_ACCURACY: 'altitudeAccuracy',\n  HEADING: 'heading',\n  POSITION: 'position',\n  PROJECTION: 'projection',\n  SPEED: 'speed',\n  TRACKING: 'tracking',\n  TRACKING_OPTIONS: 'trackingOptions'\n};\n\ngoog.provide('ol.geom.Circle');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.geom.flat.deflate');\n\n\n/**\n * @classdesc\n * Circle geometry.\n *\n * @constructor\n * @extends {ol.geom.SimpleGeometry}\n * @param {ol.Coordinate} center Center.\n * @param {number=} opt_radius Radius.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api\n */\nol.geom.Circle = function(center, opt_radius, opt_layout) {\n  ol.geom.SimpleGeometry.call(this);\n  var radius = opt_radius ? opt_radius : 0;\n  this.setCenterAndRadius(center, radius, opt_layout);\n};\nol.inherits(ol.geom.Circle, ol.geom.SimpleGeometry);\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!ol.geom.Circle} Clone.\n * @api\n */\nol.geom.Circle.prototype.clone = function() {\n  var circle = new ol.geom.Circle(null);\n  circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n  return circle;\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Circle.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n  var flatCoordinates = this.flatCoordinates;\n  var dx = x - flatCoordinates[0];\n  var dy = y - flatCoordinates[1];\n  var squaredDistance = dx * dx + dy * dy;\n  if (squaredDistance < minSquaredDistance) {\n    var i;\n    if (squaredDistance === 0) {\n      for (i = 0; i < this.stride; ++i) {\n        closestPoint[i] = flatCoordinates[i];\n      }\n    } else {\n      var delta = this.getRadius() / Math.sqrt(squaredDistance);\n      closestPoint[0] = flatCoordinates[0] + delta * dx;\n      closestPoint[1] = flatCoordinates[1] + delta * dy;\n      for (i = 2; i < this.stride; ++i) {\n        closestPoint[i] = flatCoordinates[i];\n      }\n    }\n    closestPoint.length = this.stride;\n    return squaredDistance;\n  } else {\n    return minSquaredDistance;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Circle.prototype.containsXY = function(x, y) {\n  var flatCoordinates = this.flatCoordinates;\n  var dx = x - flatCoordinates[0];\n  var dy = y - flatCoordinates[1];\n  return dx * dx + dy * dy <= this.getRadiusSquared_();\n};\n\n\n/**\n * Return the center of the circle as {@link ol.Coordinate coordinate}.\n * @return {ol.Coordinate} Center.\n * @api\n */\nol.geom.Circle.prototype.getCenter = function() {\n  return this.flatCoordinates.slice(0, this.stride);\n};\n\n\n/**\n * @inheritDoc\n */\nol.geom.Circle.prototype.computeExtent = function(extent) {\n  var flatCoordinates = this.flatCoordinates;\n  var radius = flatCoordinates[this.stride] - flatCoordinates[0];\n  return ol.extent.createOrUpdate(\n      flatCoordinates[0] - radius, flatCoordinates[1] - radius,\n      flatCoordinates[0] + radius, flatCoordinates[1] + radius,\n      extent);\n};\n\n\n/**\n * Return the radius of the circle.\n * @return {number} Radius.\n * @api\n */\nol.geom.Circle.prototype.getRadius = function() {\n  return Math.sqrt(this.getRadiusSquared_());\n};\n\n\n/**\n * @private\n * @return {number} Radius squared.\n */\nol.geom.Circle.prototype.getRadiusSquared_ = function() {\n  var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];\n  var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];\n  return dx * dx + dy * dy;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nol.geom.Circle.prototype.getType = function() {\n  return ol.geom.GeometryType.CIRCLE;\n};\n\n\n/**\n * @inheritDoc\n * @api stable\n */\nol.geom.Circle.prototype.intersectsExtent = function(extent) {\n  var circleExtent = this.getExtent();\n  if (ol.extent.intersects(extent, circleExtent)) {\n    var center = this.getCenter();\n\n    if (extent[0] <= center[0] && extent[2] >= center[0]) {\n      return true;\n    }\n    if (extent[1] <= center[1] && extent[3] >= center[1]) {\n      return true;\n    }\n\n    return ol.extent.forEachCorner(extent, this.intersectsCoordinate, this);\n  }\n  return false;\n\n};\n\n\n/**\n * Set the center of the circle as {@link ol.Coordinate coordinate}.\n * @param {ol.Coordinate} center Center.\n * @api\n */\nol.geom.Circle.prototype.setCenter = function(center) {\n  var stride = this.stride;\n  ol.DEBUG && console.assert(center.length == stride,\n      'center array length should match stride');\n  var radius = this.flatCoordinates[stride] - this.flatCoordinates[0];\n  var flatCoordinates = center.slice();\n  flatCoordinates[stride] = flatCoordinates[0] + radius;\n  var i;\n  for (i = 1; i < stride; ++i) {\n    flatCoordinates[stride + i] = center[i];\n  }\n  this.setFlatCoordinates(this.layout, flatCoordinates);\n};\n\n\n/**\n * Set the center (as {@link ol.Coordinate coordinate}) and the radius (as\n * number) of the circle.\n * @param {ol.Coordinate} center Center.\n * @param {number} radius Radius.\n * @param {ol.geom.GeometryLayout=} opt_layout Layout.\n * @api\n */\nol.geom.Circle.prototype.setCenterAndRadius = function(center, radius, opt_layout) {\n  if (!center) {\n    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);\n  } else {\n    this.setLayout(opt_layout, center, 0);\n    if (!this.flatCoordinates) {\n      this.flatCoordinates = [];\n    }\n    /** @type {Array.<number>} */\n    var flatCoordinates = this.flatCoordinates;\n    var offset = ol.geom.flat.deflate.coordinate(\n        flatCoordinates, 0, center, this.stride);\n    flatCoordinates[offset++] = flatCoordinates[0] + radius;\n    var i, ii;\n    for (i = 1, ii = this.stride; i < ii; ++i) {\n      flatCoordinates[offset++] = flatCoordinates[i];\n    }\n    flatCoordinates.length = offset;\n    this.changed();\n  }\n};\n\n\n/**\n * @param {ol.geom.GeometryLayout} layout Layout.\n * @param {Array.<number>} flatCoordinates Flat coordinates.\n */\nol.geom.Circle.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n  this.setFlatCoordinatesInternal(layout, flatCoordinates);\n  this.changed();\n};\n\n\n/**\n * Set the radius of the circle. The radius is in the units of the projection.\n * @param {number} radius Radius.\n * @api\n */\nol.geom.Circle.prototype.setRadius = function(radius) {\n  this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;\n  this.changed();\n};\n\n\n/**\n * Transform each coordinate of the circle from one coordinate reference system\n * to another. The geometry is modified in place.\n * If you do not want the geometry modified in place, first clone() it and\n * then use this function on the clone.\n *\n * Internally a circle is currently represented by two points: the center of\n * the circle `[cx, cy]`, and the point to the right of the circle\n * `[cx + r, cy]`. This `transform` function just transforms these two points.\n * So the resulting geometry is also a circle, and that circle does not\n * correspond to the shape that would be obtained by transforming every point\n * of the original circle.\n *\n * @param {ol.ProjectionLike} source The current projection.  Can be a\n *     string identifier or a {@link ol.proj.Projection} object.\n * @param {ol.ProjectionLike} destination The desired projection.  Can be a\n *     string identifier or a {@link ol.proj.Projection} object.\n * @return {ol.geom.Circle} This geometry.  Note that original geometry is\n *     modified in place.\n * @function\n * @api stable\n */\nol.geom.Circle.prototype.transform;\n\ngoog.provide('ol.geom.flat.geodesic');\n\ngoog.require('ol');\ngoog.require('ol.math');\ngoog.require('ol.proj');\n\n\n/**\n * @private\n * @param {function(number): ol.Coordinate} interpolate Interpolate function.\n * @param {ol.TransformFunction} transform Transform from longitude/latitude to\n *     projected coordinates.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Array.<number>} Flat coordinates.\n */\nol.geom.flat.geodesic.line_ = function(interpolate, transform, squaredTolerance) {\n  // FIXME reduce garbage generation\n  // FIXME optimize stack operations\n\n  /** @type {Array.<number>} */\n  var flatCoordinates = [];\n\n  var geoA = interpolate(0);\n  var geoB = interpolate(1);\n\n  var a = transform(geoA);\n  var b = transform(geoB);\n\n  /** @type {Array.<ol.Coordinate>} */\n  var geoStack = [geoB, geoA];\n  /** @type {Array.<ol.Coordinate>} */\n  var stack = [b, a];\n  /** @type {Array.<number>} */\n  var fractionStack = [1, 0];\n\n  /** @type {Object.<string, boolean>} */\n  var fractions = {};\n\n  var maxIterations = 1e5;\n  var geoM, m, fracA, fracB, fracM, key;\n\n  while (--maxIterations > 0 && fractionStack.length > 0) {\n    // Pop the a coordinate off the stack\n    fracA = fractionStack.pop();\n    geoA = geoStack.pop();\n    a = stack.pop();\n    // Add the a coordinate if it has not been added yet\n    key = fracA.toString();\n    if (!(key in fractions)) {\n      flatCoordinates.push(a[0], a[1]);\n      fractions[key] = true;\n    }\n    // Pop the b coordinate off the stack\n    fracB = fractionStack.pop();\n    geoB = geoStack.pop();\n    b = stack.pop();\n    // Find the m point between the a and b coordinates\n    fracM = (fracA + fracB) / 2;\n    geoM = interpolate(fracM);\n    m = transform(geoM);\n    if (ol.math.squaredSegmentDistance(m[0], m[1], a[0], a[1],\n        b[0], b[1]) < squaredTolerance) {\n      // If the m point is sufficiently close to the straight line, then we\n      // discard it.  Just use the b coordinate and move on to the next line\n      // segment.\n      flatCoordinates.push(b[0], b[1]);\n      key = fracB.toString();\n      ol.DEBUG && console.assert(!(key in fractions),\n          'fractions object should contain key : ' + key);\n      fractions[key] = true;\n    } else {\n      // Otherwise, we need to subdivide the current line segment.  Split it\n      // into two and push the two line segments onto the stack.\n      fractionStack.push(fracB, fracM, fracM, fracA);\n      stack.push(b, m, m, a);\n      geoStack.push(geoB, geoM, geoM, geoA);\n    }\n  }\n  ol.DEBUG && console.assert(maxIterations > 0,\n      'maxIterations should be more than 0');\n\n  return flatCoordinates;\n};\n\n\n/**\n* Generate a great-circle arcs between two lat/lon points.\n* @param {number} lon1 Longitude 1 in degrees.\n* @param {number} lat1 Latitude 1 in degrees.\n* @param {number} lon2 Longitude 2 in degrees.\n* @param {number} lat2 Latitude 2 in degrees.\n * @param {ol.proj.Projection} projection Projection.\n* @param {number} squaredTolerance Squared tolerance.\n* @return {Array.<number>} Flat coordinates.\n*/\nol.geom.flat.geodesic.greatCircleArc = function(\n    lon1, lat1, lon2, lat2, projection, squaredTolerance) {\n\n  var geoProjection = ol.proj.get('EPSG:4326');\n\n  var cosLat1 = Math.cos(ol.math.toRadians(lat1));\n  var sinLat1 = Math.sin(ol.math.toRadians(lat1));\n  var cosLat2 = Math.cos(ol.math.toRadians(lat2));\n  var sinLat2 = Math.sin(ol.math.toRadians(lat2));\n  var cosDeltaLon = Math.cos(ol.math.toRadians(lon2 - lon1));\n  var sinDeltaLon = Math.sin(ol.math.toRadians(lon2 - lon1));\n  var d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon;\n\n  return ol.geom.flat.geodesic.line_(\n      /**\n       * @param {number} frac Fraction.\n       * @return {ol.Coordinate} Coordinate.\n       */\n      function(frac) {\n        if (1 <= d) {\n          return [lon2, lat2];\n        }\n        var D = frac * Math.acos(d);\n        var cosD = Math.cos(D);\n        var sinD = Math.sin(D);\n        var y = sinDeltaLon * cosLat2;\n        var x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon;\n        var theta = Math.atan2(y, x);\n        var lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta));\n        var lon = ol.math.toRadians(lon1) +\n            Math.atan2(Math.sin(theta) * sinD * cosLat1,\n                       cosD - sinLat1 * Math.sin(lat));\n        return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)];\n      }, ol.proj.getTransform(geoProjection, projection), squaredTolerance);\n};\n\n\n/**\n * Generate a meridian (line at constant longitude).\n * @param {number} lon Longitude.\n * @param {number} lat1 Latitude 1.\n * @param {number} lat2 Latitude 2.\n * @param {ol.proj.Projection} projection Projection.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Array.<number>} Flat coordinates.\n */\nol.geom.flat.geodesic.meridian = function(lon, lat1, lat2, projection, squaredTolerance) {\n  var epsg4326Projection = ol.proj.get('EPSG:4326');\n  return ol.geom.flat.geodesic.line_(\n      /**\n       * @param {number} frac Fraction.\n       * @return {ol.Coordinate} Coordinate.\n       */\n      function(frac) {\n        return [lon, lat1 + ((lat2 - lat1) * frac)];\n      },\n      ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);\n};\n\n\n/**\n * Generate a parallel (line at constant latitude).\n * @param {number} lat Latitude.\n * @param {number} lon1 Longitude 1.\n * @param {number} lon2 Longitude 2.\n * @param {ol.proj.Projection} projection Projection.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Array.<number>} Flat coordinates.\n */\nol.geom.flat.geodesic.parallel = function(lat, lon1, lon2, projection, squaredTolerance) {\n  var epsg4326Projection = ol.proj.get('EPSG:4326');\n  return ol.geom.flat.geodesic.line_(\n      /**\n       * @param {number} frac Fraction.\n       * @return {ol.Coordinate} Coordinate.\n       */\n      function(frac) {\n        return [lon1 + ((lon2 - lon1) * frac), lat];\n      },\n      ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);\n};\n\ngoog.provide('ol.Graticule');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryLayout');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.flat.geodesic');\ngoog.require('ol.math');\ngoog.require('ol.proj');\ngoog.require('ol.render.Event');\ngoog.require('ol.style.Stroke');\n\n\n/**\n * Render a grid for a coordinate system on a map.\n * @constructor\n * @param {olx.GraticuleOptions=} opt_options Options.\n * @api\n */\nol.Graticule = function(opt_options) {\n\n  var options = opt_options || {};\n\n  /**\n   * @type {ol.Map}\n   * @private\n   */\n  this.map_ = null;\n\n  /**\n   * @type {ol.proj.Projection}\n   * @private\n   */\n  this.projection_ = null;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.maxLat_ = Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.maxLon_ = Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.minLat_ = -Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.minLon_ = -Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.maxLatP_ = Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.maxLonP_ = Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.minLatP_ = -Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.minLonP_ = -Infinity;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.targetSize_ = options.targetSize !== undefined ?\n      options.targetSize : 100;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.maxLines_ = options.maxLines !== undefined ? options.maxLines : 100;\n  ol.DEBUG && console.assert(this.maxLines_ > 0,\n      'this.maxLines_ should be more than 0');\n\n  /**\n   * @type {Array.<ol.geom.LineString>}\n   * @private\n   */\n  this.meridians_ = [];\n\n  /**\n   * @type {Array.<ol.geom.LineString>}\n   * @private\n   */\n  this.parallels_ = [];\n\n  /**\n   * @type {ol.style.Stroke}\n   * @private\n   */\n  this.strokeStyle_ = options.strokeStyle !== undefined ?\n      options.strokeStyle : ol.Graticule.DEFAULT_STROKE_STYLE_;\n\n  /**\n   * @type {ol.TransformFunction|undefined}\n   * @private\n   */\n  this.fromLonLatTransform_ = undefined;\n\n  /**\n   * @type {ol.TransformFunction|undefined}\n   * @private\n   */\n  this.toLonLatTransform_ = undefined;\n\n  /**\n   * @type {ol.Coordinate}\n   * @private\n   */\n  this.projectionCenterLonLat_ = null;\n\n  this.setMap(options.map !== undefined ? options.map : null);\n};\n\n\n/**\n * @type {ol.style.Stroke}\n * @private\n * @const\n */\nol.Graticule.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({\n  color: 'rgba(0,0,0,0.2)'\n});\n\n\n/**\n * TODO can be configurable\n * @type {Array.<number>}\n * @private\n */\nol.Graticule.intervals_ = [90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05,\n  0.01, 0.005, 0.002, 0.001];\n\n\n/**\n * @param {number} lon Longitude.\n * @param {number} minLat Minimal latitude.\n * @param {number} maxLat Maximal latitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {ol.Extent} extent Extent.\n * @param {number} index Index.\n * @return {number} Index.\n * @private\n */\nol.Graticule.prototype.addMeridian_ = function(lon, minLat, maxLat, squaredTolerance, extent, index) {\n  var lineString = this.getMeridian_(lon, minLat, maxLat,\n      squaredTolerance, index);\n  if (ol.extent.intersects(lineString.getExtent(), extent)) {\n    this.meridians_[index++] = lineString;\n  }\n  return index;\n};\n\n\n/**\n * @param {number} lat Latitude.\n * @param {number} minLon Minimal longitude.\n * @param {number} maxLon Maximal longitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {ol.Extent} extent Extent.\n * @param {number} index Index.\n * @return {number} Index.\n * @private\n */\nol.Graticule.prototype.addParallel_ = function(lat, minLon, maxLon, squaredTolerance, extent, index) {\n  var lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance,\n      index);\n  if (ol.extent.intersects(lineString.getExtent(), extent)) {\n    this.parallels_[index++] = lineString;\n  }\n  return index;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {ol.Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} squaredTolerance Squared tolerance.\n * @private\n */\nol.Graticule.prototype.createGraticule_ = function(extent, center, resolution, squaredTolerance) {\n\n  var interval = this.getInterval_(resolution);\n  if (interval == -1) {\n    this.meridians_.length = this.parallels_.length = 0;\n    return;\n  }\n\n  var centerLonLat = this.toLonLatTransform_(center);\n  var centerLon = centerLonLat[0];\n  var centerLat = centerLonLat[1];\n  var maxLines = this.maxLines_;\n  var cnt, idx, lat, lon;\n\n  var validExtent = [\n    Math.max(extent[0], this.minLonP_),\n    Math.max(extent[1], this.minLatP_),\n    Math.min(extent[2], this.maxLonP_),\n    Math.min(extent[3], this.maxLatP_)\n  ];\n\n  validExtent = ol.proj.transformExtent(validExtent, this.projection_,\n      'EPSG:4326');\n  var maxLat = validExtent[3];\n  var maxLon = validExtent[2];\n  var minLat = validExtent[1];\n  var minLon = validExtent[0];\n\n  // Create meridians\n\n  centerLon = Math.floor(centerLon / interval) * interval;\n  lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_);\n\n  idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0);\n\n  cnt = 0;\n  while (lon != this.minLon_ && cnt++ < maxLines) {\n    lon = Math.max(lon - interval, this.minLon_);\n    idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);\n  }\n\n  lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_);\n\n  cnt = 0;\n  while (lon != this.maxLon_ && cnt++ < maxLines) {\n    lon = Math.min(lon + interval, this.maxLon_);\n    idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);\n  }\n\n  this.meridians_.length = idx;\n\n  // Create parallels\n\n  centerLat = Math.floor(centerLat / interval) * interval;\n  lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_);\n\n  idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, 0);\n\n  cnt = 0;\n  while (lat != this.minLat_ && cnt++ < maxLines) {\n    lat = Math.max(lat - interval, this.minLat_);\n    idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);\n  }\n\n  lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_);\n\n  cnt = 0;\n  while (lat != this.maxLat_ && cnt++ < maxLines) {\n    lat = Math.min(lat + interval, this.maxLat_);\n    idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);\n  }\n\n  this.parallels_.length = idx;\n\n};\n\n\n/**\n * @param {number} resolution Resolution.\n * @return {number} The interval in degrees.\n * @private\n */\nol.Graticule.prototype.getInterval_ = function(resolution) {\n  var centerLon = this.projectionCenterLonLat_[0];\n  var centerLat = this.projectionCenterLonLat_[1];\n  var interval = -1;\n  var i, ii, delta, dist;\n  var target = Math.pow(this.targetSize_ * resolution, 2);\n  /** @type {Array.<number>} **/\n  var p1 = [];\n  /** @type {Array.<number>} **/\n  var p2 = [];\n  for (i = 0, ii = ol.Graticule.intervals_.length; i < ii; ++i) {\n    delta = ol.Graticule.intervals_[i] / 2;\n    p1[0] = centerLon - delta;\n    p1[1] = centerLat - delta;\n    p2[0] = centerLon + delta;\n    p2[1] = centerLat + delta;\n    this.fromLonLatTransform_(p1, p1);\n    this.fromLonLatTransform_(p2, p2);\n    dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);\n    if (dist <= target) {\n      break;\n    }\n    interval = ol.Graticule.intervals_[i];\n  }\n  return interval;\n};\n\n\n/**\n * Get the map associated with this graticule.\n * @return {ol.Map} The map.\n * @api\n */\nol.Graticule.prototype.getMap = function() {\n  return this.map_;\n};\n\n\n/**\n * @param {number} lon Longitude.\n * @param {number} minLat Minimal latitude.\n * @param {number} maxLat Maximal latitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {ol.geom.LineString} The meridian line string.\n * @param {number} index Index.\n * @private\n */\nol.Graticule.prototype.getMeridian_ = function(lon, minLat, maxLat,\n                                               squaredTolerance, index) {\n  ol.DEBUG && console.assert(lon >= this.minLon_,\n      'lon should be larger than or equal to this.minLon_');\n  ol.DEBUG && console.assert(lon <= this.maxLon_,\n      'lon should be smaller than or equal to this.maxLon_');\n  var flatCoordinates = ol.geom.flat.geodesic.meridian(lon,\n      minLat, maxLat, this.projection_, squaredTolerance);\n  ol.DEBUG && console.assert(flatCoordinates.length > 0,\n      'flatCoordinates cannot be empty');\n  var lineString = this.meridians_[index] !== undefined ?\n      this.meridians_[index] : new ol.geom.LineString(null);\n  lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);\n  return lineString;\n};\n\n\n/**\n * Get the list of meridians.  Meridians are lines of equal longitude.\n * @return {Array.<ol.geom.LineString>} The meridians.\n * @api\n */\nol.Graticule.prototype.getMeridians = function() {\n  return this.meridians_;\n};\n\n\n/**\n * @param {number} lat Latitude.\n * @param {number} minLon Minimal longitude.\n * @param {number} maxLon Maximal longitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {ol.geom.LineString} The parallel line string.\n * @param {number} index Index.\n * @private\n */\nol.Graticule.prototype.getParallel_ = function(lat, minLon, maxLon,\n                                               squaredTolerance, index) {\n  ol.DEBUG && console.assert(lat >= this.minLat_,\n      'lat should be larger than or equal to this.minLat_');\n  ol.DEBUG && console.assert(lat <= this.maxLat_,\n      'lat should be smaller than or equal to this.maxLat_');\n  var flatCoordinates = ol.geom.flat.geodesic.parallel(lat,\n      this.minLon_, this.maxLon_, this.projection_, squaredTolerance);\n  ol.DEBUG && console.assert(flatCoordinates.length > 0,\n      'flatCoordinates cannot be empty');\n  var lineString = this.parallels_[index] !== undefined ?\n      this.parallels_[index] : new ol.geom.LineString(null);\n  lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);\n  return lineString;\n};\n\n\n/**\n * Get the list of parallels.  Pallels are lines of equal latitude.\n * @return {Array.<ol.geom.LineString>} The parallels.\n * @api\n */\nol.Graticule.prototype.getParallels = function() {\n  return this.parallels_;\n};\n\n\n/**\n * @param {ol.render.Event} e Event.\n * @private\n */\nol.Graticule.prototype.handlePostCompose_ = function(e) {\n  var vectorContext = e.vectorContext;\n  var frameState = e.frameState;\n  var extent = frameState.extent;\n  var viewState = frameState.viewState;\n  var center = viewState.center;\n  var projection = viewState.projection;\n  var resolution = viewState.resolution;\n  var pixelRatio = frameState.pixelRatio;\n  var squaredTolerance =\n      resolution * resolution / (4 * pixelRatio * pixelRatio);\n\n  var updateProjectionInfo = !this.projection_ ||\n      !ol.proj.equivalent(this.projection_, projection);\n\n  if (updateProjectionInfo) {\n    this.updateProjectionInfo_(projection);\n  }\n\n  //Fix the extent if wrapped.\n  //(note: this is the same extent as vectorContext.extent_)\n  var offsetX = 0;\n  if (projection.canWrapX()) {\n    var projectionExtent = projection.getExtent();\n    var worldWidth = ol.extent.getWidth(projectionExtent);\n    var x = frameState.focus[0];\n    if (x < projectionExtent[0] || x > projectionExtent[2]) {\n      var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);\n      offsetX = worldWidth * worldsAway;\n      extent = [\n        extent[0] + offsetX, extent[1],\n        extent[2] + offsetX, extent[3]\n      ];\n    }\n  }\n\n  this.createGraticule_(extent, center, resolution, squaredTolerance);\n\n  // Draw the lines\n  vectorContext.setFillStrokeStyle(null, this.strokeStyle_);\n  var i, l, line;\n  for (i = 0, l = this.meridians_.length; i < l; ++i) {\n    line = this.meridians_[i];\n    vectorContext.drawLineString(line, null);\n  }\n  for (i = 0, l = this.parallels_.length; i < l; ++i) {\n    line = this.parallels_[i];\n    vectorContext.drawLineString(line, null);\n  }\n};\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @private\n */\nol.Graticule.prototype.updateProjectionInfo_ = function(projection) {\n  var epsg4326Projection = ol.proj.get('EPSG:4326');\n\n  var extent = projection.getExtent();\n  var worldExtent = projection.getWorldExtent();\n  var worldExtentP = ol.proj.transformExtent(worldExtent,\n      epsg4326Projection, projection);\n\n  var maxLat = worldExtent[3];\n  var maxLon = worldExtent[2];\n  var minLat = worldExtent[1];\n  var minLon = worldExtent[0];\n\n  var maxLatP = worldExtentP[3];\n  var maxLonP = worldExtentP[2];\n  var minLatP = worldExtentP[1];\n  var minLonP = worldExtentP[0];\n\n  ol.DEBUG && console.assert(maxLat !== undefined, 'maxLat should be defined');\n  ol.DEBUG && console.assert(maxLon !== undefined, 'maxLon should be defined');\n  ol.DEBUG && console.assert(minLat !== undefined, 'minLat should be defined');\n  ol.DEBUG && console.assert(minLon !== undefined, 'minLon should be defined');\n\n  ol.DEBUG && console.assert(maxLatP !== undefined,\n      'projected maxLat should be defined');\n  ol.DEBUG && console.assert(maxLonP !== undefined,\n      'projected maxLon should be defined');\n  ol.DEBUG && console.assert(minLatP !== undefined,\n      'projected minLat should be defined');\n  ol.DEBUG && console.assert(minLonP !== undefined,\n      'projected minLon should be defined');\n\n  this.maxLat_ = maxLat;\n  this.maxLon_ = maxLon;\n  this.minLat_ = minLat;\n  this.minLon_ = minLon;\n\n  this.maxLatP_ = maxLatP;\n  this.maxLonP_ = maxLonP;\n  this.minLatP_ = minLatP;\n  this.minLonP_ = minLonP;\n\n\n  this.fromLonLatTransform_ = ol.proj.getTransform(\n      epsg4326Projection, projection);\n\n  this.toLonLatTransform_ = ol.proj.getTransform(\n      projection, epsg4326Projection);\n\n  this.projectionCenterLonLat_ = this.toLonLatTransform_(\n      ol.extent.getCenter(extent));\n\n  this.projection_ = projection;\n};\n\n\n/**\n * Set the map for this graticule.  The graticule will be rendered on the\n * provided map.\n * @param {ol.Map} map Map.\n * @api\n */\nol.Graticule.prototype.setMap = function(map) {\n  if (this.map_) {\n    this.map_.un(ol.render.Event.Type.POSTCOMPOSE,\n        this.handlePostCompose_, this);\n    this.map_.render();\n  }\n  if (map) {\n    map.on(ol.render.Event.Type.POSTCOMPOSE,\n        this.handlePostCompose_, this);\n    map.render();\n  }\n  this.map_ = map;\n};\n\ngoog.provide('ol.ImageTile');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\n\n\n/**\n * @constructor\n * @extends {ol.Tile}\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Tile.State} state State.\n * @param {string} src Image source URI.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.\n */\nol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) {\n\n  ol.Tile.call(this, tileCoord, state);\n\n  /**\n   * Image URI\n   *\n   * @private\n   * @type {string}\n   */\n  this.src_ = src;\n\n  /**\n   * @private\n   * @type {Image}\n   */\n  this.image_ = new Image();\n  if (crossOrigin !== null) {\n    this.image_.crossOrigin = crossOrigin;\n  }\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.imageListenerKeys_ = null;\n\n  /**\n   * @private\n   * @type {ol.TileLoadFunctionType}\n   */\n  this.tileLoadFunction_ = tileLoadFunction;\n\n};\nol.inherits(ol.ImageTile, ol.Tile);\n\n\n/**\n * @inheritDoc\n */\nol.ImageTile.prototype.disposeInternal = function() {\n  if (this.state == ol.Tile.State.LOADING) {\n    this.unlistenImage_();\n  }\n  if (this.interimTile) {\n    this.interimTile.dispose();\n  }\n  this.state = ol.Tile.State.ABORT;\n  this.changed();\n  ol.Tile.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Get the image element for this tile.\n * @inheritDoc\n * @api\n */\nol.ImageTile.prototype.getImage = function() {\n  return this.image_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.ImageTile.prototype.getKey = function() {\n  return this.src_;\n};\n\n\n/**\n * Tracks loading or read errors.\n *\n * @private\n */\nol.ImageTile.prototype.handleImageError_ = function() {\n  this.state = ol.Tile.State.ERROR;\n  this.unlistenImage_();\n  this.changed();\n};\n\n\n/**\n * Tracks successful image load.\n *\n * @private\n */\nol.ImageTile.prototype.handleImageLoad_ = function() {\n  if (this.image_.naturalWidth && this.image_.naturalHeight) {\n    this.state = ol.Tile.State.LOADED;\n  } else {\n    this.state = ol.Tile.State.EMPTY;\n  }\n  this.unlistenImage_();\n  this.changed();\n};\n\n\n/**\n * Load the image or retry if loading previously failed.\n * Loading is taken care of by the tile queue, and calling this method is\n * only needed for preloading or for reloading in case of an error.\n * @api\n */\nol.ImageTile.prototype.load = function() {\n  if (this.state == ol.Tile.State.IDLE || this.state == ol.Tile.State.ERROR) {\n    this.state = ol.Tile.State.LOADING;\n    this.changed();\n    ol.DEBUG && console.assert(!this.imageListenerKeys_,\n        'this.imageListenerKeys_ should be null');\n    this.imageListenerKeys_ = [\n      ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,\n          this.handleImageError_, this),\n      ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,\n          this.handleImageLoad_, this)\n    ];\n    this.tileLoadFunction_(this, this.src_);\n  }\n};\n\n\n/**\n * Discards event handlers which listen for load completion or errors.\n *\n * @private\n */\nol.ImageTile.prototype.unlistenImage_ = function() {\n  this.imageListenerKeys_.forEach(ol.events.unlistenByKey);\n  this.imageListenerKeys_ = null;\n};\n\n// FIXME should handle all geo-referenced data, not just vector data\n\ngoog.provide('ol.interaction.DragAndDrop');\n\ngoog.require('ol');\ngoog.require('ol.functions');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.EventType');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.proj');\n\n\n/**\n * @classdesc\n * Handles input of vector data by drag and drop.\n *\n * @constructor\n * @extends {ol.interaction.Interaction}\n * @fires ol.interaction.DragAndDrop.Event\n * @param {olx.interaction.DragAndDropOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.DragAndDrop = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.interaction.Interaction.call(this, {\n    handleEvent: ol.interaction.DragAndDrop.handleEvent\n  });\n\n  /**\n   * @private\n   * @type {Array.<function(new: ol.format.Feature)>}\n   */\n  this.formatConstructors_ = options.formatConstructors ?\n      options.formatConstructors : [];\n\n  /**\n   * @private\n   * @type {ol.proj.Projection}\n   */\n  this.projection_ = options.projection ?\n      ol.proj.get(options.projection) : null;\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.dropListenKeys_ = null;\n\n  /**\n   * @private\n   * @type {Element}\n   */\n  this.target = options.target ? options.target : null;\n\n};\nol.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction);\n\n\n/**\n * @param {Event} event Event.\n * @this {ol.interaction.DragAndDrop}\n * @private\n */\nol.interaction.DragAndDrop.handleDrop_ = function(event) {\n  var files = event.dataTransfer.files;\n  var i, ii, file;\n  for (i = 0, ii = files.length; i < ii; ++i) {\n    file = files.item(i);\n    var reader = new FileReader();\n    reader.addEventListener(ol.events.EventType.LOAD,\n        this.handleResult_.bind(this, file));\n    reader.readAsText(file);\n  }\n};\n\n\n/**\n * @param {Event} event Event.\n * @private\n */\nol.interaction.DragAndDrop.handleStop_ = function(event) {\n  event.stopPropagation();\n  event.preventDefault();\n  event.dataTransfer.dropEffect = 'copy';\n};\n\n\n/**\n * @param {File} file File.\n * @param {Event} event Load event.\n * @private\n */\nol.interaction.DragAndDrop.prototype.handleResult_ = function(file, event) {\n  var result = event.target.result;\n  var map = this.getMap();\n  var projection = this.projection_;\n  if (!projection) {\n    var view = map.getView();\n    projection = view.getProjection();\n    ol.DEBUG && console.assert(projection !== undefined,\n        'projection should be defined');\n  }\n  var formatConstructors = this.formatConstructors_;\n  var features = [];\n  var i, ii;\n  for (i = 0, ii = formatConstructors.length; i < ii; ++i) {\n    var formatConstructor = formatConstructors[i];\n    var format = new formatConstructor();\n    features = this.tryReadFeatures_(format, result, {\n      featureProjection: projection\n    });\n    if (features && features.length > 0) {\n      break;\n    }\n  }\n  this.dispatchEvent(\n      new ol.interaction.DragAndDrop.Event(\n          ol.interaction.DragAndDrop.EventType.ADD_FEATURES, file,\n          features, projection));\n};\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and\n * neither prevents the browser default nor stops event propagation.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.DragAndDrop}\n * @api\n */\nol.interaction.DragAndDrop.handleEvent = ol.functions.TRUE;\n\n\n/**\n * @inheritDoc\n */\nol.interaction.DragAndDrop.prototype.setMap = function(map) {\n  if (this.dropListenKeys_) {\n    this.dropListenKeys_.forEach(ol.events.unlistenByKey);\n    this.dropListenKeys_ = null;\n  }\n  ol.interaction.Interaction.prototype.setMap.call(this, map);\n  if (map) {\n    var dropArea = this.target ? this.target : map.getViewport();\n    this.dropListenKeys_ = [\n      ol.events.listen(dropArea, ol.events.EventType.DROP,\n          ol.interaction.DragAndDrop.handleDrop_, this),\n      ol.events.listen(dropArea, ol.events.EventType.DRAGENTER,\n          ol.interaction.DragAndDrop.handleStop_, this),\n      ol.events.listen(dropArea, ol.events.EventType.DRAGOVER,\n          ol.interaction.DragAndDrop.handleStop_, this),\n      ol.events.listen(dropArea, ol.events.EventType.DROP,\n          ol.interaction.DragAndDrop.handleStop_, this)\n    ];\n  }\n};\n\n\n/**\n * @param {ol.format.Feature} format Format.\n * @param {string} text Text.\n * @param {olx.format.ReadOptions} options Read options.\n * @private\n * @return {Array.<ol.Feature>} Features.\n */\nol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text, options) {\n  try {\n    return format.readFeatures(text, options);\n  } catch (e) {\n    return null;\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.interaction.DragAndDrop.EventType = {\n  /**\n   * Triggered when features are added\n   * @event ol.interaction.DragAndDrop.Event#addfeatures\n   * @api stable\n   */\n  ADD_FEATURES: 'addfeatures'\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances\n * of this type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.interaction.DragAndDropEvent}\n * @param {ol.interaction.DragAndDrop.EventType} type Type.\n * @param {File} file File.\n * @param {Array.<ol.Feature>=} opt_features Features.\n * @param {ol.proj.Projection=} opt_projection Projection.\n */\nol.interaction.DragAndDrop.Event = function(type, file, opt_features, opt_projection) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The features parsed from dropped data.\n   * @type {Array.<ol.Feature>|undefined}\n   * @api stable\n   */\n  this.features = opt_features;\n\n  /**\n   * The dropped file.\n   * @type {File}\n   * @api stable\n   */\n  this.file = file;\n\n  /**\n   * The feature projection.\n   * @type {ol.proj.Projection|undefined}\n   * @api\n   */\n  this.projection = opt_projection;\n\n};\nol.inherits(ol.interaction.DragAndDrop.Event, ol.events.Event);\n\ngoog.provide('ol.interaction.DragRotateAndZoom');\n\ngoog.require('ol');\ngoog.require('ol.View');\ngoog.require('ol.events.condition');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.interaction.Pointer');\n\n\n/**\n * @classdesc\n * Allows the user to zoom and rotate the map by clicking and dragging\n * on the map.  By default, this interaction is limited to when the shift\n * key is held down.\n *\n * This interaction is only supported for mouse devices.\n *\n * And this interaction is not included in the default interactions.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @param {olx.interaction.DragRotateAndZoomOptions=} opt_options Options.\n * @api stable\n */\nol.interaction.DragRotateAndZoom = function(opt_options) {\n\n  var options = opt_options ? opt_options : {};\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.DragRotateAndZoom.handleDownEvent_,\n    handleDragEvent: ol.interaction.DragRotateAndZoom.handleDragEvent_,\n    handleUpEvent: ol.interaction.DragRotateAndZoom.handleUpEvent_\n  });\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ?\n      options.condition : ol.events.condition.shiftKeyOnly;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.lastAngle_ = undefined;\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.lastMagnitude_ = undefined;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.lastScaleDelta_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.duration_ = options.duration !== undefined ? options.duration : 400;\n\n};\nol.inherits(ol.interaction.DragRotateAndZoom, ol.interaction.Pointer);\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @this {ol.interaction.DragRotateAndZoom}\n * @private\n */\nol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return;\n  }\n\n  var map = mapBrowserEvent.map;\n  var size = map.getSize();\n  var offset = mapBrowserEvent.pixel;\n  var deltaX = offset[0] - size[0] / 2;\n  var deltaY = size[1] / 2 - offset[1];\n  var theta = Math.atan2(deltaY, deltaX);\n  var magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n  var view = map.getView();\n  if (this.lastAngle_ !== undefined) {\n    var angleDelta = theta - this.lastAngle_;\n    ol.interaction.Interaction.rotateWithoutConstraints(\n        map, view, view.getRotation() - angleDelta);\n  }\n  this.lastAngle_ = theta;\n  if (this.lastMagnitude_ !== undefined) {\n    var resolution = this.lastMagnitude_ * (view.getResolution() / magnitude);\n    ol.interaction.Interaction.zoomWithoutConstraints(map, view, resolution);\n  }\n  if (this.lastMagnitude_ !== undefined) {\n    this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;\n  }\n  this.lastMagnitude_ = magnitude;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.DragRotateAndZoom}\n * @private\n */\nol.interaction.DragRotateAndZoom.handleUpEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return true;\n  }\n\n  var map = mapBrowserEvent.map;\n  var view = map.getView();\n  view.setHint(ol.View.Hint.INTERACTING, -1);\n  var direction = this.lastScaleDelta_ - 1;\n  ol.interaction.Interaction.rotate(map, view, view.getRotation());\n  ol.interaction.Interaction.zoom(map, view, view.getResolution(),\n      undefined, this.duration_, direction);\n  this.lastScaleDelta_ = 0;\n  return false;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.DragRotateAndZoom}\n * @private\n */\nol.interaction.DragRotateAndZoom.handleDownEvent_ = function(mapBrowserEvent) {\n  if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {\n    return false;\n  }\n\n  if (this.condition_(mapBrowserEvent)) {\n    mapBrowserEvent.map.getView().setHint(ol.View.Hint.INTERACTING, 1);\n    this.lastAngle_ = undefined;\n    this.lastMagnitude_ = undefined;\n    return true;\n  } else {\n    return false;\n  }\n};\n\ngoog.provide('ol.loadingstrategy');\n\n\n/**\n * Strategy function for loading all features with a single request.\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @return {Array.<ol.Extent>} Extents.\n * @api\n */\nol.loadingstrategy.all = function(extent, resolution) {\n  return [[-Infinity, -Infinity, Infinity, Infinity]];\n};\n\n\n/**\n * Strategy function for loading features based on the view's extent and\n * resolution.\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @return {Array.<ol.Extent>} Extents.\n * @api\n */\nol.loadingstrategy.bbox = function(extent, resolution) {\n  return [extent];\n};\n\n\n/**\n * Creates a strategy function for loading features based on a tile grid.\n * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.\n * @return {function(ol.Extent, number): Array.<ol.Extent>} Loading strategy.\n * @api\n */\nol.loadingstrategy.tile = function(tileGrid) {\n  return (\n      /**\n       * @param {ol.Extent} extent Extent.\n       * @param {number} resolution Resolution.\n       * @return {Array.<ol.Extent>} Extents.\n       */\n      function(extent, resolution) {\n        var z = tileGrid.getZForResolution(resolution);\n        var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);\n        /** @type {Array.<ol.Extent>} */\n        var extents = [];\n        /** @type {ol.TileCoord} */\n        var tileCoord = [z, 0, 0];\n        for (tileCoord[1] = tileRange.minX; tileCoord[1] <= tileRange.maxX;\n             ++tileCoord[1]) {\n          for (tileCoord[2] = tileRange.minY; tileCoord[2] <= tileRange.maxY;\n               ++tileCoord[2]) {\n            extents.push(tileGrid.getTileCoordExtent(tileCoord));\n          }\n        }\n        return extents;\n      });\n};\n\n// FIXME bulk feature upload - suppress events\n// FIXME make change-detection more refined (notably, geometry hint)\n\ngoog.provide('ol.source.Vector');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.Object');\ngoog.require('ol.array');\ngoog.require('ol.asserts');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.featureloader');\ngoog.require('ol.functions');\ngoog.require('ol.loadingstrategy');\ngoog.require('ol.obj');\ngoog.require('ol.source.Source');\ngoog.require('ol.source.State');\ngoog.require('ol.structs.RBush');\n\n\n/**\n * @classdesc\n * Provides a source of features for vector layers. Vector features provided\n * by this source are suitable for editing. See {@link ol.source.VectorTile} for\n * vector data that is optimized for rendering.\n *\n * @constructor\n * @extends {ol.source.Source}\n * @fires ol.source.Vector.Event\n * @param {olx.source.VectorOptions=} opt_options Vector source options.\n * @api stable\n */\nol.source.Vector = function(opt_options) {\n\n  var options = opt_options || {};\n\n  ol.source.Source.call(this, {\n    attributions: options.attributions,\n    logo: options.logo,\n    projection: undefined,\n    state: ol.source.State.READY,\n    wrapX: options.wrapX !== undefined ? options.wrapX : true\n  });\n\n  /**\n   * @private\n   * @type {ol.FeatureLoader}\n   */\n  this.loader_ = ol.nullFunction;\n\n  /**\n   * @private\n   * @type {ol.format.Feature|undefined}\n   */\n  this.format_ = options.format;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.overlaps_ = options.overlaps == undefined ? true : options.overlaps;\n\n  /**\n   * @private\n   * @type {string|ol.FeatureUrlFunction|undefined}\n   */\n  this.url_ = options.url;\n\n  if (options.loader !== undefined) {\n    this.loader_ = options.loader;\n  } else if (this.url_ !== undefined) {\n    ol.asserts.assert(this.format_, 7); // `format` must be set when `url` is set\n    // create a XHR feature loader for \"url\" and \"format\"\n    this.loader_ = ol.featureloader.xhr(this.url_, /** @type {ol.format.Feature} */ (this.format_));\n  }\n\n  /**\n   * @private\n   * @type {ol.LoadingStrategy}\n   */\n  this.strategy_ = options.strategy !== undefined ? options.strategy :\n      ol.loadingstrategy.all;\n\n  var useSpatialIndex =\n      options.useSpatialIndex !== undefined ? options.useSpatialIndex : true;\n\n  /**\n   * @private\n   * @type {ol.structs.RBush.<ol.Feature>}\n   */\n  this.featuresRtree_ = useSpatialIndex ? new ol.structs.RBush() : null;\n\n  /**\n   * @private\n   * @type {ol.structs.RBush.<{extent: ol.Extent}>}\n   */\n  this.loadedExtentsRtree_ = new ol.structs.RBush();\n\n  /**\n   * @private\n   * @type {Object.<string, ol.Feature>}\n   */\n  this.nullGeometryFeatures_ = {};\n\n  /**\n   * A lookup of features by id (the return from feature.getId()).\n   * @private\n   * @type {Object.<string, ol.Feature>}\n   */\n  this.idIndex_ = {};\n\n  /**\n   * A lookup of features without id (keyed by ol.getUid(feature)).\n   * @private\n   * @type {Object.<string, ol.Feature>}\n   */\n  this.undefIdIndex_ = {};\n\n  /**\n   * @private\n   * @type {Object.<string, Array.<ol.EventsKey>>}\n   */\n  this.featureChangeKeys_ = {};\n\n  /**\n   * @private\n   * @type {ol.Collection.<ol.Feature>}\n   */\n  this.featuresCollection_ = null;\n\n  var collection, features;\n  if (options.features instanceof ol.Collection) {\n    collection = options.features;\n    features = collection.getArray();\n  } else if (Array.isArray(options.features)) {\n    features = options.features;\n  }\n  if (!useSpatialIndex && collection === undefined) {\n    collection = new ol.Collection(features);\n  }\n  if (features !== undefined) {\n    this.addFeaturesInternal(features);\n  }\n  if (collection !== undefined) {\n    this.bindFeaturesCollection_(collection);\n  }\n\n};\nol.inherits(ol.source.Vector, ol.source.Source);\n\n\n/**\n * Add a single feature to the source.  If you want to add a batch of features\n * at once, call {@link ol.source.Vector#addFeatures source.addFeatures()}\n * instead.\n * @param {ol.Feature} feature Feature to add.\n * @api stable\n */\nol.source.Vector.prototype.addFeature = function(feature) {\n  this.addFeatureInternal(feature);\n  this.changed();\n};\n\n\n/**\n * Add a feature without firing a `change` event.\n * @param {ol.Feature} feature Feature.\n * @protected\n */\nol.source.Vector.prototype.addFeatureInternal = function(feature) {\n  var featureKey = ol.getUid(feature).toString();\n\n  if (!this.addToIndex_(featureKey, feature)) {\n    return;\n  }\n\n  this.setupChangeEvents_(featureKey, feature);\n\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    var extent = geometry.getExtent();\n    if (this.featuresRtree_) {\n      this.featuresRtree_.insert(extent, feature);\n    }\n  } else {\n    this.nullGeometryFeatures_[featureKey] = feature;\n  }\n\n  this.dispatchEvent(\n      new ol.source.Vector.Event(ol.source.Vector.EventType.ADDFEATURE, feature));\n};\n\n\n/**\n * @param {string} featureKey Unique identifier for the feature.\n * @param {ol.Feature} feature The feature.\n * @private\n */\nol.source.Vector.prototype.setupChangeEvents_ = function(featureKey, feature) {\n  ol.DEBUG && console.assert(!(featureKey in this.featureChangeKeys_),\n      'key (%s) not yet registered in featureChangeKey', featureKey);\n  this.featureChangeKeys_[featureKey] = [\n    ol.events.listen(feature, ol.events.EventType.CHANGE,\n        this.handleFeatureChange_, this),\n    ol.events.listen(feature, ol.Object.EventType.PROPERTYCHANGE,\n        this.handleFeatureChange_, this)\n  ];\n};\n\n\n/**\n * @param {string} featureKey Unique identifier for the feature.\n * @param {ol.Feature} feature The feature.\n * @return {boolean} The feature is \"valid\", in the sense that it is also a\n *     candidate for insertion into the Rtree.\n * @private\n */\nol.source.Vector.prototype.addToIndex_ = function(featureKey, feature) {\n  var valid = true;\n  var id = feature.getId();\n  if (id !== undefined) {\n    if (!(id.toString() in this.idIndex_)) {\n      this.idIndex_[id.toString()] = feature;\n    } else {\n      valid = false;\n    }\n  } else {\n    ol.asserts.assert(!(featureKey in this.undefIdIndex_),\n        30); // The passed `feature` was already added to the source\n    this.undefIdIndex_[featureKey] = feature;\n  }\n  return valid;\n};\n\n\n/**\n * Add a batch of features to the source.\n * @param {Array.<ol.Feature>} features Features to add.\n * @api stable\n */\nol.source.Vector.prototype.addFeatures = function(features) {\n  this.addFeaturesInternal(features);\n  this.changed();\n};\n\n\n/**\n * Add features without firing a `change` event.\n * @param {Array.<ol.Feature>} features Features.\n * @protected\n */\nol.source.Vector.prototype.addFeaturesInternal = function(features) {\n  var featureKey, i, length, feature;\n\n  var extents = [];\n  var newFeatures = [];\n  var geometryFeatures = [];\n\n  for (i = 0, length = features.length; i < length; i++) {\n    feature = features[i];\n    featureKey = ol.getUid(feature).toString();\n    if (this.addToIndex_(featureKey, feature)) {\n      newFeatures.push(feature);\n    }\n  }\n\n  for (i = 0, length = newFeatures.length; i < length; i++) {\n    feature = newFeatures[i];\n    featureKey = ol.getUid(feature).toString();\n    this.setupChangeEvents_(featureKey, feature);\n\n    var geometry = feature.getGeometry();\n    if (geometry) {\n      var extent = geometry.getExtent();\n      extents.push(extent);\n      geometryFeatures.push(feature);\n    } else {\n      this.nullGeometryFeatures_[featureKey] = feature;\n    }\n  }\n  if (this.featuresRtree_) {\n    this.featuresRtree_.load(extents, geometryFeatures);\n  }\n\n  for (i = 0, length = newFeatures.length; i < length; i++) {\n    this.dispatchEvent(new ol.source.Vector.Event(\n        ol.source.Vector.EventType.ADDFEATURE, newFeatures[i]));\n  }\n};\n\n\n/**\n * @param {!ol.Collection.<ol.Feature>} collection Collection.\n * @private\n */\nol.source.Vector.prototype.bindFeaturesCollection_ = function(collection) {\n  ol.DEBUG && console.assert(!this.featuresCollection_,\n      'bindFeaturesCollection can only be called once');\n  var modifyingCollection = false;\n  ol.events.listen(this, ol.source.Vector.EventType.ADDFEATURE,\n      function(evt) {\n        if (!modifyingCollection) {\n          modifyingCollection = true;\n          collection.push(evt.feature);\n          modifyingCollection = false;\n        }\n      });\n  ol.events.listen(this, ol.source.Vector.EventType.REMOVEFEATURE,\n      function(evt) {\n        if (!modifyingCollection) {\n          modifyingCollection = true;\n          collection.remove(evt.feature);\n          modifyingCollection = false;\n        }\n      });\n  ol.events.listen(collection, ol.Collection.EventType.ADD,\n      function(evt) {\n        if (!modifyingCollection) {\n          modifyingCollection = true;\n          this.addFeature(/** @type {ol.Feature} */ (evt.element));\n          modifyingCollection = false;\n        }\n      }, this);\n  ol.events.listen(collection, ol.Collection.EventType.REMOVE,\n      function(evt) {\n        if (!modifyingCollection) {\n          modifyingCollection = true;\n          this.removeFeature(/** @type {ol.Feature} */ (evt.element));\n          modifyingCollection = false;\n        }\n      }, this);\n  this.featuresCollection_ = collection;\n};\n\n\n/**\n * Remove all features from the source.\n * @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events.\n * @api stable\n */\nol.source.Vector.prototype.clear = function(opt_fast) {\n  if (opt_fast) {\n    for (var featureId in this.featureChangeKeys_) {\n      var keys = this.featureChangeKeys_[featureId];\n      keys.forEach(ol.events.unlistenByKey);\n    }\n    if (!this.featuresCollection_) {\n      this.featureChangeKeys_ = {};\n      this.idIndex_ = {};\n      this.undefIdIndex_ = {};\n    }\n  } else {\n    if (this.featuresRtree_) {\n      this.featuresRtree_.forEach(this.removeFeatureInternal, this);\n      for (var id in this.nullGeometryFeatures_) {\n        this.removeFeatureInternal(this.nullGeometryFeatures_[id]);\n      }\n    }\n  }\n  if (this.featuresCollection_) {\n    this.featuresCollection_.clear();\n  }\n  ol.DEBUG && console.assert(ol.obj.isEmpty(this.featureChangeKeys_),\n      'featureChangeKeys is an empty object now');\n  ol.DEBUG && console.assert(ol.obj.isEmpty(this.idIndex_),\n      'idIndex is an empty object now');\n  ol.DEBUG && console.assert(ol.obj.isEmpty(this.undefIdIndex_),\n      'undefIdIndex is an empty object now');\n\n  if (this.featuresRtree_) {\n    this.featuresRtree_.clear();\n  }\n  this.loadedExtentsRtree_.clear();\n  this.nullGeometryFeatures_ = {};\n\n  var clearEvent = new ol.source.Vector.Event(ol.source.Vector.EventType.CLEAR);\n  this.dispatchEvent(clearEvent);\n  this.changed();\n};\n\n\n/**\n * Iterate through all features on the source, calling the provided callback\n * with each one.  If the callback returns any \"truthy\" value, iteration will\n * stop and the function will return the same value.\n *\n * @param {function(this: T, ol.Feature): S} callback Called with each feature\n *     on the source.  Return a truthy value to stop iteration.\n * @param {T=} opt_this The object to use as `this` in the callback.\n * @return {S|undefined} The return value from the last call to the callback.\n * @template T,S\n * @api stable\n */\nol.source.Vector.prototype.forEachFeature = function(callback, opt_this) {\n  if (this.featuresRtree_) {\n    return this.featuresRtree_.forEach(callback, opt_this);\n  } else if (this.featuresCollection_) {\n    return this.featuresCollection_.forEach(callback, opt_this);\n  }\n};\n\n\n/**\n * Iterate through all features whose geometries contain the provided\n * coordinate, calling the callback with each feature.  If the callback returns\n * a \"truthy\" value, iteration will stop and the function will return the same\n * value.\n *\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {function(this: T, ol.Feature): S} callback Called with each feature\n *     whose goemetry contains the provided coordinate.\n * @param {T=} opt_this The object to use as `this` in the callback.\n * @return {S|undefined} The return value from the last call to the callback.\n * @template T,S\n */\nol.source.Vector.prototype.forEachFeatureAtCoordinateDirect = function(coordinate, callback, opt_this) {\n  var extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]];\n  return this.forEachFeatureInExtent(extent, function(feature) {\n    var geometry = feature.getGeometry();\n    ol.DEBUG && console.assert(geometry, 'feature geometry is defined and not null');\n    if (geometry.intersectsCoordinate(coordinate)) {\n      return callback.call(opt_this, feature);\n    } else {\n      return undefined;\n    }\n  });\n};\n\n\n/**\n * Iterate through all features whose bounding box intersects the provided\n * extent (note that the feature's geometry may not intersect the extent),\n * calling the callback with each feature.  If the callback returns a \"truthy\"\n * value, iteration will stop and the function will return the same value.\n *\n * If you are interested in features whose geometry intersects an extent, call\n * the {@link ol.source.Vector#forEachFeatureIntersectingExtent\n * source.forEachFeatureIntersectingExtent()} method instead.\n *\n * When `useSpatialIndex` is set to false, this method will loop through all\n * features, equivalent to {@link ol.source.Vector#forEachFeature}.\n *\n * @param {ol.Extent} extent Extent.\n * @param {function(this: T, ol.Feature): S} callback Called with each feature\n *     whose bounding box intersects the provided extent.\n * @param {T=} opt_this The object to use as `this` in the callback.\n * @return {S|undefined} The return value from the last call to the callback.\n * @template T,S\n * @api\n */\nol.source.Vector.prototype.forEachFeatureInExtent = function(extent, callback, opt_this) {\n  if (this.featuresRtree_) {\n    return this.featuresRtree_.forEachInExtent(extent, callback, opt_this);\n  } else if (this.featuresCollection_) {\n    return this.featuresCollection_.forEach(callback, opt_this);\n  }\n};\n\n\n/**\n * Iterate through all features whose geometry intersects the provided extent,\n * calling the callback with each feature.  If the callback returns a \"truthy\"\n * value, iteration will stop and the function will return the same value.\n *\n * If you only want to test for bounding box intersection, call the\n * {@link ol.source.Vector#forEachFeatureInExtent\n * source.forEachFeatureInExtent()} method instead.\n *\n * @param {ol.Extent} extent Extent.\n * @param {function(this: T, ol.Feature): S} callback Called with each feature\n *     whose geometry intersects the provided extent.\n * @param {T=} opt_this The object to use as `this` in the callback.\n * @return {S|undefined} The return value from the last call to the callback.\n * @template T,S\n * @api\n */\nol.source.Vector.prototype.forEachFeatureIntersectingExtent = function(extent, callback, opt_this) {\n  return this.forEachFeatureInExtent(extent,\n      /**\n       * @param {ol.Feature} feature Feature.\n       * @return {S|undefined} The return value from the last call to the callback.\n       * @template S\n       */\n      function(feature) {\n        var geometry = feature.getGeometry();\n        ol.DEBUG && console.assert(geometry,\n            'feature geometry is defined and not null');\n        if (geometry.intersectsExtent(extent)) {\n          var result = callback.call(opt_this, feature);\n          if (result) {\n            return result;\n          }\n        }\n      });\n};\n\n\n/**\n * Get the features collection associated with this source. Will be `null`\n * unless the source was configured with `useSpatialIndex` set to `false`, or\n * with an {@link ol.Collection} as `features`.\n * @return {ol.Collection.<ol.Feature>} The collection of features.\n * @api\n */\nol.source.Vector.prototype.getFeaturesCollection = function() {\n  return this.featuresCollection_;\n};\n\n\n/**\n * Get all features on the source in random order.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.source.Vector.prototype.getFeatures = function() {\n  var features;\n  if (this.featuresCollection_) {\n    features = this.featuresCollection_.getArray();\n  } else if (this.featuresRtree_) {\n    features = this.featuresRtree_.getAll();\n    if (!ol.obj.isEmpty(this.nullGeometryFeatures_)) {\n      ol.array.extend(\n          features, ol.obj.getValues(this.nullGeometryFeatures_));\n    }\n  }\n  return /** @type {Array.<ol.Feature>} */ (features);\n};\n\n\n/**\n * Get all features whose geometry intersects the provided coordinate.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @return {Array.<ol.Feature>} Features.\n * @api stable\n */\nol.source.Vector.prototype.getFeaturesAtCoordinate = function(coordinate) {\n  var features = [];\n  this.forEachFeatureAtCoordinateDirect(coordinate, function(feature) {\n    features.push(feature);\n  });\n  return features;\n};\n\n\n/**\n * Get all features in the provided extent.  Note that this returns an array of\n * all features intersecting the given extent in random order (so it may include\n * features whose geometries do not intersect the extent).\n *\n * This method is not available when the source is configured with\n * `useSpatialIndex` set to `false`.\n * @param {ol.Extent} extent Extent.\n * @return {Array.<ol.Feature>} Features.\n * @api\n */\nol.source.Vector.prototype.getFeaturesInExtent = function(extent) {\n  ol.DEBUG && console.assert(this.featuresRtree_,\n      'getFeaturesInExtent does not work when useSpatialIndex is set to false');\n  return this.featuresRtree_.getInExtent(extent);\n};\n\n\n/**\n * Get the closest feature to the provided coordinate.\n *\n * This method is not available when the source is configured with\n * `useSpatialIndex` set to `false`.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {function(ol.Feature):boolean=} opt_filter Feature filter function.\n *     The filter function will receive one argument, the {@link ol.Feature feature}\n *     and it should return a boolean value. By default, no filtering is made.\n * @return {ol.Feature} Closest feature.\n * @api stable\n */\nol.source.Vector.prototype.getClosestFeatureToCoordinate = function(coordinate, opt_filter) {\n  // Find the closest feature using branch and bound.  We start searching an\n  // infinite extent, and find the distance from the first feature found.  This\n  // becomes the closest feature.  We then compute a smaller extent which any\n  // closer feature must intersect.  We continue searching with this smaller\n  // extent, trying to find a closer feature.  Every time we find a closer\n  // feature, we update the extent being searched so that any even closer\n  // feature must intersect it.  We continue until we run out of features.\n  var x = coordinate[0];\n  var y = coordinate[1];\n  var closestFeature = null;\n  var closestPoint = [NaN, NaN];\n  var minSquaredDistance = Infinity;\n  var extent = [-Infinity, -Infinity, Infinity, Infinity];\n  ol.DEBUG && console.assert(this.featuresRtree_,\n      'getClosestFeatureToCoordinate does not work with useSpatialIndex set ' +\n      'to false');\n  var filter = opt_filter ? opt_filter : ol.functions.TRUE;\n  this.featuresRtree_.forEachInExtent(extent,\n      /**\n       * @param {ol.Feature} feature Feature.\n       */\n      function(feature) {\n        if (filter(feature)) {\n          var geometry = feature.getGeometry();\n          ol.DEBUG && console.assert(geometry,\n              'feature geometry is defined and not null');\n          var previousMinSquaredDistance = minSquaredDistance;\n          minSquaredDistance = geometry.closestPointXY(\n              x, y, closestPoint, minSquaredDistance);\n          if (minSquaredDistance < previousMinSquaredDistance) {\n            closestFeature = feature;\n            // This is sneaky.  Reduce the extent that it is currently being\n            // searched while the R-Tree traversal using this same extent object\n            // is still in progress.  This is safe because the new extent is\n            // strictly contained by the old extent.\n            var minDistance = Math.sqrt(minSquaredDistance);\n            extent[0] = x - minDistance;\n            extent[1] = y - minDistance;\n            extent[2] = x + minDistance;\n            extent[3] = y + minDistance;\n          }\n        }\n      });\n  return closestFeature;\n};\n\n\n/**\n * Get the extent of the features currently in the source.\n *\n * This method is not available when the source is configured with\n * `useSpatialIndex` set to `false`.\n * @return {!ol.Extent} Extent.\n * @api stable\n */\nol.source.Vector.prototype.getExtent = function() {\n  ol.DEBUG && console.assert(this.featuresRtree_,\n      'getExtent does not work when useSpatialIndex is set to false');\n  return this.featuresRtree_.getExtent();\n};\n\n\n/**\n * Get a feature by its identifier (the value returned by feature.getId()).\n * Note that the index treats string and numeric identifiers as the same.  So\n * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`.\n *\n * @param {string|number} id Feature identifier.\n * @return {ol.Feature} The feature (or `null` if not found).\n * @api stable\n */\nol.source.Vector.prototype.getFeatureById = function(id) {\n  var feature = this.idIndex_[id.toString()];\n  return feature !== undefined ? feature : null;\n};\n\n\n/**\n * Get the format associated with this source.\n *\n * @return {ol.format.Feature|undefined} The feature format.\n * @api\n */\nol.source.Vector.prototype.getFormat = function() {\n  return this.format_;\n};\n\n\n/**\n * @return {boolean} The source can have overlapping geometries.\n */\nol.source.Vector.prototype.getOverlaps = function() {\n  return this.overlaps_;\n};\n\n\n/**\n * Get the url associated with this source.\n *\n * @return {string|ol.FeatureUrlFunction|undefined} The url.\n * @api\n */\nol.source.Vector.prototype.getUrl = function() {\n  return this.url_;\n};\n\n\n/**\n * @param {ol.events.Event} event Event.\n * @private\n */\nol.source.Vector.prototype.handleFeatureChange_ = function(event) {\n  var feature = /** @type {ol.Feature} */ (event.target);\n  var featureKey = ol.getUid(feature).toString();\n  var geometry = feature.getGeometry();\n  if (!geometry) {\n    if (!(featureKey in this.nullGeometryFeatures_)) {\n      if (this.featuresRtree_) {\n        this.featuresRtree_.remove(feature);\n      }\n      this.nullGeometryFeatures_[featureKey] = feature;\n    }\n  } else {\n    var extent = geometry.getExtent();\n    if (featureKey in this.nullGeometryFeatures_) {\n      delete this.nullGeometryFeatures_[featureKey];\n      if (this.featuresRtree_) {\n        this.featuresRtree_.insert(extent, feature);\n      }\n    } else {\n      if (this.featuresRtree_) {\n        this.featuresRtree_.update(extent, feature);\n      }\n    }\n  }\n  var id = feature.getId();\n  var removed;\n  if (id !== undefined) {\n    var sid = id.toString();\n    if (featureKey in this.undefIdIndex_) {\n      delete this.undefIdIndex_[featureKey];\n      this.idIndex_[sid] = feature;\n    } else {\n      if (this.idIndex_[sid] !== feature) {\n        removed = this.removeFromIdIndex_(feature);\n        ol.DEBUG && console.assert(removed,\n            'Expected feature to be removed from index');\n        this.idIndex_[sid] = feature;\n      }\n    }\n  } else {\n    if (!(featureKey in this.undefIdIndex_)) {\n      removed = this.removeFromIdIndex_(feature);\n      ol.DEBUG && console.assert(removed,\n          'Expected feature to be removed from index');\n      this.undefIdIndex_[featureKey] = feature;\n    } else {\n      ol.DEBUG && console.assert(this.undefIdIndex_[featureKey] === feature,\n          'feature keyed under %s in undefIdKeys', featureKey);\n    }\n  }\n  this.changed();\n  this.dispatchEvent(new ol.source.Vector.Event(\n      ol.source.Vector.EventType.CHANGEFEATURE, feature));\n};\n\n\n/**\n * @return {boolean} Is empty.\n */\nol.source.Vector.prototype.isEmpty = function() {\n  return this.featuresRtree_.isEmpty() &&\n      ol.obj.isEmpty(this.nullGeometryFeatures_);\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @param {ol.proj.Projection} projection Projection.\n */\nol.source.Vector.prototype.loadFeatures = function(\n    extent, resolution, projection) {\n  var loadedExtentsRtree = this.loadedExtentsRtree_;\n  var extentsToLoad = this.strategy_(extent, resolution);\n  var i, ii;\n  for (i = 0, ii = extentsToLoad.length; i < ii; ++i) {\n    var extentToLoad = extentsToLoad[i];\n    var alreadyLoaded = loadedExtentsRtree.forEachInExtent(extentToLoad,\n        /**\n         * @param {{extent: ol.Extent}} object Object.\n         * @return {boolean} Contains.\n         */\n        function(object) {\n          return ol.extent.containsExtent(object.extent, extentToLoad);\n        });\n    if (!alreadyLoaded) {\n      this.loader_.call(this, extentToLoad, resolution, projection);\n      loadedExtentsRtree.insert(extentToLoad, {extent: extentToLoad.slice()});\n    }\n  }\n};\n\n\n/**\n * Remove a single feature from the source.  If you want to remove all features\n * at once, use the {@link ol.source.Vector#clear source.clear()} method\n * instead.\n * @param {ol.Feature} feature Feature to remove.\n * @api stable\n */\nol.source.Vector.prototype.removeFeature = function(feature) {\n  var featureKey = ol.getUid(feature).toString();\n  if (featureKey in this.nullGeometryFeatures_) {\n    delete this.nullGeometryFeatures_[featureKey];\n  } else {\n    if (this.featuresRtree_) {\n      this.featuresRtree_.remove(feature);\n    }\n  }\n  this.removeFeatureInternal(feature);\n  this.changed();\n};\n\n\n/**\n * Remove feature without firing a `change` event.\n * @param {ol.Feature} feature Feature.\n * @protected\n */\nol.source.Vector.prototype.removeFeatureInternal = function(feature) {\n  var featureKey = ol.getUid(feature).toString();\n  ol.DEBUG && console.assert(featureKey in this.featureChangeKeys_,\n      'featureKey exists in featureChangeKeys');\n  this.featureChangeKeys_[featureKey].forEach(ol.events.unlistenByKey);\n  delete this.featureChangeKeys_[featureKey];\n  var id = feature.getId();\n  if (id !== undefined) {\n    delete this.idIndex_[id.toString()];\n  } else {\n    delete this.undefIdIndex_[featureKey];\n  }\n  this.dispatchEvent(new ol.source.Vector.Event(\n      ol.source.Vector.EventType.REMOVEFEATURE, feature));\n};\n\n\n/**\n * Remove a feature from the id index.  Called internally when the feature id\n * may have changed.\n * @param {ol.Feature} feature The feature.\n * @return {boolean} Removed the feature from the index.\n * @private\n */\nol.source.Vector.prototype.removeFromIdIndex_ = function(feature) {\n  var removed = false;\n  for (var id in this.idIndex_) {\n    if (this.idIndex_[id] === feature) {\n      delete this.idIndex_[id];\n      removed = true;\n      break;\n    }\n  }\n  return removed;\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.source.Vector} instances are instances of this\n * type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.source.Vector.Event}\n * @param {string} type Type.\n * @param {ol.Feature=} opt_feature Feature.\n */\nol.source.Vector.Event = function(type, opt_feature) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The feature being added or removed.\n   * @type {ol.Feature|undefined}\n   * @api stable\n   */\n  this.feature = opt_feature;\n\n};\nol.inherits(ol.source.Vector.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.source.Vector.EventType = {\n  /**\n   * Triggered when a feature is added to the source.\n   * @event ol.source.Vector.Event#addfeature\n   * @api stable\n   */\n  ADDFEATURE: 'addfeature',\n\n  /**\n   * Triggered when a feature is updated.\n   * @event ol.source.Vector.Event#changefeature\n   * @api\n   */\n  CHANGEFEATURE: 'changefeature',\n\n  /**\n   * Triggered when the clear method is called on the source.\n   * @event ol.source.Vector.Event#clear\n   * @api\n   */\n  CLEAR: 'clear',\n\n  /**\n   * Triggered when a feature is removed from the source.\n   * See {@link ol.source.Vector#clear source.clear()} for exceptions.\n   * @event ol.source.Vector.Event#removefeature\n   * @api stable\n   */\n  REMOVEFEATURE: 'removefeature'\n};\n\ngoog.provide('ol.interaction.Draw');\n\ngoog.require('ol');\ngoog.require('ol.events');\ngoog.require('ol.extent');\ngoog.require('ol.events.Event');\ngoog.require('ol.Feature');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.Object');\ngoog.require('ol.coordinate');\ngoog.require('ol.functions');\ngoog.require('ol.events.condition');\ngoog.require('ol.geom.Circle');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.interaction.Pointer');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.source.Vector');\ngoog.require('ol.style.Style');\n\n\n/**\n * @classdesc\n * Interaction for drawing feature geometries.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @fires ol.interaction.Draw.Event\n * @param {olx.interaction.DrawOptions} options Options.\n * @api stable\n */\nol.interaction.Draw = function(options) {\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.Draw.handleDownEvent_,\n    handleEvent: ol.interaction.Draw.handleEvent,\n    handleUpEvent: ol.interaction.Draw.handleUpEvent_\n  });\n\n  /**\n   * @type {ol.Pixel}\n   * @private\n   */\n  this.downPx_ = null;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.freehand_ = false;\n\n  /**\n   * Target source for drawn features.\n   * @type {ol.source.Vector}\n   * @private\n   */\n  this.source_ = options.source ? options.source : null;\n\n  /**\n   * Target collection for drawn features.\n   * @type {ol.Collection.<ol.Feature>}\n   * @private\n   */\n  this.features_ = options.features ? options.features : null;\n\n  /**\n   * Pixel distance for snapping.\n   * @type {number}\n   * @private\n   */\n  this.snapTolerance_ = options.snapTolerance ? options.snapTolerance : 12;\n\n  /**\n   * Geometry type.\n   * @type {ol.geom.GeometryType}\n   * @private\n   */\n  this.type_ = options.type;\n\n  /**\n   * Drawing mode (derived from geometry type.\n   * @type {ol.interaction.Draw.Mode}\n   * @private\n   */\n  this.mode_ = ol.interaction.Draw.getMode_(this.type_);\n\n  /**\n   * The number of points that must be drawn before a polygon ring or line\n   * string can be finished.  The default is 3 for polygon rings and 2 for\n   * line strings.\n   * @type {number}\n   * @private\n   */\n  this.minPoints_ = options.minPoints ?\n      options.minPoints :\n      (this.mode_ === ol.interaction.Draw.Mode.POLYGON ? 3 : 2);\n\n  /**\n   * The number of points that can be drawn before a polygon ring or line string\n   * is finished. The default is no restriction.\n   * @type {number}\n   * @private\n   */\n  this.maxPoints_ = options.maxPoints ? options.maxPoints : Infinity;\n\n  /**\n   * A function to decide if a potential finish coordinate is permissable\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.finishCondition_ = options.finishCondition ? options.finishCondition : ol.functions.TRUE;\n\n  var geometryFunction = options.geometryFunction;\n  if (!geometryFunction) {\n    if (this.type_ === ol.geom.GeometryType.CIRCLE) {\n      /**\n       * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates\n       *     The coordinates.\n       * @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.\n       * @return {ol.geom.SimpleGeometry} A geometry.\n       */\n      geometryFunction = function(coordinates, opt_geometry) {\n        var circle = opt_geometry ? /** @type {ol.geom.Circle} */ (opt_geometry) :\n            new ol.geom.Circle([NaN, NaN]);\n        var squaredLength = ol.coordinate.squaredDistance(\n            coordinates[0], coordinates[1]);\n        circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength));\n        return circle;\n      };\n    } else {\n      var Constructor;\n      var mode = this.mode_;\n      if (mode === ol.interaction.Draw.Mode.POINT) {\n        Constructor = ol.geom.Point;\n      } else if (mode === ol.interaction.Draw.Mode.LINE_STRING) {\n        Constructor = ol.geom.LineString;\n      } else if (mode === ol.interaction.Draw.Mode.POLYGON) {\n        Constructor = ol.geom.Polygon;\n      }\n      /**\n       * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates\n       *     The coordinates.\n       * @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.\n       * @return {ol.geom.SimpleGeometry} A geometry.\n       */\n      geometryFunction = function(coordinates, opt_geometry) {\n        var geometry = opt_geometry;\n        if (geometry) {\n          if (mode === ol.interaction.Draw.Mode.POLYGON) {\n            geometry.setCoordinates([coordinates[0].concat([coordinates[0][0]])]);\n          } else {\n            geometry.setCoordinates(coordinates);\n          }\n        } else {\n          geometry = new Constructor(coordinates);\n        }\n        return geometry;\n      };\n    }\n  }\n\n  /**\n   * @type {ol.DrawGeometryFunctionType}\n   * @private\n   */\n  this.geometryFunction_ = geometryFunction;\n\n  /**\n   * Finish coordinate for the feature (first point for polygons, last point for\n   * linestrings).\n   * @type {ol.Coordinate}\n   * @private\n   */\n  this.finishCoordinate_ = null;\n\n  /**\n   * Sketch feature.\n   * @type {ol.Feature}\n   * @private\n   */\n  this.sketchFeature_ = null;\n\n  /**\n   * Sketch point.\n   * @type {ol.Feature}\n   * @private\n   */\n  this.sketchPoint_ = null;\n\n  /**\n   * Sketch coordinates. Used when drawing a line or polygon.\n   * @type {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>}\n   * @private\n   */\n  this.sketchCoords_ = null;\n\n  /**\n   * Sketch line. Used when drawing polygon.\n   * @type {ol.Feature}\n   * @private\n   */\n  this.sketchLine_ = null;\n\n  /**\n   * Sketch line coordinates. Used when drawing a polygon or circle.\n   * @type {Array.<ol.Coordinate>}\n   * @private\n   */\n  this.sketchLineCoords_ = null;\n\n  /**\n   * Squared tolerance for handling up events.  If the squared distance\n   * between a down and up event is greater than this tolerance, up events\n   * will not be handled.\n   * @type {number}\n   * @private\n   */\n  this.squaredClickTolerance_ = options.clickTolerance ?\n      options.clickTolerance * options.clickTolerance : 36;\n\n  /**\n   * Draw overlay where our sketch features are drawn.\n   * @type {ol.layer.Vector}\n   * @private\n   */\n  this.overlay_ = new ol.layer.Vector({\n    source: new ol.source.Vector({\n      useSpatialIndex: false,\n      wrapX: options.wrapX ? options.wrapX : false\n    }),\n    style: options.style ? options.style :\n        ol.interaction.Draw.getDefaultStyleFunction()\n  });\n\n  /**\n   * Name of the geometry attribute for newly created features.\n   * @type {string|undefined}\n   * @private\n   */\n  this.geometryName_ = options.geometryName;\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ?\n      options.condition : ol.events.condition.noModifierKeys;\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.freehandCondition_;\n  if (options.freehand) {\n    this.freehandCondition_ = ol.events.condition.always;\n  } else {\n    this.freehandCondition_ = options.freehandCondition ?\n        options.freehandCondition : ol.events.condition.shiftKeyOnly;\n  }\n\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.interaction.Interaction.Property.ACTIVE),\n      this.updateState_, this);\n\n};\nol.inherits(ol.interaction.Draw, ol.interaction.Pointer);\n\n\n/**\n * @return {ol.StyleFunction} Styles.\n */\nol.interaction.Draw.getDefaultStyleFunction = function() {\n  var styles = ol.style.Style.createDefaultEditing();\n  return function(feature, resolution) {\n    return styles[feature.getGeometry().getType()];\n  };\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.Draw.prototype.setMap = function(map) {\n  ol.interaction.Pointer.prototype.setMap.call(this, map);\n  this.updateState_();\n};\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} and may actually\n * draw or finish the drawing.\n * @param {ol.MapBrowserEvent} event Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.Draw}\n * @api\n */\nol.interaction.Draw.handleEvent = function(event) {\n  this.freehand_ = this.mode_ !== ol.interaction.Draw.Mode.POINT && this.freehandCondition_(event);\n  var pass = !this.freehand_;\n  if (this.freehand_ &&\n      event.type === ol.MapBrowserEvent.EventType.POINTERDRAG && this.sketchFeature_ !== null) {\n    this.addToDrawing_(event);\n    pass = false;\n  } else if (event.type ===\n      ol.MapBrowserEvent.EventType.POINTERMOVE) {\n    pass = this.handlePointerMove_(event);\n  } else if (event.type === ol.MapBrowserEvent.EventType.DBLCLICK) {\n    pass = false;\n  }\n  return ol.interaction.Pointer.handleEvent.call(this, event) && pass;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} event Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.Draw}\n * @private\n */\nol.interaction.Draw.handleDownEvent_ = function(event) {\n  if (this.freehand_) {\n    this.downPx_ = event.pixel;\n    if (!this.finishCoordinate_) {\n      this.startDrawing_(event);\n    }\n    return true;\n  } else if (this.condition_(event)) {\n    this.downPx_ = event.pixel;\n    return true;\n  } else {\n    return false;\n  }\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} event Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.Draw}\n * @private\n */\nol.interaction.Draw.handleUpEvent_ = function(event) {\n  var downPx = this.downPx_;\n  var clickPx = event.pixel;\n  var dx = downPx[0] - clickPx[0];\n  var dy = downPx[1] - clickPx[1];\n  var squaredDistance = dx * dx + dy * dy;\n  var pass = true;\n  var shouldHandle = this.freehand_ ?\n      squaredDistance > this.squaredClickTolerance_ :\n      squaredDistance <= this.squaredClickTolerance_;\n  var circleMode = this.mode_ === ol.interaction.Draw.Mode.CIRCLE;\n  if (shouldHandle) {\n    this.handlePointerMove_(event);\n    if (!this.finishCoordinate_) {\n      this.startDrawing_(event);\n      if (this.mode_ === ol.interaction.Draw.Mode.POINT) {\n        this.finishDrawing();\n      }\n    } else if (this.freehand_ || circleMode) {\n      this.finishDrawing();\n    } else if (this.atFinish_(event)) {\n      if (this.finishCondition_(event)) {\n        this.finishDrawing();\n      }\n    } else {\n      this.addToDrawing_(event);\n    }\n    pass = false;\n  } else if (circleMode) {\n    this.finishCoordinate_ = null;\n  }\n  return pass;\n};\n\n\n/**\n * Handle move events.\n * @param {ol.MapBrowserEvent} event A move event.\n * @return {boolean} Pass the event to other interactions.\n * @private\n */\nol.interaction.Draw.prototype.handlePointerMove_ = function(event) {\n  if (this.finishCoordinate_) {\n    this.modifyDrawing_(event);\n  } else {\n    this.createOrUpdateSketchPoint_(event);\n  }\n  return true;\n};\n\n\n/**\n * Determine if an event is within the snapping tolerance of the start coord.\n * @param {ol.MapBrowserEvent} event Event.\n * @return {boolean} The event is within the snapping tolerance of the start.\n * @private\n */\nol.interaction.Draw.prototype.atFinish_ = function(event) {\n  var at = false;\n  if (this.sketchFeature_) {\n    var potentiallyDone = false;\n    var potentiallyFinishCoordinates = [this.finishCoordinate_];\n    if (this.mode_ === ol.interaction.Draw.Mode.LINE_STRING) {\n      potentiallyDone = this.sketchCoords_.length > this.minPoints_;\n    } else if (this.mode_ === ol.interaction.Draw.Mode.POLYGON) {\n      potentiallyDone = this.sketchCoords_[0].length >\n          this.minPoints_;\n      potentiallyFinishCoordinates = [this.sketchCoords_[0][0],\n        this.sketchCoords_[0][this.sketchCoords_[0].length - 2]];\n    }\n    if (potentiallyDone) {\n      var map = event.map;\n      for (var i = 0, ii = potentiallyFinishCoordinates.length; i < ii; i++) {\n        var finishCoordinate = potentiallyFinishCoordinates[i];\n        var finishPixel = map.getPixelFromCoordinate(finishCoordinate);\n        var pixel = event.pixel;\n        var dx = pixel[0] - finishPixel[0];\n        var dy = pixel[1] - finishPixel[1];\n        var snapTolerance = this.freehand_ ? 1 : this.snapTolerance_;\n        at = Math.sqrt(dx * dx + dy * dy) <= snapTolerance;\n        if (at) {\n          this.finishCoordinate_ = finishCoordinate;\n          break;\n        }\n      }\n    }\n  }\n  return at;\n};\n\n\n/**\n * @param {ol.MapBrowserEvent} event Event.\n * @private\n */\nol.interaction.Draw.prototype.createOrUpdateSketchPoint_ = function(event) {\n  var coordinates = event.coordinate.slice();\n  if (!this.sketchPoint_) {\n    this.sketchPoint_ = new ol.Feature(new ol.geom.Point(coordinates));\n    this.updateSketchFeatures_();\n  } else {\n    var sketchPointGeom = /** @type {ol.geom.Point} */ (this.sketchPoint_.getGeometry());\n    sketchPointGeom.setCoordinates(coordinates);\n  }\n};\n\n\n/**\n * Start the drawing.\n * @param {ol.MapBrowserEvent} event Event.\n * @private\n */\nol.interaction.Draw.prototype.startDrawing_ = function(event) {\n  var start = event.coordinate;\n  this.finishCoordinate_ = start;\n  if (this.mode_ === ol.interaction.Draw.Mode.POINT) {\n    this.sketchCoords_ = start.slice();\n  } else if (this.mode_ === ol.interaction.Draw.Mode.POLYGON) {\n    this.sketchCoords_ = [[start.slice(), start.slice()]];\n    this.sketchLineCoords_ = this.sketchCoords_[0];\n  } else {\n    this.sketchCoords_ = [start.slice(), start.slice()];\n    if (this.mode_ === ol.interaction.Draw.Mode.CIRCLE) {\n      this.sketchLineCoords_ = this.sketchCoords_;\n    }\n  }\n  if (this.sketchLineCoords_) {\n    this.sketchLine_ = new ol.Feature(\n        new ol.geom.LineString(this.sketchLineCoords_));\n  }\n  var geometry = this.geometryFunction_(this.sketchCoords_);\n  ol.DEBUG && console.assert(geometry !== undefined, 'geometry should be defined');\n  this.sketchFeature_ = new ol.Feature();\n  if (this.geometryName_) {\n    this.sketchFeature_.setGeometryName(this.geometryName_);\n  }\n  this.sketchFeature_.setGeometry(geometry);\n  this.updateSketchFeatures_();\n  this.dispatchEvent(new ol.interaction.Draw.Event(\n      ol.interaction.Draw.EventType.DRAWSTART, this.sketchFeature_));\n};\n\n\n/**\n * Modify the drawing.\n * @param {ol.MapBrowserEvent} event Event.\n * @private\n */\nol.interaction.Draw.prototype.modifyDrawing_ = function(event) {\n  var coordinate = event.coordinate;\n  var geometry = /** @type {ol.geom.SimpleGeometry} */ (this.sketchFeature_.getGeometry());\n  var coordinates, last;\n  if (this.mode_ === ol.interaction.Draw.Mode.POINT) {\n    last = this.sketchCoords_;\n  } else if (this.mode_ === ol.interaction.Draw.Mode.POLYGON) {\n    coordinates = this.sketchCoords_[0];\n    last = coordinates[coordinates.length - 1];\n    if (this.atFinish_(event)) {\n      // snap to finish\n      coordinate = this.finishCoordinate_.slice();\n    }\n  } else {\n    coordinates = this.sketchCoords_;\n    last = coordinates[coordinates.length - 1];\n  }\n  last[0] = coordinate[0];\n  last[1] = coordinate[1];\n  ol.DEBUG && console.assert(this.sketchCoords_, 'sketchCoords_ expected');\n  this.geometryFunction_(\n      /** @type {!ol.Coordinate|!Array.<ol.Coordinate>|!Array.<Array.<ol.Coordinate>>} */ (this.sketchCoords_),\n      geometry);\n  if (this.sketchPoint_) {\n    var sketchPointGeom = /** @type {ol.geom.Point} */ (this.sketchPoint_.getGeometry());\n    sketchPointGeom.setCoordinates(coordinate);\n  }\n  var sketchLineGeom;\n  if (geometry instanceof ol.geom.Polygon &&\n      this.mode_ !== ol.interaction.Draw.Mode.POLYGON) {\n    if (!this.sketchLine_) {\n      this.sketchLine_ = new ol.Feature(new ol.geom.LineString(null));\n    }\n    var ring = geometry.getLinearRing(0);\n    sketchLineGeom = /** @type {ol.geom.LineString} */ (this.sketchLine_.getGeometry());\n    sketchLineGeom.setFlatCoordinates(\n        ring.getLayout(), ring.getFlatCoordinates());\n  } else if (this.sketchLineCoords_) {\n    sketchLineGeom = /** @type {ol.geom.LineString} */ (this.sketchLine_.getGeometry());\n    sketchLineGeom.setCoordinates(this.sketchLineCoords_);\n  }\n  this.updateSketchFeatures_();\n};\n\n\n/**\n * Add a new coordinate to the drawing.\n * @param {ol.MapBrowserEvent} event Event.\n * @private\n */\nol.interaction.Draw.prototype.addToDrawing_ = function(event) {\n  var coordinate = event.coordinate;\n  var geometry = /** @type {ol.geom.SimpleGeometry} */ (this.sketchFeature_.getGeometry());\n  var done;\n  var coordinates;\n  if (this.mode_ === ol.interaction.Draw.Mode.LINE_STRING) {\n    this.finishCoordinate_ = coordinate.slice();\n    coordinates = this.sketchCoords_;\n    if (coordinates.length >= this.maxPoints_) {\n      if (this.freehand_) {\n        coordinates.pop();\n      } else {\n        done = true;\n      }\n    }\n    coordinates.push(coordinate.slice());\n    this.geometryFunction_(coordinates, geometry);\n  } else if (this.mode_ === ol.interaction.Draw.Mode.POLYGON) {\n    coordinates = this.sketchCoords_[0];\n    if (coordinates.length >= this.maxPoints_) {\n      if (this.freehand_) {\n        coordinates.pop();\n      } else {\n        done = true;\n      }\n    }\n    coordinates.push(coordinate.slice());\n    if (done) {\n      this.finishCoordinate_ = coordinates[0];\n    }\n    this.geometryFunction_(this.sketchCoords_, geometry);\n  }\n  this.updateSketchFeatures_();\n  if (done) {\n    this.finishDrawing();\n  }\n};\n\n\n/**\n * Remove last point of the feature currently being drawn.\n * @api\n */\nol.interaction.Draw.prototype.removeLastPoint = function() {\n  var geometry = /** @type {ol.geom.SimpleGeometry} */ (this.sketchFeature_.getGeometry());\n  var coordinates, sketchLineGeom;\n  if (this.mode_ === ol.interaction.Draw.Mode.LINE_STRING) {\n    coordinates = this.sketchCoords_;\n    coordinates.splice(-2, 1);\n    this.geometryFunction_(coordinates, geometry);\n  } else if (this.mode_ === ol.interaction.Draw.Mode.POLYGON) {\n    coordinates = this.sketchCoords_[0];\n    coordinates.splice(-2, 1);\n    sketchLineGeom = /** @type {ol.geom.LineString} */ (this.sketchLine_.getGeometry());\n    sketchLineGeom.setCoordinates(coordinates);\n    this.geometryFunction_(this.sketchCoords_, geometry);\n  }\n\n  if (coordinates.length === 0) {\n    this.finishCoordinate_ = null;\n  }\n\n  this.updateSketchFeatures_();\n};\n\n\n/**\n * Stop drawing and add the sketch feature to the target layer.\n * The {@link ol.interaction.Draw.EventType.DRAWEND} event is dispatched before\n * inserting the feature.\n * @api\n */\nol.interaction.Draw.prototype.finishDrawing = function() {\n  var sketchFeature = this.abortDrawing_();\n  var coordinates = this.sketchCoords_;\n  var geometry = /** @type {ol.geom.SimpleGeometry} */ (sketchFeature.getGeometry());\n  if (this.mode_ === ol.interaction.Draw.Mode.LINE_STRING) {\n    // remove the redundant last point\n    coordinates.pop();\n    this.geometryFunction_(coordinates, geometry);\n  } else if (this.mode_ === ol.interaction.Draw.Mode.POLYGON) {\n    // remove the redundant last point in ring\n    coordinates[0].pop();\n    this.geometryFunction_(coordinates, geometry);\n    coordinates = geometry.getCoordinates();\n  }\n\n  // cast multi-part geometries\n  if (this.type_ === ol.geom.GeometryType.MULTI_POINT) {\n    sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates]));\n  } else if (this.type_ === ol.geom.GeometryType.MULTI_LINE_STRING) {\n    sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates]));\n  } else if (this.type_ === ol.geom.GeometryType.MULTI_POLYGON) {\n    sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates]));\n  }\n\n  // First dispatch event to allow full set up of feature\n  this.dispatchEvent(new ol.interaction.Draw.Event(\n      ol.interaction.Draw.EventType.DRAWEND, sketchFeature));\n\n  // Then insert feature\n  if (this.features_) {\n    this.features_.push(sketchFeature);\n  }\n  if (this.source_) {\n    this.source_.addFeature(sketchFeature);\n  }\n};\n\n\n/**\n * Stop drawing without adding the sketch feature to the target layer.\n * @return {ol.Feature} The sketch feature (or null if none).\n * @private\n */\nol.interaction.Draw.prototype.abortDrawing_ = function() {\n  this.finishCoordinate_ = null;\n  var sketchFeature = this.sketchFeature_;\n  if (sketchFeature) {\n    this.sketchFeature_ = null;\n    this.sketchPoint_ = null;\n    this.sketchLine_ = null;\n    this.overlay_.getSource().clear(true);\n  }\n  return sketchFeature;\n};\n\n\n/**\n * Extend an existing geometry by adding additional points. This only works\n * on features with `LineString` geometries, where the interaction will\n * extend lines by adding points to the end of the coordinates array.\n * @param {!ol.Feature} feature Feature to be extended.\n * @api\n */\nol.interaction.Draw.prototype.extend = function(feature) {\n  var geometry = feature.getGeometry();\n  ol.DEBUG && console.assert(this.mode_ == ol.interaction.Draw.Mode.LINE_STRING,\n      'interaction mode must be \"line\"');\n  ol.DEBUG && console.assert(geometry.getType() == ol.geom.GeometryType.LINE_STRING,\n      'feature geometry must be a line string');\n  var lineString = /** @type {ol.geom.LineString} */ (geometry);\n  this.sketchFeature_ = feature;\n  this.sketchCoords_ = lineString.getCoordinates();\n  var last = this.sketchCoords_[this.sketchCoords_.length - 1];\n  this.finishCoordinate_ = last.slice();\n  this.sketchCoords_.push(last.slice());\n  this.updateSketchFeatures_();\n  this.dispatchEvent(new ol.interaction.Draw.Event(\n      ol.interaction.Draw.EventType.DRAWSTART, this.sketchFeature_));\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.Draw.prototype.shouldStopEvent = ol.functions.FALSE;\n\n\n/**\n * Redraw the sketch features.\n * @private\n */\nol.interaction.Draw.prototype.updateSketchFeatures_ = function() {\n  var sketchFeatures = [];\n  if (this.sketchFeature_) {\n    sketchFeatures.push(this.sketchFeature_);\n  }\n  if (this.sketchLine_) {\n    sketchFeatures.push(this.sketchLine_);\n  }\n  if (this.sketchPoint_) {\n    sketchFeatures.push(this.sketchPoint_);\n  }\n  var overlaySource = this.overlay_.getSource();\n  overlaySource.clear(true);\n  overlaySource.addFeatures(sketchFeatures);\n};\n\n\n/**\n * @private\n */\nol.interaction.Draw.prototype.updateState_ = function() {\n  var map = this.getMap();\n  var active = this.getActive();\n  if (!map || !active) {\n    this.abortDrawing_();\n  }\n  this.overlay_.setMap(active ? map : null);\n};\n\n\n/**\n * Create a `geometryFunction` for `type: 'Circle'` that will create a regular\n * polygon with a user specified number of sides and start angle instead of an\n * `ol.geom.Circle` geometry.\n * @param {number=} opt_sides Number of sides of the regular polygon. Default is\n *     32.\n * @param {number=} opt_angle Angle of the first point in radians. 0 means East.\n *     Default is the angle defined by the heading from the center of the\n *     regular polygon to the current pointer position.\n * @return {ol.DrawGeometryFunctionType} Function that draws a\n *     polygon.\n * @api\n */\nol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) {\n  return (\n      /**\n       * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates\n       * @param {ol.geom.SimpleGeometry=} opt_geometry\n       * @return {ol.geom.SimpleGeometry}\n       */\n      function(coordinates, opt_geometry) {\n        var center = coordinates[0];\n        var end = coordinates[1];\n        var radius = Math.sqrt(\n            ol.coordinate.squaredDistance(center, end));\n        var geometry = opt_geometry ? /** @type {ol.geom.Polygon} */ (opt_geometry) :\n            ol.geom.Polygon.fromCircle(new ol.geom.Circle(center), opt_sides);\n        var angle = opt_angle ? opt_angle :\n            Math.atan((end[1] - center[1]) / (end[0] - center[0]));\n        ol.geom.Polygon.makeRegular(geometry, center, radius, angle);\n        return geometry;\n      }\n  );\n};\n\n\n/**\n * Create a `geometryFunction` that will create a box-shaped polygon (aligned\n * with the coordinate system axes).  Use this with the draw interaction and\n * `type: 'Circle'` to return a box instead of a circle geometry.\n * @return {ol.DrawGeometryFunctionType} Function that draws a box-shaped polygon.\n * @api\n */\nol.interaction.Draw.createBox = function() {\n  return (\n    /**\n     * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates\n     * @param {ol.geom.SimpleGeometry=} opt_geometry\n     * @return {ol.geom.SimpleGeometry}\n     */\n    function(coordinates, opt_geometry) {\n      var extent = ol.extent.boundingExtent(coordinates);\n      var geometry = opt_geometry || new ol.geom.Polygon(null);\n      geometry.setCoordinates([[\n        ol.extent.getBottomLeft(extent),\n        ol.extent.getBottomRight(extent),\n        ol.extent.getTopRight(extent),\n        ol.extent.getTopLeft(extent),\n        ol.extent.getBottomLeft(extent)\n      ]]);\n      return geometry;\n    }\n  );\n};\n\n\n/**\n * Get the drawing mode.  The mode for mult-part geometries is the same as for\n * their single-part cousins.\n * @param {ol.geom.GeometryType} type Geometry type.\n * @return {ol.interaction.Draw.Mode} Drawing mode.\n * @private\n */\nol.interaction.Draw.getMode_ = function(type) {\n  var mode;\n  if (type === ol.geom.GeometryType.POINT ||\n      type === ol.geom.GeometryType.MULTI_POINT) {\n    mode = ol.interaction.Draw.Mode.POINT;\n  } else if (type === ol.geom.GeometryType.LINE_STRING ||\n      type === ol.geom.GeometryType.MULTI_LINE_STRING) {\n    mode = ol.interaction.Draw.Mode.LINE_STRING;\n  } else if (type === ol.geom.GeometryType.POLYGON ||\n      type === ol.geom.GeometryType.MULTI_POLYGON) {\n    mode = ol.interaction.Draw.Mode.POLYGON;\n  } else if (type === ol.geom.GeometryType.CIRCLE) {\n    mode = ol.interaction.Draw.Mode.CIRCLE;\n  }\n  return /** @type {!ol.interaction.Draw.Mode} */ (mode);\n};\n\n\n/**\n * Draw mode.  This collapses multi-part geometry types with their single-part\n * cousins.\n * @enum {string}\n */\nol.interaction.Draw.Mode = {\n  POINT: 'Point',\n  LINE_STRING: 'LineString',\n  POLYGON: 'Polygon',\n  CIRCLE: 'Circle'\n};\n\n/**\n * @classdesc\n * Events emitted by {@link ol.interaction.Draw} instances are instances of\n * this type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.DrawEvent}\n * @param {ol.interaction.Draw.EventType} type Type.\n * @param {ol.Feature} feature The feature drawn.\n */\nol.interaction.Draw.Event = function(type, feature) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The feature being drawn.\n   * @type {ol.Feature}\n   * @api stable\n   */\n  this.feature = feature;\n\n};\nol.inherits(ol.interaction.Draw.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.interaction.Draw.EventType = {\n  /**\n   * Triggered upon feature draw start\n   * @event ol.interaction.Draw.Event#drawstart\n   * @api stable\n   */\n  DRAWSTART: 'drawstart',\n  /**\n   * Triggered upon feature draw end\n   * @event ol.interaction.Draw.Event#drawend\n   * @api stable\n   */\n  DRAWEND: 'drawend'\n};\n\ngoog.provide('ol.interaction.Extent');\n\ngoog.require('ol');\ngoog.require('ol.Feature');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.MapBrowserPointerEvent');\ngoog.require('ol.coordinate');\ngoog.require('ol.events.Event');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.interaction.Pointer');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.source.Vector');\ngoog.require('ol.style.Style');\n\n\n/**\n * @classdesc\n * Allows the user to draw a vector box by clicking and dragging on the map.\n * Once drawn, the vector box can be modified by dragging its vertices or edges.\n * This interaction is only supported for mouse devices.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @fires ol.interaction.Extent.Event\n * @param {olx.interaction.ExtentOptions=} opt_options Options.\n * @api\n */\nol.interaction.Extent = function(opt_options) {\n\n  /**\n   * Extent of the drawn box\n   * @type {ol.Extent}\n   * @private\n   */\n  this.extent_ = null;\n\n  /**\n   * Handler for pointer move events\n   * @type {function (ol.Coordinate): ol.Extent|null}\n   * @private\n   */\n  this.pointerHandler_ = null;\n\n  /**\n   * Pixel threshold to snap to extent\n   * @type {number}\n   * @private\n   */\n  this.pixelTolerance_ = 10;\n\n  /**\n   * Is the pointer snapped to an extent vertex\n   * @type {boolean}\n   * @private\n   */\n  this.snappedToVertex_ = false;\n\n  /**\n   * Feature for displaying the visible extent\n   * @type {ol.Feature}\n   * @private\n   */\n  this.extentFeature_ = null;\n\n  /**\n   * Feature for displaying the visible pointer\n   * @type {ol.Feature}\n   * @private\n   */\n  this.vertexFeature_ = null;\n\n  if (!opt_options) {\n    opt_options = {};\n  }\n\n  if (opt_options.extent) {\n    this.setExtent(opt_options.extent);\n  }\n\n  /* Inherit ol.interaction.Pointer */\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.Extent.handleDownEvent_,\n    handleDragEvent: ol.interaction.Extent.handleDragEvent_,\n    handleEvent: ol.interaction.Extent.handleEvent_,\n    handleUpEvent: ol.interaction.Extent.handleUpEvent_\n  });\n\n  /**\n   * Layer for the extentFeature\n   * @type {ol.layer.Vector}\n   * @private\n   */\n  this.extentOverlay_ = new ol.layer.Vector({\n    source: new ol.source.Vector({\n      useSpatialIndex: false,\n      wrapX: !!opt_options.wrapX\n    }),\n    style: opt_options.boxStyle ? opt_options.boxStyle : ol.interaction.Extent.getDefaultExtentStyleFunction_(),\n    updateWhileAnimating: true,\n    updateWhileInteracting: true\n  });\n\n  /**\n   * Layer for the vertexFeature\n   * @type {ol.layer.Vector}\n   * @private\n   */\n  this.vertexOverlay_ = new ol.layer.Vector({\n    source: new ol.source.Vector({\n      useSpatialIndex: false,\n      wrapX: !!opt_options.wrapX\n    }),\n    style: opt_options.pointerStyle ? opt_options.pointerStyle : ol.interaction.Extent.getDefaultPointerStyleFunction_(),\n    updateWhileAnimating: true,\n    updateWhileInteracting: true\n  });\n};\n\nol.inherits(ol.interaction.Extent, ol.interaction.Pointer);\n\n/**\n * @param {ol.MapBrowserEvent} mapBrowserEvent Event.\n * @return {boolean} Propagate event?\n * @this {ol.interaction.Extent}\n * @private\n */\nol.interaction.Extent.handleEvent_ = function(mapBrowserEvent) {\n  if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {\n    return true;\n  }\n  //display pointer (if not dragging)\n  if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE && !this.handlingDownUpSequence) {\n    this.handlePointerMove_(mapBrowserEvent);\n  }\n  //call pointer to determine up/down/drag\n  ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent);\n  //return false to stop propagation\n  return false;\n};\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Event handled?\n * @this {ol.interaction.Extent}\n * @private\n */\nol.interaction.Extent.handleDownEvent_ = function(mapBrowserEvent) {\n  var pixel = mapBrowserEvent.pixel;\n  var map = mapBrowserEvent.map;\n\n  var extent = this.getExtent();\n  var vertex = this.snapToVertex_(pixel, map);\n\n  //find the extent corner opposite the passed corner\n  var getOpposingPoint = function(point) {\n    var x_ = null;\n    var y_ = null;\n    if (point[0] == extent[0]) {\n      x_ = extent[2];\n    } else if (point[0] == extent[2]) {\n      x_ = extent[0];\n    }\n    if (point[1] == extent[1]) {\n      y_ = extent[3];\n    } else if (point[1] == extent[3]) {\n      y_ = extent[1];\n    }\n    if (x_ !== null && y_ !== null) {\n      return [x_, y_];\n    }\n    return null;\n  };\n  if (vertex && extent) {\n    var x = (vertex[0] == extent[0] || vertex[0] == extent[2]) ? vertex[0] : null;\n    var y = (vertex[1] == extent[1] || vertex[1] == extent[3]) ? vertex[1] : null;\n\n    //snap to point\n    if (x !== null && y !== null) {\n      this.pointerHandler_ = ol.interaction.Extent.getPointHandler_(getOpposingPoint(vertex));\n    //snap to edge\n    } else if (x !== null) {\n      this.pointerHandler_ = ol.interaction.Extent.getEdgeHandler_(\n        getOpposingPoint([x, extent[1]]),\n        getOpposingPoint([x, extent[3]])\n      );\n    } else if (y !== null) {\n      this.pointerHandler_ = ol.interaction.Extent.getEdgeHandler_(\n        getOpposingPoint([extent[0], y]),\n        getOpposingPoint([extent[2], y])\n      );\n    }\n  //no snap - new bbox\n  } else {\n    vertex = map.getCoordinateFromPixel(pixel);\n    this.setExtent([vertex[0], vertex[1], vertex[0], vertex[1]]);\n    this.pointerHandler_ = ol.interaction.Extent.getPointHandler_(vertex);\n  }\n  return true; //event handled; start downup sequence\n};\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Event handled?\n * @this {ol.interaction.Extent}\n * @private\n */\nol.interaction.Extent.handleDragEvent_ = function(mapBrowserEvent) {\n  if (this.pointerHandler_) {\n    var pixelCoordinate = mapBrowserEvent.coordinate;\n    this.setExtent(this.pointerHandler_(pixelCoordinate));\n    this.createOrUpdatePointerFeature_(pixelCoordinate);\n  }\n  return true;\n};\n\n/**\n * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.Extent}\n * @private\n */\nol.interaction.Extent.handleUpEvent_ = function(mapBrowserEvent) {\n  this.pointerHandler_ = null;\n  //If bbox is zero area, set to null;\n  var extent = this.getExtent();\n  if (!extent || ol.extent.getArea(extent) === 0) {\n    this.setExtent(null);\n  }\n  return false; //Stop handling downup sequence\n};\n\n/**\n * Returns the default style for the drawn bbox\n *\n * @return {ol.StyleFunction} Default Extent style\n * @private\n */\nol.interaction.Extent.getDefaultExtentStyleFunction_ = function() {\n  var style = ol.style.Style.createDefaultEditing();\n  return function(feature, resolution) {\n    return style[ol.geom.GeometryType.POLYGON];\n  };\n};\n\n/**\n * Returns the default style for the pointer\n *\n * @return {ol.StyleFunction} Default pointer style\n * @private\n */\nol.interaction.Extent.getDefaultPointerStyleFunction_ = function() {\n  var style = ol.style.Style.createDefaultEditing();\n  return function(feature, resolution) {\n    return style[ol.geom.GeometryType.POINT];\n  };\n};\n\n/**\n * @param {ol.Coordinate} fixedPoint corner that will be unchanged in the new extent\n * @returns {function (ol.Coordinate): ol.Extent} event handler\n * @private\n */\nol.interaction.Extent.getPointHandler_ = function(fixedPoint) {\n  return function(point) {\n    return ol.extent.boundingExtent([fixedPoint, point]);\n  };\n};\n\n/**\n * @param {ol.Coordinate} fixedP1 first corner that will be unchanged in the new extent\n * @param {ol.Coordinate} fixedP2 second corner that will be unchanged in the new extent\n * @returns {function (ol.Coordinate): ol.Extent|null} event handler\n * @private\n */\nol.interaction.Extent.getEdgeHandler_ = function(fixedP1, fixedP2) {\n  if (fixedP1[0] == fixedP2[0]) {\n    return function(point) {\n      return ol.extent.boundingExtent([fixedP1, [point[0], fixedP2[1]]]);\n    };\n  } else if (fixedP1[1] == fixedP2[1]) {\n    return function(point) {\n      return ol.extent.boundingExtent([fixedP1, [fixedP2[0], point[1]]]);\n    };\n  } else {\n    return null;\n  }\n};\n\n/**\n * @param {ol.Extent} extent extent\n * @returns {Array<Array<ol.Coordinate>>} extent line segments\n * @private\n */\nol.interaction.Extent.getSegments_ = function(extent) {\n  return [\n    [[extent[0], extent[1]], [extent[0], extent[3]]],\n    [[extent[0], extent[3]], [extent[2], extent[3]]],\n    [[extent[2], extent[3]], [extent[2], extent[1]]],\n    [[extent[2], extent[1]], [extent[0], extent[1]]]\n  ];\n};\n\n/**\n * @param {ol.Pixel} pixel cursor location\n * @param {ol.Map} map map\n * @returns {ol.Coordinate|null} snapped vertex on extent\n * @private\n */\nol.interaction.Extent.prototype.snapToVertex_ = function(pixel, map) {\n  var pixelCoordinate = map.getCoordinateFromPixel(pixel);\n  var sortByDistance = function(a, b) {\n    return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a) -\n        ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b);\n  };\n  var extent = this.getExtent();\n  if (extent) {\n    //convert extents to line segments and find the segment closest to pixelCoordinate\n    var segments = ol.interaction.Extent.getSegments_(extent);\n    segments.sort(sortByDistance);\n    var closestSegment = segments[0];\n\n    var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,\n        closestSegment));\n    var vertexPixel = map.getPixelFromCoordinate(vertex);\n\n    //if the distance is within tolerance, snap to the segment\n    if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <=\n        this.pixelTolerance_) {\n\n      //test if we should further snap to a vertex\n      var pixel1 = map.getPixelFromCoordinate(closestSegment[0]);\n      var pixel2 = map.getPixelFromCoordinate(closestSegment[1]);\n      var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);\n      var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);\n      var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));\n      this.snappedToVertex_ = dist <= this.pixelTolerance_;\n      if (this.snappedToVertex_) {\n        vertex = squaredDist1 > squaredDist2 ?\n            closestSegment[1] : closestSegment[0];\n      }\n      return vertex;\n    }\n  }\n  return null;\n};\n\n/**\n * @param {ol.MapBrowserEvent} mapBrowserEvent pointer move event\n * @private\n */\nol.interaction.Extent.prototype.handlePointerMove_ = function(mapBrowserEvent) {\n  var pixel = mapBrowserEvent.pixel;\n  var map = mapBrowserEvent.map;\n\n  var vertex = this.snapToVertex_(pixel, map);\n  if (!vertex) {\n    vertex = map.getCoordinateFromPixel(pixel);\n  }\n  this.createOrUpdatePointerFeature_(vertex);\n};\n\n/**\n * @param {ol.Extent} extent extent\n * @returns {ol.Feature} extent as featrue\n * @private\n */\nol.interaction.Extent.prototype.createOrUpdateExtentFeature_ = function(extent) {\n  var extentFeature = this.extentFeature_;\n\n  if (!extentFeature) {\n    if (!extent) {\n      extentFeature = new ol.Feature({});\n    } else {\n      extentFeature = new ol.Feature(ol.geom.Polygon.fromExtent(extent));\n    }\n    this.extentFeature_ = extentFeature;\n    this.extentOverlay_.getSource().addFeature(extentFeature);\n  } else {\n    if (!extent) {\n      extentFeature.setGeometry(undefined);\n    } else {\n      extentFeature.setGeometry(ol.geom.Polygon.fromExtent(extent));\n    }\n  }\n  return extentFeature;\n};\n\n\n/**\n * @param {ol.Coordinate} vertex location of feature\n * @returns {ol.Feature} vertex as feature\n * @private\n */\nol.interaction.Extent.prototype.createOrUpdatePointerFeature_ = function(vertex) {\n  var vertexFeature = this.vertexFeature_;\n  if (!vertexFeature) {\n    vertexFeature = new ol.Feature(new ol.geom.Point(vertex));\n    this.vertexFeature_ = vertexFeature;\n    this.vertexOverlay_.getSource().addFeature(vertexFeature);\n  } else {\n    var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());\n    geometry.setCoordinates(vertex);\n  }\n  return vertexFeature;\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.Extent.prototype.setMap = function(map) {\n  this.extentOverlay_.setMap(map);\n  this.vertexOverlay_.setMap(map);\n  ol.interaction.Pointer.prototype.setMap.call(this, map);\n};\n\n/**\n * Returns the current drawn extent in the view projection\n *\n * @return {ol.Extent} Drawn extent in the view projection.\n * @api\n */\nol.interaction.Extent.prototype.getExtent = function() {\n  return this.extent_;\n};\n\n/**\n * Manually sets the drawn extent, using the view projection.\n *\n * @param {ol.Extent} extent Extent\n * @api\n */\nol.interaction.Extent.prototype.setExtent = function(extent) {\n  //Null extent means no bbox\n  this.extent_ = extent ? extent : null;\n  this.createOrUpdateExtentFeature_(extent);\n  this.dispatchEvent(new ol.interaction.Extent.Event(this.extent_));\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.interaction.Extent} instances are instances of\n * this type.\n *\n * @constructor\n * @param {ol.Extent} extent the new extent\n * @extends {ol.events.Event}\n */\nol.interaction.Extent.Event = function(extent) {\n  ol.events.Event.call(this, ol.interaction.Extent.EventType.EXTENTCHANGED);\n\n  /**\n   * The current extent.\n   * @type {ol.Extent}\n   * @api\n   */\n  this.extent_ = extent;\n};\nol.inherits(ol.interaction.Extent.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.interaction.Extent.EventType = {\n  /**\n   * Triggered after the extent is changed\n   * @event ol.interaction.Extent.Event\n   * @api\n   */\n  EXTENTCHANGED: 'extentchanged'\n};\n\ngoog.provide('ol.interaction.Modify');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.Feature');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.MapBrowserPointerEvent');\ngoog.require('ol.View');\ngoog.require('ol.array');\ngoog.require('ol.coordinate');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.EventType');\ngoog.require('ol.events.condition');\ngoog.require('ol.extent');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.geom.Point');\ngoog.require('ol.interaction.Pointer');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.source.Vector');\ngoog.require('ol.structs.RBush');\ngoog.require('ol.style.Style');\n\n\n/**\n * @classdesc\n * Interaction for modifying feature geometries.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @param {olx.interaction.ModifyOptions} options Options.\n * @fires ol.interaction.Modify.Event\n * @api\n */\nol.interaction.Modify = function(options) {\n\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.Modify.handleDownEvent_,\n    handleDragEvent: ol.interaction.Modify.handleDragEvent_,\n    handleEvent: ol.interaction.Modify.handleEvent,\n    handleUpEvent: ol.interaction.Modify.handleUpEvent_\n  });\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ?\n      options.condition : ol.events.condition.primaryAction;\n\n\n  /**\n   * @private\n   * @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.\n   * @return {boolean} Combined condition result.\n   */\n  this.defaultDeleteCondition_ = function(mapBrowserEvent) {\n    return ol.events.condition.noModifierKeys(mapBrowserEvent) &&\n      ol.events.condition.singleClick(mapBrowserEvent);\n  };\n\n  /**\n   * @type {ol.EventsConditionType}\n   * @private\n   */\n  this.deleteCondition_ = options.deleteCondition ?\n      options.deleteCondition : this.defaultDeleteCondition_;\n\n  /**\n   * Editing vertex.\n   * @type {ol.Feature}\n   * @private\n   */\n  this.vertexFeature_ = null;\n\n  /**\n   * Segments intersecting {@link this.vertexFeature_} by segment uid.\n   * @type {Object.<string, boolean>}\n   * @private\n   */\n  this.vertexSegments_ = null;\n\n  /**\n   * @type {ol.Pixel}\n   * @private\n   */\n  this.lastPixel_ = [0, 0];\n\n  /**\n   * Tracks if the next `singleclick` event should be ignored to prevent\n   * accidental deletion right after vertex creation.\n   * @type {boolean}\n   * @private\n   */\n  this.ignoreNextSingleClick_ = false;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.modified_ = false;\n\n  /**\n   * Segment RTree for each layer\n   * @type {ol.structs.RBush.<ol.ModifySegmentDataType>}\n   * @private\n   */\n  this.rBush_ = new ol.structs.RBush();\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.pixelTolerance_ = options.pixelTolerance !== undefined ?\n      options.pixelTolerance : 10;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.snappedToVertex_ = false;\n\n  /**\n   * Indicate whether the interaction is currently changing a feature's\n   * coordinates.\n   * @type {boolean}\n   * @private\n   */\n  this.changingFeature_ = false;\n\n  /**\n   * @type {Array}\n   * @private\n   */\n  this.dragSegments_ = [];\n\n  /**\n   * Draw overlay where sketch features are drawn.\n   * @type {ol.layer.Vector}\n   * @private\n   */\n  this.overlay_ = new ol.layer.Vector({\n    source: new ol.source.Vector({\n      useSpatialIndex: false,\n      wrapX: !!options.wrapX\n    }),\n    style: options.style ? options.style :\n        ol.interaction.Modify.getDefaultStyleFunction(),\n    updateWhileAnimating: true,\n    updateWhileInteracting: true\n  });\n\n  /**\n  * @const\n  * @private\n  * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>}\n  */\n  this.SEGMENT_WRITERS_ = {\n    'Point': this.writePointGeometry_,\n    'LineString': this.writeLineStringGeometry_,\n    'LinearRing': this.writeLineStringGeometry_,\n    'Polygon': this.writePolygonGeometry_,\n    'MultiPoint': this.writeMultiPointGeometry_,\n    'MultiLineString': this.writeMultiLineStringGeometry_,\n    'MultiPolygon': this.writeMultiPolygonGeometry_,\n    'GeometryCollection': this.writeGeometryCollectionGeometry_\n  };\n\n  /**\n   * @type {ol.Collection.<ol.Feature>}\n   * @private\n   */\n  this.features_ = options.features;\n\n  this.features_.forEach(this.addFeature_, this);\n  ol.events.listen(this.features_, ol.Collection.EventType.ADD,\n      this.handleFeatureAdd_, this);\n  ol.events.listen(this.features_, ol.Collection.EventType.REMOVE,\n      this.handleFeatureRemove_, this);\n\n  /**\n   * @type {ol.MapBrowserPointerEvent}\n   * @private\n   */\n  this.lastPointerEvent_ = null;\n\n};\nol.inherits(ol.interaction.Modify, ol.interaction.Pointer);\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.interaction.Modify.prototype.addFeature_ = function(feature) {\n  var geometry = feature.getGeometry();\n  if (geometry && geometry.getType() in this.SEGMENT_WRITERS_) {\n    this.SEGMENT_WRITERS_[geometry.getType()].call(this, feature, geometry);\n  }\n  var map = this.getMap();\n  if (map && map.isRendered()) {\n    this.handlePointerAtPixel_(this.lastPixel_, map);\n  }\n  ol.events.listen(feature, ol.events.EventType.CHANGE,\n      this.handleFeatureChange_, this);\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} evt Map browser event\n * @private\n */\nol.interaction.Modify.prototype.willModifyFeatures_ = function(evt) {\n  if (!this.modified_) {\n    this.modified_ = true;\n    this.dispatchEvent(new ol.interaction.Modify.Event(\n        ol.interaction.Modify.EventType.MODIFYSTART, this.features_, evt));\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.interaction.Modify.prototype.removeFeature_ = function(feature) {\n  this.removeFeatureSegmentData_(feature);\n  // Remove the vertex feature if the collection of canditate features\n  // is empty.\n  if (this.vertexFeature_ && this.features_.getLength() === 0) {\n    this.overlay_.getSource().removeFeature(this.vertexFeature_);\n    this.vertexFeature_ = null;\n  }\n  ol.events.unlisten(feature, ol.events.EventType.CHANGE,\n      this.handleFeatureChange_, this);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.interaction.Modify.prototype.removeFeatureSegmentData_ = function(feature) {\n  var rBush = this.rBush_;\n  var /** @type {Array.<ol.ModifySegmentDataType>} */ nodesToRemove = [];\n  rBush.forEach(\n      /**\n       * @param {ol.ModifySegmentDataType} node RTree node.\n       */\n      function(node) {\n        if (feature === node.feature) {\n          nodesToRemove.push(node);\n        }\n      });\n  for (var i = nodesToRemove.length - 1; i >= 0; --i) {\n    rBush.remove(nodesToRemove[i]);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.Modify.prototype.setActive = function(active) {\n  if (this.vertexFeature_ && !active) {\n    this.overlay_.getSource().removeFeature(this.vertexFeature_);\n    this.vertexFeature_ = null;\n  }\n  ol.interaction.Pointer.prototype.setActive.call(this, active);\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.Modify.prototype.setMap = function(map) {\n  this.overlay_.setMap(map);\n  ol.interaction.Pointer.prototype.setMap.call(this, map);\n};\n\n\n/**\n * @param {ol.Collection.Event} evt Event.\n * @private\n */\nol.interaction.Modify.prototype.handleFeatureAdd_ = function(evt) {\n  this.addFeature_(/** @type {ol.Feature} */ (evt.element));\n};\n\n\n/**\n * @param {ol.events.Event} evt Event.\n * @private\n */\nol.interaction.Modify.prototype.handleFeatureChange_ = function(evt) {\n  if (!this.changingFeature_) {\n    var feature = /** @type {ol.Feature} */ (evt.target);\n    this.removeFeature_(feature);\n    this.addFeature_(feature);\n  }\n};\n\n\n/**\n * @param {ol.Collection.Event} evt Event.\n * @private\n */\nol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) {\n  var feature = /** @type {ol.Feature} */ (evt.element);\n  this.removeFeature_(feature);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.Point} geometry Geometry.\n * @private\n */\nol.interaction.Modify.prototype.writePointGeometry_ = function(feature, geometry) {\n  var coordinates = geometry.getCoordinates();\n  var segmentData = /** @type {ol.ModifySegmentDataType} */ ({\n    feature: feature,\n    geometry: geometry,\n    segment: [coordinates, coordinates]\n  });\n  this.rBush_.insert(geometry.getExtent(), segmentData);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.MultiPoint} geometry Geometry.\n * @private\n */\nol.interaction.Modify.prototype.writeMultiPointGeometry_ = function(feature, geometry) {\n  var points = geometry.getCoordinates();\n  var coordinates, i, ii, segmentData;\n  for (i = 0, ii = points.length; i < ii; ++i) {\n    coordinates = points[i];\n    segmentData = /** @type {ol.ModifySegmentDataType} */ ({\n      feature: feature,\n      geometry: geometry,\n      depth: [i],\n      index: i,\n      segment: [coordinates, coordinates]\n    });\n    this.rBush_.insert(geometry.getExtent(), segmentData);\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.LineString} geometry Geometry.\n * @private\n */\nol.interaction.Modify.prototype.writeLineStringGeometry_ = function(feature, geometry) {\n  var coordinates = geometry.getCoordinates();\n  var i, ii, segment, segmentData;\n  for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n    segment = coordinates.slice(i, i + 2);\n    segmentData = /** @type {ol.ModifySegmentDataType} */ ({\n      feature: feature,\n      geometry: geometry,\n      index: i,\n      segment: segment\n    });\n    this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.MultiLineString} geometry Geometry.\n * @private\n */\nol.interaction.Modify.prototype.writeMultiLineStringGeometry_ = function(feature, geometry) {\n  var lines = geometry.getCoordinates();\n  var coordinates, i, ii, j, jj, segment, segmentData;\n  for (j = 0, jj = lines.length; j < jj; ++j) {\n    coordinates = lines[j];\n    for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n      segment = coordinates.slice(i, i + 2);\n      segmentData = /** @type {ol.ModifySegmentDataType} */ ({\n        feature: feature,\n        geometry: geometry,\n        depth: [j],\n        index: i,\n        segment: segment\n      });\n      this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n    }\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.Polygon} geometry Geometry.\n * @private\n */\nol.interaction.Modify.prototype.writePolygonGeometry_ = function(feature, geometry) {\n  var rings = geometry.getCoordinates();\n  var coordinates, i, ii, j, jj, segment, segmentData;\n  for (j = 0, jj = rings.length; j < jj; ++j) {\n    coordinates = rings[j];\n    for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n      segment = coordinates.slice(i, i + 2);\n      segmentData = /** @type {ol.ModifySegmentDataType} */ ({\n        feature: feature,\n        geometry: geometry,\n        depth: [j],\n        index: i,\n        segment: segment\n      });\n      this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n    }\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.MultiPolygon} geometry Geometry.\n * @private\n */\nol.interaction.Modify.prototype.writeMultiPolygonGeometry_ = function(feature, geometry) {\n  var polygons = geometry.getCoordinates();\n  var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData;\n  for (k = 0, kk = polygons.length; k < kk; ++k) {\n    rings = polygons[k];\n    for (j = 0, jj = rings.length; j < jj; ++j) {\n      coordinates = rings[j];\n      for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n        segment = coordinates.slice(i, i + 2);\n        segmentData = /** @type {ol.ModifySegmentDataType} */ ({\n          feature: feature,\n          geometry: geometry,\n          depth: [j, k],\n          index: i,\n          segment: segment\n        });\n        this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n      }\n    }\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.GeometryCollection} geometry Geometry.\n * @private\n */\nol.interaction.Modify.prototype.writeGeometryCollectionGeometry_ = function(feature, geometry) {\n  var i, geometries = geometry.getGeometriesArray();\n  for (i = 0; i < geometries.length; ++i) {\n    this.SEGMENT_WRITERS_[geometries[i].getType()].call(\n        this, feature, geometries[i]);\n  }\n};\n\n\n/**\n * @param {ol.Coordinate} coordinates Coordinates.\n * @return {ol.Feature} Vertex feature.\n * @private\n */\nol.interaction.Modify.prototype.createOrUpdateVertexFeature_ = function(coordinates) {\n  var vertexFeature = this.vertexFeature_;\n  if (!vertexFeature) {\n    vertexFeature = new ol.Feature(new ol.geom.Point(coordinates));\n    this.vertexFeature_ = vertexFeature;\n    this.overlay_.getSource().addFeature(vertexFeature);\n  } else {\n    var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());\n    geometry.setCoordinates(coordinates);\n  }\n  return vertexFeature;\n};\n\n\n/**\n * @param {ol.ModifySegmentDataType} a The first segment data.\n * @param {ol.ModifySegmentDataType} b The second segment data.\n * @return {number} The difference in indexes.\n * @private\n */\nol.interaction.Modify.compareIndexes_ = function(a, b) {\n  return a.index - b.index;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} evt Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.Modify}\n * @private\n */\nol.interaction.Modify.handleDownEvent_ = function(evt) {\n  if (!this.condition_(evt)) {\n    return false;\n  }\n  this.handlePointerAtPixel_(evt.pixel, evt.map);\n  this.dragSegments_.length = 0;\n  this.modified_ = false;\n  var vertexFeature = this.vertexFeature_;\n  if (vertexFeature) {\n    var insertVertices = [];\n    var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());\n    var vertex = geometry.getCoordinates();\n    var vertexExtent = ol.extent.boundingExtent([vertex]);\n    var segmentDataMatches = this.rBush_.getInExtent(vertexExtent);\n    var componentSegments = {};\n    segmentDataMatches.sort(ol.interaction.Modify.compareIndexes_);\n    for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) {\n      var segmentDataMatch = segmentDataMatches[i];\n      var segment = segmentDataMatch.segment;\n      var uid = ol.getUid(segmentDataMatch.feature);\n      var depth = segmentDataMatch.depth;\n      if (depth) {\n        uid += '-' + depth.join('-'); // separate feature components\n      }\n      if (!componentSegments[uid]) {\n        componentSegments[uid] = new Array(2);\n      }\n      if (ol.coordinate.equals(segment[0], vertex) &&\n          !componentSegments[uid][0]) {\n        this.dragSegments_.push([segmentDataMatch, 0]);\n        componentSegments[uid][0] = segmentDataMatch;\n      } else if (ol.coordinate.equals(segment[1], vertex) &&\n          !componentSegments[uid][1]) {\n\n        // prevent dragging closed linestrings by the connecting node\n        if ((segmentDataMatch.geometry.getType() ===\n            ol.geom.GeometryType.LINE_STRING ||\n            segmentDataMatch.geometry.getType() ===\n            ol.geom.GeometryType.MULTI_LINE_STRING) &&\n            componentSegments[uid][0] &&\n            componentSegments[uid][0].index === 0) {\n          continue;\n        }\n\n        this.dragSegments_.push([segmentDataMatch, 1]);\n        componentSegments[uid][1] = segmentDataMatch;\n      } else if (ol.getUid(segment) in this.vertexSegments_ &&\n          (!componentSegments[uid][0] && !componentSegments[uid][1])) {\n        insertVertices.push([segmentDataMatch, vertex]);\n      }\n    }\n    if (insertVertices.length) {\n      this.willModifyFeatures_(evt);\n    }\n    for (var j = insertVertices.length - 1; j >= 0; --j) {\n      this.insertVertex_.apply(this, insertVertices[j]);\n    }\n  }\n  return !!this.vertexFeature_;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} evt Event.\n * @this {ol.interaction.Modify}\n * @private\n */\nol.interaction.Modify.handleDragEvent_ = function(evt) {\n  this.ignoreNextSingleClick_ = false;\n  this.willModifyFeatures_(evt);\n\n  var vertex = evt.coordinate;\n  for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) {\n    var dragSegment = this.dragSegments_[i];\n    var segmentData = dragSegment[0];\n    var depth = segmentData.depth;\n    var geometry = segmentData.geometry;\n    var coordinates = geometry.getCoordinates();\n    var segment = segmentData.segment;\n    var index = dragSegment[1];\n\n    while (vertex.length < geometry.getStride()) {\n      vertex.push(segment[index][vertex.length]);\n    }\n\n    switch (geometry.getType()) {\n      case ol.geom.GeometryType.POINT:\n        coordinates = vertex;\n        segment[0] = segment[1] = vertex;\n        break;\n      case ol.geom.GeometryType.MULTI_POINT:\n        coordinates[segmentData.index] = vertex;\n        segment[0] = segment[1] = vertex;\n        break;\n      case ol.geom.GeometryType.LINE_STRING:\n        coordinates[segmentData.index + index] = vertex;\n        segment[index] = vertex;\n        break;\n      case ol.geom.GeometryType.MULTI_LINE_STRING:\n        coordinates[depth[0]][segmentData.index + index] = vertex;\n        segment[index] = vertex;\n        break;\n      case ol.geom.GeometryType.POLYGON:\n        coordinates[depth[0]][segmentData.index + index] = vertex;\n        segment[index] = vertex;\n        break;\n      case ol.geom.GeometryType.MULTI_POLYGON:\n        coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;\n        segment[index] = vertex;\n        break;\n      default:\n        // pass\n    }\n\n    this.setGeometryCoordinates_(geometry, coordinates);\n  }\n  this.createOrUpdateVertexFeature_(vertex);\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} evt Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.Modify}\n * @private\n */\nol.interaction.Modify.handleUpEvent_ = function(evt) {\n  var segmentData;\n  for (var i = this.dragSegments_.length - 1; i >= 0; --i) {\n    segmentData = this.dragSegments_[i][0];\n    this.rBush_.update(ol.extent.boundingExtent(segmentData.segment),\n        segmentData);\n  }\n  if (this.modified_) {\n    this.dispatchEvent(new ol.interaction.Modify.Event(\n        ol.interaction.Modify.EventType.MODIFYEND, this.features_, evt));\n    this.modified_ = false;\n  }\n  return false;\n};\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} and may modify the\n * geometry.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.Modify}\n * @api\n */\nol.interaction.Modify.handleEvent = function(mapBrowserEvent) {\n  if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {\n    return true;\n  }\n  this.lastPointerEvent_ = mapBrowserEvent;\n\n  var handled;\n  if (!mapBrowserEvent.map.getView().getHints()[ol.View.Hint.INTERACTING] &&\n      mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE &&\n      !this.handlingDownUpSequence) {\n    this.handlePointerMove_(mapBrowserEvent);\n  }\n  if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) {\n    if (mapBrowserEvent.type != ol.MapBrowserEvent.EventType.SINGLECLICK ||\n        !this.ignoreNextSingleClick_) {\n      handled = this.removePoint();\n    } else {\n      handled = true;\n    }\n  }\n\n  if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK) {\n    this.ignoreNextSingleClick_ = false;\n  }\n\n  return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) &&\n      !handled;\n};\n\n\n/**\n * @param {ol.MapBrowserEvent} evt Event.\n * @private\n */\nol.interaction.Modify.prototype.handlePointerMove_ = function(evt) {\n  this.lastPixel_ = evt.pixel;\n  this.handlePointerAtPixel_(evt.pixel, evt.map);\n};\n\n\n/**\n * @param {ol.Pixel} pixel Pixel\n * @param {ol.Map} map Map.\n * @private\n */\nol.interaction.Modify.prototype.handlePointerAtPixel_ = function(pixel, map) {\n  var pixelCoordinate = map.getCoordinateFromPixel(pixel);\n  var sortByDistance = function(a, b) {\n    return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a.segment) -\n        ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b.segment);\n  };\n\n  var box = ol.extent.buffer(\n      ol.extent.createOrUpdateFromCoordinate(pixelCoordinate),\n      map.getView().getResolution() * this.pixelTolerance_);\n\n  var rBush = this.rBush_;\n  var nodes = rBush.getInExtent(box);\n  if (nodes.length > 0) {\n    nodes.sort(sortByDistance);\n    var node = nodes[0];\n    var closestSegment = node.segment;\n    var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,\n        closestSegment));\n    var vertexPixel = map.getPixelFromCoordinate(vertex);\n    if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <=\n        this.pixelTolerance_) {\n      var pixel1 = map.getPixelFromCoordinate(closestSegment[0]);\n      var pixel2 = map.getPixelFromCoordinate(closestSegment[1]);\n      var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);\n      var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);\n      var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));\n      this.snappedToVertex_ = dist <= this.pixelTolerance_;\n      if (this.snappedToVertex_) {\n        vertex = squaredDist1 > squaredDist2 ?\n            closestSegment[1] : closestSegment[0];\n      }\n      this.createOrUpdateVertexFeature_(vertex);\n      var vertexSegments = {};\n      vertexSegments[ol.getUid(closestSegment)] = true;\n      var segment;\n      for (var i = 1, ii = nodes.length; i < ii; ++i) {\n        segment = nodes[i].segment;\n        if ((ol.coordinate.equals(closestSegment[0], segment[0]) &&\n            ol.coordinate.equals(closestSegment[1], segment[1]) ||\n            (ol.coordinate.equals(closestSegment[0], segment[1]) &&\n            ol.coordinate.equals(closestSegment[1], segment[0])))) {\n          vertexSegments[ol.getUid(segment)] = true;\n        } else {\n          break;\n        }\n      }\n      this.vertexSegments_ = vertexSegments;\n      return;\n    }\n  }\n  if (this.vertexFeature_) {\n    this.overlay_.getSource().removeFeature(this.vertexFeature_);\n    this.vertexFeature_ = null;\n  }\n};\n\n\n/**\n * @param {ol.ModifySegmentDataType} segmentData Segment data.\n * @param {ol.Coordinate} vertex Vertex.\n * @private\n */\nol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) {\n  var segment = segmentData.segment;\n  var feature = segmentData.feature;\n  var geometry = segmentData.geometry;\n  var depth = segmentData.depth;\n  var index = /** @type {number} */ (segmentData.index);\n  var coordinates;\n\n  while (vertex.length < geometry.getStride()) {\n    vertex.push(0);\n  }\n\n  switch (geometry.getType()) {\n    case ol.geom.GeometryType.MULTI_LINE_STRING:\n      coordinates = geometry.getCoordinates();\n      coordinates[depth[0]].splice(index + 1, 0, vertex);\n      break;\n    case ol.geom.GeometryType.POLYGON:\n      coordinates = geometry.getCoordinates();\n      coordinates[depth[0]].splice(index + 1, 0, vertex);\n      break;\n    case ol.geom.GeometryType.MULTI_POLYGON:\n      coordinates = geometry.getCoordinates();\n      coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex);\n      break;\n    case ol.geom.GeometryType.LINE_STRING:\n      coordinates = geometry.getCoordinates();\n      coordinates.splice(index + 1, 0, vertex);\n      break;\n    default:\n      return;\n  }\n\n  this.setGeometryCoordinates_(geometry, coordinates);\n  var rTree = this.rBush_;\n  rTree.remove(segmentData);\n  this.updateSegmentIndices_(geometry, index, depth, 1);\n  var newSegmentData = /** @type {ol.ModifySegmentDataType} */ ({\n    segment: [segment[0], vertex],\n    feature: feature,\n    geometry: geometry,\n    depth: depth,\n    index: index\n  });\n  rTree.insert(ol.extent.boundingExtent(newSegmentData.segment),\n      newSegmentData);\n  this.dragSegments_.push([newSegmentData, 1]);\n\n  var newSegmentData2 = /** @type {ol.ModifySegmentDataType} */ ({\n    segment: [vertex, segment[1]],\n    feature: feature,\n    geometry: geometry,\n    depth: depth,\n    index: index + 1\n  });\n  rTree.insert(ol.extent.boundingExtent(newSegmentData2.segment),\n      newSegmentData2);\n  this.dragSegments_.push([newSegmentData2, 0]);\n  this.ignoreNextSingleClick_ = true;\n};\n\n/**\n * Removes the vertex currently being pointed.\n * @return {boolean} True when a vertex was removed.\n * @api\n */\nol.interaction.Modify.prototype.removePoint = function() {\n  if (this.lastPointerEvent_ && this.lastPointerEvent_.type != ol.MapBrowserEvent.EventType.POINTERDRAG) {\n    var evt = this.lastPointerEvent_;\n    this.willModifyFeatures_(evt);\n    this.removeVertex_();\n    this.dispatchEvent(new ol.interaction.Modify.Event(\n        ol.interaction.Modify.EventType.MODIFYEND, this.features_, evt));\n    this.modified_ = false;\n    return true;\n  }\n  return false;\n};\n\n/**\n * Removes a vertex from all matching features.\n * @return {boolean} True when a vertex was removed.\n * @private\n */\nol.interaction.Modify.prototype.removeVertex_ = function() {\n  var dragSegments = this.dragSegments_;\n  var segmentsByFeature = {};\n  var deleted = false;\n  var component, coordinates, dragSegment, geometry, i, index, left;\n  var newIndex, right, segmentData, uid;\n  for (i = dragSegments.length - 1; i >= 0; --i) {\n    dragSegment = dragSegments[i];\n    segmentData = dragSegment[0];\n    uid = ol.getUid(segmentData.feature);\n    if (segmentData.depth) {\n      // separate feature components\n      uid += '-' + segmentData.depth.join('-');\n    }\n    if (!(uid in segmentsByFeature)) {\n      segmentsByFeature[uid] = {};\n    }\n    if (dragSegment[1] === 0) {\n      segmentsByFeature[uid].right = segmentData;\n      segmentsByFeature[uid].index = segmentData.index;\n    } else if (dragSegment[1] == 1) {\n      segmentsByFeature[uid].left = segmentData;\n      segmentsByFeature[uid].index = segmentData.index + 1;\n    }\n\n  }\n  for (uid in segmentsByFeature) {\n    right = segmentsByFeature[uid].right;\n    left = segmentsByFeature[uid].left;\n    index = segmentsByFeature[uid].index;\n    newIndex = index - 1;\n    if (left !== undefined) {\n      segmentData = left;\n    } else {\n      segmentData = right;\n    }\n    if (newIndex < 0) {\n      newIndex = 0;\n    }\n    geometry = segmentData.geometry;\n    coordinates = geometry.getCoordinates();\n    component = coordinates;\n    deleted = false;\n    switch (geometry.getType()) {\n      case ol.geom.GeometryType.MULTI_LINE_STRING:\n        if (coordinates[segmentData.depth[0]].length > 2) {\n          coordinates[segmentData.depth[0]].splice(index, 1);\n          deleted = true;\n        }\n        break;\n      case ol.geom.GeometryType.LINE_STRING:\n        if (coordinates.length > 2) {\n          coordinates.splice(index, 1);\n          deleted = true;\n        }\n        break;\n      case ol.geom.GeometryType.MULTI_POLYGON:\n        component = component[segmentData.depth[1]];\n        /* falls through */\n      case ol.geom.GeometryType.POLYGON:\n        component = component[segmentData.depth[0]];\n        if (component.length > 4) {\n          if (index == component.length - 1) {\n            index = 0;\n          }\n          component.splice(index, 1);\n          deleted = true;\n          if (index === 0) {\n            // close the ring again\n            component.pop();\n            component.push(component[0]);\n            newIndex = component.length - 1;\n          }\n        }\n        break;\n      default:\n        // pass\n    }\n\n    if (deleted) {\n      this.setGeometryCoordinates_(geometry, coordinates);\n      var segments = [];\n      if (left !== undefined) {\n        this.rBush_.remove(left);\n        segments.push(left.segment[0]);\n      }\n      if (right !== undefined) {\n        this.rBush_.remove(right);\n        segments.push(right.segment[1]);\n      }\n      if (left !== undefined && right !== undefined) {\n        ol.DEBUG && console.assert(newIndex >= 0, 'newIndex should be larger than 0');\n\n        var newSegmentData = /** @type {ol.ModifySegmentDataType} */ ({\n          depth: segmentData.depth,\n          feature: segmentData.feature,\n          geometry: segmentData.geometry,\n          index: newIndex,\n          segment: segments\n        });\n        this.rBush_.insert(ol.extent.boundingExtent(newSegmentData.segment),\n            newSegmentData);\n      }\n      this.updateSegmentIndices_(geometry, index, segmentData.depth, -1);\n      if (this.vertexFeature_) {\n        this.overlay_.getSource().removeFeature(this.vertexFeature_);\n        this.vertexFeature_ = null;\n      }\n    }\n\n  }\n  return deleted;\n};\n\n\n/**\n * @param {ol.geom.SimpleGeometry} geometry Geometry.\n * @param {Array} coordinates Coordinates.\n * @private\n */\nol.interaction.Modify.prototype.setGeometryCoordinates_ = function(geometry, coordinates) {\n  this.changingFeature_ = true;\n  geometry.setCoordinates(coordinates);\n  this.changingFeature_ = false;\n};\n\n\n/**\n * @param {ol.geom.SimpleGeometry} geometry Geometry.\n * @param {number} index Index.\n * @param {Array.<number>|undefined} depth Depth.\n * @param {number} delta Delta (1 or -1).\n * @private\n */\nol.interaction.Modify.prototype.updateSegmentIndices_ = function(\n    geometry, index, depth, delta) {\n  this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) {\n    if (segmentDataMatch.geometry === geometry &&\n        (depth === undefined || segmentDataMatch.depth === undefined ||\n        ol.array.equals(segmentDataMatch.depth, depth)) &&\n        segmentDataMatch.index > index) {\n      segmentDataMatch.index += delta;\n    }\n  });\n};\n\n\n/**\n * @return {ol.StyleFunction} Styles.\n */\nol.interaction.Modify.getDefaultStyleFunction = function() {\n  var style = ol.style.Style.createDefaultEditing();\n  return function(feature, resolution) {\n    return style[ol.geom.GeometryType.POINT];\n  };\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.interaction.Modify} instances are instances of\n * this type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.ModifyEvent}\n * @param {ol.interaction.Modify.EventType} type Type.\n * @param {ol.Collection.<ol.Feature>} features The features modified.\n * @param {ol.MapBrowserPointerEvent} mapBrowserPointerEvent Associated\n *     {@link ol.MapBrowserPointerEvent}.\n */\nol.interaction.Modify.Event = function(type, features, mapBrowserPointerEvent) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The features being modified.\n   * @type {ol.Collection.<ol.Feature>}\n   * @api\n   */\n  this.features = features;\n\n  /**\n   * Associated {@link ol.MapBrowserEvent}.\n   * @type {ol.MapBrowserEvent}\n   * @api\n   */\n  this.mapBrowserEvent = mapBrowserPointerEvent;\n};\nol.inherits(ol.interaction.Modify.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.interaction.Modify.EventType = {\n  /**\n   * Triggered upon feature modification start\n   * @event ol.interaction.Modify.Event#modifystart\n   * @api\n   */\n  MODIFYSTART: 'modifystart',\n  /**\n   * Triggered upon feature modification end\n   * @event ol.interaction.Modify.Event#modifyend\n   * @api\n   */\n  MODIFYEND: 'modifyend'\n};\n\ngoog.provide('ol.interaction.Select');\n\ngoog.require('ol');\ngoog.require('ol.functions');\ngoog.require('ol.Collection');\ngoog.require('ol.array');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.condition');\ngoog.require('ol.geom.GeometryType');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.obj');\ngoog.require('ol.source.Vector');\ngoog.require('ol.style.Style');\n\n\n/**\n * @classdesc\n * Interaction for selecting vector features. By default, selected features are\n * styled differently, so this interaction can be used for visual highlighting,\n * as well as selecting features for other actions, such as modification or\n * output. There are three ways of controlling which features are selected:\n * using the browser event as defined by the `condition` and optionally the\n * `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a\n * further feature filter using the `filter` option.\n *\n * Selected features are added to an internal unmanaged layer.\n *\n * @constructor\n * @extends {ol.interaction.Interaction}\n * @param {olx.interaction.SelectOptions=} opt_options Options.\n * @fires ol.interaction.Select.Event\n * @api stable\n */\nol.interaction.Select = function(opt_options) {\n\n  ol.interaction.Interaction.call(this, {\n    handleEvent: ol.interaction.Select.handleEvent\n  });\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.condition_ = options.condition ?\n      options.condition : ol.events.condition.singleClick;\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.addCondition_ = options.addCondition ?\n      options.addCondition : ol.events.condition.never;\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.removeCondition_ = options.removeCondition ?\n      options.removeCondition : ol.events.condition.never;\n\n  /**\n   * @private\n   * @type {ol.EventsConditionType}\n   */\n  this.toggleCondition_ = options.toggleCondition ?\n      options.toggleCondition : ol.events.condition.shiftKeyOnly;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.multi_ = options.multi ? options.multi : false;\n\n  /**\n   * @private\n   * @type {ol.SelectFilterFunction}\n   */\n  this.filter_ = options.filter ? options.filter :\n      ol.functions.TRUE;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.hitTolerance_ = options.hitTolerance ? options.hitTolerance : 0;\n\n  var featureOverlay = new ol.layer.Vector({\n    source: new ol.source.Vector({\n      useSpatialIndex: false,\n      features: options.features,\n      wrapX: options.wrapX\n    }),\n    style: options.style ? options.style :\n        ol.interaction.Select.getDefaultStyleFunction(),\n    updateWhileAnimating: true,\n    updateWhileInteracting: true\n  });\n\n  /**\n   * @private\n   * @type {ol.layer.Vector}\n   */\n  this.featureOverlay_ = featureOverlay;\n\n  /** @type {function(ol.layer.Layer): boolean} */\n  var layerFilter;\n  if (options.layers) {\n    if (typeof options.layers === 'function') {\n      layerFilter = options.layers;\n    } else {\n      var layers = options.layers;\n      layerFilter = function(layer) {\n        return ol.array.includes(layers, layer);\n      };\n    }\n  } else {\n    layerFilter = ol.functions.TRUE;\n  }\n\n  /**\n   * @private\n   * @type {function(ol.layer.Layer): boolean}\n   */\n  this.layerFilter_ = layerFilter;\n\n  /**\n   * An association between selected feature (key)\n   * and layer (value)\n   * @private\n   * @type {Object.<number, ol.layer.Layer>}\n   */\n  this.featureLayerAssociation_ = {};\n\n  var features = this.featureOverlay_.getSource().getFeaturesCollection();\n  ol.events.listen(features, ol.Collection.EventType.ADD,\n      this.addFeature_, this);\n  ol.events.listen(features, ol.Collection.EventType.REMOVE,\n      this.removeFeature_, this);\n\n};\nol.inherits(ol.interaction.Select, ol.interaction.Interaction);\n\n\n/**\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @param {ol.layer.Layer} layer Layer.\n * @private\n */\nol.interaction.Select.prototype.addFeatureLayerAssociation_ = function(feature, layer) {\n  var key = ol.getUid(feature);\n  this.featureLayerAssociation_[key] = layer;\n};\n\n\n/**\n * Get the selected features.\n * @return {ol.Collection.<ol.Feature>} Features collection.\n * @api stable\n */\nol.interaction.Select.prototype.getFeatures = function() {\n  return this.featureOverlay_.getSource().getFeaturesCollection();\n};\n\n\n/**\n * Returns the Hit-detection tolerance.\n * @returns {number} Hit tolerance in pixels.\n * @api\n */\nol.interaction.Select.prototype.getHitTolerance = function() {\n  return this.hitTolerance_;\n};\n\n\n/**\n * Returns the associated {@link ol.layer.Vector vectorlayer} of\n * the (last) selected feature. Note that this will not work with any\n * programmatic method like pushing features to\n * {@link ol.interaction.Select#getFeatures collection}.\n * @param {ol.Feature|ol.render.Feature} feature Feature\n * @return {ol.layer.Vector} Layer.\n * @api\n */\nol.interaction.Select.prototype.getLayer = function(feature) {\n  var key = ol.getUid(feature);\n  return /** @type {ol.layer.Vector} */ (this.featureLayerAssociation_[key]);\n};\n\n\n/**\n * Handles the {@link ol.MapBrowserEvent map browser event} and may change the\n * selected state of features.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {ol.interaction.Select}\n * @api\n */\nol.interaction.Select.handleEvent = function(mapBrowserEvent) {\n  if (!this.condition_(mapBrowserEvent)) {\n    return true;\n  }\n  var add = this.addCondition_(mapBrowserEvent);\n  var remove = this.removeCondition_(mapBrowserEvent);\n  var toggle = this.toggleCondition_(mapBrowserEvent);\n  var set = !add && !remove && !toggle;\n  var map = mapBrowserEvent.map;\n  var features = this.featureOverlay_.getSource().getFeaturesCollection();\n  var deselected = [];\n  var selected = [];\n  if (set) {\n    // Replace the currently selected feature(s) with the feature(s) at the\n    // pixel, or clear the selected feature(s) if there is no feature at\n    // the pixel.\n    ol.obj.clear(this.featureLayerAssociation_);\n    map.forEachFeatureAtPixel(mapBrowserEvent.pixel,\n      (/**\n         * @param {ol.Feature|ol.render.Feature} feature Feature.\n         * @param {ol.layer.Layer} layer Layer.\n         * @return {boolean|undefined} Continue to iterate over the features.\n         */\n        function(feature, layer) {\n          if (this.filter_(feature, layer)) {\n            selected.push(feature);\n            this.addFeatureLayerAssociation_(feature, layer);\n            return !this.multi_;\n          }\n        }).bind(this), {\n          layerFilter: this.layerFilter_,\n          hitTolerance: this.hitTolerance_\n        });\n    var i;\n    for (i = features.getLength() - 1; i >= 0; --i) {\n      var feature = features.item(i);\n      var index = selected.indexOf(feature);\n      if (index > -1) {\n        // feature is already selected\n        selected.splice(index, 1);\n      } else {\n        features.remove(feature);\n        deselected.push(feature);\n      }\n    }\n    if (selected.length !== 0) {\n      features.extend(selected);\n    }\n  } else {\n    // Modify the currently selected feature(s).\n    map.forEachFeatureAtPixel(mapBrowserEvent.pixel,\n      (/**\n         * @param {ol.Feature|ol.render.Feature} feature Feature.\n         * @param {ol.layer.Layer} layer Layer.\n         * @return {boolean|undefined} Continue to iterate over the features.\n         */\n        function(feature, layer) {\n          if (this.filter_(feature, layer)) {\n            if ((add || toggle) &&\n                !ol.array.includes(features.getArray(), feature)) {\n              selected.push(feature);\n              this.addFeatureLayerAssociation_(feature, layer);\n            } else if ((remove || toggle) &&\n                ol.array.includes(features.getArray(), feature)) {\n              deselected.push(feature);\n              this.removeFeatureLayerAssociation_(feature);\n            }\n            return !this.multi_;\n          }\n        }).bind(this), {\n          layerFilter: this.layerFilter_,\n          hitTolerance: this.hitTolerance_\n        });\n    var j;\n    for (j = deselected.length - 1; j >= 0; --j) {\n      features.remove(deselected[j]);\n    }\n    features.extend(selected);\n  }\n  if (selected.length > 0 || deselected.length > 0) {\n    this.dispatchEvent(\n        new ol.interaction.Select.Event(ol.interaction.Select.EventType.SELECT,\n            selected, deselected, mapBrowserEvent));\n  }\n  return ol.events.condition.pointerMove(mapBrowserEvent);\n};\n\n\n/**\n * Hit-detection tolerance. Pixels inside the radius around the given position\n * will be checked for features. This only works for the canvas renderer and\n * not for WebGL.\n * @param {number} hitTolerance Hit tolerance in pixels.\n * @api\n */\nol.interaction.Select.prototype.setHitTolerance = function(hitTolerance) {\n  this.hitTolerance_ = hitTolerance;\n};\n\n\n/**\n * Remove the interaction from its current map, if any,  and attach it to a new\n * map, if any. Pass `null` to just remove the interaction from the current map.\n * @param {ol.Map} map Map.\n * @api stable\n */\nol.interaction.Select.prototype.setMap = function(map) {\n  var currentMap = this.getMap();\n  var selectedFeatures =\n      this.featureOverlay_.getSource().getFeaturesCollection();\n  if (currentMap) {\n    selectedFeatures.forEach(currentMap.unskipFeature, currentMap);\n  }\n  ol.interaction.Interaction.prototype.setMap.call(this, map);\n  this.featureOverlay_.setMap(map);\n  if (map) {\n    selectedFeatures.forEach(map.skipFeature, map);\n  }\n};\n\n\n/**\n * @return {ol.StyleFunction} Styles.\n */\nol.interaction.Select.getDefaultStyleFunction = function() {\n  var styles = ol.style.Style.createDefaultEditing();\n  ol.array.extend(styles[ol.geom.GeometryType.POLYGON],\n      styles[ol.geom.GeometryType.LINE_STRING]);\n  ol.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION],\n      styles[ol.geom.GeometryType.LINE_STRING]);\n\n  return function(feature, resolution) {\n    if (!feature.getGeometry()) {\n      return null;\n    }\n    return styles[feature.getGeometry().getType()];\n  };\n};\n\n\n/**\n * @param {ol.Collection.Event} evt Event.\n * @private\n */\nol.interaction.Select.prototype.addFeature_ = function(evt) {\n  var map = this.getMap();\n  if (map) {\n    map.skipFeature(/** @type {ol.Feature} */ (evt.element));\n  }\n};\n\n\n/**\n * @param {ol.Collection.Event} evt Event.\n * @private\n */\nol.interaction.Select.prototype.removeFeature_ = function(evt) {\n  var map = this.getMap();\n  if (map) {\n    map.unskipFeature(/** @type {ol.Feature} */ (evt.element));\n  }\n};\n\n\n/**\n * @param {ol.Feature|ol.render.Feature} feature Feature.\n * @private\n */\nol.interaction.Select.prototype.removeFeatureLayerAssociation_ = function(feature) {\n  var key = ol.getUid(feature);\n  delete this.featureLayerAssociation_[key];\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.interaction.Select} instances are instances of\n * this type.\n *\n * @param {ol.interaction.Select.EventType} type The event type.\n * @param {Array.<ol.Feature>} selected Selected features.\n * @param {Array.<ol.Feature>} deselected Deselected features.\n * @param {ol.MapBrowserEvent} mapBrowserEvent Associated\n *     {@link ol.MapBrowserEvent}.\n * @implements {oli.SelectEvent}\n * @extends {ol.events.Event}\n * @constructor\n */\nol.interaction.Select.Event = function(type, selected, deselected, mapBrowserEvent) {\n  ol.events.Event.call(this, type);\n\n  /**\n   * Selected features array.\n   * @type {Array.<ol.Feature>}\n   * @api\n   */\n  this.selected = selected;\n\n  /**\n   * Deselected features array.\n   * @type {Array.<ol.Feature>}\n   * @api\n   */\n  this.deselected = deselected;\n\n  /**\n   * Associated {@link ol.MapBrowserEvent}.\n   * @type {ol.MapBrowserEvent}\n   * @api\n   */\n  this.mapBrowserEvent = mapBrowserEvent;\n};\nol.inherits(ol.interaction.Select.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.interaction.Select.EventType = {\n  /**\n   * Triggered when feature(s) has been (de)selected.\n   * @event ol.interaction.Select.Event#select\n   * @api\n   */\n  SELECT: 'select'\n};\n\ngoog.provide('ol.interaction.Snap');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.Object');\ngoog.require('ol.Observable');\ngoog.require('ol.coordinate');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.interaction.Pointer');\ngoog.require('ol.functions');\ngoog.require('ol.obj');\ngoog.require('ol.source.Vector');\ngoog.require('ol.structs.RBush');\n\n\n/**\n * @classdesc\n * Handles snapping of vector features while modifying or drawing them.  The\n * features can come from a {@link ol.source.Vector} or {@link ol.Collection}\n * Any interaction object that allows the user to interact\n * with the features using the mouse can benefit from the snapping, as long\n * as it is added before.\n *\n * The snap interaction modifies map browser event `coordinate` and `pixel`\n * properties to force the snap to occur to any interaction that them.\n *\n * Example:\n *\n *     var snap = new ol.interaction.Snap({\n *       source: source\n *     });\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @param {olx.interaction.SnapOptions=} opt_options Options.\n * @api\n */\nol.interaction.Snap = function(opt_options) {\n\n  ol.interaction.Pointer.call(this, {\n    handleEvent: ol.interaction.Snap.handleEvent_,\n    handleDownEvent: ol.functions.TRUE,\n    handleUpEvent: ol.interaction.Snap.handleUpEvent_\n  });\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @type {ol.source.Vector}\n   * @private\n   */\n  this.source_ = options.source ? options.source : null;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.vertex_ = options.vertex !== undefined ? options.vertex : true;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.edge_ = options.edge !== undefined ? options.edge : true;\n\n  /**\n   * @type {ol.Collection.<ol.Feature>}\n   * @private\n   */\n  this.features_ = options.features ? options.features : null;\n\n  /**\n   * @type {Array.<ol.EventsKey>}\n   * @private\n   */\n  this.featuresListenerKeys_ = [];\n\n  /**\n   * @type {Object.<number, ol.EventsKey>}\n   * @private\n   */\n  this.geometryChangeListenerKeys_ = {};\n\n  /**\n   * @type {Object.<number, ol.EventsKey>}\n   * @private\n   */\n  this.geometryModifyListenerKeys_ = {};\n\n  /**\n   * Extents are preserved so indexed segment can be quickly removed\n   * when its feature geometry changes\n   * @type {Object.<number, ol.Extent>}\n   * @private\n   */\n  this.indexedFeaturesExtents_ = {};\n\n  /**\n   * If a feature geometry changes while a pointer drag|move event occurs, the\n   * feature doesn't get updated right away.  It will be at the next 'pointerup'\n   * event fired.\n   * @type {Object.<number, ol.Feature>}\n   * @private\n   */\n  this.pendingFeatures_ = {};\n\n  /**\n   * Used for distance sorting in sortByDistance_\n   * @type {ol.Coordinate}\n   * @private\n   */\n  this.pixelCoordinate_ = null;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.pixelTolerance_ = options.pixelTolerance !== undefined ?\n      options.pixelTolerance : 10;\n\n  /**\n   * @type {function(ol.SnapSegmentDataType, ol.SnapSegmentDataType): number}\n   * @private\n   */\n  this.sortByDistance_ = ol.interaction.Snap.sortByDistance.bind(this);\n\n\n  /**\n  * Segment RTree for each layer\n  * @type {ol.structs.RBush.<ol.SnapSegmentDataType>}\n  * @private\n  */\n  this.rBush_ = new ol.structs.RBush();\n\n\n  /**\n  * @const\n  * @private\n  * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>}\n  */\n  this.SEGMENT_WRITERS_ = {\n    'Point': this.writePointGeometry_,\n    'LineString': this.writeLineStringGeometry_,\n    'LinearRing': this.writeLineStringGeometry_,\n    'Polygon': this.writePolygonGeometry_,\n    'MultiPoint': this.writeMultiPointGeometry_,\n    'MultiLineString': this.writeMultiLineStringGeometry_,\n    'MultiPolygon': this.writeMultiPolygonGeometry_,\n    'GeometryCollection': this.writeGeometryCollectionGeometry_\n  };\n};\nol.inherits(ol.interaction.Snap, ol.interaction.Pointer);\n\n\n/**\n * Add a feature to the collection of features that we may snap to.\n * @param {ol.Feature} feature Feature.\n * @param {boolean=} opt_listen Whether to listen to the geometry change or not\n *     Defaults to `true`.\n * @api\n */\nol.interaction.Snap.prototype.addFeature = function(feature, opt_listen) {\n  var listen = opt_listen !== undefined ? opt_listen : true;\n  var feature_uid = ol.getUid(feature);\n  var geometry = feature.getGeometry();\n  if (geometry) {\n    var segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()];\n    if (segmentWriter) {\n      this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(\n          ol.extent.createEmpty());\n      segmentWriter.call(this, feature, geometry);\n\n      if (listen) {\n        this.geometryModifyListenerKeys_[feature_uid] = ol.events.listen(\n            geometry,\n            ol.events.EventType.CHANGE,\n            this.handleGeometryModify_.bind(this, feature),\n            this);\n      }\n    }\n  }\n\n  if (listen) {\n    this.geometryChangeListenerKeys_[feature_uid] = ol.events.listen(\n        feature,\n        ol.Object.getChangeEventType(feature.getGeometryName()),\n        this.handleGeometryChange_, this);\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.interaction.Snap.prototype.forEachFeatureAdd_ = function(feature) {\n  this.addFeature(feature);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature.\n * @private\n */\nol.interaction.Snap.prototype.forEachFeatureRemove_ = function(feature) {\n  this.removeFeature(feature);\n};\n\n\n/**\n * @return {ol.Collection.<ol.Feature>|Array.<ol.Feature>} Features.\n * @private\n */\nol.interaction.Snap.prototype.getFeatures_ = function() {\n  var features;\n  if (this.features_) {\n    features = this.features_;\n  } else if (this.source_) {\n    features = this.source_.getFeatures();\n  }\n  return /** @type {!Array.<ol.Feature>|!ol.Collection.<ol.Feature>} */ (features);\n};\n\n\n/**\n * @param {ol.source.Vector.Event|ol.Collection.Event} evt Event.\n * @private\n */\nol.interaction.Snap.prototype.handleFeatureAdd_ = function(evt) {\n  var feature;\n  if (evt instanceof ol.source.Vector.Event) {\n    feature = evt.feature;\n  } else if (evt instanceof ol.Collection.Event) {\n    feature = evt.element;\n  }\n  this.addFeature(/** @type {ol.Feature} */ (feature));\n};\n\n\n/**\n * @param {ol.source.Vector.Event|ol.Collection.Event} evt Event.\n * @private\n */\nol.interaction.Snap.prototype.handleFeatureRemove_ = function(evt) {\n  var feature;\n  if (evt instanceof ol.source.Vector.Event) {\n    feature = evt.feature;\n  } else if (evt instanceof ol.Collection.Event) {\n    feature = evt.element;\n  }\n  this.removeFeature(/** @type {ol.Feature} */ (feature));\n};\n\n\n/**\n * @param {ol.events.Event} evt Event.\n * @private\n */\nol.interaction.Snap.prototype.handleGeometryChange_ = function(evt) {\n  var feature = /** @type {ol.Feature} */ (evt.target);\n  this.removeFeature(feature, true);\n  this.addFeature(feature, true);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature which geometry was modified.\n * @param {ol.events.Event} evt Event.\n * @private\n */\nol.interaction.Snap.prototype.handleGeometryModify_ = function(feature, evt) {\n  if (this.handlingDownUpSequence) {\n    var uid = ol.getUid(feature);\n    if (!(uid in this.pendingFeatures_)) {\n      this.pendingFeatures_[uid] = feature;\n    }\n  } else {\n    this.updateFeature_(feature);\n  }\n};\n\n\n/**\n * Remove a feature from the collection of features that we may snap to.\n * @param {ol.Feature} feature Feature\n * @param {boolean=} opt_unlisten Whether to unlisten to the geometry change\n *     or not. Defaults to `true`.\n * @api\n */\nol.interaction.Snap.prototype.removeFeature = function(feature, opt_unlisten) {\n  var unlisten = opt_unlisten !== undefined ? opt_unlisten : true;\n  var feature_uid = ol.getUid(feature);\n  var extent = this.indexedFeaturesExtents_[feature_uid];\n  if (extent) {\n    var rBush = this.rBush_;\n    var i, nodesToRemove = [];\n    rBush.forEachInExtent(extent, function(node) {\n      if (feature === node.feature) {\n        nodesToRemove.push(node);\n      }\n    });\n    for (i = nodesToRemove.length - 1; i >= 0; --i) {\n      rBush.remove(nodesToRemove[i]);\n    }\n    if (unlisten) {\n      ol.Observable.unByKey(this.geometryModifyListenerKeys_[feature_uid]);\n      delete this.geometryModifyListenerKeys_[feature_uid];\n    }\n  }\n\n  if (unlisten) {\n    ol.Observable.unByKey(this.geometryChangeListenerKeys_[feature_uid]);\n    delete this.geometryChangeListenerKeys_[feature_uid];\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.Snap.prototype.setMap = function(map) {\n  var currentMap = this.getMap();\n  var keys = this.featuresListenerKeys_;\n  var features = this.getFeatures_();\n\n  if (currentMap) {\n    keys.forEach(ol.Observable.unByKey);\n    keys.length = 0;\n    features.forEach(this.forEachFeatureRemove_, this);\n  }\n  ol.interaction.Pointer.prototype.setMap.call(this, map);\n\n  if (map) {\n    if (this.features_) {\n      keys.push(\n        ol.events.listen(this.features_, ol.Collection.EventType.ADD,\n            this.handleFeatureAdd_, this),\n        ol.events.listen(this.features_, ol.Collection.EventType.REMOVE,\n            this.handleFeatureRemove_, this)\n      );\n    } else if (this.source_) {\n      keys.push(\n        ol.events.listen(this.source_, ol.source.Vector.EventType.ADDFEATURE,\n            this.handleFeatureAdd_, this),\n        ol.events.listen(this.source_, ol.source.Vector.EventType.REMOVEFEATURE,\n            this.handleFeatureRemove_, this)\n      );\n    }\n    features.forEach(this.forEachFeatureAdd_, this);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.interaction.Snap.prototype.shouldStopEvent = ol.functions.FALSE;\n\n\n/**\n * @param {ol.Pixel} pixel Pixel\n * @param {ol.Coordinate} pixelCoordinate Coordinate\n * @param {ol.Map} map Map.\n * @return {ol.SnapResultType} Snap result\n */\nol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) {\n\n  var lowerLeft = map.getCoordinateFromPixel(\n      [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);\n  var upperRight = map.getCoordinateFromPixel(\n      [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);\n  var box = ol.extent.boundingExtent([lowerLeft, upperRight]);\n\n  var segments = this.rBush_.getInExtent(box);\n  var snappedToVertex = false;\n  var snapped = false;\n  var vertex = null;\n  var vertexPixel = null;\n  var dist, pixel1, pixel2, squaredDist1, squaredDist2;\n  if (segments.length > 0) {\n    this.pixelCoordinate_ = pixelCoordinate;\n    segments.sort(this.sortByDistance_);\n    var closestSegment = segments[0].segment;\n    if (this.vertex_ && !this.edge_) {\n      pixel1 = map.getPixelFromCoordinate(closestSegment[0]);\n      pixel2 = map.getPixelFromCoordinate(closestSegment[1]);\n      squaredDist1 = ol.coordinate.squaredDistance(pixel, pixel1);\n      squaredDist2 = ol.coordinate.squaredDistance(pixel, pixel2);\n      dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));\n      snappedToVertex = dist <= this.pixelTolerance_;\n      if (snappedToVertex) {\n        snapped = true;\n        vertex = squaredDist1 > squaredDist2 ?\n            closestSegment[1] : closestSegment[0];\n        vertexPixel = map.getPixelFromCoordinate(vertex);\n      }\n    } else if (this.edge_) {\n      vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,\n          closestSegment));\n      vertexPixel = map.getPixelFromCoordinate(vertex);\n      if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <=\n          this.pixelTolerance_) {\n        snapped = true;\n        if (this.vertex_) {\n          pixel1 = map.getPixelFromCoordinate(closestSegment[0]);\n          pixel2 = map.getPixelFromCoordinate(closestSegment[1]);\n          squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);\n          squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);\n          dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));\n          snappedToVertex = dist <= this.pixelTolerance_;\n          if (snappedToVertex) {\n            vertex = squaredDist1 > squaredDist2 ?\n                closestSegment[1] : closestSegment[0];\n            vertexPixel = map.getPixelFromCoordinate(vertex);\n          }\n        }\n      }\n    }\n    if (snapped) {\n      vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];\n    }\n  }\n  return /** @type {ol.SnapResultType} */ ({\n    snapped: snapped,\n    vertex: vertex,\n    vertexPixel: vertexPixel\n  });\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @private\n */\nol.interaction.Snap.prototype.updateFeature_ = function(feature) {\n  this.removeFeature(feature, false);\n  this.addFeature(feature, false);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.GeometryCollection} geometry Geometry.\n * @private\n */\nol.interaction.Snap.prototype.writeGeometryCollectionGeometry_ = function(feature, geometry) {\n  var i, geometries = geometry.getGeometriesArray();\n  for (i = 0; i < geometries.length; ++i) {\n    this.SEGMENT_WRITERS_[geometries[i].getType()].call(\n        this, feature, geometries[i]);\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.LineString} geometry Geometry.\n * @private\n */\nol.interaction.Snap.prototype.writeLineStringGeometry_ = function(feature, geometry) {\n  var coordinates = geometry.getCoordinates();\n  var i, ii, segment, segmentData;\n  for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n    segment = coordinates.slice(i, i + 2);\n    segmentData = /** @type {ol.SnapSegmentDataType} */ ({\n      feature: feature,\n      segment: segment\n    });\n    this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.MultiLineString} geometry Geometry.\n * @private\n */\nol.interaction.Snap.prototype.writeMultiLineStringGeometry_ = function(feature, geometry) {\n  var lines = geometry.getCoordinates();\n  var coordinates, i, ii, j, jj, segment, segmentData;\n  for (j = 0, jj = lines.length; j < jj; ++j) {\n    coordinates = lines[j];\n    for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n      segment = coordinates.slice(i, i + 2);\n      segmentData = /** @type {ol.SnapSegmentDataType} */ ({\n        feature: feature,\n        segment: segment\n      });\n      this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n    }\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.MultiPoint} geometry Geometry.\n * @private\n */\nol.interaction.Snap.prototype.writeMultiPointGeometry_ = function(feature, geometry) {\n  var points = geometry.getCoordinates();\n  var coordinates, i, ii, segmentData;\n  for (i = 0, ii = points.length; i < ii; ++i) {\n    coordinates = points[i];\n    segmentData = /** @type {ol.SnapSegmentDataType} */ ({\n      feature: feature,\n      segment: [coordinates, coordinates]\n    });\n    this.rBush_.insert(geometry.getExtent(), segmentData);\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.MultiPolygon} geometry Geometry.\n * @private\n */\nol.interaction.Snap.prototype.writeMultiPolygonGeometry_ = function(feature, geometry) {\n  var polygons = geometry.getCoordinates();\n  var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData;\n  for (k = 0, kk = polygons.length; k < kk; ++k) {\n    rings = polygons[k];\n    for (j = 0, jj = rings.length; j < jj; ++j) {\n      coordinates = rings[j];\n      for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n        segment = coordinates.slice(i, i + 2);\n        segmentData = /** @type {ol.SnapSegmentDataType} */ ({\n          feature: feature,\n          segment: segment\n        });\n        this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n      }\n    }\n  }\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.Point} geometry Geometry.\n * @private\n */\nol.interaction.Snap.prototype.writePointGeometry_ = function(feature, geometry) {\n  var coordinates = geometry.getCoordinates();\n  var segmentData = /** @type {ol.SnapSegmentDataType} */ ({\n    feature: feature,\n    segment: [coordinates, coordinates]\n  });\n  this.rBush_.insert(geometry.getExtent(), segmentData);\n};\n\n\n/**\n * @param {ol.Feature} feature Feature\n * @param {ol.geom.Polygon} geometry Geometry.\n * @private\n */\nol.interaction.Snap.prototype.writePolygonGeometry_ = function(feature, geometry) {\n  var rings = geometry.getCoordinates();\n  var coordinates, i, ii, j, jj, segment, segmentData;\n  for (j = 0, jj = rings.length; j < jj; ++j) {\n    coordinates = rings[j];\n    for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {\n      segment = coordinates.slice(i, i + 2);\n      segmentData = /** @type {ol.SnapSegmentDataType} */ ({\n        feature: feature,\n        segment: segment\n      });\n      this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);\n    }\n  }\n};\n\n\n/**\n * Handle all pointer events events.\n * @param {ol.MapBrowserEvent} evt A move event.\n * @return {boolean} Pass the event to other interactions.\n * @this {ol.interaction.Snap}\n * @private\n */\nol.interaction.Snap.handleEvent_ = function(evt) {\n  var result = this.snapTo(evt.pixel, evt.coordinate, evt.map);\n  if (result.snapped) {\n    evt.coordinate = result.vertex.slice(0, 2);\n    evt.pixel = result.vertexPixel;\n  }\n  return ol.interaction.Pointer.handleEvent.call(this, evt);\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} evt Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.Snap}\n * @private\n */\nol.interaction.Snap.handleUpEvent_ = function(evt) {\n  var featuresToUpdate = ol.obj.getValues(this.pendingFeatures_);\n  if (featuresToUpdate.length) {\n    featuresToUpdate.forEach(this.updateFeature_, this);\n    this.pendingFeatures_ = {};\n  }\n  return false;\n};\n\n\n/**\n * Sort segments by distance, helper function\n * @param {ol.SnapSegmentDataType} a The first segment data.\n * @param {ol.SnapSegmentDataType} b The second segment data.\n * @return {number} The difference in distance.\n * @this {ol.interaction.Snap}\n */\nol.interaction.Snap.sortByDistance = function(a, b) {\n  return ol.coordinate.squaredDistanceToSegment(\n      this.pixelCoordinate_, a.segment) -\n      ol.coordinate.squaredDistanceToSegment(\n      this.pixelCoordinate_, b.segment);\n};\n\ngoog.provide('ol.interaction.Translate');\n\ngoog.require('ol');\ngoog.require('ol.Collection');\ngoog.require('ol.events.Event');\ngoog.require('ol.functions');\ngoog.require('ol.array');\ngoog.require('ol.interaction.Pointer');\n\n\n/**\n * @classdesc\n * Interaction for translating (moving) features.\n *\n * @constructor\n * @extends {ol.interaction.Pointer}\n * @fires ol.interaction.Translate.Event\n * @param {olx.interaction.TranslateOptions=} opt_options Options.\n * @api\n */\nol.interaction.Translate = function(opt_options) {\n  ol.interaction.Pointer.call(this, {\n    handleDownEvent: ol.interaction.Translate.handleDownEvent_,\n    handleDragEvent: ol.interaction.Translate.handleDragEvent_,\n    handleMoveEvent: ol.interaction.Translate.handleMoveEvent_,\n    handleUpEvent: ol.interaction.Translate.handleUpEvent_\n  });\n\n  var options = opt_options ? opt_options : {};\n\n  /**\n   * @type {string|undefined}\n   * @private\n   */\n  this.previousCursor_ = undefined;\n\n\n  /**\n   * The last position we translated to.\n   * @type {ol.Coordinate}\n   * @private\n   */\n  this.lastCoordinate_ = null;\n\n\n  /**\n   * @type {ol.Collection.<ol.Feature>}\n   * @private\n   */\n  this.features_ = options.features !== undefined ? options.features : null;\n\n  /** @type {function(ol.layer.Layer): boolean} */\n  var layerFilter;\n  if (options.layers) {\n    if (typeof options.layers === 'function') {\n      layerFilter = options.layers;\n    } else {\n      var layers = options.layers;\n      layerFilter = function(layer) {\n        return ol.array.includes(layers, layer);\n      };\n    }\n  } else {\n    layerFilter = ol.functions.TRUE;\n  }\n\n  /**\n   * @private\n   * @type {function(ol.layer.Layer): boolean}\n   */\n  this.layerFilter_ = layerFilter;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.hitTolerance_ = options.hitTolerance ? options.hitTolerance : 0;\n\n  /**\n   * @type {ol.Feature}\n   * @private\n   */\n  this.lastFeature_ = null;\n};\nol.inherits(ol.interaction.Translate, ol.interaction.Pointer);\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} event Event.\n * @return {boolean} Start drag sequence?\n * @this {ol.interaction.Translate}\n * @private\n */\nol.interaction.Translate.handleDownEvent_ = function(event) {\n  this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);\n  if (!this.lastCoordinate_ && this.lastFeature_) {\n    this.lastCoordinate_ = event.coordinate;\n    ol.interaction.Translate.handleMoveEvent_.call(this, event);\n\n    var features = this.features_ || new ol.Collection([this.lastFeature_]);\n\n    this.dispatchEvent(\n        new ol.interaction.Translate.Event(\n            ol.interaction.Translate.EventType.TRANSLATESTART, features,\n            event.coordinate));\n    return true;\n  }\n  return false;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} event Event.\n * @return {boolean} Stop drag sequence?\n * @this {ol.interaction.Translate}\n * @private\n */\nol.interaction.Translate.handleUpEvent_ = function(event) {\n  if (this.lastCoordinate_) {\n    this.lastCoordinate_ = null;\n    ol.interaction.Translate.handleMoveEvent_.call(this, event);\n\n    var features = this.features_ || new ol.Collection([this.lastFeature_]);\n\n    this.dispatchEvent(\n        new ol.interaction.Translate.Event(\n            ol.interaction.Translate.EventType.TRANSLATEEND, features,\n            event.coordinate));\n    return true;\n  }\n  return false;\n};\n\n\n/**\n * @param {ol.MapBrowserPointerEvent} event Event.\n * @this {ol.interaction.Translate}\n * @private\n */\nol.interaction.Translate.handleDragEvent_ = function(event) {\n  if (this.lastCoordinate_) {\n    var newCoordinate = event.coordinate;\n    var deltaX = newCoordinate[0] - this.lastCoordinate_[0];\n    var deltaY = newCoordinate[1] - this.lastCoordinate_[1];\n\n    var features = this.features_ || new ol.Collection([this.lastFeature_]);\n\n    features.forEach(function(feature) {\n      var geom = feature.getGeometry();\n      geom.translate(deltaX, deltaY);\n      feature.setGeometry(geom);\n    });\n\n    this.lastCoordinate_ = newCoordinate;\n    this.dispatchEvent(\n        new ol.interaction.Translate.Event(\n            ol.interaction.Translate.EventType.TRANSLATING, features,\n            newCoordinate));\n  }\n};\n\n\n/**\n * @param {ol.MapBrowserEvent} event Event.\n * @this {ol.interaction.Translate}\n * @private\n */\nol.interaction.Translate.handleMoveEvent_ = function(event) {\n  var elem = event.map.getTargetElement();\n\n  // Change the cursor to grab/grabbing if hovering any of the features managed\n  // by the interaction\n  if (this.featuresAtPixel_(event.pixel, event.map)) {\n    this.previousCursor_ = elem.style.cursor;\n    // WebKit browsers don't support the grab icons without a prefix\n    elem.style.cursor = this.lastCoordinate_ ?\n        '-webkit-grabbing' : '-webkit-grab';\n\n    // Thankfully, attempting to set the standard ones will silently fail,\n    // keeping the prefixed icons\n    elem.style.cursor = this.lastCoordinate_ ?  'grabbing' : 'grab';\n  } else {\n    elem.style.cursor = this.previousCursor_ !== undefined ?\n        this.previousCursor_ : '';\n    this.previousCursor_ = undefined;\n  }\n};\n\n\n/**\n * Tests to see if the given coordinates intersects any of our selected\n * features.\n * @param {ol.Pixel} pixel Pixel coordinate to test for intersection.\n * @param {ol.Map} map Map to test the intersection on.\n * @return {ol.Feature} Returns the feature found at the specified pixel\n * coordinates.\n * @private\n */\nol.interaction.Translate.prototype.featuresAtPixel_ = function(pixel, map) {\n  return map.forEachFeatureAtPixel(pixel,\n      function(feature) {\n        if (!this.features_ ||\n            ol.array.includes(this.features_.getArray(), feature)) {\n          return feature;\n        }\n      }.bind(this), {\n        layerFilter: this.layerFilter_,\n        hitTolerance: this.hitTolerance_\n      });\n};\n\n\n/**\n * Returns the Hit-detection tolerance.\n * @returns {number} Hit tolerance in pixels.\n * @api\n */\nol.interaction.Translate.prototype.getHitTolerance = function() {\n  return this.hitTolerance_;\n};\n\n\n/**\n * Hit-detection tolerance. Pixels inside the radius around the given position\n * will be checked for features. This only works for the canvas renderer and\n * not for WebGL.\n * @param {number} hitTolerance Hit tolerance in pixels.\n * @api\n */\nol.interaction.Translate.prototype.setHitTolerance = function(hitTolerance) {\n  this.hitTolerance_ = hitTolerance;\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.interaction.Translate} instances are instances of\n * this type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.interaction.TranslateEvent}\n * @param {ol.interaction.Translate.EventType} type Type.\n * @param {ol.Collection.<ol.Feature>} features The features translated.\n * @param {ol.Coordinate} coordinate The event coordinate.\n */\nol.interaction.Translate.Event = function(type, features, coordinate) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The features being translated.\n   * @type {ol.Collection.<ol.Feature>}\n   * @api\n   */\n  this.features = features;\n\n  /**\n   * The coordinate of the drag event.\n   * @const\n   * @type {ol.Coordinate}\n   * @api\n   */\n  this.coordinate = coordinate;\n};\nol.inherits(ol.interaction.Translate.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.interaction.Translate.EventType = {\n  /**\n   * Triggered upon feature translation start.\n   * @event ol.interaction.Translate.Event#translatestart\n   * @api\n   */\n  TRANSLATESTART: 'translatestart',\n  /**\n   * Triggered upon feature translation.\n   * @event ol.interaction.Translate.Event#translating\n   * @api\n   */\n  TRANSLATING: 'translating',\n  /**\n   * Triggered upon feature translation end.\n   * @event ol.interaction.Translate.Event#translateend\n   * @api\n   */\n  TRANSLATEEND: 'translateend'\n};\n\ngoog.provide('ol.layer.Heatmap');\n\ngoog.require('ol.events');\ngoog.require('ol');\ngoog.require('ol.Object');\ngoog.require('ol.dom');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.math');\ngoog.require('ol.obj');\ngoog.require('ol.render.Event');\ngoog.require('ol.style.Icon');\ngoog.require('ol.style.Style');\n\n\n/**\n * @classdesc\n * Layer for rendering vector data as a heatmap.\n * Note that any property set in the options is set as a {@link ol.Object}\n * property on the layer object; for example, setting `title: 'My Title'` in the\n * options means that `title` is observable, and has get/set accessors.\n *\n * @constructor\n * @extends {ol.layer.Vector}\n * @fires ol.render.Event\n * @param {olx.layer.HeatmapOptions=} opt_options Options.\n * @api\n */\nol.layer.Heatmap = function(opt_options) {\n  var options = opt_options ? opt_options : {};\n\n  var baseOptions = ol.obj.assign({}, options);\n\n  delete baseOptions.gradient;\n  delete baseOptions.radius;\n  delete baseOptions.blur;\n  delete baseOptions.shadow;\n  delete baseOptions.weight;\n  ol.layer.Vector.call(this, /** @type {olx.layer.VectorOptions} */ (baseOptions));\n\n  /**\n   * @private\n   * @type {Uint8ClampedArray}\n   */\n  this.gradient_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.shadow_ = options.shadow !== undefined ? options.shadow : 250;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.circleImage_ = undefined;\n\n  /**\n   * @private\n   * @type {Array.<Array.<ol.style.Style>>}\n   */\n  this.styleCache_ = null;\n\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.layer.Heatmap.Property.GRADIENT),\n      this.handleGradientChanged_, this);\n\n  this.setGradient(options.gradient ?\n      options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT);\n\n  this.setBlur(options.blur !== undefined ? options.blur : 15);\n\n  this.setRadius(options.radius !== undefined ? options.radius : 8);\n\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.layer.Heatmap.Property.BLUR),\n      this.handleStyleChanged_, this);\n  ol.events.listen(this,\n      ol.Object.getChangeEventType(ol.layer.Heatmap.Property.RADIUS),\n      this.handleStyleChanged_, this);\n\n  this.handleStyleChanged_();\n\n  var weight = options.weight ? options.weight : 'weight';\n  var weightFunction;\n  if (typeof weight === 'string') {\n    weightFunction = function(feature) {\n      return feature.get(weight);\n    };\n  } else {\n    weightFunction = weight;\n  }\n  ol.DEBUG && console.assert(typeof weightFunction === 'function',\n      'weightFunction should be a function');\n\n  this.setStyle(function(feature, resolution) {\n    ol.DEBUG && console.assert(this.styleCache_, 'this.styleCache_ expected');\n    ol.DEBUG && console.assert(this.circleImage_ !== undefined,\n        'this.circleImage_ should be defined');\n    var weight = weightFunction(feature);\n    var opacity = weight !== undefined ? ol.math.clamp(weight, 0, 1) : 1;\n    // cast to 8 bits\n    var index = (255 * opacity) | 0;\n    var style = this.styleCache_[index];\n    if (!style) {\n      style = [\n        new ol.style.Style({\n          image: new ol.style.Icon({\n            opacity: opacity,\n            src: this.circleImage_\n          })\n        })\n      ];\n      this.styleCache_[index] = style;\n    }\n    return style;\n  }.bind(this));\n\n  // For performance reasons, don't sort the features before rendering.\n  // The render order is not relevant for a heatmap representation.\n  this.setRenderOrder(null);\n\n  ol.events.listen(this, ol.render.Event.Type.RENDER, this.handleRender_, this);\n\n};\nol.inherits(ol.layer.Heatmap, ol.layer.Vector);\n\n\n/**\n * @const\n * @type {Array.<string>}\n */\nol.layer.Heatmap.DEFAULT_GRADIENT = ['#00f', '#0ff', '#0f0', '#ff0', '#f00'];\n\n\n/**\n * @param {Array.<string>} colors A list of colored.\n * @return {Uint8ClampedArray} An array.\n * @private\n */\nol.layer.Heatmap.createGradient_ = function(colors) {\n  var width = 1;\n  var height = 256;\n  var context = ol.dom.createCanvasContext2D(width, height);\n\n  var gradient = context.createLinearGradient(0, 0, width, height);\n  var step = 1 / (colors.length - 1);\n  for (var i = 0, ii = colors.length; i < ii; ++i) {\n    gradient.addColorStop(i * step, colors[i]);\n  }\n\n  context.fillStyle = gradient;\n  context.fillRect(0, 0, width, height);\n\n  return context.getImageData(0, 0, width, height).data;\n};\n\n\n/**\n * @return {string} Data URL for a circle.\n * @private\n */\nol.layer.Heatmap.prototype.createCircle_ = function() {\n  var radius = this.getRadius();\n  var blur = this.getBlur();\n  ol.DEBUG && console.assert(radius !== undefined && blur !== undefined,\n      'radius and blur should be defined');\n  var halfSize = radius + blur + 1;\n  var size = 2 * halfSize;\n  var context = ol.dom.createCanvasContext2D(size, size);\n  context.shadowOffsetX = context.shadowOffsetY = this.shadow_;\n  context.shadowBlur = blur;\n  context.shadowColor = '#000';\n  context.beginPath();\n  var center = halfSize - this.shadow_;\n  context.arc(center, center, radius, 0, Math.PI * 2, true);\n  context.fill();\n  return context.canvas.toDataURL();\n};\n\n\n/**\n * Return the blur size in pixels.\n * @return {number} Blur size in pixels.\n * @api\n * @observable\n */\nol.layer.Heatmap.prototype.getBlur = function() {\n  return /** @type {number} */ (this.get(ol.layer.Heatmap.Property.BLUR));\n};\n\n\n/**\n * Return the gradient colors as array of strings.\n * @return {Array.<string>} Colors.\n * @api\n * @observable\n */\nol.layer.Heatmap.prototype.getGradient = function() {\n  return /** @type {Array.<string>} */ (\n      this.get(ol.layer.Heatmap.Property.GRADIENT));\n};\n\n\n/**\n * Return the size of the radius in pixels.\n * @return {number} Radius size in pixel.\n * @api\n * @observable\n */\nol.layer.Heatmap.prototype.getRadius = function() {\n  return /** @type {number} */ (this.get(ol.layer.Heatmap.Property.RADIUS));\n};\n\n\n/**\n * @private\n */\nol.layer.Heatmap.prototype.handleGradientChanged_ = function() {\n  this.gradient_ = ol.layer.Heatmap.createGradient_(this.getGradient());\n};\n\n\n/**\n * @private\n */\nol.layer.Heatmap.prototype.handleStyleChanged_ = function() {\n  this.circleImage_ = this.createCircle_();\n  this.styleCache_ = new Array(256);\n  this.changed();\n};\n\n\n/**\n * @param {ol.render.Event} event Post compose event\n * @private\n */\nol.layer.Heatmap.prototype.handleRender_ = function(event) {\n  ol.DEBUG && console.assert(event.type == ol.render.Event.Type.RENDER,\n      'event.type should be RENDER');\n  ol.DEBUG && console.assert(this.gradient_, 'this.gradient_ expected');\n  var context = event.context;\n  var canvas = context.canvas;\n  var image = context.getImageData(0, 0, canvas.width, canvas.height);\n  var view8 = image.data;\n  var i, ii, alpha;\n  for (i = 0, ii = view8.length; i < ii; i += 4) {\n    alpha = view8[i + 3] * 4;\n    if (alpha) {\n      view8[i] = this.gradient_[alpha];\n      view8[i + 1] = this.gradient_[alpha + 1];\n      view8[i + 2] = this.gradient_[alpha + 2];\n    }\n  }\n  context.putImageData(image, 0, 0);\n};\n\n\n/**\n * Set the blur size in pixels.\n * @param {number} blur Blur size in pixels.\n * @api\n * @observable\n */\nol.layer.Heatmap.prototype.setBlur = function(blur) {\n  this.set(ol.layer.Heatmap.Property.BLUR, blur);\n};\n\n\n/**\n * Set the gradient colors as array of strings.\n * @param {Array.<string>} colors Gradient.\n * @api\n * @observable\n */\nol.layer.Heatmap.prototype.setGradient = function(colors) {\n  this.set(ol.layer.Heatmap.Property.GRADIENT, colors);\n};\n\n\n/**\n * Set the size of the radius in pixels.\n * @param {number} radius Radius size in pixel.\n * @api\n * @observable\n */\nol.layer.Heatmap.prototype.setRadius = function(radius) {\n  this.set(ol.layer.Heatmap.Property.RADIUS, radius);\n};\n\n\n/**\n * @enum {string}\n */\nol.layer.Heatmap.Property = {\n  BLUR: 'blur',\n  GRADIENT: 'gradient',\n  RADIUS: 'radius'\n};\n\ngoog.provide('ol.net');\n\ngoog.require('ol');\n\n\n/**\n * Simple JSONP helper. Supports error callbacks and a custom callback param.\n * The error callback will be called when no JSONP is executed after 10 seconds.\n *\n * @param {string} url Request url. A 'callback' query parameter will be\n *     appended.\n * @param {Function} callback Callback on success.\n * @param {function()=} opt_errback Callback on error.\n * @param {string=} opt_callbackParam Custom query parameter for the JSONP\n *     callback. Default is 'callback'.\n */\nol.net.jsonp = function(url, callback, opt_errback, opt_callbackParam) {\n  var script = document.createElement('script');\n  var key = 'olc_' + ol.getUid(callback);\n  function cleanup() {\n    delete window[key];\n    script.parentNode.removeChild(script);\n  }\n  script.async = true;\n  script.src = url + (url.indexOf('?') == -1 ? '?' : '&') +\n      (opt_callbackParam || 'callback') + '=' + key;\n  var timer = setTimeout(function() {\n    cleanup();\n    if (opt_errback) {\n      opt_errback();\n    }\n  }, 10000);\n  window[key] = function(data) {\n    clearTimeout(timer);\n    cleanup();\n    callback(data);\n  };\n  document.getElementsByTagName('head')[0].appendChild(script);\n};\n\ngoog.provide('ol.render');\n\ngoog.require('ol.has');\ngoog.require('ol.transform');\ngoog.require('ol.render.canvas.Immediate');\n\n\n/**\n * Binds a Canvas Immediate API to a canvas context, to allow drawing geometries\n * to the context's canvas.\n *\n * The units for geometry coordinates are css pixels relative to the top left\n * corner of the canvas element.\n * ```js\n * var canvas = document.createElement('canvas');\n * var render = ol.render.toContext(canvas.getContext('2d'),\n *     { size: [100, 100] });\n * render.setFillStrokeStyle(new ol.style.Fill({ color: blue }));\n * render.drawPolygon(\n *     new ol.geom.Polygon([[[0, 0], [100, 100], [100, 0], [0, 0]]]));\n * ```\n *\n * @param {CanvasRenderingContext2D} context Canvas context.\n * @param {olx.render.ToContextOptions=} opt_options Options.\n * @return {ol.render.canvas.Immediate} Canvas Immediate.\n * @api\n */\nol.render.toContext = function(context, opt_options) {\n  var canvas = context.canvas;\n  var options = opt_options ? opt_options : {};\n  var pixelRatio = options.pixelRatio || ol.has.DEVICE_PIXEL_RATIO;\n  var size = options.size;\n  if (size) {\n    canvas.width = size[0] * pixelRatio;\n    canvas.height = size[1] * pixelRatio;\n    canvas.style.width = size[0] + 'px';\n    canvas.style.height = size[1] + 'px';\n  }\n  var extent = [0, 0, canvas.width, canvas.height];\n  var transform = ol.transform.scale(ol.transform.create(), pixelRatio, pixelRatio);\n  return new ol.render.canvas.Immediate(context, pixelRatio, extent, transform,\n      0);\n};\n\ngoog.provide('ol.reproj.Tile');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.math');\ngoog.require('ol.reproj');\ngoog.require('ol.reproj.Triangulation');\n\n\n/**\n * @classdesc\n * Class encapsulating single reprojected tile.\n * See {@link ol.source.TileImage}.\n *\n * @constructor\n * @extends {ol.Tile}\n * @param {ol.proj.Projection} sourceProj Source projection.\n * @param {ol.tilegrid.TileGrid} sourceTileGrid Source tile grid.\n * @param {ol.proj.Projection} targetProj Target projection.\n * @param {ol.tilegrid.TileGrid} targetTileGrid Target tile grid.\n * @param {ol.TileCoord} tileCoord Coordinate of the tile.\n * @param {ol.TileCoord} wrappedTileCoord Coordinate of the tile wrapped in X.\n * @param {number} pixelRatio Pixel ratio.\n * @param {number} gutter Gutter of the source tiles.\n * @param {ol.ReprojTileFunctionType} getTileFunction\n *     Function returning source tiles (z, x, y, pixelRatio).\n * @param {number=} opt_errorThreshold Acceptable reprojection error (in px).\n * @param {boolean=} opt_renderEdges Render reprojection edges.\n */\nol.reproj.Tile = function(sourceProj, sourceTileGrid,\n    targetProj, targetTileGrid, tileCoord, wrappedTileCoord,\n    pixelRatio, gutter, getTileFunction,\n    opt_errorThreshold,\n    opt_renderEdges) {\n  ol.Tile.call(this, tileCoord, ol.Tile.State.IDLE);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.renderEdges_ = opt_renderEdges !== undefined ? opt_renderEdges : false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.pixelRatio_ = pixelRatio;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.gutter_ = gutter;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = null;\n\n  /**\n   * @private\n   * @type {ol.tilegrid.TileGrid}\n   */\n  this.sourceTileGrid_ = sourceTileGrid;\n\n  /**\n   * @private\n   * @type {ol.tilegrid.TileGrid}\n   */\n  this.targetTileGrid_ = targetTileGrid;\n\n  /**\n   * @private\n   * @type {ol.TileCoord}\n   */\n  this.wrappedTileCoord_ = wrappedTileCoord ? wrappedTileCoord : tileCoord;\n\n  /**\n   * @private\n   * @type {!Array.<ol.Tile>}\n   */\n  this.sourceTiles_ = [];\n\n  /**\n   * @private\n   * @type {Array.<ol.EventsKey>}\n   */\n  this.sourcesListenerKeys_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.sourceZ_ = 0;\n\n  var targetExtent = targetTileGrid.getTileCoordExtent(this.wrappedTileCoord_);\n  var maxTargetExtent = this.targetTileGrid_.getExtent();\n  var maxSourceExtent = this.sourceTileGrid_.getExtent();\n\n  var limitedTargetExtent = maxTargetExtent ?\n      ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent;\n\n  if (ol.extent.getArea(limitedTargetExtent) === 0) {\n    // Tile is completely outside range -> EMPTY\n    // TODO: is it actually correct that the source even creates the tile ?\n    this.state = ol.Tile.State.EMPTY;\n    return;\n  }\n\n  var sourceProjExtent = sourceProj.getExtent();\n  if (sourceProjExtent) {\n    if (!maxSourceExtent) {\n      maxSourceExtent = sourceProjExtent;\n    } else {\n      maxSourceExtent = ol.extent.getIntersection(\n          maxSourceExtent, sourceProjExtent);\n    }\n  }\n\n  var targetResolution = targetTileGrid.getResolution(\n      this.wrappedTileCoord_[0]);\n\n  var targetCenter = ol.extent.getCenter(limitedTargetExtent);\n  var sourceResolution = ol.reproj.calculateSourceResolution(\n      sourceProj, targetProj, targetCenter, targetResolution);\n\n  if (!isFinite(sourceResolution) || sourceResolution <= 0) {\n    // invalid sourceResolution -> EMPTY\n    // probably edges of the projections when no extent is defined\n    this.state = ol.Tile.State.EMPTY;\n    return;\n  }\n\n  var errorThresholdInPixels = opt_errorThreshold !== undefined ?\n      opt_errorThreshold : ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD;\n\n  /**\n   * @private\n   * @type {!ol.reproj.Triangulation}\n   */\n  this.triangulation_ = new ol.reproj.Triangulation(\n      sourceProj, targetProj, limitedTargetExtent, maxSourceExtent,\n      sourceResolution * errorThresholdInPixels);\n\n  if (this.triangulation_.getTriangles().length === 0) {\n    // no valid triangles -> EMPTY\n    this.state = ol.Tile.State.EMPTY;\n    return;\n  }\n\n  this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution);\n  var sourceExtent = this.triangulation_.calculateSourceExtent();\n\n  if (maxSourceExtent) {\n    if (sourceProj.canWrapX()) {\n      sourceExtent[1] = ol.math.clamp(\n          sourceExtent[1], maxSourceExtent[1], maxSourceExtent[3]);\n      sourceExtent[3] = ol.math.clamp(\n          sourceExtent[3], maxSourceExtent[1], maxSourceExtent[3]);\n    } else {\n      sourceExtent = ol.extent.getIntersection(sourceExtent, maxSourceExtent);\n    }\n  }\n\n  if (!ol.extent.getArea(sourceExtent)) {\n    this.state = ol.Tile.State.EMPTY;\n  } else {\n    var sourceRange = sourceTileGrid.getTileRangeForExtentAndZ(\n        sourceExtent, this.sourceZ_);\n\n    var tilesRequired = sourceRange.getWidth() * sourceRange.getHeight();\n    if (ol.DEBUG && !(tilesRequired < ol.RASTER_REPROJECTION_MAX_SOURCE_TILES)) {\n      console.assert(false, 'reasonable number of tiles is required');\n      this.state = ol.Tile.State.ERROR;\n      return;\n    }\n    for (var srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) {\n      for (var srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) {\n        var tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio);\n        if (tile) {\n          this.sourceTiles_.push(tile);\n        }\n      }\n    }\n\n    if (this.sourceTiles_.length === 0) {\n      this.state = ol.Tile.State.EMPTY;\n    }\n  }\n};\nol.inherits(ol.reproj.Tile, ol.Tile);\n\n\n/**\n * @inheritDoc\n */\nol.reproj.Tile.prototype.disposeInternal = function() {\n  if (this.state == ol.Tile.State.LOADING) {\n    this.unlistenSources_();\n  }\n  ol.Tile.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * @inheritDoc\n */\nol.reproj.Tile.prototype.getImage = function() {\n  return this.canvas_;\n};\n\n\n/**\n * @private\n */\nol.reproj.Tile.prototype.reproject_ = function() {\n  var sources = [];\n  this.sourceTiles_.forEach(function(tile, i, arr) {\n    if (tile && tile.getState() == ol.Tile.State.LOADED) {\n      sources.push({\n        extent: this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord),\n        image: tile.getImage()\n      });\n    }\n  }, this);\n  this.sourceTiles_.length = 0;\n\n  if (sources.length === 0) {\n    this.state = ol.Tile.State.ERROR;\n  } else {\n    var z = this.wrappedTileCoord_[0];\n    var size = this.targetTileGrid_.getTileSize(z);\n    var width = typeof size === 'number' ? size : size[0];\n    var height = typeof size === 'number' ? size : size[1];\n    var targetResolution = this.targetTileGrid_.getResolution(z);\n    var sourceResolution = this.sourceTileGrid_.getResolution(this.sourceZ_);\n\n    var targetExtent = this.targetTileGrid_.getTileCoordExtent(\n        this.wrappedTileCoord_);\n    this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_,\n        sourceResolution, this.sourceTileGrid_.getExtent(),\n        targetResolution, targetExtent, this.triangulation_, sources,\n        this.gutter_, this.renderEdges_);\n\n    this.state = ol.Tile.State.LOADED;\n  }\n  this.changed();\n};\n\n\n/**\n * @inheritDoc\n */\nol.reproj.Tile.prototype.load = function() {\n  if (this.state == ol.Tile.State.IDLE) {\n    this.state = ol.Tile.State.LOADING;\n    this.changed();\n\n    var leftToLoad = 0;\n\n    ol.DEBUG && console.assert(!this.sourcesListenerKeys_,\n        'this.sourcesListenerKeys_ should be null');\n\n    this.sourcesListenerKeys_ = [];\n    this.sourceTiles_.forEach(function(tile, i, arr) {\n      var state = tile.getState();\n      if (state == ol.Tile.State.IDLE || state == ol.Tile.State.LOADING) {\n        leftToLoad++;\n\n        var sourceListenKey;\n        sourceListenKey = ol.events.listen(tile, ol.events.EventType.CHANGE,\n            function(e) {\n              var state = tile.getState();\n              if (state == ol.Tile.State.LOADED ||\n                  state == ol.Tile.State.ERROR ||\n                  state == ol.Tile.State.EMPTY) {\n                ol.events.unlistenByKey(sourceListenKey);\n                leftToLoad--;\n                ol.DEBUG && console.assert(leftToLoad >= 0,\n                    'leftToLoad should not be negative');\n                if (leftToLoad === 0) {\n                  this.unlistenSources_();\n                  this.reproject_();\n                }\n              }\n            }, this);\n        this.sourcesListenerKeys_.push(sourceListenKey);\n      }\n    }, this);\n\n    this.sourceTiles_.forEach(function(tile, i, arr) {\n      var state = tile.getState();\n      if (state == ol.Tile.State.IDLE) {\n        tile.load();\n      }\n    });\n\n    if (leftToLoad === 0) {\n      setTimeout(this.reproject_.bind(this), 0);\n    }\n  }\n};\n\n\n/**\n * @private\n */\nol.reproj.Tile.prototype.unlistenSources_ = function() {\n  this.sourcesListenerKeys_.forEach(ol.events.unlistenByKey);\n  this.sourcesListenerKeys_ = null;\n};\n\ngoog.provide('ol.TileUrlFunction');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.math');\ngoog.require('ol.tilecoord');\n\n\n/**\n * @param {string} template Template.\n * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.\n * @return {ol.TileUrlFunctionType} Tile URL function.\n */\nol.TileUrlFunction.createFromTemplate = function(template, tileGrid) {\n  var zRegEx = /\\{z\\}/g;\n  var xRegEx = /\\{x\\}/g;\n  var yRegEx = /\\{y\\}/g;\n  var dashYRegEx = /\\{-y\\}/g;\n  return (\n      /**\n       * @param {ol.TileCoord} tileCoord Tile Coordinate.\n       * @param {number} pixelRatio Pixel ratio.\n       * @param {ol.proj.Projection} projection Projection.\n       * @return {string|undefined} Tile URL.\n       */\n      function(tileCoord, pixelRatio, projection) {\n        if (!tileCoord) {\n          return undefined;\n        } else {\n          return template.replace(zRegEx, tileCoord[0].toString())\n              .replace(xRegEx, tileCoord[1].toString())\n              .replace(yRegEx, function() {\n                var y = -tileCoord[2] - 1;\n                return y.toString();\n              })\n              .replace(dashYRegEx, function() {\n                var z = tileCoord[0];\n                var range = tileGrid.getFullTileRange(z);\n                ol.asserts.assert(range, 55); // The {-y} placeholder requires a tile grid with extent\n                var y = range.getHeight() + tileCoord[2];\n                return y.toString();\n              });\n        }\n      });\n};\n\n\n/**\n * @param {Array.<string>} templates Templates.\n * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.\n * @return {ol.TileUrlFunctionType} Tile URL function.\n */\nol.TileUrlFunction.createFromTemplates = function(templates, tileGrid) {\n  var len = templates.length;\n  var tileUrlFunctions = new Array(len);\n  for (var i = 0; i < len; ++i) {\n    tileUrlFunctions[i] = ol.TileUrlFunction.createFromTemplate(\n        templates[i], tileGrid);\n  }\n  return ol.TileUrlFunction.createFromTileUrlFunctions(tileUrlFunctions);\n};\n\n\n/**\n * @param {Array.<ol.TileUrlFunctionType>} tileUrlFunctions Tile URL Functions.\n * @return {ol.TileUrlFunctionType} Tile URL function.\n */\nol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) {\n  ol.DEBUG && console.assert(tileUrlFunctions.length > 0,\n      'Length of tile url functions should be greater than 0');\n  if (tileUrlFunctions.length === 1) {\n    return tileUrlFunctions[0];\n  }\n  return (\n      /**\n       * @param {ol.TileCoord} tileCoord Tile Coordinate.\n       * @param {number} pixelRatio Pixel ratio.\n       * @param {ol.proj.Projection} projection Projection.\n       * @return {string|undefined} Tile URL.\n       */\n      function(tileCoord, pixelRatio, projection) {\n        if (!tileCoord) {\n          return undefined;\n        } else {\n          var h = ol.tilecoord.hash(tileCoord);\n          var index = ol.math.modulo(h, tileUrlFunctions.length);\n          return tileUrlFunctions[index](tileCoord, pixelRatio, projection);\n        }\n      });\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @return {string|undefined} Tile URL.\n */\nol.TileUrlFunction.nullTileUrlFunction = function(tileCoord, pixelRatio, projection) {\n  return undefined;\n};\n\n\n/**\n * @param {string} url URL.\n * @return {Array.<string>} Array of urls.\n */\nol.TileUrlFunction.expandUrl = function(url) {\n  var urls = [];\n  var match = /\\{([a-z])-([a-z])\\}/.exec(url);\n  if (match) {\n    // char range\n    var startCharCode = match[1].charCodeAt(0);\n    var stopCharCode = match[2].charCodeAt(0);\n    var charCode;\n    for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {\n      urls.push(url.replace(match[0], String.fromCharCode(charCode)));\n    }\n    return urls;\n  }\n  match = match = /\\{(\\d+)-(\\d+)\\}/.exec(url);\n  if (match) {\n    // number range\n    var stop = parseInt(match[2], 10);\n    for (var i = parseInt(match[1], 10); i <= stop; i++) {\n      urls.push(url.replace(match[0], i.toString()));\n    }\n    return urls;\n  }\n  urls.push(url);\n  return urls;\n};\n\ngoog.provide('ol.TileCache');\n\ngoog.require('ol');\ngoog.require('ol.structs.LRUCache');\n\n\n/**\n * @constructor\n * @extends {ol.structs.LRUCache.<ol.Tile>}\n * @param {number=} opt_highWaterMark High water mark.\n * @struct\n */\nol.TileCache = function(opt_highWaterMark) {\n\n  ol.structs.LRUCache.call(this);\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.highWaterMark_ = opt_highWaterMark !== undefined ? opt_highWaterMark : 2048;\n\n};\nol.inherits(ol.TileCache, ol.structs.LRUCache);\n\n\n/**\n * @return {boolean} Can expire cache.\n */\nol.TileCache.prototype.canExpireCache = function() {\n  return this.getCount() > this.highWaterMark_;\n};\n\n\n/**\n * @param {Object.<string, ol.TileRange>} usedTiles Used tiles.\n */\nol.TileCache.prototype.expireCache = function(usedTiles) {\n  var tile, zKey;\n  while (this.canExpireCache()) {\n    tile = this.peekLast();\n    zKey = tile.tileCoord[0].toString();\n    if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) {\n      break;\n    } else {\n      this.pop().dispose();\n    }\n  }\n};\n\ngoog.provide('ol.source.Tile');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.TileCache');\ngoog.require('ol.events.Event');\ngoog.require('ol.proj');\ngoog.require('ol.size');\ngoog.require('ol.source.Source');\ngoog.require('ol.tilecoord');\ngoog.require('ol.tilegrid');\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for sources providing images divided into a tile grid.\n *\n * @constructor\n * @extends {ol.source.Source}\n * @param {ol.SourceTileOptions} options Tile source options.\n * @api\n */\nol.source.Tile = function(options) {\n\n  ol.source.Source.call(this, {\n    attributions: options.attributions,\n    extent: options.extent,\n    logo: options.logo,\n    projection: options.projection,\n    state: options.state,\n    wrapX: options.wrapX\n  });\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.opaque_ = options.opaque !== undefined ? options.opaque : false;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.tilePixelRatio_ = options.tilePixelRatio !== undefined ?\n      options.tilePixelRatio : 1;\n\n  /**\n   * @protected\n   * @type {ol.tilegrid.TileGrid}\n   */\n  this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null;\n\n  /**\n   * @protected\n   * @type {ol.TileCache}\n   */\n  this.tileCache = new ol.TileCache(options.cacheSize);\n\n  /**\n   * @protected\n   * @type {ol.Size}\n   */\n  this.tmpSize = [0, 0];\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.key_ = '';\n\n};\nol.inherits(ol.source.Tile, ol.source.Source);\n\n\n/**\n * @return {boolean} Can expire cache.\n */\nol.source.Tile.prototype.canExpireCache = function() {\n  return this.tileCache.canExpireCache();\n};\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @param {Object.<string, ol.TileRange>} usedTiles Used tiles.\n */\nol.source.Tile.prototype.expireCache = function(projection, usedTiles) {\n  var tileCache = this.getTileCacheForProjection(projection);\n  if (tileCache) {\n    tileCache.expireCache(usedTiles);\n  }\n};\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @param {number} z Zoom level.\n * @param {ol.TileRange} tileRange Tile range.\n * @param {function(ol.Tile):(boolean|undefined)} callback Called with each\n *     loaded tile.  If the callback returns `false`, the tile will not be\n *     considered loaded.\n * @return {boolean} The tile range is fully covered with loaded tiles.\n */\nol.source.Tile.prototype.forEachLoadedTile = function(projection, z, tileRange, callback) {\n  var tileCache = this.getTileCacheForProjection(projection);\n  if (!tileCache) {\n    return false;\n  }\n\n  var covered = true;\n  var tile, tileCoordKey, loaded;\n  for (var x = tileRange.minX; x <= tileRange.maxX; ++x) {\n    for (var y = tileRange.minY; y <= tileRange.maxY; ++y) {\n      tileCoordKey = this.getKeyZXY(z, x, y);\n      loaded = false;\n      if (tileCache.containsKey(tileCoordKey)) {\n        tile = /** @type {!ol.Tile} */ (tileCache.get(tileCoordKey));\n        loaded = tile.getState() === ol.Tile.State.LOADED;\n        if (loaded) {\n          loaded = (callback(tile) !== false);\n        }\n      }\n      if (!loaded) {\n        covered = false;\n      }\n    }\n  }\n  return covered;\n};\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @return {number} Gutter.\n */\nol.source.Tile.prototype.getGutter = function(projection) {\n  return 0;\n};\n\n\n/**\n * Return the key to be used for all tiles in the source.\n * @return {string} The key for all tiles.\n * @protected\n */\nol.source.Tile.prototype.getKey = function() {\n  return this.key_;\n};\n\n\n/**\n * Set the value to be used as the key for all tiles in the source.\n * @param {string} key The key for tiles.\n * @protected\n */\nol.source.Tile.prototype.setKey = function(key) {\n  if (this.key_ !== key) {\n    this.key_ = key;\n    this.changed();\n  }\n};\n\n\n/**\n * @param {number} z Z.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {string} Key.\n * @protected\n */\nol.source.Tile.prototype.getKeyZXY = ol.tilecoord.getKeyZXY;\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @return {boolean} Opaque.\n */\nol.source.Tile.prototype.getOpaque = function(projection) {\n  return this.opaque_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.Tile.prototype.getResolutions = function() {\n  return this.tileGrid.getResolutions();\n};\n\n\n/**\n * @abstract\n * @param {number} z Tile coordinate z.\n * @param {number} x Tile coordinate x.\n * @param {number} y Tile coordinate y.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @return {!ol.Tile} Tile.\n */\nol.source.Tile.prototype.getTile = function(z, x, y, pixelRatio, projection) {};\n\n\n/**\n * Return the tile grid of the tile source.\n * @return {ol.tilegrid.TileGrid} Tile grid.\n * @api stable\n */\nol.source.Tile.prototype.getTileGrid = function() {\n  return this.tileGrid;\n};\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @return {!ol.tilegrid.TileGrid} Tile grid.\n */\nol.source.Tile.prototype.getTileGridForProjection = function(projection) {\n  if (!this.tileGrid) {\n    return ol.tilegrid.getForProjection(projection);\n  } else {\n    return this.tileGrid;\n  }\n};\n\n\n/**\n * @param {ol.proj.Projection} projection Projection.\n * @return {ol.TileCache} Tile cache.\n * @protected\n */\nol.source.Tile.prototype.getTileCacheForProjection = function(projection) {\n  var thisProj = this.getProjection();\n  if (thisProj && !ol.proj.equivalent(thisProj, projection)) {\n    return null;\n  } else {\n    return this.tileCache;\n  }\n};\n\n\n/**\n * Get the tile pixel ratio for this source. Subclasses may override this\n * method, which is meant to return a supported pixel ratio that matches the\n * provided `opt_pixelRatio` as close as possible. When no `opt_pixelRatio` is\n * provided, it is meant to return `this.tilePixelRatio_`.\n * @param {number=} opt_pixelRatio Pixel ratio.\n * @return {number} Tile pixel ratio.\n */\nol.source.Tile.prototype.getTilePixelRatio = function(opt_pixelRatio) {\n  return this.tilePixelRatio_;\n};\n\n\n/**\n * @param {number} z Z.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @return {ol.Size} Tile size.\n */\nol.source.Tile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {\n  var tileGrid = this.getTileGridForProjection(projection);\n  var tilePixelRatio = this.getTilePixelRatio(pixelRatio);\n  var tileSize = ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize);\n  if (tilePixelRatio == 1) {\n    return tileSize;\n  } else {\n    return ol.size.scale(tileSize, tilePixelRatio, this.tmpSize);\n  }\n};\n\n\n/**\n * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate\n * is outside the resolution and extent range of the tile grid, `null` will be\n * returned.\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.proj.Projection=} opt_projection Projection.\n * @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or\n *     null if no tile URL should be created for the passed `tileCoord`.\n */\nol.source.Tile.prototype.getTileCoordForTileUrlFunction = function(tileCoord, opt_projection) {\n  var projection = opt_projection !== undefined ?\n      opt_projection : this.getProjection();\n  var tileGrid = this.getTileGridForProjection(projection);\n  if (this.getWrapX() && projection.isGlobal()) {\n    tileCoord = ol.tilegrid.wrapX(tileGrid, tileCoord, projection);\n  }\n  return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.Tile.prototype.refresh = function() {\n  this.tileCache.clear();\n  this.changed();\n};\n\n\n/**\n * Marks a tile coord as being used, without triggering a load.\n * @param {number} z Tile coordinate z.\n * @param {number} x Tile coordinate x.\n * @param {number} y Tile coordinate y.\n * @param {ol.proj.Projection} projection Projection.\n */\nol.source.Tile.prototype.useTile = ol.nullFunction;\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.source.Tile} instances are instances of this\n * type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.source.Tile.Event}\n * @param {string} type Type.\n * @param {ol.Tile} tile The tile.\n */\nol.source.Tile.Event = function(type, tile) {\n\n  ol.events.Event.call(this, type);\n\n  /**\n   * The tile related to the event.\n   * @type {ol.Tile}\n   * @api\n   */\n  this.tile = tile;\n\n};\nol.inherits(ol.source.Tile.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.source.Tile.EventType = {\n\n  /**\n   * Triggered when a tile starts loading.\n   * @event ol.source.Tile.Event#tileloadstart\n   * @api stable\n   */\n  TILELOADSTART: 'tileloadstart',\n\n  /**\n   * Triggered when a tile finishes loading.\n   * @event ol.source.Tile.Event#tileloadend\n   * @api stable\n   */\n  TILELOADEND: 'tileloadend',\n\n  /**\n   * Triggered if tile loading results in an error.\n   * @event ol.source.Tile.Event#tileloaderror\n   * @api stable\n   */\n  TILELOADERROR: 'tileloaderror'\n\n};\n\ngoog.provide('ol.source.UrlTile');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.TileUrlFunction');\ngoog.require('ol.source.Tile');\n\n\n/**\n * @classdesc\n * Base class for sources providing tiles divided into a tile grid over http.\n *\n * @constructor\n * @fires ol.source.Tile.Event\n * @extends {ol.source.Tile}\n * @param {ol.SourceUrlTileOptions} options Image tile options.\n */\nol.source.UrlTile = function(options) {\n\n  ol.source.Tile.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    extent: options.extent,\n    logo: options.logo,\n    opaque: options.opaque,\n    projection: options.projection,\n    state: options.state,\n    tileGrid: options.tileGrid,\n    tilePixelRatio: options.tilePixelRatio,\n    wrapX: options.wrapX\n  });\n\n  /**\n   * @protected\n   * @type {ol.TileLoadFunctionType}\n   */\n  this.tileLoadFunction = options.tileLoadFunction;\n\n  /**\n   * @protected\n   * @type {ol.TileUrlFunctionType}\n   */\n  this.tileUrlFunction = this.fixedTileUrlFunction ?\n      this.fixedTileUrlFunction.bind(this) :\n      ol.TileUrlFunction.nullTileUrlFunction;\n\n  /**\n   * @protected\n   * @type {!Array.<string>|null}\n   */\n  this.urls = null;\n\n  if (options.urls) {\n    this.setUrls(options.urls);\n  } else if (options.url) {\n    this.setUrl(options.url);\n  }\n  if (options.tileUrlFunction) {\n    this.setTileUrlFunction(options.tileUrlFunction);\n  }\n\n};\nol.inherits(ol.source.UrlTile, ol.source.Tile);\n\n\n/**\n * @type {ol.TileUrlFunctionType|undefined}\n * @protected\n */\nol.source.UrlTile.prototype.fixedTileUrlFunction;\n\n/**\n * Return the tile load function of the source.\n * @return {ol.TileLoadFunctionType} TileLoadFunction\n * @api\n */\nol.source.UrlTile.prototype.getTileLoadFunction = function() {\n  return this.tileLoadFunction;\n};\n\n\n/**\n * Return the tile URL function of the source.\n * @return {ol.TileUrlFunctionType} TileUrlFunction\n * @api\n */\nol.source.UrlTile.prototype.getTileUrlFunction = function() {\n  return this.tileUrlFunction;\n};\n\n\n/**\n * Return the URLs used for this source.\n * When a tileUrlFunction is used instead of url or urls,\n * null will be returned.\n * @return {!Array.<string>|null} URLs.\n * @api\n */\nol.source.UrlTile.prototype.getUrls = function() {\n  return this.urls;\n};\n\n\n/**\n * Handle tile change events.\n * @param {ol.events.Event} event Event.\n * @protected\n */\nol.source.UrlTile.prototype.handleTileChange = function(event) {\n  var tile = /** @type {ol.Tile} */ (event.target);\n  switch (tile.getState()) {\n    case ol.Tile.State.LOADING:\n      this.dispatchEvent(\n          new ol.source.Tile.Event(ol.source.Tile.EventType.TILELOADSTART, tile));\n      break;\n    case ol.Tile.State.LOADED:\n      this.dispatchEvent(\n          new ol.source.Tile.Event(ol.source.Tile.EventType.TILELOADEND, tile));\n      break;\n    case ol.Tile.State.ERROR:\n      this.dispatchEvent(\n          new ol.source.Tile.Event(ol.source.Tile.EventType.TILELOADERROR, tile));\n      break;\n    default:\n      // pass\n  }\n};\n\n\n/**\n * Set the tile load function of the source.\n * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.\n * @api\n */\nol.source.UrlTile.prototype.setTileLoadFunction = function(tileLoadFunction) {\n  this.tileCache.clear();\n  this.tileLoadFunction = tileLoadFunction;\n  this.changed();\n};\n\n\n/**\n * Set the tile URL function of the source.\n * @param {ol.TileUrlFunctionType} tileUrlFunction Tile URL function.\n * @param {string=} opt_key Optional new tile key for the source.\n * @api\n */\nol.source.UrlTile.prototype.setTileUrlFunction = function(tileUrlFunction, opt_key) {\n  this.tileUrlFunction = tileUrlFunction;\n  if (typeof opt_key !== 'undefined') {\n    this.setKey(opt_key);\n  } else {\n    this.changed();\n  }\n};\n\n\n/**\n * Set the URL to use for requests.\n * @param {string} url URL.\n * @api stable\n */\nol.source.UrlTile.prototype.setUrl = function(url) {\n  var urls = this.urls = ol.TileUrlFunction.expandUrl(url);\n  this.setTileUrlFunction(this.fixedTileUrlFunction ?\n      this.fixedTileUrlFunction.bind(this) :\n      ol.TileUrlFunction.createFromTemplates(urls, this.tileGrid), url);\n};\n\n\n/**\n * Set the URLs to use for requests.\n * @param {Array.<string>} urls URLs.\n * @api stable\n */\nol.source.UrlTile.prototype.setUrls = function(urls) {\n  this.urls = urls;\n  var key = urls.join('\\n');\n  this.setTileUrlFunction(this.fixedTileUrlFunction ?\n      this.fixedTileUrlFunction.bind(this) :\n      ol.TileUrlFunction.createFromTemplates(urls, this.tileGrid), key);\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.UrlTile.prototype.useTile = function(z, x, y) {\n  var tileCoordKey = this.getKeyZXY(z, x, y);\n  if (this.tileCache.containsKey(tileCoordKey)) {\n    this.tileCache.get(tileCoordKey);\n  }\n};\n\ngoog.provide('ol.source.TileImage');\n\ngoog.require('ol');\ngoog.require('ol.ImageTile');\ngoog.require('ol.Tile');\ngoog.require('ol.TileCache');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.proj');\ngoog.require('ol.reproj.Tile');\ngoog.require('ol.source.UrlTile');\ngoog.require('ol.tilegrid');\n\n\n/**\n * @classdesc\n * Base class for sources providing images divided into a tile grid.\n *\n * @constructor\n * @fires ol.source.Tile.Event\n * @extends {ol.source.UrlTile}\n * @param {olx.source.TileImageOptions} options Image tile options.\n * @api\n */\nol.source.TileImage = function(options) {\n\n  ol.source.UrlTile.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    extent: options.extent,\n    logo: options.logo,\n    opaque: options.opaque,\n    projection: options.projection,\n    state: options.state,\n    tileGrid: options.tileGrid,\n    tileLoadFunction: options.tileLoadFunction ?\n        options.tileLoadFunction : ol.source.TileImage.defaultTileLoadFunction,\n    tilePixelRatio: options.tilePixelRatio,\n    tileUrlFunction: options.tileUrlFunction,\n    url: options.url,\n    urls: options.urls,\n    wrapX: options.wrapX\n  });\n\n  /**\n   * @protected\n   * @type {?string}\n   */\n  this.crossOrigin =\n      options.crossOrigin !== undefined ? options.crossOrigin : null;\n\n  /**\n   * @protected\n   * @type {function(new: ol.ImageTile, ol.TileCoord, ol.Tile.State, string,\n   *        ?string, ol.TileLoadFunctionType)}\n   */\n  this.tileClass = options.tileClass !== undefined ?\n      options.tileClass : ol.ImageTile;\n\n  /**\n   * @protected\n   * @type {Object.<string, ol.TileCache>}\n   */\n  this.tileCacheForProjection = {};\n\n  /**\n   * @protected\n   * @type {Object.<string, ol.tilegrid.TileGrid>}\n   */\n  this.tileGridForProjection = {};\n\n  /**\n   * @private\n   * @type {number|undefined}\n   */\n  this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.renderReprojectionEdges_ = false;\n};\nol.inherits(ol.source.TileImage, ol.source.UrlTile);\n\n\n/**\n * @inheritDoc\n */\nol.source.TileImage.prototype.canExpireCache = function() {\n  if (!ol.ENABLE_RASTER_REPROJECTION) {\n    return ol.source.UrlTile.prototype.canExpireCache.call(this);\n  }\n  if (this.tileCache.canExpireCache()) {\n    return true;\n  } else {\n    for (var key in this.tileCacheForProjection) {\n      if (this.tileCacheForProjection[key].canExpireCache()) {\n        return true;\n      }\n    }\n  }\n  return false;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileImage.prototype.expireCache = function(projection, usedTiles) {\n  if (!ol.ENABLE_RASTER_REPROJECTION) {\n    ol.source.UrlTile.prototype.expireCache.call(this, projection, usedTiles);\n    return;\n  }\n  var usedTileCache = this.getTileCacheForProjection(projection);\n\n  this.tileCache.expireCache(this.tileCache == usedTileCache ? usedTiles : {});\n  for (var id in this.tileCacheForProjection) {\n    var tileCache = this.tileCacheForProjection[id];\n    tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {});\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileImage.prototype.getGutter = function(projection) {\n  if (ol.ENABLE_RASTER_REPROJECTION &&\n      this.getProjection() && projection &&\n      !ol.proj.equivalent(this.getProjection(), projection)) {\n    return 0;\n  } else {\n    return this.getGutterInternal();\n  }\n};\n\n\n/**\n * @protected\n * @return {number} Gutter.\n */\nol.source.TileImage.prototype.getGutterInternal = function() {\n  return 0;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileImage.prototype.getOpaque = function(projection) {\n  if (ol.ENABLE_RASTER_REPROJECTION &&\n      this.getProjection() && projection &&\n      !ol.proj.equivalent(this.getProjection(), projection)) {\n    return false;\n  } else {\n    return ol.source.UrlTile.prototype.getOpaque.call(this, projection);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileImage.prototype.getTileGridForProjection = function(projection) {\n  if (!ol.ENABLE_RASTER_REPROJECTION) {\n    return ol.source.UrlTile.prototype.getTileGridForProjection.call(this, projection);\n  }\n  var thisProj = this.getProjection();\n  if (this.tileGrid &&\n      (!thisProj || ol.proj.equivalent(thisProj, projection))) {\n    return this.tileGrid;\n  } else {\n    var projKey = ol.getUid(projection).toString();\n    if (!(projKey in this.tileGridForProjection)) {\n      this.tileGridForProjection[projKey] =\n          ol.tilegrid.getForProjection(projection);\n    }\n    return /** @type {!ol.tilegrid.TileGrid} */ (this.tileGridForProjection[projKey]);\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileImage.prototype.getTileCacheForProjection = function(projection) {\n  if (!ol.ENABLE_RASTER_REPROJECTION) {\n    return ol.source.UrlTile.prototype.getTileCacheForProjection.call(this, projection);\n  }\n  var thisProj = this.getProjection();\n  if (!thisProj || ol.proj.equivalent(thisProj, projection)) {\n    return this.tileCache;\n  } else {\n    var projKey = ol.getUid(projection).toString();\n    if (!(projKey in this.tileCacheForProjection)) {\n      this.tileCacheForProjection[projKey] = new ol.TileCache();\n    }\n    return this.tileCacheForProjection[projKey];\n  }\n};\n\n\n/**\n * @param {number} z Tile coordinate z.\n * @param {number} x Tile coordinate x.\n * @param {number} y Tile coordinate y.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @param {string} key The key set on the tile.\n * @return {!ol.Tile} Tile.\n * @private\n */\nol.source.TileImage.prototype.createTile_ = function(z, x, y, pixelRatio, projection, key) {\n  var tileCoord = [z, x, y];\n  var urlTileCoord = this.getTileCoordForTileUrlFunction(\n      tileCoord, projection);\n  var tileUrl = urlTileCoord ?\n      this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;\n  var tile = new this.tileClass(\n      tileCoord,\n      tileUrl !== undefined ? ol.Tile.State.IDLE : ol.Tile.State.EMPTY,\n      tileUrl !== undefined ? tileUrl : '',\n      this.crossOrigin,\n      this.tileLoadFunction);\n  tile.key = key;\n  ol.events.listen(tile, ol.events.EventType.CHANGE,\n      this.handleTileChange, this);\n  return tile;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileImage.prototype.getTile = function(z, x, y, pixelRatio, projection) {\n  if (!ol.ENABLE_RASTER_REPROJECTION ||\n      !this.getProjection() ||\n      !projection ||\n      ol.proj.equivalent(this.getProjection(), projection)) {\n    return this.getTileInternal(z, x, y, pixelRatio, /** @type {!ol.proj.Projection} */ (projection));\n  } else {\n    var cache = this.getTileCacheForProjection(projection);\n    var tileCoord = [z, x, y];\n    var tile;\n    var tileCoordKey = this.getKeyZXY.apply(this, tileCoord);\n    if (cache.containsKey(tileCoordKey)) {\n      tile = /** @type {!ol.Tile} */ (cache.get(tileCoordKey));\n    }\n    var key = this.getKey();\n    if (tile && tile.key == key) {\n      return tile;\n    } else {\n      var sourceProjection = /** @type {!ol.proj.Projection} */ (this.getProjection());\n      var sourceTileGrid = this.getTileGridForProjection(sourceProjection);\n      var targetTileGrid = this.getTileGridForProjection(projection);\n      var wrappedTileCoord =\n          this.getTileCoordForTileUrlFunction(tileCoord, projection);\n      var newTile = new ol.reproj.Tile(\n          sourceProjection, sourceTileGrid,\n          projection, targetTileGrid,\n          tileCoord, wrappedTileCoord, this.getTilePixelRatio(pixelRatio),\n          this.getGutterInternal(),\n          function(z, x, y, pixelRatio) {\n            return this.getTileInternal(z, x, y, pixelRatio, sourceProjection);\n          }.bind(this), this.reprojectionErrorThreshold_,\n          this.renderReprojectionEdges_);\n      newTile.key = key;\n\n      if (tile) {\n        newTile.interimTile = tile;\n        cache.replace(tileCoordKey, newTile);\n      } else {\n        cache.set(tileCoordKey, newTile);\n      }\n      return newTile;\n    }\n  }\n};\n\n\n/**\n * @param {number} z Tile coordinate z.\n * @param {number} x Tile coordinate x.\n * @param {number} y Tile coordinate y.\n * @param {number} pixelRatio Pixel ratio.\n * @param {!ol.proj.Projection} projection Projection.\n * @return {!ol.Tile} Tile.\n * @protected\n */\nol.source.TileImage.prototype.getTileInternal = function(z, x, y, pixelRatio, projection) {\n  var tile = null;\n  var tileCoordKey = this.getKeyZXY(z, x, y);\n  var key = this.getKey();\n  if (!this.tileCache.containsKey(tileCoordKey)) {\n    tile = this.createTile_(z, x, y, pixelRatio, projection, key);\n    this.tileCache.set(tileCoordKey, tile);\n  } else {\n    tile = this.tileCache.get(tileCoordKey);\n    if (tile.key != key) {\n      // The source's params changed. If the tile has an interim tile and if we\n      // can use it then we use it. Otherwise we create a new tile.  In both\n      // cases we attempt to assign an interim tile to the new tile.\n      var interimTile = tile;\n      tile = this.createTile_(z, x, y, pixelRatio, projection, key);\n\n      //make the new tile the head of the list,\n      if (interimTile.getState() == ol.Tile.State.IDLE) {\n        //the old tile hasn't begun loading yet, and is now outdated, so we can simply discard it\n        tile.interimTile = interimTile.interimTile;\n      } else {\n        tile.interimTile = interimTile;\n      }\n      tile.refreshInterimChain();\n      this.tileCache.replace(tileCoordKey, tile);\n    }\n  }\n  return tile;\n};\n\n\n/**\n * Sets whether to render reprojection edges or not (usually for debugging).\n * @param {boolean} render Render the edges.\n * @api\n */\nol.source.TileImage.prototype.setRenderReprojectionEdges = function(render) {\n  if (!ol.ENABLE_RASTER_REPROJECTION ||\n      this.renderReprojectionEdges_ == render) {\n    return;\n  }\n  this.renderReprojectionEdges_ = render;\n  for (var id in this.tileCacheForProjection) {\n    this.tileCacheForProjection[id].clear();\n  }\n  this.changed();\n};\n\n\n/**\n * Sets the tile grid to use when reprojecting the tiles to the given\n * projection instead of the default tile grid for the projection.\n *\n * This can be useful when the default tile grid cannot be created\n * (e.g. projection has no extent defined) or\n * for optimization reasons (custom tile size, resolutions, ...).\n *\n * @param {ol.ProjectionLike} projection Projection.\n * @param {ol.tilegrid.TileGrid} tilegrid Tile grid to use for the projection.\n * @api\n */\nol.source.TileImage.prototype.setTileGridForProjection = function(projection, tilegrid) {\n  if (ol.ENABLE_RASTER_REPROJECTION) {\n    var proj = ol.proj.get(projection);\n    if (proj) {\n      var projKey = ol.getUid(proj).toString();\n      if (!(projKey in this.tileGridForProjection)) {\n        this.tileGridForProjection[projKey] = tilegrid;\n      }\n    }\n  }\n};\n\n\n/**\n * @param {ol.ImageTile} imageTile Image tile.\n * @param {string} src Source.\n */\nol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) {\n  imageTile.getImage().src = src;\n};\n\ngoog.provide('ol.source.BingMaps');\n\ngoog.require('ol');\ngoog.require('ol.Attribution');\ngoog.require('ol.TileUrlFunction');\ngoog.require('ol.extent');\ngoog.require('ol.net');\ngoog.require('ol.proj');\ngoog.require('ol.source.State');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.tilecoord');\ngoog.require('ol.tilegrid');\n\n\n/**\n * @classdesc\n * Layer source for Bing Maps tile data.\n *\n * @constructor\n * @extends {ol.source.TileImage}\n * @param {olx.source.BingMapsOptions} options Bing Maps options.\n * @api stable\n */\nol.source.BingMaps = function(options) {\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.hidpi_ = options.hidpi !== undefined ? options.hidpi : false;\n\n  ol.source.TileImage.call(this, {\n    cacheSize: options.cacheSize,\n    crossOrigin: 'anonymous',\n    opaque: true,\n    projection: ol.proj.get('EPSG:3857'),\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    state: ol.source.State.LOADING,\n    tileLoadFunction: options.tileLoadFunction,\n    tilePixelRatio: this.hidpi_ ? 2 : 1,\n    wrapX: options.wrapX !== undefined ? options.wrapX : true\n  });\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.culture_ = options.culture !== undefined ? options.culture : 'en-us';\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.apiKey_ = options.key;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.imagerySet_ = options.imagerySet;\n\n  var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' +\n      this.imagerySet_ +\n      '?uriScheme=https&include=ImageryProviders&key=' + this.apiKey_;\n\n  ol.net.jsonp(url, this.handleImageryMetadataResponse.bind(this), undefined,\n      'jsonp');\n\n};\nol.inherits(ol.source.BingMaps, ol.source.TileImage);\n\n\n/**\n * The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’\n * Terms Of Use.\n * @const\n * @type {ol.Attribution}\n * @api\n */\nol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({\n  html: '<a class=\"ol-attribution-bing-tos\" ' +\n      'href=\"http://www.microsoft.com/maps/product/terms.html\">' +\n      'Terms of Use</a>'\n});\n\n\n/**\n * Get the api key used for this source.\n *\n * @return {string} The api key.\n * @api\n */\nol.source.BingMaps.prototype.getApiKey = function() {\n  return this.apiKey_;\n};\n\n\n/**\n * Get the imagery set associated with this source.\n *\n * @return {string} The imagery set.\n * @api\n */\nol.source.BingMaps.prototype.getImagerySet = function() {\n  return this.imagerySet_;\n};\n\n\n/**\n * @param {BingMapsImageryMetadataResponse} response Response.\n */\nol.source.BingMaps.prototype.handleImageryMetadataResponse = function(response) {\n\n  if (response.statusCode != 200 ||\n      response.statusDescription != 'OK' ||\n      response.authenticationResultCode != 'ValidCredentials' ||\n      response.resourceSets.length != 1 ||\n      response.resourceSets[0].resources.length != 1) {\n    this.setState(ol.source.State.ERROR);\n    return;\n  }\n\n  var brandLogoUri = response.brandLogoUri;\n  if (brandLogoUri.indexOf('https') == -1) {\n    brandLogoUri = brandLogoUri.replace('http', 'https');\n  }\n  //var copyright = response.copyright;  // FIXME do we need to display this?\n  var resource = response.resourceSets[0].resources[0];\n  ol.DEBUG && console.assert(resource.imageWidth == resource.imageHeight,\n      'resource has imageWidth equal to imageHeight, i.e. is square');\n  var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_;\n\n  var sourceProjection = this.getProjection();\n  var extent = ol.tilegrid.extentFromProjection(sourceProjection);\n  var tileSize = resource.imageWidth == resource.imageHeight ?\n      resource.imageWidth : [resource.imageWidth, resource.imageHeight];\n  var tileGrid = ol.tilegrid.createXYZ({\n    extent: extent,\n    minZoom: resource.zoomMin,\n    maxZoom: maxZoom,\n    tileSize: tileSize / this.getTilePixelRatio()\n  });\n  this.tileGrid = tileGrid;\n\n  var culture = this.culture_;\n  var hidpi = this.hidpi_;\n  this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(\n      resource.imageUrlSubdomains.map(function(subdomain) {\n        var quadKeyTileCoord = [0, 0, 0];\n        var imageUrl = resource.imageUrl\n            .replace('{subdomain}', subdomain)\n            .replace('{culture}', culture);\n        return (\n            /**\n             * @param {ol.TileCoord} tileCoord Tile coordinate.\n             * @param {number} pixelRatio Pixel ratio.\n             * @param {ol.proj.Projection} projection Projection.\n             * @return {string|undefined} Tile URL.\n             */\n            function(tileCoord, pixelRatio, projection) {\n              ol.DEBUG && console.assert(ol.proj.equivalent(\n                  projection, sourceProjection),\n                  'projections are equivalent');\n              if (!tileCoord) {\n                return undefined;\n              } else {\n                ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1],\n                    -tileCoord[2] - 1, quadKeyTileCoord);\n                var url = imageUrl;\n                if (hidpi) {\n                  url += '&dpi=d1&device=mobile';\n                }\n                return url.replace('{quadkey}', ol.tilecoord.quadKey(\n                    quadKeyTileCoord));\n              }\n            });\n      }));\n\n  if (resource.imageryProviders) {\n    var transform = ol.proj.getTransformFromProjections(\n        ol.proj.get('EPSG:4326'), this.getProjection());\n\n    var attributions = resource.imageryProviders.map(function(imageryProvider) {\n      var html = imageryProvider.attribution;\n      /** @type {Object.<string, Array.<ol.TileRange>>} */\n      var tileRanges = {};\n      imageryProvider.coverageAreas.forEach(function(coverageArea) {\n        var minZ = coverageArea.zoomMin;\n        var maxZ = Math.min(coverageArea.zoomMax, maxZoom);\n        var bbox = coverageArea.bbox;\n        var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]];\n        var extent = ol.extent.applyTransform(epsg4326Extent, transform);\n        var tileRange, z, zKey;\n        for (z = minZ; z <= maxZ; ++z) {\n          zKey = z.toString();\n          tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);\n          if (zKey in tileRanges) {\n            tileRanges[zKey].push(tileRange);\n          } else {\n            tileRanges[zKey] = [tileRange];\n          }\n        }\n      });\n      return new ol.Attribution({html: html, tileRanges: tileRanges});\n    });\n    attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION);\n    this.setAttributions(attributions);\n  }\n\n  this.setLogo(brandLogoUri);\n\n  this.setState(ol.source.State.READY);\n\n};\n\ngoog.provide('ol.source.XYZ');\n\ngoog.require('ol');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.tilegrid');\n\n\n/**\n * @classdesc\n * Layer source for tile data with URLs in a set XYZ format that are\n * defined in a URL template. By default, this follows the widely-used\n * Google grid where `x` 0 and `y` 0 are in the top left. Grids like\n * TMS where `x` 0 and `y` 0 are in the bottom left can be used by\n * using the `{-y}` placeholder in the URL template, so long as the\n * source does not have a custom tile grid. In this case,\n * {@link ol.source.TileImage} can be used with a `tileUrlFunction`\n * such as:\n *\n *  tileUrlFunction: function(coordinate) {\n *    return 'http://mapserver.com/' + coordinate[0] + '/' +\n *        coordinate[1] + '/' + coordinate[2] + '.png';\n *    }\n *\n *\n * @constructor\n * @extends {ol.source.TileImage}\n * @param {olx.source.XYZOptions=} opt_options XYZ options.\n * @api stable\n */\nol.source.XYZ = function(opt_options) {\n  var options = opt_options || {};\n  var projection = options.projection !== undefined ?\n      options.projection : 'EPSG:3857';\n\n  var tileGrid = options.tileGrid !== undefined ? options.tileGrid :\n      ol.tilegrid.createXYZ({\n        extent: ol.tilegrid.extentFromProjection(projection),\n        maxZoom: options.maxZoom,\n        minZoom: options.minZoom,\n        tileSize: options.tileSize\n      });\n\n  ol.source.TileImage.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: options.crossOrigin,\n    logo: options.logo,\n    opaque: options.opaque,\n    projection: projection,\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    tileGrid: tileGrid,\n    tileLoadFunction: options.tileLoadFunction,\n    tilePixelRatio: options.tilePixelRatio,\n    tileUrlFunction: options.tileUrlFunction,\n    url: options.url,\n    urls: options.urls,\n    wrapX: options.wrapX !== undefined ? options.wrapX : true\n  });\n\n};\nol.inherits(ol.source.XYZ, ol.source.TileImage);\n\ngoog.provide('ol.source.CartoDB');\n\ngoog.require('ol');\ngoog.require('ol.obj');\ngoog.require('ol.source.State');\ngoog.require('ol.source.XYZ');\n\n\n/**\n * @classdesc\n * Layer source for the CartoDB tiles.\n *\n * @constructor\n * @extends {ol.source.XYZ}\n * @param {olx.source.CartoDBOptions} options CartoDB options.\n * @api\n */\nol.source.CartoDB = function(options) {\n\n  /**\n   * @type {string}\n   * @private\n   */\n  this.account_ = options.account;\n\n  /**\n   * @type {string}\n   * @private\n   */\n  this.mapId_ = options.map || '';\n\n  /**\n   * @type {!Object}\n   * @private\n   */\n  this.config_ = options.config || {};\n\n  /**\n   * @type {!Object.<string, CartoDBLayerInfo>}\n   * @private\n   */\n  this.templateCache_ = {};\n\n  ol.source.XYZ.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: options.crossOrigin,\n    logo: options.logo,\n    maxZoom: options.maxZoom !== undefined ? options.maxZoom : 18,\n    minZoom: options.minZoom,\n    projection: options.projection,\n    state: ol.source.State.LOADING,\n    wrapX: options.wrapX\n  });\n  this.initializeMap_();\n};\nol.inherits(ol.source.CartoDB, ol.source.XYZ);\n\n\n/**\n * Returns the current config.\n * @return {!Object} The current configuration.\n * @api\n */\nol.source.CartoDB.prototype.getConfig = function() {\n  return this.config_;\n};\n\n\n/**\n * Updates the carto db config.\n * @param {Object} config a key-value lookup. Values will replace current values\n *     in the config.\n * @api\n */\nol.source.CartoDB.prototype.updateConfig = function(config) {\n  ol.obj.assign(this.config_, config);\n  this.initializeMap_();\n};\n\n\n/**\n * Sets the CartoDB config\n * @param {Object} config In the case of anonymous maps, a CartoDB configuration\n *     object.\n * If using named maps, a key-value lookup with the template parameters.\n * @api\n */\nol.source.CartoDB.prototype.setConfig = function(config) {\n  this.config_ = config || {};\n  this.initializeMap_();\n};\n\n\n/**\n * Issue a request to initialize the CartoDB map.\n * @private\n */\nol.source.CartoDB.prototype.initializeMap_ = function() {\n  var paramHash = JSON.stringify(this.config_);\n  if (this.templateCache_[paramHash]) {\n    this.applyTemplate_(this.templateCache_[paramHash]);\n    return;\n  }\n  var mapUrl = 'https://' + this.account_ + '.cartodb.com/api/v1/map';\n\n  if (this.mapId_) {\n    mapUrl += '/named/' + this.mapId_;\n  }\n\n  var client = new XMLHttpRequest();\n  client.addEventListener('load', this.handleInitResponse_.bind(this, paramHash));\n  client.addEventListener('error', this.handleInitError_.bind(this));\n  client.open('POST', mapUrl);\n  client.setRequestHeader('Content-type', 'application/json');\n  client.send(JSON.stringify(this.config_));\n};\n\n\n/**\n * Handle map initialization response.\n * @param {string} paramHash a hash representing the parameter set that was used\n *     for the request\n * @param {Event} event Event.\n * @private\n */\nol.source.CartoDB.prototype.handleInitResponse_ = function(paramHash, event) {\n  var client = /** @type {XMLHttpRequest} */ (event.target);\n  // status will be 0 for file:// urls\n  if (!client.status || client.status >= 200 && client.status < 300) {\n    var response;\n    try {\n      response = /** @type {CartoDBLayerInfo} */(JSON.parse(client.responseText));\n    } catch (err) {\n      this.setState(ol.source.State.ERROR);\n      return;\n    }\n    this.applyTemplate_(response);\n    this.templateCache_[paramHash] = response;\n    this.setState(ol.source.State.READY);\n  } else {\n    this.setState(ol.source.State.ERROR);\n  }\n};\n\n\n/**\n * @private\n * @param {Event} event Event.\n */\nol.source.CartoDB.prototype.handleInitError_ = function(event) {\n  this.setState(ol.source.State.ERROR);\n};\n\n\n/**\n * Apply the new tile urls returned by carto db\n * @param {CartoDBLayerInfo} data Result of carto db call.\n * @private\n */\nol.source.CartoDB.prototype.applyTemplate_ = function(data) {\n  var tilesUrl = 'https://' + data.cdn_url.https + '/' + this.account_ +\n      '/api/v1/map/' + data.layergroupid + '/{z}/{x}/{y}.png';\n  this.setUrl(tilesUrl);\n};\n\n// FIXME keep cluster cache by resolution ?\n// FIXME distance not respected because of the centroid\n\ngoog.provide('ol.source.Cluster');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.Feature');\ngoog.require('ol.coordinate');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.geom.Point');\ngoog.require('ol.source.Vector');\n\n\n/**\n * @classdesc\n * Layer source to cluster vector data. Works out of the box with point\n * geometries. For other geometry types, or if not all geometries should be\n * considered for clustering, a custom `geometryFunction` can be defined.\n *\n * @constructor\n * @param {olx.source.ClusterOptions} options Constructor options.\n * @extends {ol.source.Vector}\n * @api\n */\nol.source.Cluster = function(options) {\n  ol.source.Vector.call(this, {\n    attributions: options.attributions,\n    extent: options.extent,\n    logo: options.logo,\n    projection: options.projection,\n    wrapX: options.wrapX\n  });\n\n  /**\n   * @type {number|undefined}\n   * @private\n   */\n  this.resolution_ = undefined;\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.distance_ = options.distance !== undefined ? options.distance : 20;\n\n  /**\n   * @type {Array.<ol.Feature>}\n   * @private\n   */\n  this.features_ = [];\n\n  /**\n   * @param {ol.Feature} feature Feature.\n   * @return {ol.geom.Point} Cluster calculation point.\n   */\n  this.geometryFunction_ = options.geometryFunction || function(feature) {\n    var geometry = /** @type {ol.geom.Point} */ (feature.getGeometry());\n    ol.asserts.assert(geometry instanceof ol.geom.Point,\n        10); // The default `geometryFunction` can only handle `ol.geom.Point` geometries\n    return geometry;\n  };\n\n  /**\n   * @type {ol.source.Vector}\n   * @private\n   */\n  this.source_ = options.source;\n\n  this.source_.on(ol.events.EventType.CHANGE,\n      ol.source.Cluster.prototype.refresh_, this);\n};\nol.inherits(ol.source.Cluster, ol.source.Vector);\n\n\n/**\n * Get a reference to the wrapped source.\n * @return {ol.source.Vector} Source.\n * @api\n */\nol.source.Cluster.prototype.getSource = function() {\n  return this.source_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.Cluster.prototype.loadFeatures = function(extent, resolution,\n    projection) {\n  this.source_.loadFeatures(extent, resolution, projection);\n  if (resolution !== this.resolution_) {\n    this.clear();\n    this.resolution_ = resolution;\n    this.cluster_();\n    this.addFeatures(this.features_);\n  }\n};\n\n\n/**\n * Set the distance in pixels between clusters.\n * @param {number} distance The distance in pixels.\n * @api\n */\nol.source.Cluster.prototype.setDistance = function(distance) {\n  this.distance_ = distance;\n  this.refresh_();\n};\n\n\n/**\n * handle the source changing\n * @private\n */\nol.source.Cluster.prototype.refresh_ = function() {\n  this.clear();\n  this.cluster_();\n  this.addFeatures(this.features_);\n  this.changed();\n};\n\n\n/**\n * @private\n */\nol.source.Cluster.prototype.cluster_ = function() {\n  if (this.resolution_ === undefined) {\n    return;\n  }\n  this.features_.length = 0;\n  var extent = ol.extent.createEmpty();\n  var mapDistance = this.distance_ * this.resolution_;\n  var features = this.source_.getFeatures();\n\n  /**\n   * @type {!Object.<string, boolean>}\n   */\n  var clustered = {};\n\n  for (var i = 0, ii = features.length; i < ii; i++) {\n    var feature = features[i];\n    if (!(ol.getUid(feature).toString() in clustered)) {\n      var geometry = this.geometryFunction_(feature);\n      if (geometry) {\n        var coordinates = geometry.getCoordinates();\n        ol.extent.createOrUpdateFromCoordinate(coordinates, extent);\n        ol.extent.buffer(extent, mapDistance, extent);\n\n        var neighbors = this.source_.getFeaturesInExtent(extent);\n        ol.DEBUG && console.assert(neighbors.length >= 1, 'at least one neighbor found');\n        neighbors = neighbors.filter(function(neighbor) {\n          var uid = ol.getUid(neighbor).toString();\n          if (!(uid in clustered)) {\n            clustered[uid] = true;\n            return true;\n          } else {\n            return false;\n          }\n        });\n        this.features_.push(this.createCluster_(neighbors));\n      }\n    }\n  }\n  ol.DEBUG && console.assert(\n      Object.keys(clustered).length == this.source_.getFeatures().length,\n      'number of clustered equals number of features in the source');\n};\n\n\n/**\n * @param {Array.<ol.Feature>} features Features\n * @return {ol.Feature} The cluster feature.\n * @private\n */\nol.source.Cluster.prototype.createCluster_ = function(features) {\n  var centroid = [0, 0];\n  for (var i = features.length - 1; i >= 0; --i) {\n    var geometry = this.geometryFunction_(features[i]);\n    if (geometry) {\n      ol.coordinate.add(centroid, geometry.getCoordinates());\n    } else {\n      features.splice(i, 1);\n    }\n  }\n  ol.coordinate.scale(centroid, 1 / features.length);\n\n  var cluster = new ol.Feature(new ol.geom.Point(centroid));\n  cluster.set('features', features);\n  return cluster;\n};\n\ngoog.provide('ol.uri');\n\n\n/**\n * Appends query parameters to a URI.\n *\n * @param {string} uri The original URI, which may already have query data.\n * @param {!Object} params An object where keys are URI-encoded parameter keys,\n *     and the values are arbitrary types or arrays.\n * @return {string} The new URI.\n */\nol.uri.appendParams = function(uri, params) {\n  var keyParams = [];\n  // Skip any null or undefined parameter values\n  Object.keys(params).forEach(function(k) {\n    if (params[k] !== null && params[k] !== undefined) {\n      keyParams.push(k + '=' + encodeURIComponent(params[k]));\n    }\n  });\n  var qs = keyParams.join('&');\n  // remove any trailing ? or &\n  uri = uri.replace(/[?&]$/, '');\n  // append ? or & depending on whether uri has existing parameters\n  uri = uri.indexOf('?') === -1 ? uri + '?' : uri + '&';\n  return uri + qs;\n};\n\ngoog.provide('ol.source.ImageArcGISRest');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.asserts');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.source.Image');\ngoog.require('ol.uri');\n\n\n/**\n * @classdesc\n * Source for data from ArcGIS Rest services providing single, untiled images.\n * Useful when underlying map service has labels.\n *\n * If underlying map service is not using labels,\n * take advantage of ol image caching and use\n * {@link ol.source.TileArcGISRest} data source.\n *\n * @constructor\n * @fires ol.source.Image.Event\n * @extends {ol.source.Image}\n * @param {olx.source.ImageArcGISRestOptions=} opt_options Image ArcGIS Rest Options.\n * @api\n */\nol.source.ImageArcGISRest = function(opt_options) {\n\n  var options = opt_options || {};\n\n  ol.source.Image.call(this, {\n    attributions: options.attributions,\n    logo: options.logo,\n    projection: options.projection,\n    resolutions: options.resolutions\n  });\n\n  /**\n   * @private\n   * @type {?string}\n   */\n  this.crossOrigin_ =\n      options.crossOrigin !== undefined ? options.crossOrigin : null;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.url_ = options.url;\n\n  /**\n   * @private\n   * @type {ol.ImageLoadFunctionType}\n   */\n  this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?\n      options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;\n\n\n  /**\n   * @private\n   * @type {!Object}\n   */\n  this.params_ = options.params || {};\n\n  /**\n   * @private\n   * @type {ol.Image}\n   */\n  this.image_ = null;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.imageSize_ = [0, 0];\n\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;\n\n};\nol.inherits(ol.source.ImageArcGISRest, ol.source.Image);\n\n\n/**\n * Get the user-provided params, i.e. those passed to the constructor through\n * the \"params\" option, and possibly updated using the updateParams method.\n * @return {Object} Params.\n * @api stable\n */\nol.source.ImageArcGISRest.prototype.getParams = function() {\n  return this.params_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.ImageArcGISRest.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {\n\n  if (this.url_ === undefined) {\n    return null;\n  }\n\n  resolution = this.findNearestResolution(resolution);\n\n  var image = this.image_;\n  if (image &&\n      this.renderedRevision_ == this.getRevision() &&\n      image.getResolution() == resolution &&\n      image.getPixelRatio() == pixelRatio &&\n      ol.extent.containsExtent(image.getExtent(), extent)) {\n    return image;\n  }\n\n  var params = {\n    'F': 'image',\n    'FORMAT': 'PNG32',\n    'TRANSPARENT': true\n  };\n  ol.obj.assign(params, this.params_);\n\n  extent = extent.slice();\n  var centerX = (extent[0] + extent[2]) / 2;\n  var centerY = (extent[1] + extent[3]) / 2;\n  if (this.ratio_ != 1) {\n    var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2;\n    var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2;\n    extent[0] = centerX - halfWidth;\n    extent[1] = centerY - halfHeight;\n    extent[2] = centerX + halfWidth;\n    extent[3] = centerY + halfHeight;\n  }\n\n  var imageResolution = resolution / pixelRatio;\n\n  // Compute an integer width and height.\n  var width = Math.ceil(ol.extent.getWidth(extent) / imageResolution);\n  var height = Math.ceil(ol.extent.getHeight(extent) / imageResolution);\n\n  // Modify the extent to match the integer width and height.\n  extent[0] = centerX - imageResolution * width / 2;\n  extent[2] = centerX + imageResolution * width / 2;\n  extent[1] = centerY - imageResolution * height / 2;\n  extent[3] = centerY + imageResolution * height / 2;\n\n  this.imageSize_[0] = width;\n  this.imageSize_[1] = height;\n\n  var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio,\n      projection, params);\n\n  this.image_ = new ol.Image(extent, resolution, pixelRatio,\n      this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);\n\n  this.renderedRevision_ = this.getRevision();\n\n  ol.events.listen(this.image_, ol.events.EventType.CHANGE,\n      this.handleImageChange, this);\n\n  return this.image_;\n\n};\n\n\n/**\n * Return the image load function of the source.\n * @return {ol.ImageLoadFunctionType} The image load function.\n * @api\n */\nol.source.ImageArcGISRest.prototype.getImageLoadFunction = function() {\n  return this.imageLoadFunction_;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @param {Object} params Params.\n * @return {string} Request URL.\n * @private\n */\nol.source.ImageArcGISRest.prototype.getRequestUrl_ = function(extent, size, pixelRatio, projection, params) {\n\n  ol.DEBUG && console.assert(this.url_ !== undefined, 'url is defined');\n\n  // ArcGIS Server only wants the numeric portion of the projection ID.\n  var srid = projection.getCode().split(':').pop();\n\n  params['SIZE'] = size[0] + ',' + size[1];\n  params['BBOX'] = extent.join(',');\n  params['BBOXSR'] = srid;\n  params['IMAGESR'] = srid;\n  params['DPI'] = 90 * pixelRatio;\n\n  var url = this.url_;\n\n  var modifiedUrl = url\n    .replace(/MapServer\\/?$/, 'MapServer/export')\n    .replace(/ImageServer\\/?$/, 'ImageServer/exportImage');\n  if (modifiedUrl == url) {\n    ol.asserts.assert(false, 50); // `options.featureTypes` should be an Array\n  }\n  return ol.uri.appendParams(modifiedUrl, params);\n};\n\n\n/**\n * Return the URL used for this ArcGIS source.\n * @return {string|undefined} URL.\n * @api stable\n */\nol.source.ImageArcGISRest.prototype.getUrl = function() {\n  return this.url_;\n};\n\n\n/**\n * Set the image load function of the source.\n * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.\n * @api\n */\nol.source.ImageArcGISRest.prototype.setImageLoadFunction = function(imageLoadFunction) {\n  this.image_ = null;\n  this.imageLoadFunction_ = imageLoadFunction;\n  this.changed();\n};\n\n\n/**\n * Set the URL to use for requests.\n * @param {string|undefined} url URL.\n * @api stable\n */\nol.source.ImageArcGISRest.prototype.setUrl = function(url) {\n  if (url != this.url_) {\n    this.url_ = url;\n    this.image_ = null;\n    this.changed();\n  }\n};\n\n\n/**\n * Update the user-provided params.\n * @param {Object} params Params.\n * @api stable\n */\nol.source.ImageArcGISRest.prototype.updateParams = function(params) {\n  ol.obj.assign(this.params_, params);\n  this.image_ = null;\n  this.changed();\n};\n\ngoog.provide('ol.source.ImageMapGuide');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.source.Image');\ngoog.require('ol.uri');\n\n\n/**\n * @classdesc\n * Source for images from Mapguide servers\n *\n * @constructor\n * @fires ol.source.Image.Event\n * @extends {ol.source.Image}\n * @param {olx.source.ImageMapGuideOptions} options Options.\n * @api stable\n */\nol.source.ImageMapGuide = function(options) {\n\n  ol.source.Image.call(this, {\n    projection: options.projection,\n    resolutions: options.resolutions\n  });\n\n  /**\n   * @private\n   * @type {?string}\n   */\n  this.crossOrigin_ =\n      options.crossOrigin !== undefined ? options.crossOrigin : null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.displayDpi_ = options.displayDpi !== undefined ?\n      options.displayDpi : 96;\n\n  /**\n   * @private\n   * @type {!Object}\n   */\n  this.params_ = options.params || {};\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.url_ = options.url;\n\n  /**\n   * @private\n   * @type {ol.ImageLoadFunctionType}\n   */\n  this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?\n      options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.metersPerUnit_ = options.metersPerUnit !== undefined ?\n      options.metersPerUnit : 1;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.ratio_ = options.ratio !== undefined ? options.ratio : 1;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.useOverlay_ = options.useOverlay !== undefined ?\n      options.useOverlay : false;\n\n  /**\n   * @private\n   * @type {ol.Image}\n   */\n  this.image_ = null;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_ = 0;\n\n};\nol.inherits(ol.source.ImageMapGuide, ol.source.Image);\n\n\n/**\n * Get the user-provided params, i.e. those passed to the constructor through\n * the \"params\" option, and possibly updated using the updateParams method.\n * @return {Object} Params.\n * @api stable\n */\nol.source.ImageMapGuide.prototype.getParams = function() {\n  return this.params_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.ImageMapGuide.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {\n  resolution = this.findNearestResolution(resolution);\n  pixelRatio = this.hidpi_ ? pixelRatio : 1;\n\n  var image = this.image_;\n  if (image &&\n      this.renderedRevision_ == this.getRevision() &&\n      image.getResolution() == resolution &&\n      image.getPixelRatio() == pixelRatio &&\n      ol.extent.containsExtent(image.getExtent(), extent)) {\n    return image;\n  }\n\n  if (this.ratio_ != 1) {\n    extent = extent.slice();\n    ol.extent.scaleFromCenter(extent, this.ratio_);\n  }\n  var width = ol.extent.getWidth(extent) / resolution;\n  var height = ol.extent.getHeight(extent) / resolution;\n  var size = [width * pixelRatio, height * pixelRatio];\n\n  if (this.url_ !== undefined) {\n    var imageUrl = this.getUrl(this.url_, this.params_, extent, size,\n        projection);\n    image = new ol.Image(extent, resolution, pixelRatio,\n        this.getAttributions(), imageUrl, this.crossOrigin_,\n        this.imageLoadFunction_);\n    ol.events.listen(image, ol.events.EventType.CHANGE,\n        this.handleImageChange, this);\n  } else {\n    image = null;\n  }\n  this.image_ = image;\n  this.renderedRevision_ = this.getRevision();\n\n  return image;\n};\n\n\n/**\n * Return the image load function of the source.\n * @return {ol.ImageLoadFunctionType} The image load function.\n * @api\n */\nol.source.ImageMapGuide.prototype.getImageLoadFunction = function() {\n  return this.imageLoadFunction_;\n};\n\n\n/**\n * @param {ol.Extent} extent The map extents.\n * @param {ol.Size} size The viewport size.\n * @param {number} metersPerUnit The meters-per-unit value.\n * @param {number} dpi The display resolution.\n * @return {number} The computed map scale.\n */\nol.source.ImageMapGuide.getScale = function(extent, size, metersPerUnit, dpi) {\n  var mcsW = ol.extent.getWidth(extent);\n  var mcsH = ol.extent.getHeight(extent);\n  var devW = size[0];\n  var devH = size[1];\n  var mpp = 0.0254 / dpi;\n  if (devH * mcsW > devW * mcsH) {\n    return mcsW * metersPerUnit / (devW * mpp); // width limited\n  } else {\n    return mcsH * metersPerUnit / (devH * mpp); // height limited\n  }\n};\n\n\n/**\n * Update the user-provided params.\n * @param {Object} params Params.\n * @api stable\n */\nol.source.ImageMapGuide.prototype.updateParams = function(params) {\n  ol.obj.assign(this.params_, params);\n  this.changed();\n};\n\n\n/**\n * @param {string} baseUrl The mapagent url.\n * @param {Object.<string, string|number>} params Request parameters.\n * @param {ol.Extent} extent Extent.\n * @param {ol.Size} size Size.\n * @param {ol.proj.Projection} projection Projection.\n * @return {string} The mapagent map image request URL.\n */\nol.source.ImageMapGuide.prototype.getUrl = function(baseUrl, params, extent, size, projection) {\n  var scale = ol.source.ImageMapGuide.getScale(extent, size,\n      this.metersPerUnit_, this.displayDpi_);\n  var center = ol.extent.getCenter(extent);\n  var baseParams = {\n    'OPERATION': this.useOverlay_ ? 'GETDYNAMICMAPOVERLAYIMAGE' : 'GETMAPIMAGE',\n    'VERSION': '2.0.0',\n    'LOCALE': 'en',\n    'CLIENTAGENT': 'ol.source.ImageMapGuide source',\n    'CLIP': '1',\n    'SETDISPLAYDPI': this.displayDpi_,\n    'SETDISPLAYWIDTH': Math.round(size[0]),\n    'SETDISPLAYHEIGHT': Math.round(size[1]),\n    'SETVIEWSCALE': scale,\n    'SETVIEWCENTERX': center[0],\n    'SETVIEWCENTERY': center[1]\n  };\n  ol.obj.assign(baseParams, params);\n  return ol.uri.appendParams(baseUrl, baseParams);\n};\n\n\n/**\n * Set the image load function of the MapGuide source.\n * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.\n * @api\n */\nol.source.ImageMapGuide.prototype.setImageLoadFunction = function(\n    imageLoadFunction) {\n  this.image_ = null;\n  this.imageLoadFunction_ = imageLoadFunction;\n  this.changed();\n};\n\ngoog.provide('ol.source.ImageStatic');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.proj');\ngoog.require('ol.source.Image');\n\n\n/**\n * @classdesc\n * A layer source for displaying a single, static image.\n *\n * @constructor\n * @extends {ol.source.Image}\n * @param {olx.source.ImageStaticOptions} options Options.\n * @api stable\n */\nol.source.ImageStatic = function(options) {\n  var imageExtent = options.imageExtent;\n\n  var crossOrigin = options.crossOrigin !== undefined ?\n      options.crossOrigin : null;\n\n  var /** @type {ol.ImageLoadFunctionType} */ imageLoadFunction =\n      options.imageLoadFunction !== undefined ?\n      options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;\n\n  ol.source.Image.call(this, {\n    attributions: options.attributions,\n    logo: options.logo,\n    projection: ol.proj.get(options.projection)\n  });\n\n  /**\n   * @private\n   * @type {ol.Image}\n   */\n  this.image_ = new ol.Image(imageExtent, undefined, 1, this.getAttributions(),\n      options.url, crossOrigin, imageLoadFunction);\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.imageSize_ = options.imageSize ? options.imageSize : null;\n\n  ol.events.listen(this.image_, ol.events.EventType.CHANGE,\n      this.handleImageChange, this);\n\n};\nol.inherits(ol.source.ImageStatic, ol.source.Image);\n\n\n/**\n * @inheritDoc\n */\nol.source.ImageStatic.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {\n  if (ol.extent.intersects(extent, this.image_.getExtent())) {\n    return this.image_;\n  }\n  return null;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.ImageStatic.prototype.handleImageChange = function(evt) {\n  if (this.image_.getState() == ol.Image.State.LOADED) {\n    var imageExtent = this.image_.getExtent();\n    var image = this.image_.getImage();\n    var imageWidth, imageHeight;\n    if (this.imageSize_) {\n      imageWidth = this.imageSize_[0];\n      imageHeight = this.imageSize_[1];\n    } else {\n      // TODO: remove the type cast when a closure-compiler > 20160315 is used.\n      // see: https://github.com/google/closure-compiler/pull/1664\n      imageWidth = /** @type {number} */ (image.width);\n      imageHeight = /** @type {number} */ (image.height);\n    }\n    var resolution = ol.extent.getHeight(imageExtent) / imageHeight;\n    var targetWidth = Math.ceil(ol.extent.getWidth(imageExtent) / resolution);\n    if (targetWidth != imageWidth) {\n      var context = ol.dom.createCanvasContext2D(targetWidth, imageHeight);\n      var canvas = context.canvas;\n      context.drawImage(image, 0, 0, imageWidth, imageHeight,\n          0, 0, canvas.width, canvas.height);\n      this.image_.setImage(canvas);\n    }\n  }\n  ol.source.Image.prototype.handleImageChange.call(this, evt);\n};\n\ngoog.provide('ol.source.WMSServerType');\n\n\n/**\n * Available server types: `'carmentaserver'`, `'geoserver'`, `'mapserver'`,\n *     `'qgis'`. These are servers that have vendor parameters beyond the WMS\n *     specification that OpenLayers can make use of.\n * @enum {string}\n */\nol.source.WMSServerType = {\n  CARMENTA_SERVER: 'carmentaserver',\n  GEOSERVER: 'geoserver',\n  MAPSERVER: 'mapserver',\n  QGIS: 'qgis'\n};\n\n// FIXME cannot be shared between maps with different projections\n\ngoog.provide('ol.source.ImageWMS');\n\ngoog.require('ol');\ngoog.require('ol.Image');\ngoog.require('ol.asserts');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\ngoog.require('ol.source.Image');\ngoog.require('ol.source.WMSServerType');\ngoog.require('ol.string');\ngoog.require('ol.uri');\n\n\n/**\n * @classdesc\n * Source for WMS servers providing single, untiled images.\n *\n * @constructor\n * @fires ol.source.Image.Event\n * @extends {ol.source.Image}\n * @param {olx.source.ImageWMSOptions=} opt_options Options.\n * @api stable\n */\nol.source.ImageWMS = function(opt_options) {\n\n  var options = opt_options || {};\n\n  ol.source.Image.call(this, {\n    attributions: options.attributions,\n    logo: options.logo,\n    projection: options.projection,\n    resolutions: options.resolutions\n  });\n\n  /**\n   * @private\n   * @type {?string}\n   */\n  this.crossOrigin_ =\n      options.crossOrigin !== undefined ? options.crossOrigin : null;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.url_ = options.url;\n\n  /**\n   * @private\n   * @type {ol.ImageLoadFunctionType}\n   */\n  this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?\n      options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;\n\n  /**\n   * @private\n   * @type {!Object}\n   */\n  this.params_ = options.params || {};\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.v13_ = true;\n  this.updateV13_();\n\n  /**\n   * @private\n   * @type {ol.source.WMSServerType|undefined}\n   */\n  this.serverType_ =\n      /** @type {ol.source.WMSServerType|undefined} */ (options.serverType);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;\n\n  /**\n   * @private\n   * @type {ol.Image}\n   */\n  this.image_ = null;\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.imageSize_ = [0, 0];\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.renderedRevision_ = 0;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;\n\n};\nol.inherits(ol.source.ImageWMS, ol.source.Image);\n\n\n/**\n * @const\n * @type {ol.Size}\n * @private\n */\nol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_ = [101, 101];\n\n\n/**\n * Return the GetFeatureInfo URL for the passed coordinate, resolution, and\n * projection. Return `undefined` if the GetFeatureInfo URL cannot be\n * constructed.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} resolution Resolution.\n * @param {ol.ProjectionLike} projection Projection.\n * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should\n *     be provided. If `QUERY_LAYERS` is not provided then the layers specified\n *     in the `LAYERS` parameter will be used. `VERSION` should not be\n *     specified here.\n * @return {string|undefined} GetFeatureInfo URL.\n * @api stable\n */\nol.source.ImageWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {\n\n  ol.DEBUG && console.assert(!('VERSION' in params),\n      'key VERSION is not allowed in params');\n\n  if (this.url_ === undefined) {\n    return undefined;\n  }\n\n  var extent = ol.extent.getForViewAndSize(\n      coordinate, resolution, 0,\n      ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_);\n\n  var baseParams = {\n    'SERVICE': 'WMS',\n    'VERSION': ol.DEFAULT_WMS_VERSION,\n    'REQUEST': 'GetFeatureInfo',\n    'FORMAT': 'image/png',\n    'TRANSPARENT': true,\n    'QUERY_LAYERS': this.params_['LAYERS']\n  };\n  ol.obj.assign(baseParams, this.params_, params);\n\n  var x = Math.floor((coordinate[0] - extent[0]) / resolution);\n  var y = Math.floor((extent[3] - coordinate[1]) / resolution);\n  baseParams[this.v13_ ? 'I' : 'X'] = x;\n  baseParams[this.v13_ ? 'J' : 'Y'] = y;\n\n  return this.getRequestUrl_(\n      extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_,\n      1, ol.proj.get(projection), baseParams);\n};\n\n\n/**\n * Get the user-provided params, i.e. those passed to the constructor through\n * the \"params\" option, and possibly updated using the updateParams method.\n * @return {Object} Params.\n * @api stable\n */\nol.source.ImageWMS.prototype.getParams = function() {\n  return this.params_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.ImageWMS.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {\n\n  if (this.url_ === undefined) {\n    return null;\n  }\n\n  resolution = this.findNearestResolution(resolution);\n\n  if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {\n    pixelRatio = 1;\n  }\n\n  extent = extent.slice();\n  var centerX = (extent[0] + extent[2]) / 2;\n  var centerY = (extent[1] + extent[3]) / 2;\n\n  var imageResolution = resolution / pixelRatio;\n  var imageWidth = ol.extent.getWidth(extent) / imageResolution;\n  var imageHeight = ol.extent.getHeight(extent) / imageResolution;\n\n  var image = this.image_;\n  if (image &&\n      this.renderedRevision_ == this.getRevision() &&\n      image.getResolution() == resolution &&\n      image.getPixelRatio() == pixelRatio &&\n      ol.extent.containsExtent(image.getExtent(), extent)) {\n    return image;\n  }\n\n  if (this.ratio_ != 1) {\n    var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2;\n    var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2;\n    extent[0] = centerX - halfWidth;\n    extent[1] = centerY - halfHeight;\n    extent[2] = centerX + halfWidth;\n    extent[3] = centerY + halfHeight;\n  }\n\n  var params = {\n    'SERVICE': 'WMS',\n    'VERSION': ol.DEFAULT_WMS_VERSION,\n    'REQUEST': 'GetMap',\n    'FORMAT': 'image/png',\n    'TRANSPARENT': true\n  };\n  ol.obj.assign(params, this.params_);\n\n  this.imageSize_[0] = Math.ceil(imageWidth * this.ratio_);\n  this.imageSize_[1] = Math.ceil(imageHeight * this.ratio_);\n\n  var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio,\n      projection, params);\n\n  this.image_ = new ol.Image(extent, resolution, pixelRatio,\n      this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);\n\n  this.renderedRevision_ = this.getRevision();\n\n  ol.events.listen(this.image_, ol.events.EventType.CHANGE,\n      this.handleImageChange, this);\n\n  return this.image_;\n\n};\n\n\n/**\n * Return the image load function of the source.\n * @return {ol.ImageLoadFunctionType} The image load function.\n * @api\n */\nol.source.ImageWMS.prototype.getImageLoadFunction = function() {\n  return this.imageLoadFunction_;\n};\n\n\n/**\n * @param {ol.Extent} extent Extent.\n * @param {ol.Size} size Size.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @param {Object} params Params.\n * @return {string} Request URL.\n * @private\n */\nol.source.ImageWMS.prototype.getRequestUrl_ = function(extent, size, pixelRatio, projection, params) {\n\n  ol.asserts.assert(this.url_ !== undefined, 9); // `url` must be configured or set using `#setUrl()`\n\n  params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();\n\n  if (!('STYLES' in this.params_)) {\n    params['STYLES'] = '';\n  }\n\n  if (pixelRatio != 1) {\n    switch (this.serverType_) {\n      case ol.source.WMSServerType.GEOSERVER:\n        var dpi = (90 * pixelRatio + 0.5) | 0;\n        if ('FORMAT_OPTIONS' in params) {\n          params['FORMAT_OPTIONS'] += ';dpi:' + dpi;\n        } else {\n          params['FORMAT_OPTIONS'] = 'dpi:' + dpi;\n        }\n        break;\n      case ol.source.WMSServerType.MAPSERVER:\n        params['MAP_RESOLUTION'] = 90 * pixelRatio;\n        break;\n      case ol.source.WMSServerType.CARMENTA_SERVER:\n      case ol.source.WMSServerType.QGIS:\n        params['DPI'] = 90 * pixelRatio;\n        break;\n      default:\n        ol.asserts.assert(false, 8); // Unknown `serverType` configured\n        break;\n    }\n  }\n\n  params['WIDTH'] = size[0];\n  params['HEIGHT'] = size[1];\n\n  var axisOrientation = projection.getAxisOrientation();\n  var bbox;\n  if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {\n    bbox = [extent[1], extent[0], extent[3], extent[2]];\n  } else {\n    bbox = extent;\n  }\n  params['BBOX'] = bbox.join(',');\n\n  return ol.uri.appendParams(/** @type {string} */ (this.url_), params);\n};\n\n\n/**\n * Return the URL used for this WMS source.\n * @return {string|undefined} URL.\n * @api stable\n */\nol.source.ImageWMS.prototype.getUrl = function() {\n  return this.url_;\n};\n\n\n/**\n * Set the image load function of the source.\n * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.\n * @api\n */\nol.source.ImageWMS.prototype.setImageLoadFunction = function(\n    imageLoadFunction) {\n  this.image_ = null;\n  this.imageLoadFunction_ = imageLoadFunction;\n  this.changed();\n};\n\n\n/**\n * Set the URL to use for requests.\n * @param {string|undefined} url URL.\n * @api stable\n */\nol.source.ImageWMS.prototype.setUrl = function(url) {\n  if (url != this.url_) {\n    this.url_ = url;\n    this.image_ = null;\n    this.changed();\n  }\n};\n\n\n/**\n * Update the user-provided params.\n * @param {Object} params Params.\n * @api stable\n */\nol.source.ImageWMS.prototype.updateParams = function(params) {\n  ol.obj.assign(this.params_, params);\n  this.updateV13_();\n  this.image_ = null;\n  this.changed();\n};\n\n\n/**\n * @private\n */\nol.source.ImageWMS.prototype.updateV13_ = function() {\n  var version = this.params_['VERSION'] || ol.DEFAULT_WMS_VERSION;\n  this.v13_ = ol.string.compareVersions(version, '1.3') >= 0;\n};\n\ngoog.provide('ol.source.OSM');\n\ngoog.require('ol');\ngoog.require('ol.Attribution');\ngoog.require('ol.source.XYZ');\n\n\n/**\n * @classdesc\n * Layer source for the OpenStreetMap tile server.\n *\n * @constructor\n * @extends {ol.source.XYZ}\n * @param {olx.source.OSMOptions=} opt_options Open Street Map options.\n * @api stable\n */\nol.source.OSM = function(opt_options) {\n\n  var options = opt_options || {};\n\n  var attributions;\n  if (options.attributions !== undefined) {\n    attributions = options.attributions;\n  } else {\n    attributions = [ol.source.OSM.ATTRIBUTION];\n  }\n\n  var crossOrigin = options.crossOrigin !== undefined ?\n      options.crossOrigin : 'anonymous';\n\n  var url = options.url !== undefined ?\n      options.url : 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png';\n\n  ol.source.XYZ.call(this, {\n    attributions: attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: crossOrigin,\n    opaque: options.opaque !== undefined ? options.opaque : true,\n    maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19,\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    tileLoadFunction: options.tileLoadFunction,\n    url: url,\n    wrapX: options.wrapX\n  });\n\n};\nol.inherits(ol.source.OSM, ol.source.XYZ);\n\n\n/**\n * The attribution containing a link to the OpenStreetMap Copyright and License\n * page.\n * @const\n * @type {ol.Attribution}\n * @api\n */\nol.source.OSM.ATTRIBUTION = new ol.Attribution({\n  html: '&copy; ' +\n      '<a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> ' +\n      'contributors.'\n});\n\ngoog.provide('ol.ext.pixelworks');\n/** @typedef {function(*)} */\nol.ext.pixelworks;\n(function() {\nvar exports = {};\nvar module = {exports: exports};\nvar define;\n/**\n * @fileoverview\n * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}\n */\n(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){\nvar Processor = _dereq_('./processor');\n\nexports.Processor = Processor;\n\n},{\"./processor\":2}],2:[function(_dereq_,module,exports){\nvar newImageData = _dereq_('./util').newImageData;\n\n/**\n * Create a function for running operations.  This function is serialized for\n * use in a worker.\n * @param {function(Array, Object):*} operation The operation.\n * @return {function(Object):ArrayBuffer} A function that takes an object with\n * buffers, meta, imageOps, width, and height properties and returns an array\n * buffer.\n */\nfunction createMinion(operation) {\n  var workerHasImageData = true;\n  try {\n    new ImageData(10, 10);\n  } catch (_) {\n    workerHasImageData = false;\n  }\n\n  function newWorkerImageData(data, width, height) {\n    if (workerHasImageData) {\n      return new ImageData(data, width, height);\n    } else {\n      return {data: data, width: width, height: height};\n    }\n  }\n\n  return function(data) {\n    // bracket notation for minification support\n    var buffers = data['buffers'];\n    var meta = data['meta'];\n    var imageOps = data['imageOps'];\n    var width = data['width'];\n    var height = data['height'];\n\n    var numBuffers = buffers.length;\n    var numBytes = buffers[0].byteLength;\n    var output, b;\n\n    if (imageOps) {\n      var images = new Array(numBuffers);\n      for (b = 0; b < numBuffers; ++b) {\n        images[b] = newWorkerImageData(\n            new Uint8ClampedArray(buffers[b]), width, height);\n      }\n      output = operation(images, meta).data;\n    } else {\n      output = new Uint8ClampedArray(numBytes);\n      var arrays = new Array(numBuffers);\n      var pixels = new Array(numBuffers);\n      for (b = 0; b < numBuffers; ++b) {\n        arrays[b] = new Uint8ClampedArray(buffers[b]);\n        pixels[b] = [0, 0, 0, 0];\n      }\n      for (var i = 0; i < numBytes; i += 4) {\n        for (var j = 0; j < numBuffers; ++j) {\n          var array = arrays[j];\n          pixels[j][0] = array[i];\n          pixels[j][1] = array[i + 1];\n          pixels[j][2] = array[i + 2];\n          pixels[j][3] = array[i + 3];\n        }\n        var pixel = operation(pixels, meta);\n        output[i] = pixel[0];\n        output[i + 1] = pixel[1];\n        output[i + 2] = pixel[2];\n        output[i + 3] = pixel[3];\n      }\n    }\n    return output.buffer;\n  };\n}\n\n/**\n * Create a worker for running operations.\n * @param {Object} config Configuration.\n * @param {function(MessageEvent)} onMessage Called with a message event.\n * @return {Worker} The worker.\n */\nfunction createWorker(config, onMessage) {\n  var lib = Object.keys(config.lib || {}).map(function(name) {\n    return 'var ' + name + ' = ' + config.lib[name].toString() + ';';\n  });\n\n  var lines = lib.concat([\n    'var __minion__ = (' + createMinion.toString() + ')(', config.operation.toString(), ');',\n    'self.addEventListener(\"message\", function(event) {',\n    '  var buffer = __minion__(event.data);',\n    '  self.postMessage({buffer: buffer, meta: event.data.meta}, [buffer]);',\n    '});'\n  ]);\n\n  var blob = new Blob(lines, {type: 'text/javascript'});\n  var source = URL.createObjectURL(blob);\n  var worker = new Worker(source);\n  worker.addEventListener('message', onMessage);\n  return worker;\n}\n\n/**\n * Create a faux worker for running operations.\n * @param {Object} config Configuration.\n * @param {function(MessageEvent)} onMessage Called with a message event.\n * @return {Object} The faux worker.\n */\nfunction createFauxWorker(config, onMessage) {\n  var minion = createMinion(config.operation);\n  return {\n    postMessage: function(data) {\n      setTimeout(function() {\n        onMessage({'data': {'buffer': minion(data), 'meta': data['meta']}});\n      }, 0);\n    }\n  };\n}\n\n/**\n * A processor runs pixel or image operations in workers.\n * @param {Object} config Configuration.\n */\nfunction Processor(config) {\n  this._imageOps = !!config.imageOps;\n  var threads;\n  if (config.threads === 0) {\n    threads = 0;\n  } else if (this._imageOps) {\n    threads = 1;\n  } else {\n    threads = config.threads || 1;\n  }\n  var workers = [];\n  if (threads) {\n    for (var i = 0; i < threads; ++i) {\n      workers[i] = createWorker(config, this._onWorkerMessage.bind(this, i));\n    }\n  } else {\n    workers[0] = createFauxWorker(config, this._onWorkerMessage.bind(this, 0));\n  }\n  this._workers = workers;\n  this._queue = [];\n  this._maxQueueLength = config.queue || Infinity;\n  this._running = 0;\n  this._dataLookup = {};\n  this._job = null;\n}\n\n/**\n * Run operation on input data.\n * @param {Array.<Array|ImageData>} inputs Array of pixels or image data\n *     (depending on the operation type).\n * @param {Object} meta A user data object.  This is passed to all operations\n *     and must be serializable.\n * @param {function(Error, ImageData, Object)} callback Called when work\n *     completes.  The first argument is any error.  The second is the ImageData\n *     generated by operations.  The third is the user data object.\n */\nProcessor.prototype.process = function(inputs, meta, callback) {\n  this._enqueue({\n    inputs: inputs,\n    meta: meta,\n    callback: callback\n  });\n  this._dispatch();\n};\n\n/**\n * Stop responding to any completed work and destroy the processor.\n */\nProcessor.prototype.destroy = function() {\n  for (var key in this) {\n    this[key] = null;\n  }\n  this._destroyed = true;\n};\n\n/**\n * Add a job to the queue.\n * @param {Object} job The job.\n */\nProcessor.prototype._enqueue = function(job) {\n  this._queue.push(job);\n  while (this._queue.length > this._maxQueueLength) {\n    this._queue.shift().callback(null, null);\n  }\n};\n\n/**\n * Dispatch a job.\n */\nProcessor.prototype._dispatch = function() {\n  if (this._running === 0 && this._queue.length > 0) {\n    var job = this._job = this._queue.shift();\n    var width = job.inputs[0].width;\n    var height = job.inputs[0].height;\n    var buffers = job.inputs.map(function(input) {\n      return input.data.buffer;\n    });\n    var threads = this._workers.length;\n    this._running = threads;\n    if (threads === 1) {\n      this._workers[0].postMessage({\n        'buffers': buffers,\n        'meta': job.meta,\n        'imageOps': this._imageOps,\n        'width': width,\n        'height': height\n      }, buffers);\n    } else {\n      var length = job.inputs[0].data.length;\n      var segmentLength = 4 * Math.ceil(length / 4 / threads);\n      for (var i = 0; i < threads; ++i) {\n        var offset = i * segmentLength;\n        var slices = [];\n        for (var j = 0, jj = buffers.length; j < jj; ++j) {\n          slices.push(buffers[i].slice(offset, offset + segmentLength));\n        }\n        this._workers[i].postMessage({\n          'buffers': slices,\n          'meta': job.meta,\n          'imageOps': this._imageOps,\n          'width': width,\n          'height': height\n        }, slices);\n      }\n    }\n  }\n};\n\n/**\n * Handle messages from the worker.\n * @param {number} index The worker index.\n * @param {MessageEvent} event The message event.\n */\nProcessor.prototype._onWorkerMessage = function(index, event) {\n  if (this._destroyed) {\n    return;\n  }\n  this._dataLookup[index] = event.data;\n  --this._running;\n  if (this._running === 0) {\n    this._resolveJob();\n  }\n};\n\n/**\n * Resolve a job.  If there are no more worker threads, the processor callback\n * will be called.\n */\nProcessor.prototype._resolveJob = function() {\n  var job = this._job;\n  var threads = this._workers.length;\n  var data, meta;\n  if (threads === 1) {\n    data = new Uint8ClampedArray(this._dataLookup[0]['buffer']);\n    meta = this._dataLookup[0]['meta'];\n  } else {\n    var length = job.inputs[0].data.length;\n    data = new Uint8ClampedArray(length);\n    meta = new Array(length);\n    var segmentLength = 4 * Math.ceil(length / 4 / threads);\n    for (var i = 0; i < threads; ++i) {\n      var buffer = this._dataLookup[i]['buffer'];\n      var offset = i * segmentLength;\n      data.set(new Uint8ClampedArray(buffer), offset);\n      meta[i] = this._dataLookup[i]['meta'];\n    }\n  }\n  this._job = null;\n  this._dataLookup = {};\n  job.callback(null,\n      newImageData(data, job.inputs[0].width, job.inputs[0].height), meta);\n  this._dispatch();\n};\n\nmodule.exports = Processor;\n\n},{\"./util\":3}],3:[function(_dereq_,module,exports){\nvar hasImageData = true;\ntry {\n  new ImageData(10, 10);\n} catch (_) {\n  hasImageData = false;\n}\n\nvar context = document.createElement('canvas').getContext('2d');\n\nfunction newImageData(data, width, height) {\n  if (hasImageData) {\n    return new ImageData(data, width, height);\n  } else {\n    var imageData = context.createImageData(width, height);\n    imageData.data.set(data);\n    return imageData;\n  }\n}\n\nexports.newImageData = newImageData;\n\n},{}]},{},[1])(1)\n});\nol.ext.pixelworks = module.exports;\n})();\n\ngoog.provide('ol.source.Raster');\n\ngoog.require('ol');\ngoog.require('ol.transform');\ngoog.require('ol.ImageCanvas');\ngoog.require('ol.TileQueue');\ngoog.require('ol.dom');\ngoog.require('ol.events');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.EventType');\ngoog.require('ol.ext.pixelworks');\ngoog.require('ol.extent');\ngoog.require('ol.layer.Image');\ngoog.require('ol.layer.Tile');\ngoog.require('ol.obj');\ngoog.require('ol.renderer.canvas.ImageLayer');\ngoog.require('ol.renderer.canvas.TileLayer');\ngoog.require('ol.source.Image');\ngoog.require('ol.source.State');\ngoog.require('ol.source.Tile');\n\n\n/**\n * @classdesc\n * A source that transforms data from any number of input sources using an array\n * of {@link ol.RasterOperation} functions to transform input pixel values into\n * output pixel values.\n *\n * @constructor\n * @extends {ol.source.Image}\n * @fires ol.source.Raster.Event\n * @param {olx.source.RasterOptions} options Options.\n * @api\n */\nol.source.Raster = function(options) {\n\n  /**\n   * @private\n   * @type {*}\n   */\n  this.worker_ = null;\n\n  /**\n   * @private\n   * @type {ol.source.Raster.OperationType}\n   */\n  this.operationType_ = options.operationType !== undefined ?\n      options.operationType : ol.source.Raster.OperationType.PIXEL;\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.threads_ = options.threads !== undefined ? options.threads : 1;\n\n  /**\n   * @private\n   * @type {Array.<ol.renderer.canvas.Layer>}\n   */\n  this.renderers_ = ol.source.Raster.createRenderers_(options.sources);\n\n  for (var r = 0, rr = this.renderers_.length; r < rr; ++r) {\n    ol.events.listen(this.renderers_[r], ol.events.EventType.CHANGE,\n        this.changed, this);\n  }\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.canvasContext_ = ol.dom.createCanvasContext2D();\n\n  /**\n   * @private\n   * @type {ol.TileQueue}\n   */\n  this.tileQueue_ = new ol.TileQueue(\n      function() {\n        return 1;\n      },\n      this.changed.bind(this));\n\n  var layerStatesArray = ol.source.Raster.getLayerStatesArray_(this.renderers_);\n  var layerStates = {};\n  for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) {\n    layerStates[ol.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];\n  }\n\n  /**\n   * The most recently rendered state.\n   * @type {?ol.SourceRasterRenderedState}\n   * @private\n   */\n  this.renderedState_ = null;\n\n  /**\n   * The most recently rendered image canvas.\n   * @type {ol.ImageCanvas}\n   * @private\n   */\n  this.renderedImageCanvas_ = null;\n\n  /**\n   * @private\n   * @type {olx.FrameState}\n   */\n  this.frameState_ = {\n    animate: false,\n    attributions: {},\n    coordinateToPixelTransform: ol.transform.create(),\n    extent: null,\n    focus: null,\n    index: 0,\n    layerStates: layerStates,\n    layerStatesArray: layerStatesArray,\n    logos: {},\n    pixelRatio: 1,\n    pixelToCoordinateTransform: ol.transform.create(),\n    postRenderFunctions: [],\n    size: [0, 0],\n    skippedFeatureUids: {},\n    tileQueue: this.tileQueue_,\n    time: Date.now(),\n    usedTiles: {},\n    viewState: /** @type {olx.ViewState} */ ({\n      rotation: 0\n    }),\n    viewHints: [],\n    wantedTiles: {}\n  };\n\n  ol.source.Image.call(this, {});\n\n  if (options.operation !== undefined) {\n    this.setOperation(options.operation, options.lib);\n  }\n\n};\nol.inherits(ol.source.Raster, ol.source.Image);\n\n\n/**\n * Set the operation.\n * @param {ol.RasterOperation} operation New operation.\n * @param {Object=} opt_lib Functions that will be available to operations run\n *     in a worker.\n * @api\n */\nol.source.Raster.prototype.setOperation = function(operation, opt_lib) {\n  this.worker_ = new ol.ext.pixelworks.Processor({\n    operation: operation,\n    imageOps: this.operationType_ === ol.source.Raster.OperationType.IMAGE,\n    queue: 1,\n    lib: opt_lib,\n    threads: this.threads_\n  });\n  this.changed();\n};\n\n\n/**\n * Update the stored frame state.\n * @param {ol.Extent} extent The view extent (in map units).\n * @param {number} resolution The view resolution.\n * @param {ol.proj.Projection} projection The view projection.\n * @return {olx.FrameState} The updated frame state.\n * @private\n */\nol.source.Raster.prototype.updateFrameState_ = function(extent, resolution, projection) {\n\n  var frameState = /** @type {olx.FrameState} */ (\n      ol.obj.assign({}, this.frameState_));\n\n  frameState.viewState = /** @type {olx.ViewState} */ (\n      ol.obj.assign({}, frameState.viewState));\n\n  var center = ol.extent.getCenter(extent);\n  var width = Math.round(ol.extent.getWidth(extent) / resolution);\n  var height = Math.round(ol.extent.getHeight(extent) / resolution);\n\n  frameState.extent = extent;\n  frameState.focus = ol.extent.getCenter(extent);\n  frameState.size[0] = width;\n  frameState.size[1] = height;\n\n  var viewState = frameState.viewState;\n  viewState.center = center;\n  viewState.projection = projection;\n  viewState.resolution = resolution;\n  return frameState;\n};\n\n\n/**\n * Determine if the most recently rendered image canvas is dirty.\n * @param {ol.Extent} extent The requested extent.\n * @param {number} resolution The requested resolution.\n * @return {boolean} The image is dirty.\n * @private\n */\nol.source.Raster.prototype.isDirty_ = function(extent, resolution) {\n  var state = this.renderedState_;\n  return !state ||\n      this.getRevision() !== state.revision ||\n      resolution !== state.resolution ||\n      !ol.extent.equals(extent, state.extent);\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.Raster.prototype.getImage = function(extent, resolution, pixelRatio, projection) {\n\n  if (!this.allSourcesReady_()) {\n    return null;\n  }\n\n  var currentExtent = extent.slice();\n  if (!this.isDirty_(currentExtent, resolution)) {\n    return this.renderedImageCanvas_;\n  }\n\n  var context = this.canvasContext_;\n  var canvas = context.canvas;\n\n  var width = Math.round(ol.extent.getWidth(currentExtent) / resolution);\n  var height = Math.round(ol.extent.getHeight(currentExtent) / resolution);\n\n  if (width !== canvas.width ||\n      height !== canvas.height) {\n    canvas.width = width;\n    canvas.height = height;\n  }\n\n  var frameState = this.updateFrameState_(currentExtent, resolution, projection);\n\n  var imageCanvas = new ol.ImageCanvas(\n      currentExtent, resolution, 1, this.getAttributions(), canvas,\n      this.composeFrame_.bind(this, frameState));\n\n  this.renderedImageCanvas_ = imageCanvas;\n\n  this.renderedState_ = {\n    extent: currentExtent,\n    resolution: resolution,\n    revision: this.getRevision()\n  };\n\n  return imageCanvas;\n};\n\n\n/**\n * Determine if all sources are ready.\n * @return {boolean} All sources are ready.\n * @private\n */\nol.source.Raster.prototype.allSourcesReady_ = function() {\n  var ready = true;\n  var source;\n  for (var i = 0, ii = this.renderers_.length; i < ii; ++i) {\n    source = this.renderers_[i].getLayer().getSource();\n    if (source.getState() !== ol.source.State.READY) {\n      ready = false;\n      break;\n    }\n  }\n  return ready;\n};\n\n\n/**\n * Compose the frame.  This renders data from all sources, runs pixel-wise\n * operations, and renders the result to the stored canvas context.\n * @param {olx.FrameState} frameState The frame state.\n * @param {function(Error)} callback Called when composition is complete.\n * @private\n */\nol.source.Raster.prototype.composeFrame_ = function(frameState, callback) {\n  var len = this.renderers_.length;\n  var imageDatas = new Array(len);\n  for (var i = 0; i < len; ++i) {\n    var imageData = ol.source.Raster.getImageData_(\n        this.renderers_[i], frameState, frameState.layerStatesArray[i]);\n    if (imageData) {\n      imageDatas[i] = imageData;\n    } else {\n      // image not yet ready\n      imageDatas = null;\n      break;\n    }\n  }\n\n  if (imageDatas) {\n    var data = {};\n    this.dispatchEvent(new ol.source.Raster.Event(\n        ol.source.Raster.EventType.BEFOREOPERATIONS, frameState, data));\n\n    this.worker_.process(imageDatas, data,\n        this.onWorkerComplete_.bind(this, frameState, callback));\n  }\n\n  frameState.tileQueue.loadMoreTiles(16, 16);\n};\n\n\n/**\n * Called when pixel processing is complete.\n * @param {olx.FrameState} frameState The frame state.\n * @param {function(Error)} callback Called when rendering is complete.\n * @param {Error} err Any error during processing.\n * @param {ImageData} output The output image data.\n * @param {Object} data The user data.\n * @private\n */\nol.source.Raster.prototype.onWorkerComplete_ = function(frameState, callback, err, output, data) {\n  if (err) {\n    callback(err);\n    return;\n  }\n  if (!output) {\n    // job aborted\n    return;\n  }\n\n  this.dispatchEvent(new ol.source.Raster.Event(\n      ol.source.Raster.EventType.AFTEROPERATIONS, frameState, data));\n\n  var resolution = frameState.viewState.resolution / frameState.pixelRatio;\n  if (!this.isDirty_(frameState.extent, resolution)) {\n    this.canvasContext_.putImageData(output, 0, 0);\n  }\n\n  callback(null);\n};\n\n\n/**\n * Get image data from a renderer.\n * @param {ol.renderer.canvas.Layer} renderer Layer renderer.\n * @param {olx.FrameState} frameState The frame state.\n * @param {ol.LayerState} layerState The layer state.\n * @return {ImageData} The image data.\n * @private\n */\nol.source.Raster.getImageData_ = function(renderer, frameState, layerState) {\n  if (!renderer.prepareFrame(frameState, layerState)) {\n    return null;\n  }\n  var width = frameState.size[0];\n  var height = frameState.size[1];\n  if (!ol.source.Raster.context_) {\n    ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);\n  } else {\n    var canvas = ol.source.Raster.context_.canvas;\n    if (canvas.width !== width || canvas.height !== height) {\n      ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);\n    } else {\n      ol.source.Raster.context_.clearRect(0, 0, width, height);\n    }\n  }\n  renderer.composeFrame(frameState, layerState, ol.source.Raster.context_);\n  return ol.source.Raster.context_.getImageData(0, 0, width, height);\n};\n\n\n/**\n * A reusable canvas context.\n * @type {CanvasRenderingContext2D}\n * @private\n */\nol.source.Raster.context_ = null;\n\n\n/**\n * Get a list of layer states from a list of renderers.\n * @param {Array.<ol.renderer.canvas.Layer>} renderers Layer renderers.\n * @return {Array.<ol.LayerState>} The layer states.\n * @private\n */\nol.source.Raster.getLayerStatesArray_ = function(renderers) {\n  return renderers.map(function(renderer) {\n    return renderer.getLayer().getLayerState();\n  });\n};\n\n\n/**\n * Create renderers for all sources.\n * @param {Array.<ol.source.Source>} sources The sources.\n * @return {Array.<ol.renderer.canvas.Layer>} Array of layer renderers.\n * @private\n */\nol.source.Raster.createRenderers_ = function(sources) {\n  var len = sources.length;\n  var renderers = new Array(len);\n  for (var i = 0; i < len; ++i) {\n    renderers[i] = ol.source.Raster.createRenderer_(sources[i]);\n  }\n  return renderers;\n};\n\n\n/**\n * Create a renderer for the provided source.\n * @param {ol.source.Source} source The source.\n * @return {ol.renderer.canvas.Layer} The renderer.\n * @private\n */\nol.source.Raster.createRenderer_ = function(source) {\n  var renderer = null;\n  if (source instanceof ol.source.Tile) {\n    renderer = ol.source.Raster.createTileRenderer_(source);\n  } else if (source instanceof ol.source.Image) {\n    renderer = ol.source.Raster.createImageRenderer_(source);\n  } else {\n    ol.DEBUG && console.assert(false, 'Unsupported source type: ' + source);\n  }\n  return renderer;\n};\n\n\n/**\n * Create an image renderer for the provided source.\n * @param {ol.source.Image} source The source.\n * @return {ol.renderer.canvas.Layer} The renderer.\n * @private\n */\nol.source.Raster.createImageRenderer_ = function(source) {\n  var layer = new ol.layer.Image({source: source});\n  return new ol.renderer.canvas.ImageLayer(layer);\n};\n\n\n/**\n * Create a tile renderer for the provided source.\n * @param {ol.source.Tile} source The source.\n * @return {ol.renderer.canvas.Layer} The renderer.\n * @private\n */\nol.source.Raster.createTileRenderer_ = function(source) {\n  var layer = new ol.layer.Tile({source: source});\n  return new ol.renderer.canvas.TileLayer(layer);\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link ol.source.Raster} instances are instances of this\n * type.\n *\n * @constructor\n * @extends {ol.events.Event}\n * @implements {oli.source.RasterEvent}\n * @param {string} type Type.\n * @param {olx.FrameState} frameState The frame state.\n * @param {Object} data An object made available to operations.\n */\nol.source.Raster.Event = function(type, frameState, data) {\n  ol.events.Event.call(this, type);\n\n  /**\n   * The raster extent.\n   * @type {ol.Extent}\n   * @api\n   */\n  this.extent = frameState.extent;\n\n  /**\n   * The pixel resolution (map units per pixel).\n   * @type {number}\n   * @api\n   */\n  this.resolution = frameState.viewState.resolution / frameState.pixelRatio;\n\n  /**\n   * An object made available to all operations.  This can be used by operations\n   * as a storage object (e.g. for calculating statistics).\n   * @type {Object}\n   * @api\n   */\n  this.data = data;\n\n};\nol.inherits(ol.source.Raster.Event, ol.events.Event);\n\n\n/**\n * @enum {string}\n */\nol.source.Raster.EventType = {\n  /**\n   * Triggered before operations are run.\n   * @event ol.source.Raster.Event#beforeoperations\n   * @api\n   */\n  BEFOREOPERATIONS: 'beforeoperations',\n\n  /**\n   * Triggered after operations are run.\n   * @event ol.source.Raster.Event#afteroperations\n   * @api\n   */\n  AFTEROPERATIONS: 'afteroperations'\n};\n\n\n/**\n * Raster operation type. Supported values are `'pixel'` and `'image'`.\n * @enum {string}\n */\nol.source.Raster.OperationType = {\n  PIXEL: 'pixel',\n  IMAGE: 'image'\n};\n\ngoog.provide('ol.source.Stamen');\n\ngoog.require('ol');\ngoog.require('ol.Attribution');\ngoog.require('ol.source.OSM');\ngoog.require('ol.source.XYZ');\n\n\n/**\n * @classdesc\n * Layer source for the Stamen tile server.\n *\n * @constructor\n * @extends {ol.source.XYZ}\n * @param {olx.source.StamenOptions} options Stamen options.\n * @api stable\n */\nol.source.Stamen = function(options) {\n\n  var i = options.layer.indexOf('-');\n  var provider = i == -1 ? options.layer : options.layer.slice(0, i);\n  ol.DEBUG && console.assert(provider in ol.source.Stamen.ProviderConfig,\n      'known provider configured');\n  var providerConfig = ol.source.Stamen.ProviderConfig[provider];\n\n  ol.DEBUG && console.assert(options.layer in ol.source.Stamen.LayerConfig,\n      'known layer configured');\n  var layerConfig = ol.source.Stamen.LayerConfig[options.layer];\n\n  var url = options.url !== undefined ? options.url :\n      'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer +\n      '/{z}/{x}/{y}.' + layerConfig.extension;\n\n  ol.source.XYZ.call(this, {\n    attributions: ol.source.Stamen.ATTRIBUTIONS,\n    cacheSize: options.cacheSize,\n    crossOrigin: 'anonymous',\n    maxZoom: options.maxZoom != undefined ? options.maxZoom : providerConfig.maxZoom,\n    minZoom: options.minZoom != undefined ? options.minZoom : providerConfig.minZoom,\n    opaque: layerConfig.opaque,\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    tileLoadFunction: options.tileLoadFunction,\n    url: url\n  });\n\n};\nol.inherits(ol.source.Stamen, ol.source.XYZ);\n\n\n/**\n * @const\n * @type {Array.<ol.Attribution>}\n */\nol.source.Stamen.ATTRIBUTIONS = [\n  new ol.Attribution({\n    html: 'Map tiles by <a href=\"http://stamen.com/\">Stamen Design</a>, ' +\n        'under <a href=\"http://creativecommons.org/licenses/by/3.0/\">CC BY' +\n        ' 3.0</a>.'\n  }),\n  ol.source.OSM.ATTRIBUTION\n];\n\n/**\n * @type {Object.<string, {extension: string, opaque: boolean}>}\n */\nol.source.Stamen.LayerConfig = {\n  'terrain': {\n    extension: 'jpg',\n    opaque: true\n  },\n  'terrain-background': {\n    extension: 'jpg',\n    opaque: true\n  },\n  'terrain-labels': {\n    extension: 'png',\n    opaque: false\n  },\n  'terrain-lines': {\n    extension: 'png',\n    opaque: false\n  },\n  'toner-background': {\n    extension: 'png',\n    opaque: true\n  },\n  'toner': {\n    extension: 'png',\n    opaque: true\n  },\n  'toner-hybrid': {\n    extension: 'png',\n    opaque: false\n  },\n  'toner-labels': {\n    extension: 'png',\n    opaque: false\n  },\n  'toner-lines': {\n    extension: 'png',\n    opaque: false\n  },\n  'toner-lite': {\n    extension: 'png',\n    opaque: true\n  },\n  'watercolor': {\n    extension: 'jpg',\n    opaque: true\n  }\n};\n\n/**\n * @type {Object.<string, {minZoom: number, maxZoom: number}>}\n */\nol.source.Stamen.ProviderConfig = {\n  'terrain': {\n    minZoom: 4,\n    maxZoom: 18\n  },\n  'toner': {\n    minZoom: 0,\n    maxZoom: 20\n  },\n  'watercolor': {\n    minZoom: 1,\n    maxZoom: 16\n  }\n};\n\ngoog.provide('ol.source.TileArcGISRest');\n\ngoog.require('ol');\ngoog.require('ol.extent');\ngoog.require('ol.math');\ngoog.require('ol.obj');\ngoog.require('ol.size');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.tilecoord');\ngoog.require('ol.uri');\n\n\n/**\n * @classdesc\n * Layer source for tile data from ArcGIS Rest services. Map and Image\n * Services are supported.\n *\n * For cached ArcGIS services, better performance is available using the\n * {@link ol.source.XYZ} data source.\n *\n * @constructor\n * @extends {ol.source.TileImage}\n * @param {olx.source.TileArcGISRestOptions=} opt_options Tile ArcGIS Rest\n *     options.\n * @api\n */\nol.source.TileArcGISRest = function(opt_options) {\n\n  var options = opt_options || {};\n\n  ol.source.TileImage.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: options.crossOrigin,\n    logo: options.logo,\n    projection: options.projection,\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    tileGrid: options.tileGrid,\n    tileLoadFunction: options.tileLoadFunction,\n    url: options.url,\n    urls: options.urls,\n    wrapX: options.wrapX !== undefined ? options.wrapX : true\n  });\n\n  /**\n   * @private\n   * @type {!Object}\n   */\n  this.params_ = options.params || {};\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.tmpExtent_ = ol.extent.createEmpty();\n\n  this.setKey(this.getKeyForParams_());\n};\nol.inherits(ol.source.TileArcGISRest, ol.source.TileImage);\n\n\n/**\n * @private\n * @return {string} The key for the current params.\n */\nol.source.TileArcGISRest.prototype.getKeyForParams_ = function() {\n  var i = 0;\n  var res = [];\n  for (var key in this.params_) {\n    res[i++] = key + '-' + this.params_[key];\n  }\n  return res.join('/');\n};\n\n\n/**\n * Get the user-provided params, i.e. those passed to the constructor through\n * the \"params\" option, and possibly updated using the updateParams method.\n * @return {Object} Params.\n * @api\n */\nol.source.TileArcGISRest.prototype.getParams = function() {\n  return this.params_;\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Size} tileSize Tile size.\n * @param {ol.Extent} tileExtent Tile extent.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @param {Object} params Params.\n * @return {string|undefined} Request URL.\n * @private\n */\nol.source.TileArcGISRest.prototype.getRequestUrl_ = function(tileCoord, tileSize, tileExtent,\n        pixelRatio, projection, params) {\n\n  var urls = this.urls;\n  if (!urls) {\n    return undefined;\n  }\n\n  // ArcGIS Server only wants the numeric portion of the projection ID.\n  var srid = projection.getCode().split(':').pop();\n\n  params['SIZE'] = tileSize[0] + ',' + tileSize[1];\n  params['BBOX'] = tileExtent.join(',');\n  params['BBOXSR'] = srid;\n  params['IMAGESR'] = srid;\n  params['DPI'] = Math.round(\n      params['DPI'] ? params['DPI'] * pixelRatio : 90 * pixelRatio\n      );\n\n  var url;\n  if (urls.length == 1) {\n    url = urls[0];\n  } else {\n    var index = ol.math.modulo(ol.tilecoord.hash(tileCoord), urls.length);\n    url = urls[index];\n  }\n\n  var modifiedUrl = url\n      .replace(/MapServer\\/?$/, 'MapServer/export')\n      .replace(/ImageServer\\/?$/, 'ImageServer/exportImage');\n  return ol.uri.appendParams(modifiedUrl, params);\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileArcGISRest.prototype.getTilePixelRatio = function(pixelRatio) {\n  return /** @type {number} */ (pixelRatio);\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileArcGISRest.prototype.fixedTileUrlFunction = function(tileCoord, pixelRatio, projection) {\n\n  var tileGrid = this.getTileGrid();\n  if (!tileGrid) {\n    tileGrid = this.getTileGridForProjection(projection);\n  }\n\n  if (tileGrid.getResolutions().length <= tileCoord[0]) {\n    return undefined;\n  }\n\n  var tileExtent = tileGrid.getTileCoordExtent(\n      tileCoord, this.tmpExtent_);\n  var tileSize = ol.size.toSize(\n      tileGrid.getTileSize(tileCoord[0]), this.tmpSize);\n\n  if (pixelRatio != 1) {\n    tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize);\n  }\n\n  // Apply default params and override with user specified values.\n  var baseParams = {\n    'F': 'image',\n    'FORMAT': 'PNG32',\n    'TRANSPARENT': true\n  };\n  ol.obj.assign(baseParams, this.params_);\n\n  return this.getRequestUrl_(tileCoord, tileSize, tileExtent,\n      pixelRatio, projection, baseParams);\n};\n\n\n/**\n * Update the user-provided params.\n * @param {Object} params Params.\n * @api stable\n */\nol.source.TileArcGISRest.prototype.updateParams = function(params) {\n  ol.obj.assign(this.params_, params);\n  this.setKey(this.getKeyForParams_());\n};\n\ngoog.provide('ol.source.TileDebug');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.dom');\ngoog.require('ol.size');\ngoog.require('ol.source.Tile');\n\n\n/**\n * @classdesc\n * A pseudo tile source, which does not fetch tiles from a server, but renders\n * a grid outline for the tile grid/projection along with the coordinates for\n * each tile. See examples/canvas-tiles for an example.\n *\n * Uses Canvas context2d, so requires Canvas support.\n *\n * @constructor\n * @extends {ol.source.Tile}\n * @param {olx.source.TileDebugOptions} options Debug tile options.\n * @api\n */\nol.source.TileDebug = function(options) {\n\n  ol.source.Tile.call(this, {\n    opaque: false,\n    projection: options.projection,\n    tileGrid: options.tileGrid,\n    wrapX: options.wrapX !== undefined ? options.wrapX : true\n  });\n\n};\nol.inherits(ol.source.TileDebug, ol.source.Tile);\n\n\n/**\n * @inheritDoc\n */\nol.source.TileDebug.prototype.getTile = function(z, x, y) {\n  var tileCoordKey = this.getKeyZXY(z, x, y);\n  if (this.tileCache.containsKey(tileCoordKey)) {\n    return /** @type {!ol.source.TileDebug.Tile_} */ (this.tileCache.get(tileCoordKey));\n  } else {\n    var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));\n    var tileCoord = [z, x, y];\n    var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord);\n    var text = !textTileCoord ? '' :\n        this.getTileCoordForTileUrlFunction(textTileCoord).toString();\n    var tile = new ol.source.TileDebug.Tile_(tileCoord, tileSize, text);\n    this.tileCache.set(tileCoordKey, tile);\n    return tile;\n  }\n};\n\n\n/**\n * @constructor\n * @extends {ol.Tile}\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Size} tileSize Tile size.\n * @param {string} text Text.\n * @private\n */\nol.source.TileDebug.Tile_ = function(tileCoord, tileSize, text) {\n\n  ol.Tile.call(this, tileCoord, ol.Tile.State.LOADED);\n\n  /**\n   * @private\n   * @type {ol.Size}\n   */\n  this.tileSize_ = tileSize;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.text_ = text;\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = null;\n\n};\nol.inherits(ol.source.TileDebug.Tile_, ol.Tile);\n\n\n/**\n * Get the image element for this tile.\n * @return {HTMLCanvasElement} Image.\n */\nol.source.TileDebug.Tile_.prototype.getImage = function() {\n  if (this.canvas_) {\n    return this.canvas_;\n  } else {\n    var tileSize = this.tileSize_;\n    var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]);\n\n    context.strokeStyle = 'black';\n    context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5);\n\n    context.fillStyle = 'black';\n    context.textAlign = 'center';\n    context.textBaseline = 'middle';\n    context.font = '24px sans-serif';\n    context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2);\n\n    this.canvas_ = context.canvas;\n    return context.canvas;\n  }\n};\n\n// FIXME check order of async callbacks\n\n/**\n * @see http://mapbox.com/developers/api/\n */\n\ngoog.provide('ol.source.TileJSON');\n\ngoog.require('ol');\ngoog.require('ol.Attribution');\ngoog.require('ol.TileUrlFunction');\ngoog.require('ol.extent');\ngoog.require('ol.net');\ngoog.require('ol.proj');\ngoog.require('ol.source.State');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.tilegrid');\n\n\n/**\n * @classdesc\n * Layer source for tile data in TileJSON format.\n *\n * @constructor\n * @extends {ol.source.TileImage}\n * @param {olx.source.TileJSONOptions} options TileJSON options.\n * @api stable\n */\nol.source.TileJSON = function(options) {\n\n  /**\n   * @type {TileJSON}\n   * @private\n   */\n  this.tileJSON_ = null;\n\n  ol.source.TileImage.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: options.crossOrigin,\n    projection: ol.proj.get('EPSG:3857'),\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    state: ol.source.State.LOADING,\n    tileLoadFunction: options.tileLoadFunction,\n    wrapX: options.wrapX !== undefined ? options.wrapX : true\n  });\n\n  if (options.jsonp) {\n    ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),\n        this.handleTileJSONError.bind(this));\n  } else {\n    var client = new XMLHttpRequest();\n    client.addEventListener('load', this.onXHRLoad_.bind(this));\n    client.addEventListener('error', this.onXHRError_.bind(this));\n    client.open('GET', options.url);\n    client.send();\n  }\n\n};\nol.inherits(ol.source.TileJSON, ol.source.TileImage);\n\n\n/**\n * @private\n * @param {Event} event The load event.\n */\nol.source.TileJSON.prototype.onXHRLoad_ = function(event) {\n  var client = /** @type {XMLHttpRequest} */ (event.target);\n  // status will be 0 for file:// urls\n  if (!client.status || client.status >= 200 && client.status < 300) {\n    var response;\n    try {\n      response = /** @type {TileJSON} */(JSON.parse(client.responseText));\n    } catch (err) {\n      this.handleTileJSONError();\n      return;\n    }\n    this.handleTileJSONResponse(response);\n  } else {\n    this.handleTileJSONError();\n  }\n};\n\n\n/**\n * @private\n * @param {Event} event The error event.\n */\nol.source.TileJSON.prototype.onXHRError_ = function(event) {\n  this.handleTileJSONError();\n};\n\n\n/**\n * @return {TileJSON} The tilejson object.\n * @api\n */\nol.source.TileJSON.prototype.getTileJSON = function() {\n  return this.tileJSON_;\n};\n\n\n/**\n * @protected\n * @param {TileJSON} tileJSON Tile JSON.\n */\nol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {\n\n  var epsg4326Projection = ol.proj.get('EPSG:4326');\n\n  var sourceProjection = this.getProjection();\n  var extent;\n  if (tileJSON.bounds !== undefined) {\n    var transform = ol.proj.getTransformFromProjections(\n        epsg4326Projection, sourceProjection);\n    extent = ol.extent.applyTransform(tileJSON.bounds, transform);\n  }\n\n  if (tileJSON.scheme !== undefined) {\n    ol.DEBUG && console.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is \"xyz\"');\n  }\n  var minZoom = tileJSON.minzoom || 0;\n  var maxZoom = tileJSON.maxzoom || 22;\n  var tileGrid = ol.tilegrid.createXYZ({\n    extent: ol.tilegrid.extentFromProjection(sourceProjection),\n    maxZoom: maxZoom,\n    minZoom: minZoom\n  });\n  this.tileGrid = tileGrid;\n\n  this.tileUrlFunction =\n      ol.TileUrlFunction.createFromTemplates(tileJSON.tiles, tileGrid);\n\n  if (tileJSON.attribution !== undefined && !this.getAttributions()) {\n    var attributionExtent = extent !== undefined ?\n        extent : epsg4326Projection.getExtent();\n    /** @type {Object.<string, Array.<ol.TileRange>>} */\n    var tileRanges = {};\n    var z, zKey;\n    for (z = minZoom; z <= maxZoom; ++z) {\n      zKey = z.toString();\n      tileRanges[zKey] =\n          [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];\n    }\n    this.setAttributions([\n      new ol.Attribution({\n        html: tileJSON.attribution,\n        tileRanges: tileRanges\n      })\n    ]);\n  }\n  this.tileJSON_ = tileJSON;\n  this.setState(ol.source.State.READY);\n\n};\n\n\n/**\n * @protected\n */\nol.source.TileJSON.prototype.handleTileJSONError = function() {\n  this.setState(ol.source.State.ERROR);\n};\n\ngoog.provide('ol.source.TileUTFGrid');\n\ngoog.require('ol');\ngoog.require('ol.Attribution');\ngoog.require('ol.Tile');\ngoog.require('ol.TileUrlFunction');\ngoog.require('ol.asserts');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.extent');\ngoog.require('ol.net');\ngoog.require('ol.proj');\ngoog.require('ol.source.State');\ngoog.require('ol.source.Tile');\ngoog.require('ol.tilegrid');\n\n\n/**\n * @classdesc\n * Layer source for UTFGrid interaction data loaded from TileJSON format.\n *\n * @constructor\n * @extends {ol.source.Tile}\n * @param {olx.source.TileUTFGridOptions} options Source options.\n * @api\n */\nol.source.TileUTFGrid = function(options) {\n  ol.source.Tile.call(this, {\n    projection: ol.proj.get('EPSG:3857'),\n    state: ol.source.State.LOADING\n  });\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.preemptive_ = options.preemptive !== undefined ?\n      options.preemptive : true;\n\n  /**\n   * @private\n   * @type {!ol.TileUrlFunctionType}\n   */\n  this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction;\n\n  /**\n   * @private\n   * @type {string|undefined}\n   */\n  this.template_ = undefined;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.jsonp_ = options.jsonp || false;\n\n  if (options.url) {\n    if (this.jsonp_) {\n      ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),\n          this.handleTileJSONError.bind(this));\n    } else {\n      var client = new XMLHttpRequest();\n      client.addEventListener('load', this.onXHRLoad_.bind(this));\n      client.addEventListener('error', this.onXHRError_.bind(this));\n      client.open('GET', options.url);\n      client.send();\n    }\n  } else if (options.tileJSON) {\n    this.handleTileJSONResponse(options.tileJSON);\n  } else {\n    ol.asserts.assert(false, 51); // Either `url` or `tileJSON` options must be provided\n  }\n};\nol.inherits(ol.source.TileUTFGrid, ol.source.Tile);\n\n\n/**\n * @private\n * @param {Event} event The load event.\n */\nol.source.TileUTFGrid.prototype.onXHRLoad_ = function(event) {\n  var client = /** @type {XMLHttpRequest} */ (event.target);\n  // status will be 0 for file:// urls\n  if (!client.status || client.status >= 200 && client.status < 300) {\n    var response;\n    try {\n      response = /** @type {TileJSON} */(JSON.parse(client.responseText));\n    } catch (err) {\n      this.handleTileJSONError();\n      return;\n    }\n    this.handleTileJSONResponse(response);\n  } else {\n    this.handleTileJSONError();\n  }\n};\n\n\n/**\n * @private\n * @param {Event} event The error event.\n */\nol.source.TileUTFGrid.prototype.onXHRError_ = function(event) {\n  this.handleTileJSONError();\n};\n\n\n/**\n * Return the template from TileJSON.\n * @return {string|undefined} The template from TileJSON.\n * @api\n */\nol.source.TileUTFGrid.prototype.getTemplate = function() {\n  return this.template_;\n};\n\n\n/**\n * Calls the callback (synchronously by default) with the available data\n * for given coordinate and resolution (or `null` if not yet loaded or\n * in case of an error).\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} resolution Resolution.\n * @param {function(this: T, *)} callback Callback.\n * @param {T=} opt_this The object to use as `this` in the callback.\n * @param {boolean=} opt_request If `true` the callback is always async.\n *                               The tile data is requested if not yet loaded.\n * @template T\n * @api\n */\nol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function(\n    coordinate, resolution, callback, opt_this, opt_request) {\n  if (this.tileGrid) {\n    var tileCoord = this.tileGrid.getTileCoordForCoordAndResolution(\n        coordinate, resolution);\n    var tile = /** @type {!ol.source.TileUTFGrid.Tile_} */(this.getTile(\n        tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection()));\n    tile.forDataAtCoordinate(coordinate, callback, opt_this, opt_request);\n  } else {\n    if (opt_request === true) {\n      setTimeout(function() {\n        callback.call(opt_this, null);\n      }, 0);\n    } else {\n      callback.call(opt_this, null);\n    }\n  }\n};\n\n\n/**\n * @protected\n */\nol.source.TileUTFGrid.prototype.handleTileJSONError = function() {\n  this.setState(ol.source.State.ERROR);\n};\n\n\n/**\n * TODO: very similar to ol.source.TileJSON#handleTileJSONResponse\n * @protected\n * @param {TileJSON} tileJSON Tile JSON.\n */\nol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {\n\n  var epsg4326Projection = ol.proj.get('EPSG:4326');\n\n  var sourceProjection = this.getProjection();\n  var extent;\n  if (tileJSON.bounds !== undefined) {\n    var transform = ol.proj.getTransformFromProjections(\n        epsg4326Projection, sourceProjection);\n    extent = ol.extent.applyTransform(tileJSON.bounds, transform);\n  }\n\n  if (tileJSON.scheme !== undefined) {\n    ol.DEBUG && console.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is \"xyz\"');\n  }\n  var minZoom = tileJSON.minzoom || 0;\n  var maxZoom = tileJSON.maxzoom || 22;\n  var tileGrid = ol.tilegrid.createXYZ({\n    extent: ol.tilegrid.extentFromProjection(sourceProjection),\n    maxZoom: maxZoom,\n    minZoom: minZoom\n  });\n  this.tileGrid = tileGrid;\n\n  this.template_ = tileJSON.template;\n\n  var grids = tileJSON.grids;\n  if (!grids) {\n    this.setState(ol.source.State.ERROR);\n    return;\n  }\n\n  this.tileUrlFunction_ =\n      ol.TileUrlFunction.createFromTemplates(grids, tileGrid);\n\n  if (tileJSON.attribution !== undefined) {\n    var attributionExtent = extent !== undefined ?\n        extent : epsg4326Projection.getExtent();\n    /** @type {Object.<string, Array.<ol.TileRange>>} */\n    var tileRanges = {};\n    var z, zKey;\n    for (z = minZoom; z <= maxZoom; ++z) {\n      zKey = z.toString();\n      tileRanges[zKey] =\n          [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];\n    }\n    this.setAttributions([\n      new ol.Attribution({\n        html: tileJSON.attribution,\n        tileRanges: tileRanges\n      })\n    ]);\n  }\n\n  this.setState(ol.source.State.READY);\n\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileUTFGrid.prototype.getTile = function(z, x, y, pixelRatio, projection) {\n  var tileCoordKey = this.getKeyZXY(z, x, y);\n  if (this.tileCache.containsKey(tileCoordKey)) {\n    return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));\n  } else {\n    ol.DEBUG && console.assert(projection, 'argument projection is truthy');\n    var tileCoord = [z, x, y];\n    var urlTileCoord =\n        this.getTileCoordForTileUrlFunction(tileCoord, projection);\n    var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection);\n    var tile = new ol.source.TileUTFGrid.Tile_(\n        tileCoord,\n        tileUrl !== undefined ? ol.Tile.State.IDLE : ol.Tile.State.EMPTY,\n        tileUrl !== undefined ? tileUrl : '',\n        this.tileGrid.getTileCoordExtent(tileCoord),\n        this.preemptive_,\n        this.jsonp_);\n    this.tileCache.set(tileCoordKey, tile);\n    return tile;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileUTFGrid.prototype.useTile = function(z, x, y) {\n  var tileCoordKey = this.getKeyZXY(z, x, y);\n  if (this.tileCache.containsKey(tileCoordKey)) {\n    this.tileCache.get(tileCoordKey);\n  }\n};\n\n\n/**\n * @constructor\n * @extends {ol.Tile}\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Tile.State} state State.\n * @param {string} src Image source URI.\n * @param {ol.Extent} extent Extent of the tile.\n * @param {boolean} preemptive Load the tile when visible (before it's needed).\n * @param {boolean} jsonp Load the tile as a script.\n * @private\n */\nol.source.TileUTFGrid.Tile_ = function(tileCoord, state, src, extent, preemptive, jsonp) {\n\n  ol.Tile.call(this, tileCoord, state);\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.src_ = src;\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.extent_ = extent;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.preemptive_ = preemptive;\n\n  /**\n   * @private\n   * @type {Array.<string>}\n   */\n  this.grid_ = null;\n\n  /**\n   * @private\n   * @type {Array.<string>}\n   */\n  this.keys_ = null;\n\n  /**\n   * @private\n   * @type {Object.<string, Object>|undefined}\n   */\n  this.data_ = null;\n\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.jsonp_ = jsonp;\n\n};\nol.inherits(ol.source.TileUTFGrid.Tile_, ol.Tile);\n\n\n/**\n * Get the image element for this tile.\n * @return {Image} Image.\n */\nol.source.TileUTFGrid.Tile_.prototype.getImage = function() {\n  return null;\n};\n\n\n/**\n * Synchronously returns data at given coordinate (if available).\n * @param {ol.Coordinate} coordinate Coordinate.\n * @return {*} The data.\n */\nol.source.TileUTFGrid.Tile_.prototype.getData = function(coordinate) {\n  if (!this.grid_ || !this.keys_) {\n    return null;\n  }\n  var xRelative = (coordinate[0] - this.extent_[0]) /\n      (this.extent_[2] - this.extent_[0]);\n  var yRelative = (coordinate[1] - this.extent_[1]) /\n      (this.extent_[3] - this.extent_[1]);\n\n  var row = this.grid_[Math.floor((1 - yRelative) * this.grid_.length)];\n\n  if (typeof row !== 'string') {\n    return null;\n  }\n\n  var code = row.charCodeAt(Math.floor(xRelative * row.length));\n  if (code >= 93) {\n    code--;\n  }\n  if (code >= 35) {\n    code--;\n  }\n  code -= 32;\n\n  var data = null;\n  if (code in this.keys_) {\n    var id = this.keys_[code];\n    if (this.data_ && id in this.data_) {\n      data = this.data_[id];\n    } else {\n      data = id;\n    }\n  }\n  return data;\n};\n\n\n/**\n * Calls the callback (synchronously by default) with the available data\n * for given coordinate (or `null` if not yet loaded).\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {function(this: T, *)} callback Callback.\n * @param {T=} opt_this The object to use as `this` in the callback.\n * @param {boolean=} opt_request If `true` the callback is always async.\n *                               The tile data is requested if not yet loaded.\n * @template T\n */\nol.source.TileUTFGrid.Tile_.prototype.forDataAtCoordinate = function(coordinate, callback, opt_this, opt_request) {\n  if (this.state == ol.Tile.State.IDLE && opt_request === true) {\n    ol.events.listenOnce(this, ol.events.EventType.CHANGE, function(e) {\n      callback.call(opt_this, this.getData(coordinate));\n    }, this);\n    this.loadInternal_();\n  } else {\n    if (opt_request === true) {\n      setTimeout(function() {\n        callback.call(opt_this, this.getData(coordinate));\n      }.bind(this), 0);\n    } else {\n      callback.call(opt_this, this.getData(coordinate));\n    }\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileUTFGrid.Tile_.prototype.getKey = function() {\n  return this.src_;\n};\n\n\n/**\n * @private\n */\nol.source.TileUTFGrid.Tile_.prototype.handleError_ = function() {\n  this.state = ol.Tile.State.ERROR;\n  this.changed();\n};\n\n\n/**\n * @param {!UTFGridJSON} json UTFGrid data.\n * @private\n */\nol.source.TileUTFGrid.Tile_.prototype.handleLoad_ = function(json) {\n  this.grid_ = json.grid;\n  this.keys_ = json.keys;\n  this.data_ = json.data;\n\n  this.state = ol.Tile.State.EMPTY;\n  this.changed();\n};\n\n\n/**\n * @private\n */\nol.source.TileUTFGrid.Tile_.prototype.loadInternal_ = function() {\n  if (this.state == ol.Tile.State.IDLE) {\n    this.state = ol.Tile.State.LOADING;\n    if (this.jsonp_) {\n      ol.net.jsonp(this.src_, this.handleLoad_.bind(this),\n          this.handleError_.bind(this));\n    } else {\n      var client = new XMLHttpRequest();\n      client.addEventListener('load', this.onXHRLoad_.bind(this));\n      client.addEventListener('error', this.onXHRError_.bind(this));\n      client.open('GET', this.src_);\n      client.send();\n    }\n  }\n};\n\n\n/**\n * @private\n * @param {Event} event The load event.\n */\nol.source.TileUTFGrid.Tile_.prototype.onXHRLoad_ = function(event) {\n  var client = /** @type {XMLHttpRequest} */ (event.target);\n  // status will be 0 for file:// urls\n  if (!client.status || client.status >= 200 && client.status < 300) {\n    var response;\n    try {\n      response = /** @type {!UTFGridJSON} */(JSON.parse(client.responseText));\n    } catch (err) {\n      this.handleError_();\n      return;\n    }\n    this.handleLoad_(response);\n  } else {\n    this.handleError_();\n  }\n};\n\n\n/**\n * @private\n * @param {Event} event The error event.\n */\nol.source.TileUTFGrid.Tile_.prototype.onXHRError_ = function(event) {\n  this.handleError_();\n};\n\n\n/**\n * Load not yet loaded URI.\n */\nol.source.TileUTFGrid.Tile_.prototype.load = function() {\n  if (this.preemptive_) {\n    this.loadInternal_();\n  }\n};\n\n// FIXME add minZoom support\n// FIXME add date line wrap (tile coord transform)\n// FIXME cannot be shared between maps with different projections\n\ngoog.provide('ol.source.TileWMS');\n\ngoog.require('ol');\ngoog.require('ol.asserts');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.math');\ngoog.require('ol.proj');\ngoog.require('ol.size');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.source.WMSServerType');\ngoog.require('ol.tilecoord');\ngoog.require('ol.string');\ngoog.require('ol.uri');\n\n/**\n * @classdesc\n * Layer source for tile data from WMS servers.\n *\n * @constructor\n * @extends {ol.source.TileImage}\n * @param {olx.source.TileWMSOptions=} opt_options Tile WMS options.\n * @api stable\n */\nol.source.TileWMS = function(opt_options) {\n\n  var options = opt_options || {};\n\n  var params = options.params || {};\n\n  var transparent = 'TRANSPARENT' in params ? params['TRANSPARENT'] : true;\n\n  ol.source.TileImage.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: options.crossOrigin,\n    logo: options.logo,\n    opaque: !transparent,\n    projection: options.projection,\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    tileGrid: options.tileGrid,\n    tileLoadFunction: options.tileLoadFunction,\n    url: options.url,\n    urls: options.urls,\n    wrapX: options.wrapX !== undefined ? options.wrapX : true\n  });\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.gutter_ = options.gutter !== undefined ? options.gutter : 0;\n\n  /**\n   * @private\n   * @type {!Object}\n   */\n  this.params_ = params;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.v13_ = true;\n\n  /**\n   * @private\n   * @type {ol.source.WMSServerType|undefined}\n   */\n  this.serverType_ =\n      /** @type {ol.source.WMSServerType|undefined} */ (options.serverType);\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.coordKeyPrefix_ = '';\n  this.resetCoordKeyPrefix_();\n\n  /**\n   * @private\n   * @type {ol.Extent}\n   */\n  this.tmpExtent_ = ol.extent.createEmpty();\n\n  this.updateV13_();\n  this.setKey(this.getKeyForParams_());\n\n};\nol.inherits(ol.source.TileWMS, ol.source.TileImage);\n\n\n/**\n * Return the GetFeatureInfo URL for the passed coordinate, resolution, and\n * projection. Return `undefined` if the GetFeatureInfo URL cannot be\n * constructed.\n * @param {ol.Coordinate} coordinate Coordinate.\n * @param {number} resolution Resolution.\n * @param {ol.ProjectionLike} projection Projection.\n * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should\n *     be provided. If `QUERY_LAYERS` is not provided then the layers specified\n *     in the `LAYERS` parameter will be used. `VERSION` should not be\n *     specified here.\n * @return {string|undefined} GetFeatureInfo URL.\n * @api stable\n */\nol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {\n\n  ol.DEBUG && console.assert(!('VERSION' in params),\n      'key VERSION is not allowed in params');\n\n  var projectionObj = ol.proj.get(projection);\n\n  var tileGrid = this.getTileGrid();\n  if (!tileGrid) {\n    tileGrid = this.getTileGridForProjection(projectionObj);\n  }\n\n  var tileCoord = tileGrid.getTileCoordForCoordAndResolution(\n      coordinate, resolution);\n\n  if (tileGrid.getResolutions().length <= tileCoord[0]) {\n    return undefined;\n  }\n\n  var tileResolution = tileGrid.getResolution(tileCoord[0]);\n  var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);\n  var tileSize = ol.size.toSize(\n      tileGrid.getTileSize(tileCoord[0]), this.tmpSize);\n\n  var gutter = this.gutter_;\n  if (gutter !== 0) {\n    tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);\n    tileExtent = ol.extent.buffer(tileExtent,\n        tileResolution * gutter, tileExtent);\n  }\n\n  var baseParams = {\n    'SERVICE': 'WMS',\n    'VERSION': ol.DEFAULT_WMS_VERSION,\n    'REQUEST': 'GetFeatureInfo',\n    'FORMAT': 'image/png',\n    'TRANSPARENT': true,\n    'QUERY_LAYERS': this.params_['LAYERS']\n  };\n  ol.obj.assign(baseParams, this.params_, params);\n\n  var x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution);\n  var y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution);\n\n  baseParams[this.v13_ ? 'I' : 'X'] = x;\n  baseParams[this.v13_ ? 'J' : 'Y'] = y;\n\n  return this.getRequestUrl_(tileCoord, tileSize, tileExtent,\n      1, projectionObj, baseParams);\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileWMS.prototype.getGutterInternal = function() {\n  return this.gutter_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileWMS.prototype.getKeyZXY = function(z, x, y) {\n  return this.coordKeyPrefix_ + ol.source.TileImage.prototype.getKeyZXY.call(this, z, x, y);\n};\n\n\n/**\n * Get the user-provided params, i.e. those passed to the constructor through\n * the \"params\" option, and possibly updated using the updateParams method.\n * @return {Object} Params.\n * @api stable\n */\nol.source.TileWMS.prototype.getParams = function() {\n  return this.params_;\n};\n\n\n/**\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Size} tileSize Tile size.\n * @param {ol.Extent} tileExtent Tile extent.\n * @param {number} pixelRatio Pixel ratio.\n * @param {ol.proj.Projection} projection Projection.\n * @param {Object} params Params.\n * @return {string|undefined} Request URL.\n * @private\n */\nol.source.TileWMS.prototype.getRequestUrl_ = function(tileCoord, tileSize, tileExtent,\n        pixelRatio, projection, params) {\n\n  var urls = this.urls;\n  if (!urls) {\n    return undefined;\n  }\n\n  params['WIDTH'] = tileSize[0];\n  params['HEIGHT'] = tileSize[1];\n\n  params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();\n\n  if (!('STYLES' in this.params_)) {\n    params['STYLES'] = '';\n  }\n\n  if (pixelRatio != 1) {\n    switch (this.serverType_) {\n      case ol.source.WMSServerType.GEOSERVER:\n        var dpi = (90 * pixelRatio + 0.5) | 0;\n        if ('FORMAT_OPTIONS' in params) {\n          params['FORMAT_OPTIONS'] += ';dpi:' + dpi;\n        } else {\n          params['FORMAT_OPTIONS'] = 'dpi:' + dpi;\n        }\n        break;\n      case ol.source.WMSServerType.MAPSERVER:\n        params['MAP_RESOLUTION'] = 90 * pixelRatio;\n        break;\n      case ol.source.WMSServerType.CARMENTA_SERVER:\n      case ol.source.WMSServerType.QGIS:\n        params['DPI'] = 90 * pixelRatio;\n        break;\n      default:\n        ol.asserts.assert(false, 52); // Unknown `serverType` configured\n        break;\n    }\n  }\n\n  var axisOrientation = projection.getAxisOrientation();\n  var bbox = tileExtent;\n  if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {\n    var tmp;\n    tmp = tileExtent[0];\n    bbox[0] = tileExtent[1];\n    bbox[1] = tmp;\n    tmp = tileExtent[2];\n    bbox[2] = tileExtent[3];\n    bbox[3] = tmp;\n  }\n  params['BBOX'] = bbox.join(',');\n\n  var url;\n  if (urls.length == 1) {\n    url = urls[0];\n  } else {\n    var index = ol.math.modulo(ol.tilecoord.hash(tileCoord), urls.length);\n    url = urls[index];\n  }\n  return ol.uri.appendParams(url, params);\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileWMS.prototype.getTilePixelRatio = function(pixelRatio) {\n  return (!this.hidpi_ || this.serverType_ === undefined) ? 1 :\n      /** @type {number} */ (pixelRatio);\n};\n\n\n/**\n * @private\n */\nol.source.TileWMS.prototype.resetCoordKeyPrefix_ = function() {\n  var i = 0;\n  var res = [];\n\n  if (this.urls) {\n    var j, jj;\n    for (j = 0, jj = this.urls.length; j < jj; ++j) {\n      res[i++] = this.urls[j];\n    }\n  }\n\n  this.coordKeyPrefix_ = res.join('#');\n};\n\n\n/**\n * @private\n * @return {string} The key for the current params.\n */\nol.source.TileWMS.prototype.getKeyForParams_ = function() {\n  var i = 0;\n  var res = [];\n  for (var key in this.params_) {\n    res[i++] = key + '-' + this.params_[key];\n  }\n  return res.join('/');\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.TileWMS.prototype.fixedTileUrlFunction = function(tileCoord, pixelRatio, projection) {\n\n  var tileGrid = this.getTileGrid();\n  if (!tileGrid) {\n    tileGrid = this.getTileGridForProjection(projection);\n  }\n\n  if (tileGrid.getResolutions().length <= tileCoord[0]) {\n    return undefined;\n  }\n\n  if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {\n    pixelRatio = 1;\n  }\n\n  var tileResolution = tileGrid.getResolution(tileCoord[0]);\n  var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);\n  var tileSize = ol.size.toSize(\n      tileGrid.getTileSize(tileCoord[0]), this.tmpSize);\n\n  var gutter = this.gutter_;\n  if (gutter !== 0) {\n    tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);\n    tileExtent = ol.extent.buffer(tileExtent,\n        tileResolution * gutter, tileExtent);\n  }\n\n  if (pixelRatio != 1) {\n    tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize);\n  }\n\n  var baseParams = {\n    'SERVICE': 'WMS',\n    'VERSION': ol.DEFAULT_WMS_VERSION,\n    'REQUEST': 'GetMap',\n    'FORMAT': 'image/png',\n    'TRANSPARENT': true\n  };\n  ol.obj.assign(baseParams, this.params_);\n\n  return this.getRequestUrl_(tileCoord, tileSize, tileExtent,\n      pixelRatio, projection, baseParams);\n};\n\n/**\n * @inheritDoc\n */\nol.source.TileWMS.prototype.setUrls = function(urls) {\n  ol.source.TileImage.prototype.setUrls.call(this, urls);\n  this.resetCoordKeyPrefix_();\n};\n\n\n/**\n * Update the user-provided params.\n * @param {Object} params Params.\n * @api stable\n */\nol.source.TileWMS.prototype.updateParams = function(params) {\n  ol.obj.assign(this.params_, params);\n  this.resetCoordKeyPrefix_();\n  this.updateV13_();\n  this.setKey(this.getKeyForParams_());\n};\n\n\n/**\n * @private\n */\nol.source.TileWMS.prototype.updateV13_ = function() {\n  var version = this.params_['VERSION'] || ol.DEFAULT_WMS_VERSION;\n  this.v13_ = ol.string.compareVersions(version, '1.3') >= 0;\n};\n\ngoog.provide('ol.VectorTile');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.dom');\ngoog.require('ol.featureloader');\n\n\n/**\n * @constructor\n * @extends {ol.Tile}\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Tile.State} state State.\n * @param {string} src Data source url.\n * @param {ol.format.Feature} format Feature format.\n * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.\n */\nol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {\n\n  ol.Tile.call(this, tileCoord, state);\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.context_ = ol.dom.createCanvasContext2D();\n\n  /**\n   * @private\n   * @type {ol.format.Feature}\n   */\n  this.format_ = format;\n\n  /**\n   * @private\n   * @type {Array.<ol.Feature>}\n   */\n  this.features_ = null;\n\n  /**\n   * @private\n   * @type {ol.FeatureLoader}\n   */\n  this.loader_;\n\n  /**\n   * Data projection\n   * @private\n   * @type {ol.proj.Projection}\n   */\n  this.projection_;\n\n  /**\n   * @private\n   * @type {ol.TileReplayState}\n   */\n  this.replayState_ = {\n    dirty: false,\n    renderedRenderOrder: null,\n    renderedRevision: -1,\n    renderedTileRevision: -1,\n    replayGroup: null\n  };\n\n  /**\n   * @private\n   * @type {ol.TileLoadFunctionType}\n   */\n  this.tileLoadFunction_ = tileLoadFunction;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.url_ = src;\n\n};\nol.inherits(ol.VectorTile, ol.Tile);\n\n\n/**\n * @return {CanvasRenderingContext2D} The rendering context.\n */\nol.VectorTile.prototype.getContext = function() {\n  return this.context_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.VectorTile.prototype.getImage = function() {\n  return this.replayState_.renderedTileRevision == -1 ?\n      null : this.context_.canvas;\n};\n\n\n/**\n * Get the feature format assigned for reading this tile's features.\n * @return {ol.format.Feature} Feature format.\n * @api\n */\nol.VectorTile.prototype.getFormat = function() {\n  return this.format_;\n};\n\n\n/**\n * @return {Array.<ol.Feature>} Features.\n */\nol.VectorTile.prototype.getFeatures = function() {\n  return this.features_;\n};\n\n\n/**\n * @return {ol.TileReplayState} The replay state.\n */\nol.VectorTile.prototype.getReplayState = function() {\n  return this.replayState_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.VectorTile.prototype.getKey = function() {\n  return this.url_;\n};\n\n\n/**\n * @return {ol.proj.Projection} Feature projection.\n */\nol.VectorTile.prototype.getProjection = function() {\n  return this.projection_;\n};\n\n\n/**\n * Load the tile.\n */\nol.VectorTile.prototype.load = function() {\n  if (this.state == ol.Tile.State.IDLE) {\n    this.setState(ol.Tile.State.LOADING);\n    this.tileLoadFunction_(this, this.url_);\n    this.loader_(null, NaN, null);\n  }\n};\n\n\n/**\n * Handler for successful tile load.\n * @param {Array.<ol.Feature>} features The loaded features.\n * @param {ol.proj.Projection} dataProjection Data projection.\n */\nol.VectorTile.prototype.onLoad_ = function(features, dataProjection) {\n  this.setProjection(dataProjection);\n  this.setFeatures(features);\n};\n\n\n/**\n * Handler for tile load errors.\n */\nol.VectorTile.prototype.onError_ = function() {\n  this.setState(ol.Tile.State.ERROR);\n};\n\n\n/**\n * @param {Array.<ol.Feature>} features Features.\n * @api\n */\nol.VectorTile.prototype.setFeatures = function(features) {\n  this.features_ = features;\n  this.setState(ol.Tile.State.LOADED);\n};\n\n\n/**\n * Set the projection of the features that were added with {@link #setFeatures}.\n * @param {ol.proj.Projection} projection Feature projection.\n * @api\n */\nol.VectorTile.prototype.setProjection = function(projection) {\n  this.projection_ = projection;\n};\n\n\n/**\n * @param {ol.Tile.State} tileState Tile state.\n */\nol.VectorTile.prototype.setState = function(tileState) {\n  this.state = tileState;\n  this.changed();\n};\n\n\n/**\n * Set the feature loader for reading this tile's features.\n * @param {ol.FeatureLoader} loader Feature loader.\n * @api\n */\nol.VectorTile.prototype.setLoader = function(loader) {\n  this.loader_ = loader;\n};\n\n\n/**\n * Sets the loader for a tile.\n * @param {ol.VectorTile} tile Vector tile.\n * @param {string} url URL.\n */\nol.VectorTile.defaultLoadFunction = function(tile, url) {\n  var loader = ol.featureloader.loadFeaturesXhr(\n      url, tile.getFormat(), tile.onLoad_.bind(tile), tile.onError_.bind(tile));\n\n  tile.setLoader(loader);\n};\n\ngoog.provide('ol.source.VectorTile');\n\ngoog.require('ol');\ngoog.require('ol.Tile');\ngoog.require('ol.VectorTile');\ngoog.require('ol.events');\ngoog.require('ol.events.EventType');\ngoog.require('ol.size');\ngoog.require('ol.source.UrlTile');\n\n\n/**\n * @classdesc\n * Class for layer sources providing vector data divided into a tile grid, to be\n * used with {@link ol.layer.VectorTile}. Although this source receives tiles\n * with vector features from the server, it is not meant for feature editing.\n * Features are optimized for rendering, their geometries are clipped at or near\n * tile boundaries and simplified for a view resolution. See\n * {@link ol.source.Vector} for vector sources that are suitable for feature\n * editing.\n *\n * @constructor\n * @fires ol.source.Tile.Event\n * @extends {ol.source.UrlTile}\n * @param {olx.source.VectorTileOptions} options Vector tile options.\n * @api\n */\nol.source.VectorTile = function(options) {\n\n  ol.source.UrlTile.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize !== undefined ? options.cacheSize : 128,\n    extent: options.extent,\n    logo: options.logo,\n    opaque: false,\n    projection: options.projection,\n    state: options.state,\n    tileGrid: options.tileGrid,\n    tileLoadFunction: options.tileLoadFunction ?\n        options.tileLoadFunction : ol.VectorTile.defaultLoadFunction,\n    tileUrlFunction: options.tileUrlFunction,\n    tilePixelRatio: options.tilePixelRatio,\n    url: options.url,\n    urls: options.urls,\n    wrapX: options.wrapX === undefined ? true : options.wrapX\n  });\n\n  /**\n   * @private\n   * @type {ol.format.Feature}\n   */\n  this.format_ = options.format ? options.format : null;\n\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this.overlaps_ = options.overlaps == undefined ? true : options.overlaps;\n\n  /**\n   * @protected\n   * @type {function(new: ol.VectorTile, ol.TileCoord, ol.Tile.State, string,\n   *        ol.format.Feature, ol.TileLoadFunctionType)}\n   */\n  this.tileClass = options.tileClass ? options.tileClass : ol.VectorTile;\n\n};\nol.inherits(ol.source.VectorTile, ol.source.UrlTile);\n\n\n/**\n * @return {boolean} The source can have overlapping geometries.\n */\nol.source.VectorTile.prototype.getOverlaps = function() {\n  return this.overlaps_;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projection) {\n  var tileCoordKey = this.getKeyZXY(z, x, y);\n  if (this.tileCache.containsKey(tileCoordKey)) {\n    return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));\n  } else {\n    var tileCoord = [z, x, y];\n    var urlTileCoord = this.getTileCoordForTileUrlFunction(\n        tileCoord, projection);\n    var tileUrl = urlTileCoord ?\n        this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;\n    var tile = new this.tileClass(\n        tileCoord,\n        tileUrl !== undefined ? ol.Tile.State.IDLE : ol.Tile.State.EMPTY,\n        tileUrl !== undefined ? tileUrl : '',\n        this.format_, this.tileLoadFunction);\n    ol.events.listen(tile, ol.events.EventType.CHANGE,\n        this.handleTileChange, this);\n\n    this.tileCache.set(tileCoordKey, tile);\n    return tile;\n  }\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.VectorTile.prototype.getTilePixelRatio = function(opt_pixelRatio) {\n  return opt_pixelRatio == undefined ?\n      ol.source.UrlTile.prototype.getTilePixelRatio.call(this, opt_pixelRatio) :\n      opt_pixelRatio;\n};\n\n\n/**\n * @inheritDoc\n */\nol.source.VectorTile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {\n  var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));\n  return [Math.round(tileSize[0] * pixelRatio), Math.round(tileSize[1] * pixelRatio)];\n};\n\ngoog.provide('ol.tilegrid.WMTS');\n\ngoog.require('ol');\ngoog.require('ol.array');\ngoog.require('ol.proj');\ngoog.require('ol.tilegrid.TileGrid');\n\n\n/**\n * @classdesc\n * Set the grid pattern for sources accessing WMTS tiled-image servers.\n *\n * @constructor\n * @extends {ol.tilegrid.TileGrid}\n * @param {olx.tilegrid.WMTSOptions} options WMTS options.\n * @struct\n * @api\n */\nol.tilegrid.WMTS = function(options) {\n\n  ol.DEBUG && console.assert(\n      options.resolutions.length == options.matrixIds.length,\n      'options resolutions and matrixIds must have equal length (%s == %s)',\n      options.resolutions.length, options.matrixIds.length);\n\n  /**\n   * @private\n   * @type {!Array.<string>}\n   */\n  this.matrixIds_ = options.matrixIds;\n  // FIXME: should the matrixIds become optionnal?\n\n  ol.tilegrid.TileGrid.call(this, {\n    extent: options.extent,\n    origin: options.origin,\n    origins: options.origins,\n    resolutions: options.resolutions,\n    tileSize: options.tileSize,\n    tileSizes: options.tileSizes,\n    sizes: options.sizes\n  });\n\n};\nol.inherits(ol.tilegrid.WMTS, ol.tilegrid.TileGrid);\n\n\n/**\n * @param {number} z Z.\n * @return {string} MatrixId..\n */\nol.tilegrid.WMTS.prototype.getMatrixId = function(z) {\n  ol.DEBUG && console.assert(0 <= z && z < this.matrixIds_.length,\n      'attempted to retrieve matrixId for illegal z (%s)', z);\n  return this.matrixIds_[z];\n};\n\n\n/**\n * Get the list of matrix identifiers.\n * @return {Array.<string>} MatrixIds.\n * @api\n */\nol.tilegrid.WMTS.prototype.getMatrixIds = function() {\n  return this.matrixIds_;\n};\n\n\n/**\n * Create a tile grid from a WMTS capabilities matrix set and an\n * optional TileMatrixSetLimits.\n * @param {Object} matrixSet An object representing a matrixSet in the\n *     capabilities document.\n * @param {ol.Extent=} opt_extent An optional extent to restrict the tile\n *     ranges the server provides.\n * @param {Array.<Object>=} opt_matrixLimits An optional object representing\n *     the available matrices for tileGrid.\n * @return {ol.tilegrid.WMTS} WMTS tileGrid instance.\n * @api\n */\nol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = function(matrixSet, opt_extent,\n opt_matrixLimits) {\n\n  /** @type {!Array.<number>} */\n  var resolutions = [];\n  /** @type {!Array.<string>} */\n  var matrixIds = [];\n  /** @type {!Array.<ol.Coordinate>} */\n  var origins = [];\n  /** @type {!Array.<ol.Size>} */\n  var tileSizes = [];\n  /** @type {!Array.<ol.Size>} */\n  var sizes = [];\n\n  var matrixLimits = opt_matrixLimits !== undefined ? opt_matrixLimits : [];\n\n  var supportedCRSPropName = 'SupportedCRS';\n  var matrixIdsPropName = 'TileMatrix';\n  var identifierPropName = 'Identifier';\n  var scaleDenominatorPropName = 'ScaleDenominator';\n  var topLeftCornerPropName = 'TopLeftCorner';\n  var tileWidthPropName = 'TileWidth';\n  var tileHeightPropName = 'TileHeight';\n\n  var projection;\n  projection = ol.proj.get(matrixSet[supportedCRSPropName].replace(\n      /urn:ogc:def:crs:(\\w+):(.*:)?(\\w+)$/, '$1:$3'));\n  var metersPerUnit = projection.getMetersPerUnit();\n  // swap origin x and y coordinates if axis orientation is lat/long\n  var switchOriginXY = projection.getAxisOrientation().substr(0, 2) == 'ne';\n\n  matrixSet[matrixIdsPropName].sort(function(a, b) {\n    return b[scaleDenominatorPropName] - a[scaleDenominatorPropName];\n  });\n\n  matrixSet[matrixIdsPropName].forEach(function(elt, index, array) {\n\n    var matrixAvailable;\n    // use of matrixLimits to filter TileMatrices from GetCapabilities\n    // TileMatrixSet from unavailable matrix levels.\n    if (matrixLimits.length > 0) {\n      matrixAvailable = ol.array.find(matrixLimits,\n          function(elt_ml, index_ml, array_ml) {\n            return elt[identifierPropName] == elt_ml[matrixIdsPropName];\n          });\n    } else {\n      matrixAvailable = true;\n    }\n\n    if (matrixAvailable) {\n      matrixIds.push(elt[identifierPropName]);\n      var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit;\n      var tileWidth = elt[tileWidthPropName];\n      var tileHeight = elt[tileHeightPropName];\n      if (switchOriginXY) {\n        origins.push([elt[topLeftCornerPropName][1],\n          elt[topLeftCornerPropName][0]]);\n      } else {\n        origins.push(elt[topLeftCornerPropName]);\n      }\n      resolutions.push(resolution);\n      tileSizes.push(tileWidth == tileHeight ?\n          tileWidth : [tileWidth, tileHeight]);\n      // top-left origin, so height is negative\n      sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]);\n    }\n  });\n\n  return new ol.tilegrid.WMTS({\n    extent: opt_extent,\n    origins: origins,\n    resolutions: resolutions,\n    matrixIds: matrixIds,\n    tileSizes: tileSizes,\n    sizes: sizes\n  });\n};\n\ngoog.provide('ol.source.WMTS');\n\ngoog.require('ol');\ngoog.require('ol.TileUrlFunction');\ngoog.require('ol.array');\ngoog.require('ol.extent');\ngoog.require('ol.obj');\ngoog.require('ol.proj');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.tilegrid.WMTS');\ngoog.require('ol.uri');\n\n\n/**\n * @classdesc\n * Layer source for tile data from WMTS servers.\n *\n * @constructor\n * @extends {ol.source.TileImage}\n * @param {olx.source.WMTSOptions} options WMTS options.\n * @api stable\n */\nol.source.WMTS = function(options) {\n\n  // TODO: add support for TileMatrixLimits\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.version_ = options.version !== undefined ? options.version : '1.0.0';\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.format_ = options.format !== undefined ? options.format : 'image/jpeg';\n\n  /**\n   * @private\n   * @type {!Object}\n   */\n  this.dimensions_ = options.dimensions !== undefined ? options.dimensions : {};\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.layer_ = options.layer;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.matrixSet_ = options.matrixSet;\n\n  /**\n   * @private\n   * @type {string}\n   */\n  this.style_ = options.style;\n\n  var urls = options.urls;\n  if (urls === undefined && options.url !== undefined) {\n    urls = ol.TileUrlFunction.expandUrl(options.url);\n  }\n\n  // FIXME: should we guess this requestEncoding from options.url(s)\n  //        structure? that would mean KVP only if a template is not provided.\n\n  /**\n   * @private\n   * @type {ol.source.WMTS.RequestEncoding}\n   */\n  this.requestEncoding_ = options.requestEncoding !== undefined ?\n      /** @type {ol.source.WMTS.RequestEncoding} */ (options.requestEncoding) :\n      ol.source.WMTS.RequestEncoding.KVP;\n\n  var requestEncoding = this.requestEncoding_;\n\n  // FIXME: should we create a default tileGrid?\n  // we could issue a getCapabilities xhr to retrieve missing configuration\n  var tileGrid = options.tileGrid;\n\n  // context property names are lower case to allow for a case insensitive\n  // replacement as some services use different naming conventions\n  var context = {\n    'layer': this.layer_,\n    'style': this.style_,\n    'tilematrixset': this.matrixSet_\n  };\n\n  if (requestEncoding == ol.source.WMTS.RequestEncoding.KVP) {\n    ol.obj.assign(context, {\n      'Service': 'WMTS',\n      'Request': 'GetTile',\n      'Version': this.version_,\n      'Format': this.format_\n    });\n  }\n\n  var dimensions = this.dimensions_;\n\n  /**\n   * @param {string} template Template.\n   * @return {ol.TileUrlFunctionType} Tile URL function.\n   */\n  function createFromWMTSTemplate(template) {\n\n    // TODO: we may want to create our own appendParams function so that params\n    // order conforms to wmts spec guidance, and so that we can avoid to escape\n    // special template params\n\n    template = (requestEncoding == ol.source.WMTS.RequestEncoding.KVP) ?\n        ol.uri.appendParams(template, context) :\n        template.replace(/\\{(\\w+?)\\}/g, function(m, p) {\n          return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m;\n        });\n\n    return (\n        /**\n         * @param {ol.TileCoord} tileCoord Tile coordinate.\n         * @param {number} pixelRatio Pixel ratio.\n         * @param {ol.proj.Projection} projection Projection.\n         * @return {string|undefined} Tile URL.\n         */\n        function(tileCoord, pixelRatio, projection) {\n          if (!tileCoord) {\n            return undefined;\n          } else {\n            var localContext = {\n              'TileMatrix': tileGrid.getMatrixId(tileCoord[0]),\n              'TileCol': tileCoord[1],\n              'TileRow': -tileCoord[2] - 1\n            };\n            ol.obj.assign(localContext, dimensions);\n            var url = template;\n            if (requestEncoding == ol.source.WMTS.RequestEncoding.KVP) {\n              url = ol.uri.appendParams(url, localContext);\n            } else {\n              url = url.replace(/\\{(\\w+?)\\}/g, function(m, p) {\n                return localContext[p];\n              });\n            }\n            return url;\n          }\n        });\n  }\n\n  var tileUrlFunction = (urls && urls.length > 0) ?\n      ol.TileUrlFunction.createFromTileUrlFunctions(\n          urls.map(createFromWMTSTemplate)) :\n      ol.TileUrlFunction.nullTileUrlFunction;\n\n  ol.source.TileImage.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: options.crossOrigin,\n    logo: options.logo,\n    projection: options.projection,\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    tileClass: options.tileClass,\n    tileGrid: tileGrid,\n    tileLoadFunction: options.tileLoadFunction,\n    tilePixelRatio: options.tilePixelRatio,\n    tileUrlFunction: tileUrlFunction,\n    urls: urls,\n    wrapX: options.wrapX !== undefined ? options.wrapX : false\n  });\n\n  this.setKey(this.getKeyForDimensions_());\n\n};\nol.inherits(ol.source.WMTS, ol.source.TileImage);\n\n\n/**\n * Get the dimensions, i.e. those passed to the constructor through the\n * \"dimensions\" option, and possibly updated using the updateDimensions\n * method.\n * @return {!Object} Dimensions.\n * @api\n */\nol.source.WMTS.prototype.getDimensions = function() {\n  return this.dimensions_;\n};\n\n\n/**\n * Return the image format of the WMTS source.\n * @return {string} Format.\n * @api\n */\nol.source.WMTS.prototype.getFormat = function() {\n  return this.format_;\n};\n\n\n/**\n * Return the layer of the WMTS source.\n * @return {string} Layer.\n * @api\n */\nol.source.WMTS.prototype.getLayer = function() {\n  return this.layer_;\n};\n\n\n/**\n * Return the matrix set of the WMTS source.\n * @return {string} MatrixSet.\n * @api\n */\nol.source.WMTS.prototype.getMatrixSet = function() {\n  return this.matrixSet_;\n};\n\n\n/**\n * Return the request encoding, either \"KVP\" or \"REST\".\n * @return {ol.source.WMTS.RequestEncoding} Request encoding.\n * @api\n */\nol.source.WMTS.prototype.getRequestEncoding = function() {\n  return this.requestEncoding_;\n};\n\n\n/**\n * Return the style of the WMTS source.\n * @return {string} Style.\n * @api\n */\nol.source.WMTS.prototype.getStyle = function() {\n  return this.style_;\n};\n\n\n/**\n * Return the version of the WMTS source.\n * @return {string} Version.\n * @api\n */\nol.source.WMTS.prototype.getVersion = function() {\n  return this.version_;\n};\n\n\n/**\n * @private\n * @return {string} The key for the current dimensions.\n */\nol.source.WMTS.prototype.getKeyForDimensions_ = function() {\n  var i = 0;\n  var res = [];\n  for (var key in this.dimensions_) {\n    res[i++] = key + '-' + this.dimensions_[key];\n  }\n  return res.join('/');\n};\n\n\n/**\n * Update the dimensions.\n * @param {Object} dimensions Dimensions.\n * @api\n */\nol.source.WMTS.prototype.updateDimensions = function(dimensions) {\n  ol.obj.assign(this.dimensions_, dimensions);\n  this.setKey(this.getKeyForDimensions_());\n};\n\n\n/**\n * Generate source options from a capabilities object.\n * @param {Object} wmtsCap An object representing the capabilities document.\n * @param {Object} config Configuration properties for the layer.  Defaults for\n *                  the layer will apply if not provided.\n *\n * Required config properties:\n *  - layer - {string} The layer identifier.\n *\n * Optional config properties:\n *  - matrixSet - {string} The matrix set identifier, required if there is\n *       more than one matrix set in the layer capabilities.\n *  - projection - {string} The desired CRS when no matrixSet is specified.\n *       eg: \"EPSG:3857\". If the desired projection is not available,\n *       an error is thrown.\n *  - requestEncoding - {string} url encoding format for the layer. Default is\n *       the first tile url format found in the GetCapabilities response.\n *  - style - {string} The name of the style\n *  - format - {string} Image format for the layer. Default is the first\n *       format returned in the GetCapabilities response.\n * @return {olx.source.WMTSOptions} WMTS source options object.\n * @api\n */\nol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {\n\n  // TODO: add support for TileMatrixLimits\n  ol.DEBUG && console.assert(config['layer'],\n      'config \"layer\" must not be null');\n\n  var layers = wmtsCap['Contents']['Layer'];\n  var l = ol.array.find(layers, function(elt, index, array) {\n    return elt['Identifier'] == config['layer'];\n  });\n  ol.DEBUG && console.assert(l, 'found a matching layer in Contents/Layer');\n\n  ol.DEBUG && console.assert(l['TileMatrixSetLink'].length > 0,\n      'layer has TileMatrixSetLink');\n  var tileMatrixSets = wmtsCap['Contents']['TileMatrixSet'];\n  var idx, matrixSet, matrixLimits;\n  if (l['TileMatrixSetLink'].length > 1) {\n    if ('projection' in config) {\n      idx = ol.array.findIndex(l['TileMatrixSetLink'],\n          function(elt, index, array) {\n            var tileMatrixSet = ol.array.find(tileMatrixSets, function(el) {\n              return el['Identifier'] == elt['TileMatrixSet'];\n            });\n            var supportedCRS = tileMatrixSet['SupportedCRS'].replace(/urn:ogc:def:crs:(\\w+):(.*:)?(\\w+)$/, '$1:$3');\n            var proj1 = ol.proj.get(supportedCRS);\n            var proj2 = ol.proj.get(config['projection']);\n            if (proj1 && proj2) {\n              return ol.proj.equivalent(proj1, proj2);\n            } else {\n              return supportedCRS == config['projection'];\n            }\n          });\n    } else {\n      idx = ol.array.findIndex(l['TileMatrixSetLink'],\n          function(elt, index, array) {\n            return elt['TileMatrixSet'] == config['matrixSet'];\n          });\n    }\n  } else {\n    idx = 0;\n  }\n  if (idx < 0) {\n    idx = 0;\n  }\n  matrixSet = /** @type {string} */\n      (l['TileMatrixSetLink'][idx]['TileMatrixSet']);\n  matrixLimits = /** @type {Array.<Object>} */\n      (l['TileMatrixSetLink'][idx]['TileMatrixSetLimits']);\n\n  ol.DEBUG && console.assert(matrixSet, 'TileMatrixSet must not be null');\n\n  var format = /** @type {string} */ (l['Format'][0]);\n  if ('format' in config) {\n    format = config['format'];\n  }\n  idx = ol.array.findIndex(l['Style'], function(elt, index, array) {\n    if ('style' in config) {\n      return elt['Title'] == config['style'];\n    } else {\n      return elt['isDefault'];\n    }\n  });\n  if (idx < 0) {\n    idx = 0;\n  }\n  var style = /** @type {string} */ (l['Style'][idx]['Identifier']);\n\n  var dimensions = {};\n  if ('Dimension' in l) {\n    l['Dimension'].forEach(function(elt, index, array) {\n      var key = elt['Identifier'];\n      var value = elt['Default'];\n      if (value !== undefined) {\n        ol.DEBUG && console.assert(ol.array.includes(elt['Value'], value),\n            'default value contained in values');\n      } else {\n        value = elt['Value'][0];\n      }\n      ol.DEBUG && console.assert(value !== undefined, 'value could be found');\n      dimensions[key] = value;\n    });\n  }\n\n  var matrixSets = wmtsCap['Contents']['TileMatrixSet'];\n  var matrixSetObj = ol.array.find(matrixSets, function(elt, index, array) {\n    return elt['Identifier'] == matrixSet;\n  });\n  ol.DEBUG && console.assert(matrixSetObj,\n      'found matrixSet in Contents/TileMatrixSet');\n\n  var projection;\n  if ('projection' in config) {\n    projection = ol.proj.get(config['projection']);\n  } else {\n    projection = ol.proj.get(matrixSetObj['SupportedCRS'].replace(\n        /urn:ogc:def:crs:(\\w+):(.*:)?(\\w+)$/, '$1:$3'));\n  }\n\n  var wgs84BoundingBox = l['WGS84BoundingBox'];\n  var extent, wrapX;\n  if (wgs84BoundingBox !== undefined) {\n    var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent();\n    wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] &&\n        wgs84BoundingBox[2] == wgs84ProjectionExtent[2]);\n    extent = ol.proj.transformExtent(\n        wgs84BoundingBox, 'EPSG:4326', projection);\n    var projectionExtent = projection.getExtent();\n    if (projectionExtent) {\n      // If possible, do a sanity check on the extent - it should never be\n      // bigger than the validity extent of the projection of a matrix set.\n      if (!ol.extent.containsExtent(projectionExtent, extent)) {\n        extent = undefined;\n      }\n    }\n  }\n\n  var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(\n      matrixSetObj, extent, matrixLimits);\n\n  /** @type {!Array.<string>} */\n  var urls = [];\n  var requestEncoding = config['requestEncoding'];\n  requestEncoding = requestEncoding !== undefined ? requestEncoding : '';\n\n  ol.DEBUG && console.assert(\n      ol.array.includes(['REST', 'RESTful', 'KVP', ''], requestEncoding),\n      'requestEncoding (%s) is one of \"REST\", \"RESTful\", \"KVP\" or \"\"',\n      requestEncoding);\n\n  if ('OperationsMetadata' in wmtsCap && 'GetTile' in wmtsCap['OperationsMetadata']) {\n    var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get'];\n    ol.DEBUG && console.assert(gets.length >= 1);\n\n    for (var i = 0, ii = gets.length; i < ii; ++i) {\n      var constraint = ol.array.find(gets[i]['Constraint'], function(element) {\n        return element['name'] == 'GetEncoding';\n      });\n      var encodings = constraint['AllowedValues']['Value'];\n      ol.DEBUG && console.assert(encodings.length >= 1);\n\n      if (requestEncoding === '') {\n        // requestEncoding not provided, use the first encoding from the list\n        requestEncoding = encodings[0];\n      }\n      if (requestEncoding === ol.source.WMTS.RequestEncoding.KVP) {\n        if (ol.array.includes(encodings, ol.source.WMTS.RequestEncoding.KVP)) {\n          urls.push(/** @type {string} */ (gets[i]['href']));\n        }\n      } else {\n        break;\n      }\n    }\n  }\n  if (urls.length === 0) {\n    requestEncoding = ol.source.WMTS.RequestEncoding.REST;\n    l['ResourceURL'].forEach(function(element) {\n      if (element['resourceType'] === 'tile') {\n        format = element['format'];\n        urls.push(/** @type {string} */ (element['template']));\n      }\n    });\n  }\n  ol.DEBUG && console.assert(urls.length > 0, 'At least one URL found');\n\n  return {\n    urls: urls,\n    layer: config['layer'],\n    matrixSet: matrixSet,\n    format: format,\n    projection: projection,\n    requestEncoding: requestEncoding,\n    tileGrid: tileGrid,\n    style: style,\n    dimensions: dimensions,\n    wrapX: wrapX\n  };\n\n};\n\n\n/**\n * Request encoding. One of 'KVP', 'REST'.\n * @enum {string}\n */\nol.source.WMTS.RequestEncoding = {\n  KVP: 'KVP',  // see spec §8\n  REST: 'REST' // see spec §10\n};\n\ngoog.provide('ol.source.Zoomify');\n\ngoog.require('ol');\ngoog.require('ol.ImageTile');\ngoog.require('ol.Tile');\ngoog.require('ol.asserts');\ngoog.require('ol.dom');\ngoog.require('ol.extent');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.tilegrid.TileGrid');\n\n\n/**\n * @classdesc\n * Layer source for tile data in Zoomify format.\n *\n * @constructor\n * @extends {ol.source.TileImage}\n * @param {olx.source.ZoomifyOptions=} opt_options Options.\n * @api stable\n */\nol.source.Zoomify = function(opt_options) {\n\n  var options = opt_options || {};\n\n  var size = options.size;\n  var tierSizeCalculation = options.tierSizeCalculation !== undefined ?\n      options.tierSizeCalculation :\n      ol.source.Zoomify.TierSizeCalculation.DEFAULT;\n\n  var imageWidth = size[0];\n  var imageHeight = size[1];\n  var tierSizeInTiles = [];\n  var tileSize = ol.DEFAULT_TILE_SIZE;\n\n  switch (tierSizeCalculation) {\n    case ol.source.Zoomify.TierSizeCalculation.DEFAULT:\n      while (imageWidth > tileSize || imageHeight > tileSize) {\n        tierSizeInTiles.push([\n          Math.ceil(imageWidth / tileSize),\n          Math.ceil(imageHeight / tileSize)\n        ]);\n        tileSize += tileSize;\n      }\n      break;\n    case ol.source.Zoomify.TierSizeCalculation.TRUNCATED:\n      var width = imageWidth;\n      var height = imageHeight;\n      while (width > tileSize || height > tileSize) {\n        tierSizeInTiles.push([\n          Math.ceil(width / tileSize),\n          Math.ceil(height / tileSize)\n        ]);\n        width >>= 1;\n        height >>= 1;\n      }\n      break;\n    default:\n      ol.asserts.assert(false, 53); // Unknown `tierSizeCalculation` configured\n      break;\n  }\n\n  tierSizeInTiles.push([1, 1]);\n  tierSizeInTiles.reverse();\n\n  var resolutions = [1];\n  var tileCountUpToTier = [0];\n  var i, ii;\n  for (i = 1, ii = tierSizeInTiles.length; i < ii; i++) {\n    resolutions.push(1 << i);\n    tileCountUpToTier.push(\n        tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +\n        tileCountUpToTier[i - 1]\n    );\n  }\n  resolutions.reverse();\n\n  var extent = [0, -size[1], size[0], 0];\n  var tileGrid = new ol.tilegrid.TileGrid({\n    extent: extent,\n    origin: ol.extent.getTopLeft(extent),\n    resolutions: resolutions\n  });\n\n  var url = options.url;\n\n  /**\n   * @this {ol.source.TileImage}\n   * @param {ol.TileCoord} tileCoord Tile Coordinate.\n   * @param {number} pixelRatio Pixel ratio.\n   * @param {ol.proj.Projection} projection Projection.\n   * @return {string|undefined} Tile URL.\n   */\n  function tileUrlFunction(tileCoord, pixelRatio, projection) {\n    if (!tileCoord) {\n      return undefined;\n    } else {\n      var tileCoordZ = tileCoord[0];\n      var tileCoordX = tileCoord[1];\n      var tileCoordY = -tileCoord[2] - 1;\n      var tileIndex =\n          tileCoordX +\n          tileCoordY * tierSizeInTiles[tileCoordZ][0] +\n          tileCountUpToTier[tileCoordZ];\n      var tileGroup = (tileIndex / ol.DEFAULT_TILE_SIZE) | 0;\n      return url + 'TileGroup' + tileGroup + '/' +\n          tileCoordZ + '-' + tileCoordX + '-' + tileCoordY + '.jpg';\n    }\n  }\n\n  ol.source.TileImage.call(this, {\n    attributions: options.attributions,\n    cacheSize: options.cacheSize,\n    crossOrigin: options.crossOrigin,\n    logo: options.logo,\n    reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n    tileClass: ol.source.Zoomify.Tile_,\n    tileGrid: tileGrid,\n    tileUrlFunction: tileUrlFunction\n  });\n\n};\nol.inherits(ol.source.Zoomify, ol.source.TileImage);\n\n\n/**\n * @constructor\n * @extends {ol.ImageTile}\n * @param {ol.TileCoord} tileCoord Tile coordinate.\n * @param {ol.Tile.State} state State.\n * @param {string} src Image source URI.\n * @param {?string} crossOrigin Cross origin.\n * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.\n * @private\n */\nol.source.Zoomify.Tile_ = function(\n    tileCoord, state, src, crossOrigin, tileLoadFunction) {\n\n  ol.ImageTile.call(this, tileCoord, state, src, crossOrigin, tileLoadFunction);\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement}\n   */\n  this.zoomifyImage_ = null;\n\n};\nol.inherits(ol.source.Zoomify.Tile_, ol.ImageTile);\n\n\n/**\n * @inheritDoc\n */\nol.source.Zoomify.Tile_.prototype.getImage = function() {\n  if (this.zoomifyImage_) {\n    return this.zoomifyImage_;\n  }\n  var tileSize = ol.DEFAULT_TILE_SIZE;\n  var image = ol.ImageTile.prototype.getImage.call(this);\n  if (this.state == ol.Tile.State.LOADED) {\n    if (image.width == tileSize && image.height == tileSize) {\n      this.zoomifyImage_ = image;\n      return image;\n    } else {\n      var context = ol.dom.createCanvasContext2D(tileSize, tileSize);\n      context.drawImage(image, 0, 0);\n      this.zoomifyImage_ = context.canvas;\n      return context.canvas;\n    }\n  } else {\n    return image;\n  }\n};\n\n\n/**\n * @enum {string}\n */\nol.source.Zoomify.TierSizeCalculation = {\n  DEFAULT: 'default',\n  TRUNCATED: 'truncated'\n};\n\ngoog.provide('ol.style.Atlas');\n\ngoog.require('ol');\ngoog.require('ol.dom');\n\n\n/**\n * This class facilitates the creation of image atlases.\n *\n * Images added to an atlas will be rendered onto a single\n * atlas canvas. The distribution of images on the canvas is\n * managed with the bin packing algorithm described in:\n * http://www.blackpawn.com/texts/lightmaps/\n *\n * @constructor\n * @struct\n * @param {number} size The size in pixels of the sprite image.\n * @param {number} space The space in pixels between images.\n *    Because texture coordinates are float values, the edges of\n *    images might not be completely correct (in a way that the\n *    edges overlap when being rendered). To avoid this we add a\n *    padding around each image.\n */\nol.style.Atlas = function(size, space) {\n\n  /**\n   * @private\n   * @type {number}\n   */\n  this.space_ = space;\n\n  /**\n   * @private\n   * @type {Array.<ol.AtlasBlock>}\n   */\n  this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}];\n\n  /**\n   * @private\n   * @type {Object.<string, ol.AtlasInfo>}\n   */\n  this.entries_ = {};\n\n  /**\n   * @private\n   * @type {CanvasRenderingContext2D}\n   */\n  this.context_ = ol.dom.createCanvasContext2D(size, size);\n\n  /**\n   * @private\n   * @type {HTMLCanvasElement}\n   */\n  this.canvas_ = this.context_.canvas;\n};\n\n\n/**\n * @param {string} id The identifier of the entry to check.\n * @return {?ol.AtlasInfo} The atlas info.\n */\nol.style.Atlas.prototype.get = function(id) {\n  return this.entries_[id] || null;\n};\n\n\n/**\n * @param {string} id The identifier of the entry to add.\n * @param {number} width The width.\n * @param {number} height The height.\n * @param {function(CanvasRenderingContext2D, number, number)} renderCallback\n *    Called to render the new image onto an atlas image.\n * @param {Object=} opt_this Value to use as `this` when executing\n *    `renderCallback`.\n * @return {?ol.AtlasInfo} The position and atlas image for the entry.\n */\nol.style.Atlas.prototype.add = function(id, width, height, renderCallback, opt_this) {\n  var block, i, ii;\n  for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) {\n    block = this.emptyBlocks_[i];\n    if (block.width >= width + this.space_ &&\n        block.height >= height + this.space_) {\n      // we found a block that is big enough for our entry\n      var entry = {\n        offsetX: block.x + this.space_,\n        offsetY: block.y + this.space_,\n        image: this.canvas_\n      };\n      this.entries_[id] = entry;\n\n      // render the image on the atlas image\n      renderCallback.call(opt_this, this.context_,\n          block.x + this.space_, block.y + this.space_);\n\n      // split the block after the insertion, either horizontally or vertically\n      this.split_(i, block, width + this.space_, height + this.space_);\n\n      return entry;\n    }\n  }\n\n  // there is no space for the new entry in this atlas\n  return null;\n};\n\n\n/**\n * @private\n * @param {number} index The index of the block.\n * @param {ol.AtlasBlock} block The block to split.\n * @param {number} width The width of the entry to insert.\n * @param {number} height The height of the entry to insert.\n */\nol.style.Atlas.prototype.split_ = function(index, block, width, height) {\n  var deltaWidth = block.width - width;\n  var deltaHeight = block.height - height;\n\n  /** @type {ol.AtlasBlock} */\n  var newBlock1;\n  /** @type {ol.AtlasBlock} */\n  var newBlock2;\n\n  if (deltaWidth > deltaHeight) {\n    // split vertically\n    // block right of the inserted entry\n    newBlock1 = {\n      x: block.x + width,\n      y: block.y,\n      width: block.width - width,\n      height: block.height\n    };\n\n    // block below the inserted entry\n    newBlock2 = {\n      x: block.x,\n      y: block.y + height,\n      width: width,\n      height: block.height - height\n    };\n    this.updateBlocks_(index, newBlock1, newBlock2);\n  } else {\n    // split horizontally\n    // block right of the inserted entry\n    newBlock1 = {\n      x: block.x + width,\n      y: block.y,\n      width: block.width - width,\n      height: height\n    };\n\n    // block below the inserted entry\n    newBlock2 = {\n      x: block.x,\n      y: block.y + height,\n      width: block.width,\n      height: block.height - height\n    };\n    this.updateBlocks_(index, newBlock1, newBlock2);\n  }\n};\n\n\n/**\n * Remove the old block and insert new blocks at the same array position.\n * The new blocks are inserted at the same position, so that splitted\n * blocks (that are potentially smaller) are filled first.\n * @private\n * @param {number} index The index of the block to remove.\n * @param {ol.AtlasBlock} newBlock1 The 1st block to add.\n * @param {ol.AtlasBlock} newBlock2 The 2nd block to add.\n */\nol.style.Atlas.prototype.updateBlocks_ = function(index, newBlock1, newBlock2) {\n  var args = [index, 1];\n  if (newBlock1.width > 0 && newBlock1.height > 0) {\n    args.push(newBlock1);\n  }\n  if (newBlock2.width > 0 && newBlock2.height > 0) {\n    args.push(newBlock2);\n  }\n  this.emptyBlocks_.splice.apply(this.emptyBlocks_, args);\n};\n\ngoog.provide('ol.style.AtlasManager');\n\ngoog.require('ol');\ngoog.require('ol.style.Atlas');\n\n\n/**\n * Manages the creation of image atlases.\n *\n * Images added to this manager will be inserted into an atlas, which\n * will be used for rendering.\n * The `size` given in the constructor is the size for the first\n * atlas. After that, when new atlases are created, they will have\n * twice the size as the latest atlas (until `maxSize` is reached).\n *\n * If an application uses many images or very large images, it is recommended\n * to set a higher `size` value to avoid the creation of too many atlases.\n *\n * @constructor\n * @struct\n * @api\n * @param {olx.style.AtlasManagerOptions=} opt_options Options.\n */\nol.style.AtlasManager = function(opt_options) {\n\n  var options = opt_options || {};\n\n  /**\n   * The size in pixels of the latest atlas image.\n   * @private\n   * @type {number}\n   */\n  this.currentSize_ = options.initialSize !== undefined ?\n      options.initialSize : ol.INITIAL_ATLAS_SIZE;\n\n  /**\n   * The maximum size in pixels of atlas images.\n   * @private\n   * @type {number}\n   */\n  this.maxSize_ = options.maxSize !== undefined ?\n      options.maxSize : ol.MAX_ATLAS_SIZE != -1 ?\n          ol.MAX_ATLAS_SIZE : ol.WEBGL_MAX_TEXTURE_SIZE !== undefined ?\n              ol.WEBGL_MAX_TEXTURE_SIZE : 2048;\n\n  /**\n   * The size in pixels between images.\n   * @private\n   * @type {number}\n   */\n  this.space_ = options.space !== undefined ? options.space : 1;\n\n  /**\n   * @private\n   * @type {Array.<ol.style.Atlas>}\n   */\n  this.atlases_ = [new ol.style.Atlas(this.currentSize_, this.space_)];\n\n  /**\n   * The size in pixels of the latest atlas image for hit-detection images.\n   * @private\n   * @type {number}\n   */\n  this.currentHitSize_ = this.currentSize_;\n\n  /**\n   * @private\n   * @type {Array.<ol.style.Atlas>}\n   */\n  this.hitAtlases_ = [new ol.style.Atlas(this.currentHitSize_, this.space_)];\n};\n\n\n/**\n * @param {string} id The identifier of the entry to check.\n * @return {?ol.AtlasManagerInfo} The position and atlas image for the\n *    entry, or `null` if the entry is not part of the atlas manager.\n */\nol.style.AtlasManager.prototype.getInfo = function(id) {\n  /** @type {?ol.AtlasInfo} */\n  var info = this.getInfo_(this.atlases_, id);\n\n  if (!info) {\n    return null;\n  }\n  var hitInfo = /** @type {ol.AtlasInfo} */ (this.getInfo_(this.hitAtlases_, id));\n\n  return this.mergeInfos_(info, hitInfo);\n};\n\n\n/**\n * @private\n * @param {Array.<ol.style.Atlas>} atlases The atlases to search.\n * @param {string} id The identifier of the entry to check.\n * @return {?ol.AtlasInfo} The position and atlas image for the entry,\n *    or `null` if the entry is not part of the atlases.\n */\nol.style.AtlasManager.prototype.getInfo_ = function(atlases, id) {\n  var atlas, info, i, ii;\n  for (i = 0, ii = atlases.length; i < ii; ++i) {\n    atlas = atlases[i];\n    info = atlas.get(id);\n    if (info) {\n      return info;\n    }\n  }\n  return null;\n};\n\n\n/**\n * @private\n * @param {ol.AtlasInfo} info The info for the real image.\n * @param {ol.AtlasInfo} hitInfo The info for the hit-detection\n *    image.\n * @return {?ol.AtlasManagerInfo} The position and atlas image for the\n *    entry, or `null` if the entry is not part of the atlases.\n */\nol.style.AtlasManager.prototype.mergeInfos_ = function(info, hitInfo) {\n  ol.DEBUG && console.assert(info.offsetX === hitInfo.offsetX,\n      'in order to merge, offsetX of info and hitInfo must be equal');\n  ol.DEBUG && console.assert(info.offsetY === hitInfo.offsetY,\n      'in order to merge, offsetY of info and hitInfo must be equal');\n  return /** @type {ol.AtlasManagerInfo} */ ({\n    offsetX: info.offsetX,\n    offsetY: info.offsetY,\n    image: info.image,\n    hitImage: hitInfo.image\n  });\n};\n\n\n/**\n * Add an image to the atlas manager.\n *\n * If an entry for the given id already exists, the entry will\n * be overridden (but the space on the atlas graphic will not be freed).\n *\n * If `renderHitCallback` is provided, the image (or the hit-detection version\n * of the image) will be rendered into a separate hit-detection atlas image.\n *\n * @param {string} id The identifier of the entry to add.\n * @param {number} width The width.\n * @param {number} height The height.\n * @param {function(CanvasRenderingContext2D, number, number)} renderCallback\n *    Called to render the new image onto an atlas image.\n * @param {function(CanvasRenderingContext2D, number, number)=}\n *    opt_renderHitCallback Called to render a hit-detection image onto a hit\n *    detection atlas image.\n * @param {Object=} opt_this Value to use as `this` when executing\n *    `renderCallback` and `renderHitCallback`.\n * @return {?ol.AtlasManagerInfo}  The position and atlas image for the\n *    entry, or `null` if the image is too big.\n */\nol.style.AtlasManager.prototype.add = function(id, width, height,\n        renderCallback, opt_renderHitCallback, opt_this) {\n  if (width + this.space_ > this.maxSize_ ||\n      height + this.space_ > this.maxSize_) {\n    return null;\n  }\n\n  /** @type {?ol.AtlasInfo} */\n  var info = this.add_(false,\n      id, width, height, renderCallback, opt_this);\n  if (!info) {\n    return null;\n  }\n\n  // even if no hit-detection entry is requested, we insert a fake entry into\n  // the hit-detection atlas, to make sure that the offset is the same for\n  // the original image and the hit-detection image.\n  var renderHitCallback = opt_renderHitCallback !== undefined ?\n      opt_renderHitCallback : ol.nullFunction;\n\n  var hitInfo = /** @type {ol.AtlasInfo} */ (this.add_(true,\n      id, width, height, renderHitCallback, opt_this));\n\n  return this.mergeInfos_(info, hitInfo);\n};\n\n\n/**\n * @private\n * @param {boolean} isHitAtlas If the hit-detection atlases are used.\n * @param {string} id The identifier of the entry to add.\n * @param {number} width The width.\n * @param {number} height The height.\n * @param {function(CanvasRenderingContext2D, number, number)} renderCallback\n *    Called to render the new image onto an atlas image.\n * @param {Object=} opt_this Value to use as `this` when executing\n *    `renderCallback` and `renderHitCallback`.\n * @return {?ol.AtlasInfo}  The position and atlas image for the entry,\n *    or `null` if the image is too big.\n */\nol.style.AtlasManager.prototype.add_ = function(isHitAtlas, id, width, height,\n        renderCallback, opt_this) {\n  var atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_;\n  var atlas, info, i, ii;\n  for (i = 0, ii = atlases.length; i < ii; ++i) {\n    atlas = atlases[i];\n    info = atlas.add(id, width, height, renderCallback, opt_this);\n    if (info) {\n      return info;\n    } else if (!info && i === ii - 1) {\n      // the entry could not be added to one of the existing atlases,\n      // create a new atlas that is twice as big and try to add to this one.\n      var size;\n      if (isHitAtlas) {\n        size = Math.min(this.currentHitSize_ * 2, this.maxSize_);\n        this.currentHitSize_ = size;\n      } else {\n        size = Math.min(this.currentSize_ * 2, this.maxSize_);\n        this.currentSize_ = size;\n      }\n      atlas = new ol.style.Atlas(size, this.space_);\n      atlases.push(atlas);\n      // run the loop another time\n      ++ii;\n    }\n  }\n  ol.DEBUG && console.assert(false, 'Failed to add to atlasmanager');\n  return null;\n};\n\n// Copyright 2009 The Closure Library Authors.\n// All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// This file has been auto-generated by GenJsDeps, please do not edit.\n\ngoog.addDependency(\n    'demos/editor/equationeditor.js', ['goog.demos.editor.EquationEditor'],\n    ['goog.ui.equation.EquationEditorDialog']);\ngoog.addDependency(\n    'demos/editor/helloworld.js', ['goog.demos.editor.HelloWorld'],\n    ['goog.dom', 'goog.dom.TagName', 'goog.editor.Plugin']);\ngoog.addDependency(\n    'demos/editor/helloworlddialog.js',\n    [\n      'goog.demos.editor.HelloWorldDialog',\n      'goog.demos.editor.HelloWorldDialog.OkEvent'\n    ],\n    [\n      'goog.dom.TagName', 'goog.events.Event', 'goog.string',\n      'goog.ui.editor.AbstractDialog', 'goog.ui.editor.AbstractDialog.Builder',\n      'goog.ui.editor.AbstractDialog.EventType'\n    ]);\ngoog.addDependency(\n    'demos/editor/helloworlddialogplugin.js',\n    [\n      'goog.demos.editor.HelloWorldDialogPlugin',\n      'goog.demos.editor.HelloWorldDialogPlugin.Command'\n    ],\n    [\n      'goog.demos.editor.HelloWorldDialog', 'goog.dom.TagName',\n      'goog.editor.plugins.AbstractDialogPlugin', 'goog.editor.range',\n      'goog.functions', 'goog.ui.editor.AbstractDialog.EventType'\n    ]);\n\n/**\n * @fileoverview Custom exports file.\n * @suppress {checkVars,extraRequire}\n */\n\ngoog.require('ol');\ngoog.require('ol.AssertionError');\ngoog.require('ol.Attribution');\ngoog.require('ol.Collection');\ngoog.require('ol.DeviceOrientation');\ngoog.require('ol.Feature');\ngoog.require('ol.Geolocation');\ngoog.require('ol.Graticule');\ngoog.require('ol.Image');\ngoog.require('ol.ImageTile');\ngoog.require('ol.Kinetic');\ngoog.require('ol.Map');\ngoog.require('ol.MapBrowserEvent');\ngoog.require('ol.MapEvent');\ngoog.require('ol.Object');\ngoog.require('ol.Observable');\ngoog.require('ol.Overlay');\ngoog.require('ol.Sphere');\ngoog.require('ol.Tile');\ngoog.require('ol.VectorTile');\ngoog.require('ol.View');\ngoog.require('ol.animation');\ngoog.require('ol.color');\ngoog.require('ol.colorlike');\ngoog.require('ol.control');\ngoog.require('ol.control.Attribution');\ngoog.require('ol.control.Control');\ngoog.require('ol.control.FullScreen');\ngoog.require('ol.control.MousePosition');\ngoog.require('ol.control.OverviewMap');\ngoog.require('ol.control.Rotate');\ngoog.require('ol.control.ScaleLine');\ngoog.require('ol.control.Zoom');\ngoog.require('ol.control.ZoomSlider');\ngoog.require('ol.control.ZoomToExtent');\ngoog.require('ol.coordinate');\ngoog.require('ol.easing');\ngoog.require('ol.events.Event');\ngoog.require('ol.events.condition');\ngoog.require('ol.extent');\ngoog.require('ol.featureloader');\ngoog.require('ol.format.EsriJSON');\ngoog.require('ol.format.Feature');\ngoog.require('ol.format.GML');\ngoog.require('ol.format.GML2');\ngoog.require('ol.format.GML3');\ngoog.require('ol.format.GMLBase');\ngoog.require('ol.format.GPX');\ngoog.require('ol.format.GeoJSON');\ngoog.require('ol.format.IGC');\ngoog.require('ol.format.KML');\ngoog.require('ol.format.MVT');\ngoog.require('ol.format.OSMXML');\ngoog.require('ol.format.Polyline');\ngoog.require('ol.format.TopoJSON');\ngoog.require('ol.format.WFS');\ngoog.require('ol.format.WKT');\ngoog.require('ol.format.WMSCapabilities');\ngoog.require('ol.format.WMSGetFeatureInfo');\ngoog.require('ol.format.WMTSCapabilities');\ngoog.require('ol.format.filter');\ngoog.require('ol.format.filter.And');\ngoog.require('ol.format.filter.Bbox');\ngoog.require('ol.format.filter.Comparison');\ngoog.require('ol.format.filter.ComparisonBinary');\ngoog.require('ol.format.filter.EqualTo');\ngoog.require('ol.format.filter.Filter');\ngoog.require('ol.format.filter.GreaterThan');\ngoog.require('ol.format.filter.GreaterThanOrEqualTo');\ngoog.require('ol.format.filter.Intersects');\ngoog.require('ol.format.filter.IsBetween');\ngoog.require('ol.format.filter.IsLike');\ngoog.require('ol.format.filter.IsNull');\ngoog.require('ol.format.filter.LessThan');\ngoog.require('ol.format.filter.LessThanOrEqualTo');\ngoog.require('ol.format.filter.Not');\ngoog.require('ol.format.filter.NotEqualTo');\ngoog.require('ol.format.filter.Or');\ngoog.require('ol.format.filter.Spatial');\ngoog.require('ol.format.filter.Within');\ngoog.require('ol.geom.Circle');\ngoog.require('ol.geom.Geometry');\ngoog.require('ol.geom.GeometryCollection');\ngoog.require('ol.geom.LineString');\ngoog.require('ol.geom.LinearRing');\ngoog.require('ol.geom.MultiLineString');\ngoog.require('ol.geom.MultiPoint');\ngoog.require('ol.geom.MultiPolygon');\ngoog.require('ol.geom.Point');\ngoog.require('ol.geom.Polygon');\ngoog.require('ol.geom.SimpleGeometry');\ngoog.require('ol.has');\ngoog.require('ol.interaction');\ngoog.require('ol.interaction.DoubleClickZoom');\ngoog.require('ol.interaction.DragAndDrop');\ngoog.require('ol.interaction.DragBox');\ngoog.require('ol.interaction.DragPan');\ngoog.require('ol.interaction.DragRotate');\ngoog.require('ol.interaction.DragRotateAndZoom');\ngoog.require('ol.interaction.DragZoom');\ngoog.require('ol.interaction.Draw');\ngoog.require('ol.interaction.Extent');\ngoog.require('ol.interaction.Interaction');\ngoog.require('ol.interaction.KeyboardPan');\ngoog.require('ol.interaction.KeyboardZoom');\ngoog.require('ol.interaction.Modify');\ngoog.require('ol.interaction.MouseWheelZoom');\ngoog.require('ol.interaction.PinchRotate');\ngoog.require('ol.interaction.PinchZoom');\ngoog.require('ol.interaction.Pointer');\ngoog.require('ol.interaction.Select');\ngoog.require('ol.interaction.Snap');\ngoog.require('ol.interaction.Translate');\ngoog.require('ol.layer.Base');\ngoog.require('ol.layer.Group');\ngoog.require('ol.layer.Heatmap');\ngoog.require('ol.layer.Image');\ngoog.require('ol.layer.Layer');\ngoog.require('ol.layer.Tile');\ngoog.require('ol.layer.Vector');\ngoog.require('ol.layer.VectorTile');\ngoog.require('ol.loadingstrategy');\ngoog.require('ol.proj');\ngoog.require('ol.proj.Projection');\ngoog.require('ol.proj.Units');\ngoog.require('ol.proj.common');\ngoog.require('ol.render');\ngoog.require('ol.render.Event');\ngoog.require('ol.render.Feature');\ngoog.require('ol.render.VectorContext');\ngoog.require('ol.render.canvas.Immediate');\ngoog.require('ol.render.webgl.Immediate');\ngoog.require('ol.size');\ngoog.require('ol.source.BingMaps');\ngoog.require('ol.source.CartoDB');\ngoog.require('ol.source.Cluster');\ngoog.require('ol.source.Image');\ngoog.require('ol.source.ImageArcGISRest');\ngoog.require('ol.source.ImageCanvas');\ngoog.require('ol.source.ImageMapGuide');\ngoog.require('ol.source.ImageStatic');\ngoog.require('ol.source.ImageVector');\ngoog.require('ol.source.ImageWMS');\ngoog.require('ol.source.OSM');\ngoog.require('ol.source.Raster');\ngoog.require('ol.source.Source');\ngoog.require('ol.source.Stamen');\ngoog.require('ol.source.Tile');\ngoog.require('ol.source.TileArcGISRest');\ngoog.require('ol.source.TileDebug');\ngoog.require('ol.source.TileImage');\ngoog.require('ol.source.TileJSON');\ngoog.require('ol.source.TileUTFGrid');\ngoog.require('ol.source.TileWMS');\ngoog.require('ol.source.UrlTile');\ngoog.require('ol.source.Vector');\ngoog.require('ol.source.VectorTile');\ngoog.require('ol.source.WMTS');\ngoog.require('ol.source.XYZ');\ngoog.require('ol.source.Zoomify');\ngoog.require('ol.style.AtlasManager');\ngoog.require('ol.style.Circle');\ngoog.require('ol.style.Fill');\ngoog.require('ol.style.Icon');\ngoog.require('ol.style.Image');\ngoog.require('ol.style.RegularShape');\ngoog.require('ol.style.Stroke');\ngoog.require('ol.style.Style');\ngoog.require('ol.style.Text');\ngoog.require('ol.tilegrid');\ngoog.require('ol.tilegrid.TileGrid');\ngoog.require('ol.tilegrid.WMTS');\ngoog.require('ol.webgl.Context');\ngoog.require('ol.xml');\n\n\n\ngoog.exportSymbol(\n    'ol.animation.bounce',\n    ol.animation.bounce,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.animation.pan',\n    ol.animation.pan,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.animation.rotate',\n    ol.animation.rotate,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.animation.zoom',\n    ol.animation.zoom,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.AssertionError.prototype,\n    'code',\n    ol.AssertionError.prototype.code);\n\ngoog.exportSymbol(\n    'ol.Attribution',\n    ol.Attribution,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Attribution.prototype,\n    'getHTML',\n    ol.Attribution.prototype.getHTML);\n\ngoog.exportSymbol(\n    'ol.Collection',\n    ol.Collection,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'clear',\n    ol.Collection.prototype.clear);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'extend',\n    ol.Collection.prototype.extend);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'forEach',\n    ol.Collection.prototype.forEach);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'getArray',\n    ol.Collection.prototype.getArray);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'item',\n    ol.Collection.prototype.item);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'getLength',\n    ol.Collection.prototype.getLength);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'insertAt',\n    ol.Collection.prototype.insertAt);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'pop',\n    ol.Collection.prototype.pop);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'push',\n    ol.Collection.prototype.push);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'remove',\n    ol.Collection.prototype.remove);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'removeAt',\n    ol.Collection.prototype.removeAt);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'setAt',\n    ol.Collection.prototype.setAt);\n\ngoog.exportProperty(\n    ol.Collection.Event.prototype,\n    'element',\n    ol.Collection.Event.prototype.element);\n\ngoog.exportSymbol(\n    'ol.color.asArray',\n    ol.color.asArray,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.color.asString',\n    ol.color.asString,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.colorlike.asColorLike',\n    ol.colorlike.asColorLike,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.coordinate.add',\n    ol.coordinate.add,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.coordinate.createStringXY',\n    ol.coordinate.createStringXY,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.coordinate.format',\n    ol.coordinate.format,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.coordinate.rotate',\n    ol.coordinate.rotate,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.coordinate.toStringHDMS',\n    ol.coordinate.toStringHDMS,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.coordinate.toStringXY',\n    ol.coordinate.toStringXY,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.DeviceOrientation',\n    ol.DeviceOrientation,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getAlpha',\n    ol.DeviceOrientation.prototype.getAlpha);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getBeta',\n    ol.DeviceOrientation.prototype.getBeta);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getGamma',\n    ol.DeviceOrientation.prototype.getGamma);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getHeading',\n    ol.DeviceOrientation.prototype.getHeading);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getTracking',\n    ol.DeviceOrientation.prototype.getTracking);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'setTracking',\n    ol.DeviceOrientation.prototype.setTracking);\n\ngoog.exportSymbol(\n    'ol.easing.easeIn',\n    ol.easing.easeIn,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.easing.easeOut',\n    ol.easing.easeOut,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.easing.inAndOut',\n    ol.easing.inAndOut,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.easing.linear',\n    ol.easing.linear,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.easing.upAndDown',\n    ol.easing.upAndDown,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.Feature',\n    ol.Feature,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'clone',\n    ol.Feature.prototype.clone);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getGeometry',\n    ol.Feature.prototype.getGeometry);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getId',\n    ol.Feature.prototype.getId);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getGeometryName',\n    ol.Feature.prototype.getGeometryName);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getStyle',\n    ol.Feature.prototype.getStyle);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getStyleFunction',\n    ol.Feature.prototype.getStyleFunction);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'setGeometry',\n    ol.Feature.prototype.setGeometry);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'setStyle',\n    ol.Feature.prototype.setStyle);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'setId',\n    ol.Feature.prototype.setId);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'setGeometryName',\n    ol.Feature.prototype.setGeometryName);\n\ngoog.exportSymbol(\n    'ol.featureloader.xhr',\n    ol.featureloader.xhr,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.Geolocation',\n    ol.Geolocation,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getAccuracy',\n    ol.Geolocation.prototype.getAccuracy);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getAccuracyGeometry',\n    ol.Geolocation.prototype.getAccuracyGeometry);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getAltitude',\n    ol.Geolocation.prototype.getAltitude);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getAltitudeAccuracy',\n    ol.Geolocation.prototype.getAltitudeAccuracy);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getHeading',\n    ol.Geolocation.prototype.getHeading);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getPosition',\n    ol.Geolocation.prototype.getPosition);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getProjection',\n    ol.Geolocation.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getSpeed',\n    ol.Geolocation.prototype.getSpeed);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getTracking',\n    ol.Geolocation.prototype.getTracking);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getTrackingOptions',\n    ol.Geolocation.prototype.getTrackingOptions);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'setProjection',\n    ol.Geolocation.prototype.setProjection);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'setTracking',\n    ol.Geolocation.prototype.setTracking);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'setTrackingOptions',\n    ol.Geolocation.prototype.setTrackingOptions);\n\ngoog.exportSymbol(\n    'ol.Graticule',\n    ol.Graticule,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Graticule.prototype,\n    'getMap',\n    ol.Graticule.prototype.getMap);\n\ngoog.exportProperty(\n    ol.Graticule.prototype,\n    'getMeridians',\n    ol.Graticule.prototype.getMeridians);\n\ngoog.exportProperty(\n    ol.Graticule.prototype,\n    'getParallels',\n    ol.Graticule.prototype.getParallels);\n\ngoog.exportProperty(\n    ol.Graticule.prototype,\n    'setMap',\n    ol.Graticule.prototype.setMap);\n\ngoog.exportSymbol(\n    'ol.has.DEVICE_PIXEL_RATIO',\n    ol.has.DEVICE_PIXEL_RATIO,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.has.CANVAS',\n    ol.has.CANVAS,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.has.DEVICE_ORIENTATION',\n    ol.has.DEVICE_ORIENTATION,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.has.GEOLOCATION',\n    ol.has.GEOLOCATION,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.has.TOUCH',\n    ol.has.TOUCH,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.has.WEBGL',\n    ol.has.WEBGL,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Image.prototype,\n    'getImage',\n    ol.Image.prototype.getImage);\n\ngoog.exportProperty(\n    ol.Image.prototype,\n    'load',\n    ol.Image.prototype.load);\n\ngoog.exportProperty(\n    ol.ImageTile.prototype,\n    'getImage',\n    ol.ImageTile.prototype.getImage);\n\ngoog.exportProperty(\n    ol.ImageTile.prototype,\n    'load',\n    ol.ImageTile.prototype.load);\n\ngoog.exportSymbol(\n    'ol.inherits',\n    ol.inherits,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.Kinetic',\n    ol.Kinetic,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.loadingstrategy.all',\n    ol.loadingstrategy.all,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.loadingstrategy.bbox',\n    ol.loadingstrategy.bbox,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.loadingstrategy.tile',\n    ol.loadingstrategy.tile,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.Map',\n    ol.Map,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'addControl',\n    ol.Map.prototype.addControl);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'addInteraction',\n    ol.Map.prototype.addInteraction);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'addLayer',\n    ol.Map.prototype.addLayer);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'addOverlay',\n    ol.Map.prototype.addOverlay);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'beforeRender',\n    ol.Map.prototype.beforeRender);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'forEachFeatureAtPixel',\n    ol.Map.prototype.forEachFeatureAtPixel);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'forEachLayerAtPixel',\n    ol.Map.prototype.forEachLayerAtPixel);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'hasFeatureAtPixel',\n    ol.Map.prototype.hasFeatureAtPixel);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getEventCoordinate',\n    ol.Map.prototype.getEventCoordinate);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getEventPixel',\n    ol.Map.prototype.getEventPixel);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getTarget',\n    ol.Map.prototype.getTarget);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getTargetElement',\n    ol.Map.prototype.getTargetElement);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getCoordinateFromPixel',\n    ol.Map.prototype.getCoordinateFromPixel);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getControls',\n    ol.Map.prototype.getControls);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getOverlays',\n    ol.Map.prototype.getOverlays);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getOverlayById',\n    ol.Map.prototype.getOverlayById);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getInteractions',\n    ol.Map.prototype.getInteractions);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getLayerGroup',\n    ol.Map.prototype.getLayerGroup);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getLayers',\n    ol.Map.prototype.getLayers);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getPixelFromCoordinate',\n    ol.Map.prototype.getPixelFromCoordinate);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getSize',\n    ol.Map.prototype.getSize);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getView',\n    ol.Map.prototype.getView);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getViewport',\n    ol.Map.prototype.getViewport);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'renderSync',\n    ol.Map.prototype.renderSync);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'render',\n    ol.Map.prototype.render);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'removeControl',\n    ol.Map.prototype.removeControl);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'removeInteraction',\n    ol.Map.prototype.removeInteraction);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'removeLayer',\n    ol.Map.prototype.removeLayer);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'removeOverlay',\n    ol.Map.prototype.removeOverlay);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'setLayerGroup',\n    ol.Map.prototype.setLayerGroup);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'setSize',\n    ol.Map.prototype.setSize);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'setTarget',\n    ol.Map.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'setView',\n    ol.Map.prototype.setView);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'updateSize',\n    ol.Map.prototype.updateSize);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'originalEvent',\n    ol.MapBrowserEvent.prototype.originalEvent);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'pixel',\n    ol.MapBrowserEvent.prototype.pixel);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'coordinate',\n    ol.MapBrowserEvent.prototype.coordinate);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'dragging',\n    ol.MapBrowserEvent.prototype.dragging);\n\ngoog.exportProperty(\n    ol.MapEvent.prototype,\n    'map',\n    ol.MapEvent.prototype.map);\n\ngoog.exportProperty(\n    ol.MapEvent.prototype,\n    'frameState',\n    ol.MapEvent.prototype.frameState);\n\ngoog.exportSymbol(\n    'ol.Object',\n    ol.Object,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'get',\n    ol.Object.prototype.get);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'getKeys',\n    ol.Object.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'getProperties',\n    ol.Object.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'set',\n    ol.Object.prototype.set);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'setProperties',\n    ol.Object.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'unset',\n    ol.Object.prototype.unset);\n\ngoog.exportProperty(\n    ol.Object.Event.prototype,\n    'key',\n    ol.Object.Event.prototype.key);\n\ngoog.exportProperty(\n    ol.Object.Event.prototype,\n    'oldValue',\n    ol.Object.Event.prototype.oldValue);\n\ngoog.exportSymbol(\n    'ol.Observable',\n    ol.Observable,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.Observable.unByKey',\n    ol.Observable.unByKey,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Observable.prototype,\n    'changed',\n    ol.Observable.prototype.changed);\n\ngoog.exportProperty(\n    ol.Observable.prototype,\n    'dispatchEvent',\n    ol.Observable.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.Observable.prototype,\n    'getRevision',\n    ol.Observable.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.Observable.prototype,\n    'on',\n    ol.Observable.prototype.on);\n\ngoog.exportProperty(\n    ol.Observable.prototype,\n    'once',\n    ol.Observable.prototype.once);\n\ngoog.exportProperty(\n    ol.Observable.prototype,\n    'un',\n    ol.Observable.prototype.un);\n\ngoog.exportProperty(\n    ol.Observable.prototype,\n    'unByKey',\n    ol.Observable.prototype.unByKey);\n\ngoog.exportSymbol(\n    'ol.Overlay',\n    ol.Overlay,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getElement',\n    ol.Overlay.prototype.getElement);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getId',\n    ol.Overlay.prototype.getId);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getMap',\n    ol.Overlay.prototype.getMap);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getOffset',\n    ol.Overlay.prototype.getOffset);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getPosition',\n    ol.Overlay.prototype.getPosition);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getPositioning',\n    ol.Overlay.prototype.getPositioning);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'setElement',\n    ol.Overlay.prototype.setElement);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'setMap',\n    ol.Overlay.prototype.setMap);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'setOffset',\n    ol.Overlay.prototype.setOffset);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'setPosition',\n    ol.Overlay.prototype.setPosition);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'setPositioning',\n    ol.Overlay.prototype.setPositioning);\n\ngoog.exportSymbol(\n    'ol.render.toContext',\n    ol.render.toContext,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.size.toSize',\n    ol.size.toSize,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Tile.prototype,\n    'getTileCoord',\n    ol.Tile.prototype.getTileCoord);\n\ngoog.exportProperty(\n    ol.Tile.prototype,\n    'load',\n    ol.Tile.prototype.load);\n\ngoog.exportProperty(\n    ol.VectorTile.prototype,\n    'getFormat',\n    ol.VectorTile.prototype.getFormat);\n\ngoog.exportProperty(\n    ol.VectorTile.prototype,\n    'setFeatures',\n    ol.VectorTile.prototype.setFeatures);\n\ngoog.exportProperty(\n    ol.VectorTile.prototype,\n    'setProjection',\n    ol.VectorTile.prototype.setProjection);\n\ngoog.exportProperty(\n    ol.VectorTile.prototype,\n    'setLoader',\n    ol.VectorTile.prototype.setLoader);\n\ngoog.exportSymbol(\n    'ol.View',\n    ol.View,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'animate',\n    ol.View.prototype.animate);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'constrainCenter',\n    ol.View.prototype.constrainCenter);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'constrainResolution',\n    ol.View.prototype.constrainResolution);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'constrainRotation',\n    ol.View.prototype.constrainRotation);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getCenter',\n    ol.View.prototype.getCenter);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'calculateExtent',\n    ol.View.prototype.calculateExtent);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getMaxResolution',\n    ol.View.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getMinResolution',\n    ol.View.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getProjection',\n    ol.View.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getResolution',\n    ol.View.prototype.getResolution);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getResolutions',\n    ol.View.prototype.getResolutions);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getRotation',\n    ol.View.prototype.getRotation);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getZoom',\n    ol.View.prototype.getZoom);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'fit',\n    ol.View.prototype.fit);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'centerOn',\n    ol.View.prototype.centerOn);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'rotate',\n    ol.View.prototype.rotate);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'setCenter',\n    ol.View.prototype.setCenter);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'setResolution',\n    ol.View.prototype.setResolution);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'setRotation',\n    ol.View.prototype.setRotation);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'setZoom',\n    ol.View.prototype.setZoom);\n\ngoog.exportSymbol(\n    'ol.xml.getAllTextContent',\n    ol.xml.getAllTextContent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.xml.parse',\n    ol.xml.parse,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.webgl.Context.prototype,\n    'getGL',\n    ol.webgl.Context.prototype.getGL);\n\ngoog.exportProperty(\n    ol.webgl.Context.prototype,\n    'useProgram',\n    ol.webgl.Context.prototype.useProgram);\n\ngoog.exportSymbol(\n    'ol.tilegrid.createXYZ',\n    ol.tilegrid.createXYZ,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.tilegrid.TileGrid',\n    ol.tilegrid.TileGrid,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'forEachTileCoord',\n    ol.tilegrid.TileGrid.prototype.forEachTileCoord);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getMaxZoom',\n    ol.tilegrid.TileGrid.prototype.getMaxZoom);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getMinZoom',\n    ol.tilegrid.TileGrid.prototype.getMinZoom);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getOrigin',\n    ol.tilegrid.TileGrid.prototype.getOrigin);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getResolution',\n    ol.tilegrid.TileGrid.prototype.getResolution);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getResolutions',\n    ol.tilegrid.TileGrid.prototype.getResolutions);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getTileCoordExtent',\n    ol.tilegrid.TileGrid.prototype.getTileCoordExtent);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getTileCoordForCoordAndResolution',\n    ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getTileCoordForCoordAndZ',\n    ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getTileSize',\n    ol.tilegrid.TileGrid.prototype.getTileSize);\n\ngoog.exportProperty(\n    ol.tilegrid.TileGrid.prototype,\n    'getZForResolution',\n    ol.tilegrid.TileGrid.prototype.getZForResolution);\n\ngoog.exportSymbol(\n    'ol.tilegrid.WMTS',\n    ol.tilegrid.WMTS,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getMatrixIds',\n    ol.tilegrid.WMTS.prototype.getMatrixIds);\n\ngoog.exportSymbol(\n    'ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet',\n    ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.style.AtlasManager',\n    ol.style.AtlasManager,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.style.Circle',\n    ol.style.Circle,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'clone',\n    ol.style.Circle.prototype.clone);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'setRadius',\n    ol.style.Circle.prototype.setRadius);\n\ngoog.exportSymbol(\n    'ol.style.Fill',\n    ol.style.Fill,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.Fill.prototype,\n    'clone',\n    ol.style.Fill.prototype.clone);\n\ngoog.exportProperty(\n    ol.style.Fill.prototype,\n    'getColor',\n    ol.style.Fill.prototype.getColor);\n\ngoog.exportProperty(\n    ol.style.Fill.prototype,\n    'setColor',\n    ol.style.Fill.prototype.setColor);\n\ngoog.exportSymbol(\n    'ol.style.Icon',\n    ol.style.Icon,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'clone',\n    ol.style.Icon.prototype.clone);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getAnchor',\n    ol.style.Icon.prototype.getAnchor);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getColor',\n    ol.style.Icon.prototype.getColor);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getImage',\n    ol.style.Icon.prototype.getImage);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getOrigin',\n    ol.style.Icon.prototype.getOrigin);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getSrc',\n    ol.style.Icon.prototype.getSrc);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getSize',\n    ol.style.Icon.prototype.getSize);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'load',\n    ol.style.Icon.prototype.load);\n\ngoog.exportSymbol(\n    'ol.style.Image',\n    ol.style.Image,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'getOpacity',\n    ol.style.Image.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'getRotateWithView',\n    ol.style.Image.prototype.getRotateWithView);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'getRotation',\n    ol.style.Image.prototype.getRotation);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'getScale',\n    ol.style.Image.prototype.getScale);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'getSnapToPixel',\n    ol.style.Image.prototype.getSnapToPixel);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'setOpacity',\n    ol.style.Image.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'setRotation',\n    ol.style.Image.prototype.setRotation);\n\ngoog.exportProperty(\n    ol.style.Image.prototype,\n    'setScale',\n    ol.style.Image.prototype.setScale);\n\ngoog.exportSymbol(\n    'ol.style.RegularShape',\n    ol.style.RegularShape,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'clone',\n    ol.style.RegularShape.prototype.clone);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getAnchor',\n    ol.style.RegularShape.prototype.getAnchor);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getAngle',\n    ol.style.RegularShape.prototype.getAngle);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getFill',\n    ol.style.RegularShape.prototype.getFill);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getImage',\n    ol.style.RegularShape.prototype.getImage);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getOrigin',\n    ol.style.RegularShape.prototype.getOrigin);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getPoints',\n    ol.style.RegularShape.prototype.getPoints);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getRadius',\n    ol.style.RegularShape.prototype.getRadius);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getRadius2',\n    ol.style.RegularShape.prototype.getRadius2);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getSize',\n    ol.style.RegularShape.prototype.getSize);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getStroke',\n    ol.style.RegularShape.prototype.getStroke);\n\ngoog.exportSymbol(\n    'ol.style.Stroke',\n    ol.style.Stroke,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'clone',\n    ol.style.Stroke.prototype.clone);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'getColor',\n    ol.style.Stroke.prototype.getColor);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'getLineCap',\n    ol.style.Stroke.prototype.getLineCap);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'getLineDash',\n    ol.style.Stroke.prototype.getLineDash);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'getLineJoin',\n    ol.style.Stroke.prototype.getLineJoin);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'getMiterLimit',\n    ol.style.Stroke.prototype.getMiterLimit);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'getWidth',\n    ol.style.Stroke.prototype.getWidth);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'setColor',\n    ol.style.Stroke.prototype.setColor);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'setLineCap',\n    ol.style.Stroke.prototype.setLineCap);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'setLineDash',\n    ol.style.Stroke.prototype.setLineDash);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'setLineJoin',\n    ol.style.Stroke.prototype.setLineJoin);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'setMiterLimit',\n    ol.style.Stroke.prototype.setMiterLimit);\n\ngoog.exportProperty(\n    ol.style.Stroke.prototype,\n    'setWidth',\n    ol.style.Stroke.prototype.setWidth);\n\ngoog.exportSymbol(\n    'ol.style.Style',\n    ol.style.Style,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'clone',\n    ol.style.Style.prototype.clone);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'getGeometry',\n    ol.style.Style.prototype.getGeometry);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'getGeometryFunction',\n    ol.style.Style.prototype.getGeometryFunction);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'getFill',\n    ol.style.Style.prototype.getFill);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'setFill',\n    ol.style.Style.prototype.setFill);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'getImage',\n    ol.style.Style.prototype.getImage);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'setImage',\n    ol.style.Style.prototype.setImage);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'getStroke',\n    ol.style.Style.prototype.getStroke);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'setStroke',\n    ol.style.Style.prototype.setStroke);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'getText',\n    ol.style.Style.prototype.getText);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'setText',\n    ol.style.Style.prototype.setText);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'getZIndex',\n    ol.style.Style.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'setGeometry',\n    ol.style.Style.prototype.setGeometry);\n\ngoog.exportProperty(\n    ol.style.Style.prototype,\n    'setZIndex',\n    ol.style.Style.prototype.setZIndex);\n\ngoog.exportSymbol(\n    'ol.style.Text',\n    ol.style.Text,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'clone',\n    ol.style.Text.prototype.clone);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getFont',\n    ol.style.Text.prototype.getFont);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getOffsetX',\n    ol.style.Text.prototype.getOffsetX);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getOffsetY',\n    ol.style.Text.prototype.getOffsetY);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getFill',\n    ol.style.Text.prototype.getFill);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getRotateWithView',\n    ol.style.Text.prototype.getRotateWithView);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getRotation',\n    ol.style.Text.prototype.getRotation);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getScale',\n    ol.style.Text.prototype.getScale);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getStroke',\n    ol.style.Text.prototype.getStroke);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getText',\n    ol.style.Text.prototype.getText);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getTextAlign',\n    ol.style.Text.prototype.getTextAlign);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'getTextBaseline',\n    ol.style.Text.prototype.getTextBaseline);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setFont',\n    ol.style.Text.prototype.setFont);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setOffsetX',\n    ol.style.Text.prototype.setOffsetX);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setOffsetY',\n    ol.style.Text.prototype.setOffsetY);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setFill',\n    ol.style.Text.prototype.setFill);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setRotation',\n    ol.style.Text.prototype.setRotation);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setScale',\n    ol.style.Text.prototype.setScale);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setStroke',\n    ol.style.Text.prototype.setStroke);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setText',\n    ol.style.Text.prototype.setText);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setTextAlign',\n    ol.style.Text.prototype.setTextAlign);\n\ngoog.exportProperty(\n    ol.style.Text.prototype,\n    'setTextBaseline',\n    ol.style.Text.prototype.setTextBaseline);\n\ngoog.exportSymbol(\n    'ol.Sphere',\n    ol.Sphere,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Sphere.prototype,\n    'geodesicArea',\n    ol.Sphere.prototype.geodesicArea);\n\ngoog.exportProperty(\n    ol.Sphere.prototype,\n    'haversineDistance',\n    ol.Sphere.prototype.haversineDistance);\n\ngoog.exportSymbol(\n    'ol.source.BingMaps',\n    ol.source.BingMaps,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.BingMaps.TOS_ATTRIBUTION',\n    ol.source.BingMaps.TOS_ATTRIBUTION,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getApiKey',\n    ol.source.BingMaps.prototype.getApiKey);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getImagerySet',\n    ol.source.BingMaps.prototype.getImagerySet);\n\ngoog.exportSymbol(\n    'ol.source.CartoDB',\n    ol.source.CartoDB,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getConfig',\n    ol.source.CartoDB.prototype.getConfig);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'updateConfig',\n    ol.source.CartoDB.prototype.updateConfig);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setConfig',\n    ol.source.CartoDB.prototype.setConfig);\n\ngoog.exportSymbol(\n    'ol.source.Cluster',\n    ol.source.Cluster,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getSource',\n    ol.source.Cluster.prototype.getSource);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'setDistance',\n    ol.source.Cluster.prototype.setDistance);\n\ngoog.exportSymbol(\n    'ol.source.Image',\n    ol.source.Image,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.Image.Event.prototype,\n    'image',\n    ol.source.Image.Event.prototype.image);\n\ngoog.exportSymbol(\n    'ol.source.ImageArcGISRest',\n    ol.source.ImageArcGISRest,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getParams',\n    ol.source.ImageArcGISRest.prototype.getParams);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getImageLoadFunction',\n    ol.source.ImageArcGISRest.prototype.getImageLoadFunction);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getUrl',\n    ol.source.ImageArcGISRest.prototype.getUrl);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'setImageLoadFunction',\n    ol.source.ImageArcGISRest.prototype.setImageLoadFunction);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'setUrl',\n    ol.source.ImageArcGISRest.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'updateParams',\n    ol.source.ImageArcGISRest.prototype.updateParams);\n\ngoog.exportSymbol(\n    'ol.source.ImageCanvas',\n    ol.source.ImageCanvas,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.ImageMapGuide',\n    ol.source.ImageMapGuide,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getParams',\n    ol.source.ImageMapGuide.prototype.getParams);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getImageLoadFunction',\n    ol.source.ImageMapGuide.prototype.getImageLoadFunction);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'updateParams',\n    ol.source.ImageMapGuide.prototype.updateParams);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'setImageLoadFunction',\n    ol.source.ImageMapGuide.prototype.setImageLoadFunction);\n\ngoog.exportSymbol(\n    'ol.source.ImageStatic',\n    ol.source.ImageStatic,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.ImageVector',\n    ol.source.ImageVector,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getSource',\n    ol.source.ImageVector.prototype.getSource);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getStyle',\n    ol.source.ImageVector.prototype.getStyle);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getStyleFunction',\n    ol.source.ImageVector.prototype.getStyleFunction);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'setStyle',\n    ol.source.ImageVector.prototype.setStyle);\n\ngoog.exportSymbol(\n    'ol.source.ImageWMS',\n    ol.source.ImageWMS,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getGetFeatureInfoUrl',\n    ol.source.ImageWMS.prototype.getGetFeatureInfoUrl);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getParams',\n    ol.source.ImageWMS.prototype.getParams);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getImageLoadFunction',\n    ol.source.ImageWMS.prototype.getImageLoadFunction);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getUrl',\n    ol.source.ImageWMS.prototype.getUrl);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'setImageLoadFunction',\n    ol.source.ImageWMS.prototype.setImageLoadFunction);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'setUrl',\n    ol.source.ImageWMS.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'updateParams',\n    ol.source.ImageWMS.prototype.updateParams);\n\ngoog.exportSymbol(\n    'ol.source.OSM',\n    ol.source.OSM,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.OSM.ATTRIBUTION',\n    ol.source.OSM.ATTRIBUTION,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.Raster',\n    ol.source.Raster,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'setOperation',\n    ol.source.Raster.prototype.setOperation);\n\ngoog.exportProperty(\n    ol.source.Raster.Event.prototype,\n    'extent',\n    ol.source.Raster.Event.prototype.extent);\n\ngoog.exportProperty(\n    ol.source.Raster.Event.prototype,\n    'resolution',\n    ol.source.Raster.Event.prototype.resolution);\n\ngoog.exportProperty(\n    ol.source.Raster.Event.prototype,\n    'data',\n    ol.source.Raster.Event.prototype.data);\n\ngoog.exportSymbol(\n    'ol.source.Source',\n    ol.source.Source,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'getAttributions',\n    ol.source.Source.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'getLogo',\n    ol.source.Source.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'getProjection',\n    ol.source.Source.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'getState',\n    ol.source.Source.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'refresh',\n    ol.source.Source.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'setAttributions',\n    ol.source.Source.prototype.setAttributions);\n\ngoog.exportSymbol(\n    'ol.source.Stamen',\n    ol.source.Stamen,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.Tile',\n    ol.source.Tile,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getTileGrid',\n    ol.source.Tile.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.Tile.Event.prototype,\n    'tile',\n    ol.source.Tile.Event.prototype.tile);\n\ngoog.exportSymbol(\n    'ol.source.TileArcGISRest',\n    ol.source.TileArcGISRest,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getParams',\n    ol.source.TileArcGISRest.prototype.getParams);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'updateParams',\n    ol.source.TileArcGISRest.prototype.updateParams);\n\ngoog.exportSymbol(\n    'ol.source.TileDebug',\n    ol.source.TileDebug,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.TileImage',\n    ol.source.TileImage,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.TileImage.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setTileGridForProjection',\n    ol.source.TileImage.prototype.setTileGridForProjection);\n\ngoog.exportSymbol(\n    'ol.source.TileJSON',\n    ol.source.TileJSON,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getTileJSON',\n    ol.source.TileJSON.prototype.getTileJSON);\n\ngoog.exportSymbol(\n    'ol.source.TileUTFGrid',\n    ol.source.TileUTFGrid,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getTemplate',\n    ol.source.TileUTFGrid.prototype.getTemplate);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'forDataAtCoordinateAndResolution',\n    ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution);\n\ngoog.exportSymbol(\n    'ol.source.TileWMS',\n    ol.source.TileWMS,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getGetFeatureInfoUrl',\n    ol.source.TileWMS.prototype.getGetFeatureInfoUrl);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getParams',\n    ol.source.TileWMS.prototype.getParams);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'updateParams',\n    ol.source.TileWMS.prototype.updateParams);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getTileLoadFunction',\n    ol.source.UrlTile.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getTileUrlFunction',\n    ol.source.UrlTile.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getUrls',\n    ol.source.UrlTile.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'setTileLoadFunction',\n    ol.source.UrlTile.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'setTileUrlFunction',\n    ol.source.UrlTile.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'setUrl',\n    ol.source.UrlTile.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'setUrls',\n    ol.source.UrlTile.prototype.setUrls);\n\ngoog.exportSymbol(\n    'ol.source.Vector',\n    ol.source.Vector,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'addFeature',\n    ol.source.Vector.prototype.addFeature);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'addFeatures',\n    ol.source.Vector.prototype.addFeatures);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'clear',\n    ol.source.Vector.prototype.clear);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'forEachFeature',\n    ol.source.Vector.prototype.forEachFeature);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'forEachFeatureInExtent',\n    ol.source.Vector.prototype.forEachFeatureInExtent);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'forEachFeatureIntersectingExtent',\n    ol.source.Vector.prototype.forEachFeatureIntersectingExtent);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getFeaturesCollection',\n    ol.source.Vector.prototype.getFeaturesCollection);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getFeatures',\n    ol.source.Vector.prototype.getFeatures);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getFeaturesAtCoordinate',\n    ol.source.Vector.prototype.getFeaturesAtCoordinate);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getFeaturesInExtent',\n    ol.source.Vector.prototype.getFeaturesInExtent);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getClosestFeatureToCoordinate',\n    ol.source.Vector.prototype.getClosestFeatureToCoordinate);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getExtent',\n    ol.source.Vector.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getFeatureById',\n    ol.source.Vector.prototype.getFeatureById);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getFormat',\n    ol.source.Vector.prototype.getFormat);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getUrl',\n    ol.source.Vector.prototype.getUrl);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'removeFeature',\n    ol.source.Vector.prototype.removeFeature);\n\ngoog.exportProperty(\n    ol.source.Vector.Event.prototype,\n    'feature',\n    ol.source.Vector.Event.prototype.feature);\n\ngoog.exportSymbol(\n    'ol.source.VectorTile',\n    ol.source.VectorTile,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.WMTS',\n    ol.source.WMTS,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getDimensions',\n    ol.source.WMTS.prototype.getDimensions);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getFormat',\n    ol.source.WMTS.prototype.getFormat);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getLayer',\n    ol.source.WMTS.prototype.getLayer);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getMatrixSet',\n    ol.source.WMTS.prototype.getMatrixSet);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getRequestEncoding',\n    ol.source.WMTS.prototype.getRequestEncoding);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getStyle',\n    ol.source.WMTS.prototype.getStyle);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getVersion',\n    ol.source.WMTS.prototype.getVersion);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'updateDimensions',\n    ol.source.WMTS.prototype.updateDimensions);\n\ngoog.exportSymbol(\n    'ol.source.WMTS.optionsFromCapabilities',\n    ol.source.WMTS.optionsFromCapabilities,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.XYZ',\n    ol.source.XYZ,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.source.Zoomify',\n    ol.source.Zoomify,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'vectorContext',\n    ol.render.Event.prototype.vectorContext);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'frameState',\n    ol.render.Event.prototype.frameState);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'context',\n    ol.render.Event.prototype.context);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'glContext',\n    ol.render.Event.prototype.glContext);\n\ngoog.exportProperty(\n    ol.render.Feature.prototype,\n    'get',\n    ol.render.Feature.prototype.get);\n\ngoog.exportProperty(\n    ol.render.Feature.prototype,\n    'getExtent',\n    ol.render.Feature.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.render.Feature.prototype,\n    'getGeometry',\n    ol.render.Feature.prototype.getGeometry);\n\ngoog.exportProperty(\n    ol.render.Feature.prototype,\n    'getProperties',\n    ol.render.Feature.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.render.Feature.prototype,\n    'getType',\n    ol.render.Feature.prototype.getType);\n\ngoog.exportSymbol(\n    'ol.render.VectorContext',\n    ol.render.VectorContext,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.render.webgl.Immediate.prototype,\n    'setStyle',\n    ol.render.webgl.Immediate.prototype.setStyle);\n\ngoog.exportProperty(\n    ol.render.webgl.Immediate.prototype,\n    'drawGeometry',\n    ol.render.webgl.Immediate.prototype.drawGeometry);\n\ngoog.exportProperty(\n    ol.render.webgl.Immediate.prototype,\n    'drawFeature',\n    ol.render.webgl.Immediate.prototype.drawFeature);\n\ngoog.exportProperty(\n    ol.render.canvas.Immediate.prototype,\n    'drawCircle',\n    ol.render.canvas.Immediate.prototype.drawCircle);\n\ngoog.exportProperty(\n    ol.render.canvas.Immediate.prototype,\n    'setStyle',\n    ol.render.canvas.Immediate.prototype.setStyle);\n\ngoog.exportProperty(\n    ol.render.canvas.Immediate.prototype,\n    'drawGeometry',\n    ol.render.canvas.Immediate.prototype.drawGeometry);\n\ngoog.exportProperty(\n    ol.render.canvas.Immediate.prototype,\n    'drawFeature',\n    ol.render.canvas.Immediate.prototype.drawFeature);\n\ngoog.exportSymbol(\n    'ol.proj.common.add',\n    ol.proj.common.add,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.METERS_PER_UNIT',\n    ol.proj.METERS_PER_UNIT,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.setProj4',\n    ol.proj.setProj4,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.getPointResolution',\n    ol.proj.getPointResolution,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.addEquivalentProjections',\n    ol.proj.addEquivalentProjections,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.addProjection',\n    ol.proj.addProjection,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.addCoordinateTransforms',\n    ol.proj.addCoordinateTransforms,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.fromLonLat',\n    ol.proj.fromLonLat,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.toLonLat',\n    ol.proj.toLonLat,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.get',\n    ol.proj.get,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.equivalent',\n    ol.proj.equivalent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.getTransform',\n    ol.proj.getTransform,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.transform',\n    ol.proj.transform,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.transformExtent',\n    ol.proj.transformExtent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.proj.Projection',\n    ol.proj.Projection,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'getCode',\n    ol.proj.Projection.prototype.getCode);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'getExtent',\n    ol.proj.Projection.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'getUnits',\n    ol.proj.Projection.prototype.getUnits);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'getMetersPerUnit',\n    ol.proj.Projection.prototype.getMetersPerUnit);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'getWorldExtent',\n    ol.proj.Projection.prototype.getWorldExtent);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'isGlobal',\n    ol.proj.Projection.prototype.isGlobal);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'setGlobal',\n    ol.proj.Projection.prototype.setGlobal);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'setExtent',\n    ol.proj.Projection.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'setWorldExtent',\n    ol.proj.Projection.prototype.setWorldExtent);\n\ngoog.exportProperty(\n    ol.proj.Projection.prototype,\n    'setGetPointResolution',\n    ol.proj.Projection.prototype.setGetPointResolution);\n\ngoog.exportSymbol(\n    'ol.proj.Units.METERS_PER_UNIT',\n    ol.proj.Units.METERS_PER_UNIT,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.layer.Base',\n    ol.layer.Base,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getExtent',\n    ol.layer.Base.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getMaxResolution',\n    ol.layer.Base.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getMinResolution',\n    ol.layer.Base.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getOpacity',\n    ol.layer.Base.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getVisible',\n    ol.layer.Base.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getZIndex',\n    ol.layer.Base.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'setExtent',\n    ol.layer.Base.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'setMaxResolution',\n    ol.layer.Base.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'setMinResolution',\n    ol.layer.Base.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'setOpacity',\n    ol.layer.Base.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'setVisible',\n    ol.layer.Base.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'setZIndex',\n    ol.layer.Base.prototype.setZIndex);\n\ngoog.exportSymbol(\n    'ol.layer.Group',\n    ol.layer.Group,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getLayers',\n    ol.layer.Group.prototype.getLayers);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setLayers',\n    ol.layer.Group.prototype.setLayers);\n\ngoog.exportSymbol(\n    'ol.layer.Heatmap',\n    ol.layer.Heatmap,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getBlur',\n    ol.layer.Heatmap.prototype.getBlur);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getGradient',\n    ol.layer.Heatmap.prototype.getGradient);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getRadius',\n    ol.layer.Heatmap.prototype.getRadius);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setBlur',\n    ol.layer.Heatmap.prototype.setBlur);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setGradient',\n    ol.layer.Heatmap.prototype.setGradient);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setRadius',\n    ol.layer.Heatmap.prototype.setRadius);\n\ngoog.exportSymbol(\n    'ol.layer.Image',\n    ol.layer.Image,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getSource',\n    ol.layer.Image.prototype.getSource);\n\ngoog.exportSymbol(\n    'ol.layer.Layer',\n    ol.layer.Layer,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getSource',\n    ol.layer.Layer.prototype.getSource);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setMap',\n    ol.layer.Layer.prototype.setMap);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setSource',\n    ol.layer.Layer.prototype.setSource);\n\ngoog.exportSymbol(\n    'ol.layer.Tile',\n    ol.layer.Tile,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getPreload',\n    ol.layer.Tile.prototype.getPreload);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getSource',\n    ol.layer.Tile.prototype.getSource);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setPreload',\n    ol.layer.Tile.prototype.setPreload);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getUseInterimTilesOnError',\n    ol.layer.Tile.prototype.getUseInterimTilesOnError);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setUseInterimTilesOnError',\n    ol.layer.Tile.prototype.setUseInterimTilesOnError);\n\ngoog.exportSymbol(\n    'ol.layer.Vector',\n    ol.layer.Vector,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getSource',\n    ol.layer.Vector.prototype.getSource);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getStyle',\n    ol.layer.Vector.prototype.getStyle);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getStyleFunction',\n    ol.layer.Vector.prototype.getStyleFunction);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setStyle',\n    ol.layer.Vector.prototype.setStyle);\n\ngoog.exportSymbol(\n    'ol.layer.VectorTile',\n    ol.layer.VectorTile,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getPreload',\n    ol.layer.VectorTile.prototype.getPreload);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getUseInterimTilesOnError',\n    ol.layer.VectorTile.prototype.getUseInterimTilesOnError);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setPreload',\n    ol.layer.VectorTile.prototype.setPreload);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setUseInterimTilesOnError',\n    ol.layer.VectorTile.prototype.setUseInterimTilesOnError);\n\ngoog.exportSymbol(\n    'ol.interaction.DoubleClickZoom',\n    ol.interaction.DoubleClickZoom,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.DoubleClickZoom.handleEvent',\n    ol.interaction.DoubleClickZoom.handleEvent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.DragAndDrop',\n    ol.interaction.DragAndDrop,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.DragAndDrop.handleEvent',\n    ol.interaction.DragAndDrop.handleEvent,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.Event.prototype,\n    'features',\n    ol.interaction.DragAndDrop.Event.prototype.features);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.Event.prototype,\n    'file',\n    ol.interaction.DragAndDrop.Event.prototype.file);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.Event.prototype,\n    'projection',\n    ol.interaction.DragAndDrop.Event.prototype.projection);\n\ngoog.exportSymbol(\n    'ol.interaction.DragBox',\n    ol.interaction.DragBox,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'getGeometry',\n    ol.interaction.DragBox.prototype.getGeometry);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.Event.prototype,\n    'coordinate',\n    ol.interaction.DragBox.Event.prototype.coordinate);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.Event.prototype,\n    'mapBrowserEvent',\n    ol.interaction.DragBox.Event.prototype.mapBrowserEvent);\n\ngoog.exportSymbol(\n    'ol.interaction.DragPan',\n    ol.interaction.DragPan,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.DragRotate',\n    ol.interaction.DragRotate,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.DragRotateAndZoom',\n    ol.interaction.DragRotateAndZoom,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.DragZoom',\n    ol.interaction.DragZoom,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Draw',\n    ol.interaction.Draw,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Draw.handleEvent',\n    ol.interaction.Draw.handleEvent,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'removeLastPoint',\n    ol.interaction.Draw.prototype.removeLastPoint);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'finishDrawing',\n    ol.interaction.Draw.prototype.finishDrawing);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'extend',\n    ol.interaction.Draw.prototype.extend);\n\ngoog.exportSymbol(\n    'ol.interaction.Draw.createRegularPolygon',\n    ol.interaction.Draw.createRegularPolygon,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Draw.createBox',\n    ol.interaction.Draw.createBox,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Draw.Event.prototype,\n    'feature',\n    ol.interaction.Draw.Event.prototype.feature);\n\ngoog.exportSymbol(\n    'ol.interaction.Extent',\n    ol.interaction.Extent,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'getExtent',\n    ol.interaction.Extent.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'setExtent',\n    ol.interaction.Extent.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.interaction.Extent.Event.prototype,\n    'extent_',\n    ol.interaction.Extent.Event.prototype.extent_);\n\ngoog.exportSymbol(\n    'ol.interaction.defaults',\n    ol.interaction.defaults,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Interaction',\n    ol.interaction.Interaction,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'getActive',\n    ol.interaction.Interaction.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'getMap',\n    ol.interaction.Interaction.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'setActive',\n    ol.interaction.Interaction.prototype.setActive);\n\ngoog.exportSymbol(\n    'ol.interaction.KeyboardPan',\n    ol.interaction.KeyboardPan,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.KeyboardPan.handleEvent',\n    ol.interaction.KeyboardPan.handleEvent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.KeyboardZoom',\n    ol.interaction.KeyboardZoom,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.KeyboardZoom.handleEvent',\n    ol.interaction.KeyboardZoom.handleEvent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Modify',\n    ol.interaction.Modify,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Modify.handleEvent',\n    ol.interaction.Modify.handleEvent,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'removePoint',\n    ol.interaction.Modify.prototype.removePoint);\n\ngoog.exportProperty(\n    ol.interaction.Modify.Event.prototype,\n    'features',\n    ol.interaction.Modify.Event.prototype.features);\n\ngoog.exportProperty(\n    ol.interaction.Modify.Event.prototype,\n    'mapBrowserEvent',\n    ol.interaction.Modify.Event.prototype.mapBrowserEvent);\n\ngoog.exportSymbol(\n    'ol.interaction.MouseWheelZoom',\n    ol.interaction.MouseWheelZoom,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.MouseWheelZoom.handleEvent',\n    ol.interaction.MouseWheelZoom.handleEvent,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'setMouseAnchor',\n    ol.interaction.MouseWheelZoom.prototype.setMouseAnchor);\n\ngoog.exportSymbol(\n    'ol.interaction.PinchRotate',\n    ol.interaction.PinchRotate,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.PinchZoom',\n    ol.interaction.PinchZoom,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Pointer',\n    ol.interaction.Pointer,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Pointer.handleEvent',\n    ol.interaction.Pointer.handleEvent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.interaction.Select',\n    ol.interaction.Select,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getFeatures',\n    ol.interaction.Select.prototype.getFeatures);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getHitTolerance',\n    ol.interaction.Select.prototype.getHitTolerance);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getLayer',\n    ol.interaction.Select.prototype.getLayer);\n\ngoog.exportSymbol(\n    'ol.interaction.Select.handleEvent',\n    ol.interaction.Select.handleEvent,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'setHitTolerance',\n    ol.interaction.Select.prototype.setHitTolerance);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'setMap',\n    ol.interaction.Select.prototype.setMap);\n\ngoog.exportProperty(\n    ol.interaction.Select.Event.prototype,\n    'selected',\n    ol.interaction.Select.Event.prototype.selected);\n\ngoog.exportProperty(\n    ol.interaction.Select.Event.prototype,\n    'deselected',\n    ol.interaction.Select.Event.prototype.deselected);\n\ngoog.exportProperty(\n    ol.interaction.Select.Event.prototype,\n    'mapBrowserEvent',\n    ol.interaction.Select.Event.prototype.mapBrowserEvent);\n\ngoog.exportSymbol(\n    'ol.interaction.Snap',\n    ol.interaction.Snap,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'addFeature',\n    ol.interaction.Snap.prototype.addFeature);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'removeFeature',\n    ol.interaction.Snap.prototype.removeFeature);\n\ngoog.exportSymbol(\n    'ol.interaction.Translate',\n    ol.interaction.Translate,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'getHitTolerance',\n    ol.interaction.Translate.prototype.getHitTolerance);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'setHitTolerance',\n    ol.interaction.Translate.prototype.setHitTolerance);\n\ngoog.exportProperty(\n    ol.interaction.Translate.Event.prototype,\n    'features',\n    ol.interaction.Translate.Event.prototype.features);\n\ngoog.exportProperty(\n    ol.interaction.Translate.Event.prototype,\n    'coordinate',\n    ol.interaction.Translate.Event.prototype.coordinate);\n\ngoog.exportSymbol(\n    'ol.geom.Circle',\n    ol.geom.Circle,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'clone',\n    ol.geom.Circle.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getCenter',\n    ol.geom.Circle.prototype.getCenter);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getRadius',\n    ol.geom.Circle.prototype.getRadius);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getType',\n    ol.geom.Circle.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'intersectsExtent',\n    ol.geom.Circle.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'setCenter',\n    ol.geom.Circle.prototype.setCenter);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'setCenterAndRadius',\n    ol.geom.Circle.prototype.setCenterAndRadius);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'setRadius',\n    ol.geom.Circle.prototype.setRadius);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'transform',\n    ol.geom.Circle.prototype.transform);\n\ngoog.exportSymbol(\n    'ol.geom.Geometry',\n    ol.geom.Geometry,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'getClosestPoint',\n    ol.geom.Geometry.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'intersectsCoordinate',\n    ol.geom.Geometry.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'getExtent',\n    ol.geom.Geometry.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'rotate',\n    ol.geom.Geometry.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'scale',\n    ol.geom.Geometry.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'simplify',\n    ol.geom.Geometry.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'transform',\n    ol.geom.Geometry.prototype.transform);\n\ngoog.exportSymbol(\n    'ol.geom.GeometryCollection',\n    ol.geom.GeometryCollection,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'clone',\n    ol.geom.GeometryCollection.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'getGeometries',\n    ol.geom.GeometryCollection.prototype.getGeometries);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'getType',\n    ol.geom.GeometryCollection.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'intersectsExtent',\n    ol.geom.GeometryCollection.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'setGeometries',\n    ol.geom.GeometryCollection.prototype.setGeometries);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'applyTransform',\n    ol.geom.GeometryCollection.prototype.applyTransform);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'translate',\n    ol.geom.GeometryCollection.prototype.translate);\n\ngoog.exportSymbol(\n    'ol.geom.LinearRing',\n    ol.geom.LinearRing,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'clone',\n    ol.geom.LinearRing.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getArea',\n    ol.geom.LinearRing.prototype.getArea);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getCoordinates',\n    ol.geom.LinearRing.prototype.getCoordinates);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getType',\n    ol.geom.LinearRing.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'setCoordinates',\n    ol.geom.LinearRing.prototype.setCoordinates);\n\ngoog.exportSymbol(\n    'ol.geom.LineString',\n    ol.geom.LineString,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'appendCoordinate',\n    ol.geom.LineString.prototype.appendCoordinate);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'clone',\n    ol.geom.LineString.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'forEachSegment',\n    ol.geom.LineString.prototype.forEachSegment);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getCoordinateAtM',\n    ol.geom.LineString.prototype.getCoordinateAtM);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getCoordinates',\n    ol.geom.LineString.prototype.getCoordinates);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getCoordinateAt',\n    ol.geom.LineString.prototype.getCoordinateAt);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getLength',\n    ol.geom.LineString.prototype.getLength);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getType',\n    ol.geom.LineString.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'intersectsExtent',\n    ol.geom.LineString.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'setCoordinates',\n    ol.geom.LineString.prototype.setCoordinates);\n\ngoog.exportSymbol(\n    'ol.geom.MultiLineString',\n    ol.geom.MultiLineString,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'appendLineString',\n    ol.geom.MultiLineString.prototype.appendLineString);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'clone',\n    ol.geom.MultiLineString.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getCoordinateAtM',\n    ol.geom.MultiLineString.prototype.getCoordinateAtM);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getCoordinates',\n    ol.geom.MultiLineString.prototype.getCoordinates);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getLineString',\n    ol.geom.MultiLineString.prototype.getLineString);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getLineStrings',\n    ol.geom.MultiLineString.prototype.getLineStrings);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getType',\n    ol.geom.MultiLineString.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'intersectsExtent',\n    ol.geom.MultiLineString.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'setCoordinates',\n    ol.geom.MultiLineString.prototype.setCoordinates);\n\ngoog.exportSymbol(\n    'ol.geom.MultiPoint',\n    ol.geom.MultiPoint,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'appendPoint',\n    ol.geom.MultiPoint.prototype.appendPoint);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'clone',\n    ol.geom.MultiPoint.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getCoordinates',\n    ol.geom.MultiPoint.prototype.getCoordinates);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getPoint',\n    ol.geom.MultiPoint.prototype.getPoint);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getPoints',\n    ol.geom.MultiPoint.prototype.getPoints);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getType',\n    ol.geom.MultiPoint.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'intersectsExtent',\n    ol.geom.MultiPoint.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'setCoordinates',\n    ol.geom.MultiPoint.prototype.setCoordinates);\n\ngoog.exportSymbol(\n    'ol.geom.MultiPolygon',\n    ol.geom.MultiPolygon,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'appendPolygon',\n    ol.geom.MultiPolygon.prototype.appendPolygon);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'clone',\n    ol.geom.MultiPolygon.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getArea',\n    ol.geom.MultiPolygon.prototype.getArea);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getCoordinates',\n    ol.geom.MultiPolygon.prototype.getCoordinates);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getInteriorPoints',\n    ol.geom.MultiPolygon.prototype.getInteriorPoints);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getPolygon',\n    ol.geom.MultiPolygon.prototype.getPolygon);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getPolygons',\n    ol.geom.MultiPolygon.prototype.getPolygons);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getType',\n    ol.geom.MultiPolygon.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'intersectsExtent',\n    ol.geom.MultiPolygon.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'setCoordinates',\n    ol.geom.MultiPolygon.prototype.setCoordinates);\n\ngoog.exportSymbol(\n    'ol.geom.Point',\n    ol.geom.Point,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'clone',\n    ol.geom.Point.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getCoordinates',\n    ol.geom.Point.prototype.getCoordinates);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getType',\n    ol.geom.Point.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'intersectsExtent',\n    ol.geom.Point.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'setCoordinates',\n    ol.geom.Point.prototype.setCoordinates);\n\ngoog.exportSymbol(\n    'ol.geom.Polygon',\n    ol.geom.Polygon,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'appendLinearRing',\n    ol.geom.Polygon.prototype.appendLinearRing);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'clone',\n    ol.geom.Polygon.prototype.clone);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getArea',\n    ol.geom.Polygon.prototype.getArea);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getCoordinates',\n    ol.geom.Polygon.prototype.getCoordinates);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getInteriorPoint',\n    ol.geom.Polygon.prototype.getInteriorPoint);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getLinearRingCount',\n    ol.geom.Polygon.prototype.getLinearRingCount);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getLinearRing',\n    ol.geom.Polygon.prototype.getLinearRing);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getLinearRings',\n    ol.geom.Polygon.prototype.getLinearRings);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getType',\n    ol.geom.Polygon.prototype.getType);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'intersectsExtent',\n    ol.geom.Polygon.prototype.intersectsExtent);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'setCoordinates',\n    ol.geom.Polygon.prototype.setCoordinates);\n\ngoog.exportSymbol(\n    'ol.geom.Polygon.circular',\n    ol.geom.Polygon.circular,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.geom.Polygon.fromExtent',\n    ol.geom.Polygon.fromExtent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.geom.Polygon.fromCircle',\n    ol.geom.Polygon.fromCircle,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.geom.SimpleGeometry',\n    ol.geom.SimpleGeometry,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getFirstCoordinate',\n    ol.geom.SimpleGeometry.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getLastCoordinate',\n    ol.geom.SimpleGeometry.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getLayout',\n    ol.geom.SimpleGeometry.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'applyTransform',\n    ol.geom.SimpleGeometry.prototype.applyTransform);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'translate',\n    ol.geom.SimpleGeometry.prototype.translate);\n\ngoog.exportSymbol(\n    'ol.format.EsriJSON',\n    ol.format.EsriJSON,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'readFeature',\n    ol.format.EsriJSON.prototype.readFeature);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'readFeatures',\n    ol.format.EsriJSON.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'readGeometry',\n    ol.format.EsriJSON.prototype.readGeometry);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'readProjection',\n    ol.format.EsriJSON.prototype.readProjection);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'writeGeometry',\n    ol.format.EsriJSON.prototype.writeGeometry);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'writeGeometryObject',\n    ol.format.EsriJSON.prototype.writeGeometryObject);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'writeFeature',\n    ol.format.EsriJSON.prototype.writeFeature);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'writeFeatureObject',\n    ol.format.EsriJSON.prototype.writeFeatureObject);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'writeFeatures',\n    ol.format.EsriJSON.prototype.writeFeatures);\n\ngoog.exportProperty(\n    ol.format.EsriJSON.prototype,\n    'writeFeaturesObject',\n    ol.format.EsriJSON.prototype.writeFeaturesObject);\n\ngoog.exportSymbol(\n    'ol.format.Feature',\n    ol.format.Feature,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.GeoJSON',\n    ol.format.GeoJSON,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'readFeature',\n    ol.format.GeoJSON.prototype.readFeature);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'readFeatures',\n    ol.format.GeoJSON.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'readGeometry',\n    ol.format.GeoJSON.prototype.readGeometry);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'readProjection',\n    ol.format.GeoJSON.prototype.readProjection);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'writeFeature',\n    ol.format.GeoJSON.prototype.writeFeature);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'writeFeatureObject',\n    ol.format.GeoJSON.prototype.writeFeatureObject);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'writeFeatures',\n    ol.format.GeoJSON.prototype.writeFeatures);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'writeFeaturesObject',\n    ol.format.GeoJSON.prototype.writeFeaturesObject);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'writeGeometry',\n    ol.format.GeoJSON.prototype.writeGeometry);\n\ngoog.exportProperty(\n    ol.format.GeoJSON.prototype,\n    'writeGeometryObject',\n    ol.format.GeoJSON.prototype.writeGeometryObject);\n\ngoog.exportSymbol(\n    'ol.format.GML',\n    ol.format.GML,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.GML.prototype,\n    'writeFeatures',\n    ol.format.GML.prototype.writeFeatures);\n\ngoog.exportProperty(\n    ol.format.GML.prototype,\n    'writeFeaturesNode',\n    ol.format.GML.prototype.writeFeaturesNode);\n\ngoog.exportSymbol(\n    'ol.format.GML2',\n    ol.format.GML2,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.GML3',\n    ol.format.GML3,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.GML3.prototype,\n    'writeGeometryNode',\n    ol.format.GML3.prototype.writeGeometryNode);\n\ngoog.exportProperty(\n    ol.format.GML3.prototype,\n    'writeFeatures',\n    ol.format.GML3.prototype.writeFeatures);\n\ngoog.exportProperty(\n    ol.format.GML3.prototype,\n    'writeFeaturesNode',\n    ol.format.GML3.prototype.writeFeaturesNode);\n\ngoog.exportProperty(\n    ol.format.GMLBase.prototype,\n    'readFeatures',\n    ol.format.GMLBase.prototype.readFeatures);\n\ngoog.exportSymbol(\n    'ol.format.GPX',\n    ol.format.GPX,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.GPX.prototype,\n    'readFeature',\n    ol.format.GPX.prototype.readFeature);\n\ngoog.exportProperty(\n    ol.format.GPX.prototype,\n    'readFeatures',\n    ol.format.GPX.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.GPX.prototype,\n    'readProjection',\n    ol.format.GPX.prototype.readProjection);\n\ngoog.exportProperty(\n    ol.format.GPX.prototype,\n    'writeFeatures',\n    ol.format.GPX.prototype.writeFeatures);\n\ngoog.exportProperty(\n    ol.format.GPX.prototype,\n    'writeFeaturesNode',\n    ol.format.GPX.prototype.writeFeaturesNode);\n\ngoog.exportSymbol(\n    'ol.format.IGC',\n    ol.format.IGC,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.IGC.prototype,\n    'readFeature',\n    ol.format.IGC.prototype.readFeature);\n\ngoog.exportProperty(\n    ol.format.IGC.prototype,\n    'readFeatures',\n    ol.format.IGC.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.IGC.prototype,\n    'readProjection',\n    ol.format.IGC.prototype.readProjection);\n\ngoog.exportSymbol(\n    'ol.format.KML',\n    ol.format.KML,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'readFeature',\n    ol.format.KML.prototype.readFeature);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'readFeatures',\n    ol.format.KML.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'readName',\n    ol.format.KML.prototype.readName);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'readNetworkLinks',\n    ol.format.KML.prototype.readNetworkLinks);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'readRegion',\n    ol.format.KML.prototype.readRegion);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'readRegionFromNode',\n    ol.format.KML.prototype.readRegionFromNode);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'readProjection',\n    ol.format.KML.prototype.readProjection);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'writeFeatures',\n    ol.format.KML.prototype.writeFeatures);\n\ngoog.exportProperty(\n    ol.format.KML.prototype,\n    'writeFeaturesNode',\n    ol.format.KML.prototype.writeFeaturesNode);\n\ngoog.exportSymbol(\n    'ol.format.MVT',\n    ol.format.MVT,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.MVT.prototype,\n    'readFeatures',\n    ol.format.MVT.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.MVT.prototype,\n    'readProjection',\n    ol.format.MVT.prototype.readProjection);\n\ngoog.exportProperty(\n    ol.format.MVT.prototype,\n    'setLayers',\n    ol.format.MVT.prototype.setLayers);\n\ngoog.exportSymbol(\n    'ol.format.OSMXML',\n    ol.format.OSMXML,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.OSMXML.prototype,\n    'readFeatures',\n    ol.format.OSMXML.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.OSMXML.prototype,\n    'readProjection',\n    ol.format.OSMXML.prototype.readProjection);\n\ngoog.exportSymbol(\n    'ol.format.Polyline',\n    ol.format.Polyline,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.Polyline.encodeDeltas',\n    ol.format.Polyline.encodeDeltas,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.Polyline.decodeDeltas',\n    ol.format.Polyline.decodeDeltas,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.Polyline.encodeFloats',\n    ol.format.Polyline.encodeFloats,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.Polyline.decodeFloats',\n    ol.format.Polyline.decodeFloats,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.Polyline.prototype,\n    'readFeature',\n    ol.format.Polyline.prototype.readFeature);\n\ngoog.exportProperty(\n    ol.format.Polyline.prototype,\n    'readFeatures',\n    ol.format.Polyline.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.Polyline.prototype,\n    'readGeometry',\n    ol.format.Polyline.prototype.readGeometry);\n\ngoog.exportProperty(\n    ol.format.Polyline.prototype,\n    'readProjection',\n    ol.format.Polyline.prototype.readProjection);\n\ngoog.exportProperty(\n    ol.format.Polyline.prototype,\n    'writeGeometry',\n    ol.format.Polyline.prototype.writeGeometry);\n\ngoog.exportSymbol(\n    'ol.format.TopoJSON',\n    ol.format.TopoJSON,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.TopoJSON.prototype,\n    'readFeatures',\n    ol.format.TopoJSON.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.TopoJSON.prototype,\n    'readProjection',\n    ol.format.TopoJSON.prototype.readProjection);\n\ngoog.exportSymbol(\n    'ol.format.WFS',\n    ol.format.WFS,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.WFS.prototype,\n    'readFeatures',\n    ol.format.WFS.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.WFS.prototype,\n    'readTransactionResponse',\n    ol.format.WFS.prototype.readTransactionResponse);\n\ngoog.exportProperty(\n    ol.format.WFS.prototype,\n    'readFeatureCollectionMetadata',\n    ol.format.WFS.prototype.readFeatureCollectionMetadata);\n\ngoog.exportProperty(\n    ol.format.WFS.prototype,\n    'writeGetFeature',\n    ol.format.WFS.prototype.writeGetFeature);\n\ngoog.exportProperty(\n    ol.format.WFS.prototype,\n    'writeTransaction',\n    ol.format.WFS.prototype.writeTransaction);\n\ngoog.exportProperty(\n    ol.format.WFS.prototype,\n    'readProjection',\n    ol.format.WFS.prototype.readProjection);\n\ngoog.exportSymbol(\n    'ol.format.WKT',\n    ol.format.WKT,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.WKT.prototype,\n    'readFeature',\n    ol.format.WKT.prototype.readFeature);\n\ngoog.exportProperty(\n    ol.format.WKT.prototype,\n    'readFeatures',\n    ol.format.WKT.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.WKT.prototype,\n    'readGeometry',\n    ol.format.WKT.prototype.readGeometry);\n\ngoog.exportProperty(\n    ol.format.WKT.prototype,\n    'writeFeature',\n    ol.format.WKT.prototype.writeFeature);\n\ngoog.exportProperty(\n    ol.format.WKT.prototype,\n    'writeFeatures',\n    ol.format.WKT.prototype.writeFeatures);\n\ngoog.exportProperty(\n    ol.format.WKT.prototype,\n    'writeGeometry',\n    ol.format.WKT.prototype.writeGeometry);\n\ngoog.exportSymbol(\n    'ol.format.WMSCapabilities',\n    ol.format.WMSCapabilities,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.WMSCapabilities.prototype,\n    'read',\n    ol.format.WMSCapabilities.prototype.read);\n\ngoog.exportSymbol(\n    'ol.format.WMSGetFeatureInfo',\n    ol.format.WMSGetFeatureInfo,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.WMSGetFeatureInfo.prototype,\n    'readFeatures',\n    ol.format.WMSGetFeatureInfo.prototype.readFeatures);\n\ngoog.exportSymbol(\n    'ol.format.WMTSCapabilities',\n    ol.format.WMTSCapabilities,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.format.WMTSCapabilities.prototype,\n    'read',\n    ol.format.WMTSCapabilities.prototype.read);\n\ngoog.exportSymbol(\n    'ol.format.filter.And',\n    ol.format.filter.And,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Bbox',\n    ol.format.filter.Bbox,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Comparison',\n    ol.format.filter.Comparison,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.ComparisonBinary',\n    ol.format.filter.ComparisonBinary,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.EqualTo',\n    ol.format.filter.EqualTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Filter',\n    ol.format.filter.Filter,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.GreaterThan',\n    ol.format.filter.GreaterThan,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.GreaterThanOrEqualTo',\n    ol.format.filter.GreaterThanOrEqualTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.and',\n    ol.format.filter.and,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.or',\n    ol.format.filter.or,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.not',\n    ol.format.filter.not,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.bbox',\n    ol.format.filter.bbox,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.intersects',\n    ol.format.filter.intersects,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.within',\n    ol.format.filter.within,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.equalTo',\n    ol.format.filter.equalTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.notEqualTo',\n    ol.format.filter.notEqualTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.lessThan',\n    ol.format.filter.lessThan,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.lessThanOrEqualTo',\n    ol.format.filter.lessThanOrEqualTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.greaterThan',\n    ol.format.filter.greaterThan,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.greaterThanOrEqualTo',\n    ol.format.filter.greaterThanOrEqualTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.isNull',\n    ol.format.filter.isNull,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.between',\n    ol.format.filter.between,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.like',\n    ol.format.filter.like,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Intersects',\n    ol.format.filter.Intersects,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.IsBetween',\n    ol.format.filter.IsBetween,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.IsLike',\n    ol.format.filter.IsLike,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.IsNull',\n    ol.format.filter.IsNull,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.LessThan',\n    ol.format.filter.LessThan,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.LessThanOrEqualTo',\n    ol.format.filter.LessThanOrEqualTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Not',\n    ol.format.filter.Not,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.NotEqualTo',\n    ol.format.filter.NotEqualTo,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Or',\n    ol.format.filter.Or,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Spatial',\n    ol.format.filter.Spatial,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.format.filter.Within',\n    ol.format.filter.Within,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.boundingExtent',\n    ol.extent.boundingExtent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.buffer',\n    ol.extent.buffer,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.containsCoordinate',\n    ol.extent.containsCoordinate,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.containsExtent',\n    ol.extent.containsExtent,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.containsXY',\n    ol.extent.containsXY,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.createEmpty',\n    ol.extent.createEmpty,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.equals',\n    ol.extent.equals,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.extend',\n    ol.extent.extend,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getBottomLeft',\n    ol.extent.getBottomLeft,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getBottomRight',\n    ol.extent.getBottomRight,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getCenter',\n    ol.extent.getCenter,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getHeight',\n    ol.extent.getHeight,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getIntersection',\n    ol.extent.getIntersection,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getSize',\n    ol.extent.getSize,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getTopLeft',\n    ol.extent.getTopLeft,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getTopRight',\n    ol.extent.getTopRight,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.getWidth',\n    ol.extent.getWidth,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.intersects',\n    ol.extent.intersects,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.isEmpty',\n    ol.extent.isEmpty,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.extent.applyTransform',\n    ol.extent.applyTransform,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.altKeyOnly',\n    ol.events.condition.altKeyOnly,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.altShiftKeysOnly',\n    ol.events.condition.altShiftKeysOnly,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.always',\n    ol.events.condition.always,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.click',\n    ol.events.condition.click,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.never',\n    ol.events.condition.never,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.pointerMove',\n    ol.events.condition.pointerMove,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.singleClick',\n    ol.events.condition.singleClick,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.doubleClick',\n    ol.events.condition.doubleClick,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.noModifierKeys',\n    ol.events.condition.noModifierKeys,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.platformModifierKeyOnly',\n    ol.events.condition.platformModifierKeyOnly,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.shiftKeyOnly',\n    ol.events.condition.shiftKeyOnly,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.targetNotEditable',\n    ol.events.condition.targetNotEditable,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.mouseOnly',\n    ol.events.condition.mouseOnly,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.events.condition.primaryAction',\n    ol.events.condition.primaryAction,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.events.Event.prototype,\n    'type',\n    ol.events.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.events.Event.prototype,\n    'target',\n    ol.events.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.events.Event.prototype,\n    'preventDefault',\n    ol.events.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.events.Event.prototype,\n    'stopPropagation',\n    ol.events.Event.prototype.stopPropagation);\n\ngoog.exportSymbol(\n    'ol.control.Attribution',\n    ol.control.Attribution,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.Attribution.render',\n    ol.control.Attribution.render,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'getCollapsible',\n    ol.control.Attribution.prototype.getCollapsible);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'setCollapsible',\n    ol.control.Attribution.prototype.setCollapsible);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'setCollapsed',\n    ol.control.Attribution.prototype.setCollapsed);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'getCollapsed',\n    ol.control.Attribution.prototype.getCollapsed);\n\ngoog.exportSymbol(\n    'ol.control.Control',\n    ol.control.Control,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'getMap',\n    ol.control.Control.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'setMap',\n    ol.control.Control.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'setTarget',\n    ol.control.Control.prototype.setTarget);\n\ngoog.exportSymbol(\n    'ol.control.FullScreen',\n    ol.control.FullScreen,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.defaults',\n    ol.control.defaults,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.MousePosition',\n    ol.control.MousePosition,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.MousePosition.render',\n    ol.control.MousePosition.render,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'getCoordinateFormat',\n    ol.control.MousePosition.prototype.getCoordinateFormat);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'getProjection',\n    ol.control.MousePosition.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'setCoordinateFormat',\n    ol.control.MousePosition.prototype.setCoordinateFormat);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'setProjection',\n    ol.control.MousePosition.prototype.setProjection);\n\ngoog.exportSymbol(\n    'ol.control.OverviewMap',\n    ol.control.OverviewMap,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.OverviewMap.render',\n    ol.control.OverviewMap.render,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'getCollapsible',\n    ol.control.OverviewMap.prototype.getCollapsible);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'setCollapsible',\n    ol.control.OverviewMap.prototype.setCollapsible);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'setCollapsed',\n    ol.control.OverviewMap.prototype.setCollapsed);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'getCollapsed',\n    ol.control.OverviewMap.prototype.getCollapsed);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'getOverviewMap',\n    ol.control.OverviewMap.prototype.getOverviewMap);\n\ngoog.exportSymbol(\n    'ol.control.Rotate',\n    ol.control.Rotate,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.Rotate.render',\n    ol.control.Rotate.render,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.ScaleLine',\n    ol.control.ScaleLine,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'getUnits',\n    ol.control.ScaleLine.prototype.getUnits);\n\ngoog.exportSymbol(\n    'ol.control.ScaleLine.render',\n    ol.control.ScaleLine.render,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'setUnits',\n    ol.control.ScaleLine.prototype.setUnits);\n\ngoog.exportSymbol(\n    'ol.control.Zoom',\n    ol.control.Zoom,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.ZoomSlider',\n    ol.control.ZoomSlider,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.ZoomSlider.render',\n    ol.control.ZoomSlider.render,\n    OPENLAYERS);\n\ngoog.exportSymbol(\n    'ol.control.ZoomToExtent',\n    ol.control.ZoomToExtent,\n    OPENLAYERS);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'changed',\n    ol.Object.prototype.changed);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'dispatchEvent',\n    ol.Object.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'getRevision',\n    ol.Object.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'on',\n    ol.Object.prototype.on);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'once',\n    ol.Object.prototype.once);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'un',\n    ol.Object.prototype.un);\n\ngoog.exportProperty(\n    ol.Object.prototype,\n    'unByKey',\n    ol.Object.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'get',\n    ol.Collection.prototype.get);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'getKeys',\n    ol.Collection.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'getProperties',\n    ol.Collection.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'set',\n    ol.Collection.prototype.set);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'setProperties',\n    ol.Collection.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'unset',\n    ol.Collection.prototype.unset);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'changed',\n    ol.Collection.prototype.changed);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'dispatchEvent',\n    ol.Collection.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'getRevision',\n    ol.Collection.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'on',\n    ol.Collection.prototype.on);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'once',\n    ol.Collection.prototype.once);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'un',\n    ol.Collection.prototype.un);\n\ngoog.exportProperty(\n    ol.Collection.prototype,\n    'unByKey',\n    ol.Collection.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.Collection.Event.prototype,\n    'type',\n    ol.Collection.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.Collection.Event.prototype,\n    'target',\n    ol.Collection.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.Collection.Event.prototype,\n    'preventDefault',\n    ol.Collection.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.Collection.Event.prototype,\n    'stopPropagation',\n    ol.Collection.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'get',\n    ol.DeviceOrientation.prototype.get);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getKeys',\n    ol.DeviceOrientation.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getProperties',\n    ol.DeviceOrientation.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'set',\n    ol.DeviceOrientation.prototype.set);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'setProperties',\n    ol.DeviceOrientation.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'unset',\n    ol.DeviceOrientation.prototype.unset);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'changed',\n    ol.DeviceOrientation.prototype.changed);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'dispatchEvent',\n    ol.DeviceOrientation.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'getRevision',\n    ol.DeviceOrientation.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'on',\n    ol.DeviceOrientation.prototype.on);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'once',\n    ol.DeviceOrientation.prototype.once);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'un',\n    ol.DeviceOrientation.prototype.un);\n\ngoog.exportProperty(\n    ol.DeviceOrientation.prototype,\n    'unByKey',\n    ol.DeviceOrientation.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'get',\n    ol.Feature.prototype.get);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getKeys',\n    ol.Feature.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getProperties',\n    ol.Feature.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'set',\n    ol.Feature.prototype.set);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'setProperties',\n    ol.Feature.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'unset',\n    ol.Feature.prototype.unset);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'changed',\n    ol.Feature.prototype.changed);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'dispatchEvent',\n    ol.Feature.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'getRevision',\n    ol.Feature.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'on',\n    ol.Feature.prototype.on);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'once',\n    ol.Feature.prototype.once);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'un',\n    ol.Feature.prototype.un);\n\ngoog.exportProperty(\n    ol.Feature.prototype,\n    'unByKey',\n    ol.Feature.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'get',\n    ol.Geolocation.prototype.get);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getKeys',\n    ol.Geolocation.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getProperties',\n    ol.Geolocation.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'set',\n    ol.Geolocation.prototype.set);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'setProperties',\n    ol.Geolocation.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'unset',\n    ol.Geolocation.prototype.unset);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'changed',\n    ol.Geolocation.prototype.changed);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'dispatchEvent',\n    ol.Geolocation.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'getRevision',\n    ol.Geolocation.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'on',\n    ol.Geolocation.prototype.on);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'once',\n    ol.Geolocation.prototype.once);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'un',\n    ol.Geolocation.prototype.un);\n\ngoog.exportProperty(\n    ol.Geolocation.prototype,\n    'unByKey',\n    ol.Geolocation.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.ImageTile.prototype,\n    'getTileCoord',\n    ol.ImageTile.prototype.getTileCoord);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'get',\n    ol.Map.prototype.get);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getKeys',\n    ol.Map.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getProperties',\n    ol.Map.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'set',\n    ol.Map.prototype.set);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'setProperties',\n    ol.Map.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'unset',\n    ol.Map.prototype.unset);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'changed',\n    ol.Map.prototype.changed);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'dispatchEvent',\n    ol.Map.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'getRevision',\n    ol.Map.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'on',\n    ol.Map.prototype.on);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'once',\n    ol.Map.prototype.once);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'un',\n    ol.Map.prototype.un);\n\ngoog.exportProperty(\n    ol.Map.prototype,\n    'unByKey',\n    ol.Map.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.MapEvent.prototype,\n    'type',\n    ol.MapEvent.prototype.type);\n\ngoog.exportProperty(\n    ol.MapEvent.prototype,\n    'target',\n    ol.MapEvent.prototype.target);\n\ngoog.exportProperty(\n    ol.MapEvent.prototype,\n    'preventDefault',\n    ol.MapEvent.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.MapEvent.prototype,\n    'stopPropagation',\n    ol.MapEvent.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'map',\n    ol.MapBrowserEvent.prototype.map);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'frameState',\n    ol.MapBrowserEvent.prototype.frameState);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'type',\n    ol.MapBrowserEvent.prototype.type);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'target',\n    ol.MapBrowserEvent.prototype.target);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'preventDefault',\n    ol.MapBrowserEvent.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.MapBrowserEvent.prototype,\n    'stopPropagation',\n    ol.MapBrowserEvent.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'originalEvent',\n    ol.MapBrowserPointerEvent.prototype.originalEvent);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'pixel',\n    ol.MapBrowserPointerEvent.prototype.pixel);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'coordinate',\n    ol.MapBrowserPointerEvent.prototype.coordinate);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'dragging',\n    ol.MapBrowserPointerEvent.prototype.dragging);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'preventDefault',\n    ol.MapBrowserPointerEvent.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'stopPropagation',\n    ol.MapBrowserPointerEvent.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'map',\n    ol.MapBrowserPointerEvent.prototype.map);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'frameState',\n    ol.MapBrowserPointerEvent.prototype.frameState);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'type',\n    ol.MapBrowserPointerEvent.prototype.type);\n\ngoog.exportProperty(\n    ol.MapBrowserPointerEvent.prototype,\n    'target',\n    ol.MapBrowserPointerEvent.prototype.target);\n\ngoog.exportProperty(\n    ol.Object.Event.prototype,\n    'type',\n    ol.Object.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.Object.Event.prototype,\n    'target',\n    ol.Object.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.Object.Event.prototype,\n    'preventDefault',\n    ol.Object.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.Object.Event.prototype,\n    'stopPropagation',\n    ol.Object.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'get',\n    ol.Overlay.prototype.get);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getKeys',\n    ol.Overlay.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getProperties',\n    ol.Overlay.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'set',\n    ol.Overlay.prototype.set);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'setProperties',\n    ol.Overlay.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'unset',\n    ol.Overlay.prototype.unset);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'changed',\n    ol.Overlay.prototype.changed);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'dispatchEvent',\n    ol.Overlay.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'getRevision',\n    ol.Overlay.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'on',\n    ol.Overlay.prototype.on);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'once',\n    ol.Overlay.prototype.once);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'un',\n    ol.Overlay.prototype.un);\n\ngoog.exportProperty(\n    ol.Overlay.prototype,\n    'unByKey',\n    ol.Overlay.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.VectorTile.prototype,\n    'getTileCoord',\n    ol.VectorTile.prototype.getTileCoord);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'get',\n    ol.View.prototype.get);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getKeys',\n    ol.View.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getProperties',\n    ol.View.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'set',\n    ol.View.prototype.set);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'setProperties',\n    ol.View.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'unset',\n    ol.View.prototype.unset);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'changed',\n    ol.View.prototype.changed);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'dispatchEvent',\n    ol.View.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'getRevision',\n    ol.View.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'on',\n    ol.View.prototype.on);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'once',\n    ol.View.prototype.once);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'un',\n    ol.View.prototype.un);\n\ngoog.exportProperty(\n    ol.View.prototype,\n    'unByKey',\n    ol.View.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'forEachTileCoord',\n    ol.tilegrid.WMTS.prototype.forEachTileCoord);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getMaxZoom',\n    ol.tilegrid.WMTS.prototype.getMaxZoom);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getMinZoom',\n    ol.tilegrid.WMTS.prototype.getMinZoom);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getOrigin',\n    ol.tilegrid.WMTS.prototype.getOrigin);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getResolution',\n    ol.tilegrid.WMTS.prototype.getResolution);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getResolutions',\n    ol.tilegrid.WMTS.prototype.getResolutions);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getTileCoordExtent',\n    ol.tilegrid.WMTS.prototype.getTileCoordExtent);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getTileCoordForCoordAndResolution',\n    ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndResolution);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getTileCoordForCoordAndZ',\n    ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndZ);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getTileSize',\n    ol.tilegrid.WMTS.prototype.getTileSize);\n\ngoog.exportProperty(\n    ol.tilegrid.WMTS.prototype,\n    'getZForResolution',\n    ol.tilegrid.WMTS.prototype.getZForResolution);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getOpacity',\n    ol.style.RegularShape.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getRotateWithView',\n    ol.style.RegularShape.prototype.getRotateWithView);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getRotation',\n    ol.style.RegularShape.prototype.getRotation);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getScale',\n    ol.style.RegularShape.prototype.getScale);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'getSnapToPixel',\n    ol.style.RegularShape.prototype.getSnapToPixel);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'setOpacity',\n    ol.style.RegularShape.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'setRotation',\n    ol.style.RegularShape.prototype.setRotation);\n\ngoog.exportProperty(\n    ol.style.RegularShape.prototype,\n    'setScale',\n    ol.style.RegularShape.prototype.setScale);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getAngle',\n    ol.style.Circle.prototype.getAngle);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getFill',\n    ol.style.Circle.prototype.getFill);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getPoints',\n    ol.style.Circle.prototype.getPoints);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getRadius',\n    ol.style.Circle.prototype.getRadius);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getRadius2',\n    ol.style.Circle.prototype.getRadius2);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getStroke',\n    ol.style.Circle.prototype.getStroke);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getOpacity',\n    ol.style.Circle.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getRotateWithView',\n    ol.style.Circle.prototype.getRotateWithView);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getRotation',\n    ol.style.Circle.prototype.getRotation);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getScale',\n    ol.style.Circle.prototype.getScale);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'getSnapToPixel',\n    ol.style.Circle.prototype.getSnapToPixel);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'setOpacity',\n    ol.style.Circle.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'setRotation',\n    ol.style.Circle.prototype.setRotation);\n\ngoog.exportProperty(\n    ol.style.Circle.prototype,\n    'setScale',\n    ol.style.Circle.prototype.setScale);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getOpacity',\n    ol.style.Icon.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getRotateWithView',\n    ol.style.Icon.prototype.getRotateWithView);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getRotation',\n    ol.style.Icon.prototype.getRotation);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getScale',\n    ol.style.Icon.prototype.getScale);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'getSnapToPixel',\n    ol.style.Icon.prototype.getSnapToPixel);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'setOpacity',\n    ol.style.Icon.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'setRotation',\n    ol.style.Icon.prototype.setRotation);\n\ngoog.exportProperty(\n    ol.style.Icon.prototype,\n    'setScale',\n    ol.style.Icon.prototype.setScale);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'get',\n    ol.source.Source.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'getKeys',\n    ol.source.Source.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'getProperties',\n    ol.source.Source.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'set',\n    ol.source.Source.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'setProperties',\n    ol.source.Source.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'unset',\n    ol.source.Source.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'changed',\n    ol.source.Source.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'dispatchEvent',\n    ol.source.Source.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'getRevision',\n    ol.source.Source.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'on',\n    ol.source.Source.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'once',\n    ol.source.Source.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'un',\n    ol.source.Source.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Source.prototype,\n    'unByKey',\n    ol.source.Source.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getAttributions',\n    ol.source.Tile.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getLogo',\n    ol.source.Tile.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getProjection',\n    ol.source.Tile.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getState',\n    ol.source.Tile.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'refresh',\n    ol.source.Tile.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'setAttributions',\n    ol.source.Tile.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'get',\n    ol.source.Tile.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getKeys',\n    ol.source.Tile.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getProperties',\n    ol.source.Tile.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'set',\n    ol.source.Tile.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'setProperties',\n    ol.source.Tile.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'unset',\n    ol.source.Tile.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'changed',\n    ol.source.Tile.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'dispatchEvent',\n    ol.source.Tile.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'getRevision',\n    ol.source.Tile.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'on',\n    ol.source.Tile.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'once',\n    ol.source.Tile.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'un',\n    ol.source.Tile.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Tile.prototype,\n    'unByKey',\n    ol.source.Tile.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getTileGrid',\n    ol.source.UrlTile.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'refresh',\n    ol.source.UrlTile.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getAttributions',\n    ol.source.UrlTile.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getLogo',\n    ol.source.UrlTile.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getProjection',\n    ol.source.UrlTile.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getState',\n    ol.source.UrlTile.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'setAttributions',\n    ol.source.UrlTile.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'get',\n    ol.source.UrlTile.prototype.get);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getKeys',\n    ol.source.UrlTile.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getProperties',\n    ol.source.UrlTile.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'set',\n    ol.source.UrlTile.prototype.set);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'setProperties',\n    ol.source.UrlTile.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'unset',\n    ol.source.UrlTile.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'changed',\n    ol.source.UrlTile.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'dispatchEvent',\n    ol.source.UrlTile.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'getRevision',\n    ol.source.UrlTile.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'on',\n    ol.source.UrlTile.prototype.on);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'once',\n    ol.source.UrlTile.prototype.once);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'un',\n    ol.source.UrlTile.prototype.un);\n\ngoog.exportProperty(\n    ol.source.UrlTile.prototype,\n    'unByKey',\n    ol.source.UrlTile.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getTileLoadFunction',\n    ol.source.TileImage.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getTileUrlFunction',\n    ol.source.TileImage.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getUrls',\n    ol.source.TileImage.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setTileLoadFunction',\n    ol.source.TileImage.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setTileUrlFunction',\n    ol.source.TileImage.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setUrl',\n    ol.source.TileImage.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setUrls',\n    ol.source.TileImage.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getTileGrid',\n    ol.source.TileImage.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'refresh',\n    ol.source.TileImage.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getAttributions',\n    ol.source.TileImage.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getLogo',\n    ol.source.TileImage.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getProjection',\n    ol.source.TileImage.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getState',\n    ol.source.TileImage.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setAttributions',\n    ol.source.TileImage.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'get',\n    ol.source.TileImage.prototype.get);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getKeys',\n    ol.source.TileImage.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getProperties',\n    ol.source.TileImage.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'set',\n    ol.source.TileImage.prototype.set);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'setProperties',\n    ol.source.TileImage.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'unset',\n    ol.source.TileImage.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'changed',\n    ol.source.TileImage.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'dispatchEvent',\n    ol.source.TileImage.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'getRevision',\n    ol.source.TileImage.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'on',\n    ol.source.TileImage.prototype.on);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'once',\n    ol.source.TileImage.prototype.once);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'un',\n    ol.source.TileImage.prototype.un);\n\ngoog.exportProperty(\n    ol.source.TileImage.prototype,\n    'unByKey',\n    ol.source.TileImage.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.BingMaps.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setTileGridForProjection',\n    ol.source.BingMaps.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getTileLoadFunction',\n    ol.source.BingMaps.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getTileUrlFunction',\n    ol.source.BingMaps.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getUrls',\n    ol.source.BingMaps.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setTileLoadFunction',\n    ol.source.BingMaps.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setTileUrlFunction',\n    ol.source.BingMaps.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setUrl',\n    ol.source.BingMaps.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setUrls',\n    ol.source.BingMaps.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getTileGrid',\n    ol.source.BingMaps.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'refresh',\n    ol.source.BingMaps.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getAttributions',\n    ol.source.BingMaps.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getLogo',\n    ol.source.BingMaps.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getProjection',\n    ol.source.BingMaps.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getState',\n    ol.source.BingMaps.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setAttributions',\n    ol.source.BingMaps.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'get',\n    ol.source.BingMaps.prototype.get);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getKeys',\n    ol.source.BingMaps.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getProperties',\n    ol.source.BingMaps.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'set',\n    ol.source.BingMaps.prototype.set);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'setProperties',\n    ol.source.BingMaps.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'unset',\n    ol.source.BingMaps.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'changed',\n    ol.source.BingMaps.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'dispatchEvent',\n    ol.source.BingMaps.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'getRevision',\n    ol.source.BingMaps.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'on',\n    ol.source.BingMaps.prototype.on);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'once',\n    ol.source.BingMaps.prototype.once);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'un',\n    ol.source.BingMaps.prototype.un);\n\ngoog.exportProperty(\n    ol.source.BingMaps.prototype,\n    'unByKey',\n    ol.source.BingMaps.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.XYZ.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setTileGridForProjection',\n    ol.source.XYZ.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getTileLoadFunction',\n    ol.source.XYZ.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getTileUrlFunction',\n    ol.source.XYZ.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getUrls',\n    ol.source.XYZ.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setTileLoadFunction',\n    ol.source.XYZ.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setTileUrlFunction',\n    ol.source.XYZ.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setUrl',\n    ol.source.XYZ.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setUrls',\n    ol.source.XYZ.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getTileGrid',\n    ol.source.XYZ.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'refresh',\n    ol.source.XYZ.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getAttributions',\n    ol.source.XYZ.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getLogo',\n    ol.source.XYZ.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getProjection',\n    ol.source.XYZ.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getState',\n    ol.source.XYZ.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setAttributions',\n    ol.source.XYZ.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'get',\n    ol.source.XYZ.prototype.get);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getKeys',\n    ol.source.XYZ.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getProperties',\n    ol.source.XYZ.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'set',\n    ol.source.XYZ.prototype.set);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'setProperties',\n    ol.source.XYZ.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'unset',\n    ol.source.XYZ.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'changed',\n    ol.source.XYZ.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'dispatchEvent',\n    ol.source.XYZ.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'getRevision',\n    ol.source.XYZ.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'on',\n    ol.source.XYZ.prototype.on);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'once',\n    ol.source.XYZ.prototype.once);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'un',\n    ol.source.XYZ.prototype.un);\n\ngoog.exportProperty(\n    ol.source.XYZ.prototype,\n    'unByKey',\n    ol.source.XYZ.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.CartoDB.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setTileGridForProjection',\n    ol.source.CartoDB.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getTileLoadFunction',\n    ol.source.CartoDB.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getTileUrlFunction',\n    ol.source.CartoDB.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getUrls',\n    ol.source.CartoDB.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setTileLoadFunction',\n    ol.source.CartoDB.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setTileUrlFunction',\n    ol.source.CartoDB.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setUrl',\n    ol.source.CartoDB.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setUrls',\n    ol.source.CartoDB.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getTileGrid',\n    ol.source.CartoDB.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'refresh',\n    ol.source.CartoDB.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getAttributions',\n    ol.source.CartoDB.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getLogo',\n    ol.source.CartoDB.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getProjection',\n    ol.source.CartoDB.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getState',\n    ol.source.CartoDB.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setAttributions',\n    ol.source.CartoDB.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'get',\n    ol.source.CartoDB.prototype.get);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getKeys',\n    ol.source.CartoDB.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getProperties',\n    ol.source.CartoDB.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'set',\n    ol.source.CartoDB.prototype.set);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'setProperties',\n    ol.source.CartoDB.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'unset',\n    ol.source.CartoDB.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'changed',\n    ol.source.CartoDB.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'dispatchEvent',\n    ol.source.CartoDB.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'getRevision',\n    ol.source.CartoDB.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'on',\n    ol.source.CartoDB.prototype.on);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'once',\n    ol.source.CartoDB.prototype.once);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'un',\n    ol.source.CartoDB.prototype.un);\n\ngoog.exportProperty(\n    ol.source.CartoDB.prototype,\n    'unByKey',\n    ol.source.CartoDB.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getAttributions',\n    ol.source.Vector.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getLogo',\n    ol.source.Vector.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getProjection',\n    ol.source.Vector.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getState',\n    ol.source.Vector.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'refresh',\n    ol.source.Vector.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'setAttributions',\n    ol.source.Vector.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'get',\n    ol.source.Vector.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getKeys',\n    ol.source.Vector.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getProperties',\n    ol.source.Vector.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'set',\n    ol.source.Vector.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'setProperties',\n    ol.source.Vector.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'unset',\n    ol.source.Vector.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'changed',\n    ol.source.Vector.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'dispatchEvent',\n    ol.source.Vector.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'getRevision',\n    ol.source.Vector.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'on',\n    ol.source.Vector.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'once',\n    ol.source.Vector.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'un',\n    ol.source.Vector.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Vector.prototype,\n    'unByKey',\n    ol.source.Vector.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'addFeature',\n    ol.source.Cluster.prototype.addFeature);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'addFeatures',\n    ol.source.Cluster.prototype.addFeatures);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'clear',\n    ol.source.Cluster.prototype.clear);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'forEachFeature',\n    ol.source.Cluster.prototype.forEachFeature);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'forEachFeatureInExtent',\n    ol.source.Cluster.prototype.forEachFeatureInExtent);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'forEachFeatureIntersectingExtent',\n    ol.source.Cluster.prototype.forEachFeatureIntersectingExtent);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getFeaturesCollection',\n    ol.source.Cluster.prototype.getFeaturesCollection);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getFeatures',\n    ol.source.Cluster.prototype.getFeatures);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getFeaturesAtCoordinate',\n    ol.source.Cluster.prototype.getFeaturesAtCoordinate);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getFeaturesInExtent',\n    ol.source.Cluster.prototype.getFeaturesInExtent);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getClosestFeatureToCoordinate',\n    ol.source.Cluster.prototype.getClosestFeatureToCoordinate);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getExtent',\n    ol.source.Cluster.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getFeatureById',\n    ol.source.Cluster.prototype.getFeatureById);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getFormat',\n    ol.source.Cluster.prototype.getFormat);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getUrl',\n    ol.source.Cluster.prototype.getUrl);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'removeFeature',\n    ol.source.Cluster.prototype.removeFeature);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getAttributions',\n    ol.source.Cluster.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getLogo',\n    ol.source.Cluster.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getProjection',\n    ol.source.Cluster.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getState',\n    ol.source.Cluster.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'refresh',\n    ol.source.Cluster.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'setAttributions',\n    ol.source.Cluster.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'get',\n    ol.source.Cluster.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getKeys',\n    ol.source.Cluster.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getProperties',\n    ol.source.Cluster.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'set',\n    ol.source.Cluster.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'setProperties',\n    ol.source.Cluster.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'unset',\n    ol.source.Cluster.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'changed',\n    ol.source.Cluster.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'dispatchEvent',\n    ol.source.Cluster.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'getRevision',\n    ol.source.Cluster.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'on',\n    ol.source.Cluster.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'once',\n    ol.source.Cluster.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'un',\n    ol.source.Cluster.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Cluster.prototype,\n    'unByKey',\n    ol.source.Cluster.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'getAttributions',\n    ol.source.Image.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'getLogo',\n    ol.source.Image.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'getProjection',\n    ol.source.Image.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'getState',\n    ol.source.Image.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'refresh',\n    ol.source.Image.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'setAttributions',\n    ol.source.Image.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'get',\n    ol.source.Image.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'getKeys',\n    ol.source.Image.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'getProperties',\n    ol.source.Image.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'set',\n    ol.source.Image.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'setProperties',\n    ol.source.Image.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'unset',\n    ol.source.Image.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'changed',\n    ol.source.Image.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'dispatchEvent',\n    ol.source.Image.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'getRevision',\n    ol.source.Image.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'on',\n    ol.source.Image.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'once',\n    ol.source.Image.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'un',\n    ol.source.Image.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Image.prototype,\n    'unByKey',\n    ol.source.Image.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Image.Event.prototype,\n    'type',\n    ol.source.Image.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.source.Image.Event.prototype,\n    'target',\n    ol.source.Image.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.source.Image.Event.prototype,\n    'preventDefault',\n    ol.source.Image.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.source.Image.Event.prototype,\n    'stopPropagation',\n    ol.source.Image.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getAttributions',\n    ol.source.ImageArcGISRest.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getLogo',\n    ol.source.ImageArcGISRest.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getProjection',\n    ol.source.ImageArcGISRest.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getState',\n    ol.source.ImageArcGISRest.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'refresh',\n    ol.source.ImageArcGISRest.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'setAttributions',\n    ol.source.ImageArcGISRest.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'get',\n    ol.source.ImageArcGISRest.prototype.get);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getKeys',\n    ol.source.ImageArcGISRest.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getProperties',\n    ol.source.ImageArcGISRest.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'set',\n    ol.source.ImageArcGISRest.prototype.set);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'setProperties',\n    ol.source.ImageArcGISRest.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'unset',\n    ol.source.ImageArcGISRest.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'changed',\n    ol.source.ImageArcGISRest.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'dispatchEvent',\n    ol.source.ImageArcGISRest.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'getRevision',\n    ol.source.ImageArcGISRest.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'on',\n    ol.source.ImageArcGISRest.prototype.on);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'once',\n    ol.source.ImageArcGISRest.prototype.once);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'un',\n    ol.source.ImageArcGISRest.prototype.un);\n\ngoog.exportProperty(\n    ol.source.ImageArcGISRest.prototype,\n    'unByKey',\n    ol.source.ImageArcGISRest.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'getAttributions',\n    ol.source.ImageCanvas.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'getLogo',\n    ol.source.ImageCanvas.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'getProjection',\n    ol.source.ImageCanvas.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'getState',\n    ol.source.ImageCanvas.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'refresh',\n    ol.source.ImageCanvas.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'setAttributions',\n    ol.source.ImageCanvas.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'get',\n    ol.source.ImageCanvas.prototype.get);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'getKeys',\n    ol.source.ImageCanvas.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'getProperties',\n    ol.source.ImageCanvas.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'set',\n    ol.source.ImageCanvas.prototype.set);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'setProperties',\n    ol.source.ImageCanvas.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'unset',\n    ol.source.ImageCanvas.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'changed',\n    ol.source.ImageCanvas.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'dispatchEvent',\n    ol.source.ImageCanvas.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'getRevision',\n    ol.source.ImageCanvas.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'on',\n    ol.source.ImageCanvas.prototype.on);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'once',\n    ol.source.ImageCanvas.prototype.once);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'un',\n    ol.source.ImageCanvas.prototype.un);\n\ngoog.exportProperty(\n    ol.source.ImageCanvas.prototype,\n    'unByKey',\n    ol.source.ImageCanvas.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getAttributions',\n    ol.source.ImageMapGuide.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getLogo',\n    ol.source.ImageMapGuide.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getProjection',\n    ol.source.ImageMapGuide.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getState',\n    ol.source.ImageMapGuide.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'refresh',\n    ol.source.ImageMapGuide.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'setAttributions',\n    ol.source.ImageMapGuide.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'get',\n    ol.source.ImageMapGuide.prototype.get);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getKeys',\n    ol.source.ImageMapGuide.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getProperties',\n    ol.source.ImageMapGuide.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'set',\n    ol.source.ImageMapGuide.prototype.set);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'setProperties',\n    ol.source.ImageMapGuide.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'unset',\n    ol.source.ImageMapGuide.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'changed',\n    ol.source.ImageMapGuide.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'dispatchEvent',\n    ol.source.ImageMapGuide.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'getRevision',\n    ol.source.ImageMapGuide.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'on',\n    ol.source.ImageMapGuide.prototype.on);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'once',\n    ol.source.ImageMapGuide.prototype.once);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'un',\n    ol.source.ImageMapGuide.prototype.un);\n\ngoog.exportProperty(\n    ol.source.ImageMapGuide.prototype,\n    'unByKey',\n    ol.source.ImageMapGuide.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'getAttributions',\n    ol.source.ImageStatic.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'getLogo',\n    ol.source.ImageStatic.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'getProjection',\n    ol.source.ImageStatic.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'getState',\n    ol.source.ImageStatic.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'refresh',\n    ol.source.ImageStatic.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'setAttributions',\n    ol.source.ImageStatic.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'get',\n    ol.source.ImageStatic.prototype.get);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'getKeys',\n    ol.source.ImageStatic.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'getProperties',\n    ol.source.ImageStatic.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'set',\n    ol.source.ImageStatic.prototype.set);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'setProperties',\n    ol.source.ImageStatic.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'unset',\n    ol.source.ImageStatic.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'changed',\n    ol.source.ImageStatic.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'dispatchEvent',\n    ol.source.ImageStatic.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'getRevision',\n    ol.source.ImageStatic.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'on',\n    ol.source.ImageStatic.prototype.on);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'once',\n    ol.source.ImageStatic.prototype.once);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'un',\n    ol.source.ImageStatic.prototype.un);\n\ngoog.exportProperty(\n    ol.source.ImageStatic.prototype,\n    'unByKey',\n    ol.source.ImageStatic.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getAttributions',\n    ol.source.ImageVector.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getLogo',\n    ol.source.ImageVector.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getProjection',\n    ol.source.ImageVector.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getState',\n    ol.source.ImageVector.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'refresh',\n    ol.source.ImageVector.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'setAttributions',\n    ol.source.ImageVector.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'get',\n    ol.source.ImageVector.prototype.get);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getKeys',\n    ol.source.ImageVector.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getProperties',\n    ol.source.ImageVector.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'set',\n    ol.source.ImageVector.prototype.set);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'setProperties',\n    ol.source.ImageVector.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'unset',\n    ol.source.ImageVector.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'changed',\n    ol.source.ImageVector.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'dispatchEvent',\n    ol.source.ImageVector.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'getRevision',\n    ol.source.ImageVector.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'on',\n    ol.source.ImageVector.prototype.on);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'once',\n    ol.source.ImageVector.prototype.once);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'un',\n    ol.source.ImageVector.prototype.un);\n\ngoog.exportProperty(\n    ol.source.ImageVector.prototype,\n    'unByKey',\n    ol.source.ImageVector.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getAttributions',\n    ol.source.ImageWMS.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getLogo',\n    ol.source.ImageWMS.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getProjection',\n    ol.source.ImageWMS.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getState',\n    ol.source.ImageWMS.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'refresh',\n    ol.source.ImageWMS.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'setAttributions',\n    ol.source.ImageWMS.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'get',\n    ol.source.ImageWMS.prototype.get);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getKeys',\n    ol.source.ImageWMS.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getProperties',\n    ol.source.ImageWMS.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'set',\n    ol.source.ImageWMS.prototype.set);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'setProperties',\n    ol.source.ImageWMS.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'unset',\n    ol.source.ImageWMS.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'changed',\n    ol.source.ImageWMS.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'dispatchEvent',\n    ol.source.ImageWMS.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'getRevision',\n    ol.source.ImageWMS.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'on',\n    ol.source.ImageWMS.prototype.on);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'once',\n    ol.source.ImageWMS.prototype.once);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'un',\n    ol.source.ImageWMS.prototype.un);\n\ngoog.exportProperty(\n    ol.source.ImageWMS.prototype,\n    'unByKey',\n    ol.source.ImageWMS.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.OSM.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setTileGridForProjection',\n    ol.source.OSM.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getTileLoadFunction',\n    ol.source.OSM.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getTileUrlFunction',\n    ol.source.OSM.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getUrls',\n    ol.source.OSM.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setTileLoadFunction',\n    ol.source.OSM.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setTileUrlFunction',\n    ol.source.OSM.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setUrl',\n    ol.source.OSM.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setUrls',\n    ol.source.OSM.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getTileGrid',\n    ol.source.OSM.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'refresh',\n    ol.source.OSM.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getAttributions',\n    ol.source.OSM.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getLogo',\n    ol.source.OSM.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getProjection',\n    ol.source.OSM.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getState',\n    ol.source.OSM.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setAttributions',\n    ol.source.OSM.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'get',\n    ol.source.OSM.prototype.get);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getKeys',\n    ol.source.OSM.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getProperties',\n    ol.source.OSM.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'set',\n    ol.source.OSM.prototype.set);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'setProperties',\n    ol.source.OSM.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'unset',\n    ol.source.OSM.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'changed',\n    ol.source.OSM.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'dispatchEvent',\n    ol.source.OSM.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'getRevision',\n    ol.source.OSM.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'on',\n    ol.source.OSM.prototype.on);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'once',\n    ol.source.OSM.prototype.once);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'un',\n    ol.source.OSM.prototype.un);\n\ngoog.exportProperty(\n    ol.source.OSM.prototype,\n    'unByKey',\n    ol.source.OSM.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'getAttributions',\n    ol.source.Raster.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'getLogo',\n    ol.source.Raster.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'getProjection',\n    ol.source.Raster.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'getState',\n    ol.source.Raster.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'refresh',\n    ol.source.Raster.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'setAttributions',\n    ol.source.Raster.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'get',\n    ol.source.Raster.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'getKeys',\n    ol.source.Raster.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'getProperties',\n    ol.source.Raster.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'set',\n    ol.source.Raster.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'setProperties',\n    ol.source.Raster.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'unset',\n    ol.source.Raster.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'changed',\n    ol.source.Raster.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'dispatchEvent',\n    ol.source.Raster.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'getRevision',\n    ol.source.Raster.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'on',\n    ol.source.Raster.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'once',\n    ol.source.Raster.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'un',\n    ol.source.Raster.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Raster.prototype,\n    'unByKey',\n    ol.source.Raster.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Raster.Event.prototype,\n    'type',\n    ol.source.Raster.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.source.Raster.Event.prototype,\n    'target',\n    ol.source.Raster.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.source.Raster.Event.prototype,\n    'preventDefault',\n    ol.source.Raster.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.source.Raster.Event.prototype,\n    'stopPropagation',\n    ol.source.Raster.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.Stamen.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setTileGridForProjection',\n    ol.source.Stamen.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getTileLoadFunction',\n    ol.source.Stamen.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getTileUrlFunction',\n    ol.source.Stamen.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getUrls',\n    ol.source.Stamen.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setTileLoadFunction',\n    ol.source.Stamen.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setTileUrlFunction',\n    ol.source.Stamen.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setUrl',\n    ol.source.Stamen.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setUrls',\n    ol.source.Stamen.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getTileGrid',\n    ol.source.Stamen.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'refresh',\n    ol.source.Stamen.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getAttributions',\n    ol.source.Stamen.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getLogo',\n    ol.source.Stamen.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getProjection',\n    ol.source.Stamen.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getState',\n    ol.source.Stamen.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setAttributions',\n    ol.source.Stamen.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'get',\n    ol.source.Stamen.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getKeys',\n    ol.source.Stamen.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getProperties',\n    ol.source.Stamen.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'set',\n    ol.source.Stamen.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'setProperties',\n    ol.source.Stamen.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'unset',\n    ol.source.Stamen.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'changed',\n    ol.source.Stamen.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'dispatchEvent',\n    ol.source.Stamen.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'getRevision',\n    ol.source.Stamen.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'on',\n    ol.source.Stamen.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'once',\n    ol.source.Stamen.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'un',\n    ol.source.Stamen.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Stamen.prototype,\n    'unByKey',\n    ol.source.Stamen.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Tile.Event.prototype,\n    'type',\n    ol.source.Tile.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.source.Tile.Event.prototype,\n    'target',\n    ol.source.Tile.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.source.Tile.Event.prototype,\n    'preventDefault',\n    ol.source.Tile.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.source.Tile.Event.prototype,\n    'stopPropagation',\n    ol.source.Tile.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.TileArcGISRest.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setTileGridForProjection',\n    ol.source.TileArcGISRest.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getTileLoadFunction',\n    ol.source.TileArcGISRest.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getTileUrlFunction',\n    ol.source.TileArcGISRest.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getUrls',\n    ol.source.TileArcGISRest.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setTileLoadFunction',\n    ol.source.TileArcGISRest.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setTileUrlFunction',\n    ol.source.TileArcGISRest.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setUrl',\n    ol.source.TileArcGISRest.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setUrls',\n    ol.source.TileArcGISRest.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getTileGrid',\n    ol.source.TileArcGISRest.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'refresh',\n    ol.source.TileArcGISRest.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getAttributions',\n    ol.source.TileArcGISRest.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getLogo',\n    ol.source.TileArcGISRest.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getProjection',\n    ol.source.TileArcGISRest.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getState',\n    ol.source.TileArcGISRest.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setAttributions',\n    ol.source.TileArcGISRest.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'get',\n    ol.source.TileArcGISRest.prototype.get);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getKeys',\n    ol.source.TileArcGISRest.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getProperties',\n    ol.source.TileArcGISRest.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'set',\n    ol.source.TileArcGISRest.prototype.set);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'setProperties',\n    ol.source.TileArcGISRest.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'unset',\n    ol.source.TileArcGISRest.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'changed',\n    ol.source.TileArcGISRest.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'dispatchEvent',\n    ol.source.TileArcGISRest.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'getRevision',\n    ol.source.TileArcGISRest.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'on',\n    ol.source.TileArcGISRest.prototype.on);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'once',\n    ol.source.TileArcGISRest.prototype.once);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'un',\n    ol.source.TileArcGISRest.prototype.un);\n\ngoog.exportProperty(\n    ol.source.TileArcGISRest.prototype,\n    'unByKey',\n    ol.source.TileArcGISRest.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getTileGrid',\n    ol.source.TileDebug.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'refresh',\n    ol.source.TileDebug.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getAttributions',\n    ol.source.TileDebug.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getLogo',\n    ol.source.TileDebug.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getProjection',\n    ol.source.TileDebug.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getState',\n    ol.source.TileDebug.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'setAttributions',\n    ol.source.TileDebug.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'get',\n    ol.source.TileDebug.prototype.get);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getKeys',\n    ol.source.TileDebug.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getProperties',\n    ol.source.TileDebug.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'set',\n    ol.source.TileDebug.prototype.set);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'setProperties',\n    ol.source.TileDebug.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'unset',\n    ol.source.TileDebug.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'changed',\n    ol.source.TileDebug.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'dispatchEvent',\n    ol.source.TileDebug.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'getRevision',\n    ol.source.TileDebug.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'on',\n    ol.source.TileDebug.prototype.on);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'once',\n    ol.source.TileDebug.prototype.once);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'un',\n    ol.source.TileDebug.prototype.un);\n\ngoog.exportProperty(\n    ol.source.TileDebug.prototype,\n    'unByKey',\n    ol.source.TileDebug.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.TileJSON.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setTileGridForProjection',\n    ol.source.TileJSON.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getTileLoadFunction',\n    ol.source.TileJSON.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getTileUrlFunction',\n    ol.source.TileJSON.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getUrls',\n    ol.source.TileJSON.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setTileLoadFunction',\n    ol.source.TileJSON.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setTileUrlFunction',\n    ol.source.TileJSON.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setUrl',\n    ol.source.TileJSON.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setUrls',\n    ol.source.TileJSON.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getTileGrid',\n    ol.source.TileJSON.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'refresh',\n    ol.source.TileJSON.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getAttributions',\n    ol.source.TileJSON.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getLogo',\n    ol.source.TileJSON.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getProjection',\n    ol.source.TileJSON.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getState',\n    ol.source.TileJSON.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setAttributions',\n    ol.source.TileJSON.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'get',\n    ol.source.TileJSON.prototype.get);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getKeys',\n    ol.source.TileJSON.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getProperties',\n    ol.source.TileJSON.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'set',\n    ol.source.TileJSON.prototype.set);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'setProperties',\n    ol.source.TileJSON.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'unset',\n    ol.source.TileJSON.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'changed',\n    ol.source.TileJSON.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'dispatchEvent',\n    ol.source.TileJSON.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'getRevision',\n    ol.source.TileJSON.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'on',\n    ol.source.TileJSON.prototype.on);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'once',\n    ol.source.TileJSON.prototype.once);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'un',\n    ol.source.TileJSON.prototype.un);\n\ngoog.exportProperty(\n    ol.source.TileJSON.prototype,\n    'unByKey',\n    ol.source.TileJSON.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getTileGrid',\n    ol.source.TileUTFGrid.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'refresh',\n    ol.source.TileUTFGrid.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getAttributions',\n    ol.source.TileUTFGrid.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getLogo',\n    ol.source.TileUTFGrid.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getProjection',\n    ol.source.TileUTFGrid.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getState',\n    ol.source.TileUTFGrid.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'setAttributions',\n    ol.source.TileUTFGrid.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'get',\n    ol.source.TileUTFGrid.prototype.get);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getKeys',\n    ol.source.TileUTFGrid.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getProperties',\n    ol.source.TileUTFGrid.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'set',\n    ol.source.TileUTFGrid.prototype.set);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'setProperties',\n    ol.source.TileUTFGrid.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'unset',\n    ol.source.TileUTFGrid.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'changed',\n    ol.source.TileUTFGrid.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'dispatchEvent',\n    ol.source.TileUTFGrid.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'getRevision',\n    ol.source.TileUTFGrid.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'on',\n    ol.source.TileUTFGrid.prototype.on);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'once',\n    ol.source.TileUTFGrid.prototype.once);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'un',\n    ol.source.TileUTFGrid.prototype.un);\n\ngoog.exportProperty(\n    ol.source.TileUTFGrid.prototype,\n    'unByKey',\n    ol.source.TileUTFGrid.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.TileWMS.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setTileGridForProjection',\n    ol.source.TileWMS.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getTileLoadFunction',\n    ol.source.TileWMS.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getTileUrlFunction',\n    ol.source.TileWMS.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getUrls',\n    ol.source.TileWMS.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setTileLoadFunction',\n    ol.source.TileWMS.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setTileUrlFunction',\n    ol.source.TileWMS.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setUrl',\n    ol.source.TileWMS.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setUrls',\n    ol.source.TileWMS.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getTileGrid',\n    ol.source.TileWMS.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'refresh',\n    ol.source.TileWMS.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getAttributions',\n    ol.source.TileWMS.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getLogo',\n    ol.source.TileWMS.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getProjection',\n    ol.source.TileWMS.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getState',\n    ol.source.TileWMS.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setAttributions',\n    ol.source.TileWMS.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'get',\n    ol.source.TileWMS.prototype.get);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getKeys',\n    ol.source.TileWMS.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getProperties',\n    ol.source.TileWMS.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'set',\n    ol.source.TileWMS.prototype.set);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'setProperties',\n    ol.source.TileWMS.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'unset',\n    ol.source.TileWMS.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'changed',\n    ol.source.TileWMS.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'dispatchEvent',\n    ol.source.TileWMS.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'getRevision',\n    ol.source.TileWMS.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'on',\n    ol.source.TileWMS.prototype.on);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'once',\n    ol.source.TileWMS.prototype.once);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'un',\n    ol.source.TileWMS.prototype.un);\n\ngoog.exportProperty(\n    ol.source.TileWMS.prototype,\n    'unByKey',\n    ol.source.TileWMS.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Vector.Event.prototype,\n    'type',\n    ol.source.Vector.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.source.Vector.Event.prototype,\n    'target',\n    ol.source.Vector.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.source.Vector.Event.prototype,\n    'preventDefault',\n    ol.source.Vector.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.source.Vector.Event.prototype,\n    'stopPropagation',\n    ol.source.Vector.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getTileLoadFunction',\n    ol.source.VectorTile.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getTileUrlFunction',\n    ol.source.VectorTile.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getUrls',\n    ol.source.VectorTile.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'setTileLoadFunction',\n    ol.source.VectorTile.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'setTileUrlFunction',\n    ol.source.VectorTile.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'setUrl',\n    ol.source.VectorTile.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'setUrls',\n    ol.source.VectorTile.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getTileGrid',\n    ol.source.VectorTile.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'refresh',\n    ol.source.VectorTile.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getAttributions',\n    ol.source.VectorTile.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getLogo',\n    ol.source.VectorTile.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getProjection',\n    ol.source.VectorTile.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getState',\n    ol.source.VectorTile.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'setAttributions',\n    ol.source.VectorTile.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'get',\n    ol.source.VectorTile.prototype.get);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getKeys',\n    ol.source.VectorTile.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getProperties',\n    ol.source.VectorTile.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'set',\n    ol.source.VectorTile.prototype.set);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'setProperties',\n    ol.source.VectorTile.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'unset',\n    ol.source.VectorTile.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'changed',\n    ol.source.VectorTile.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'dispatchEvent',\n    ol.source.VectorTile.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'getRevision',\n    ol.source.VectorTile.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'on',\n    ol.source.VectorTile.prototype.on);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'once',\n    ol.source.VectorTile.prototype.once);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'un',\n    ol.source.VectorTile.prototype.un);\n\ngoog.exportProperty(\n    ol.source.VectorTile.prototype,\n    'unByKey',\n    ol.source.VectorTile.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.WMTS.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setTileGridForProjection',\n    ol.source.WMTS.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getTileLoadFunction',\n    ol.source.WMTS.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getTileUrlFunction',\n    ol.source.WMTS.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getUrls',\n    ol.source.WMTS.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setTileLoadFunction',\n    ol.source.WMTS.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setTileUrlFunction',\n    ol.source.WMTS.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setUrl',\n    ol.source.WMTS.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setUrls',\n    ol.source.WMTS.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getTileGrid',\n    ol.source.WMTS.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'refresh',\n    ol.source.WMTS.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getAttributions',\n    ol.source.WMTS.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getLogo',\n    ol.source.WMTS.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getProjection',\n    ol.source.WMTS.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getState',\n    ol.source.WMTS.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setAttributions',\n    ol.source.WMTS.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'get',\n    ol.source.WMTS.prototype.get);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getKeys',\n    ol.source.WMTS.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getProperties',\n    ol.source.WMTS.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'set',\n    ol.source.WMTS.prototype.set);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'setProperties',\n    ol.source.WMTS.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'unset',\n    ol.source.WMTS.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'changed',\n    ol.source.WMTS.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'dispatchEvent',\n    ol.source.WMTS.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'getRevision',\n    ol.source.WMTS.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'on',\n    ol.source.WMTS.prototype.on);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'once',\n    ol.source.WMTS.prototype.once);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'un',\n    ol.source.WMTS.prototype.un);\n\ngoog.exportProperty(\n    ol.source.WMTS.prototype,\n    'unByKey',\n    ol.source.WMTS.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setRenderReprojectionEdges',\n    ol.source.Zoomify.prototype.setRenderReprojectionEdges);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setTileGridForProjection',\n    ol.source.Zoomify.prototype.setTileGridForProjection);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getTileLoadFunction',\n    ol.source.Zoomify.prototype.getTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getTileUrlFunction',\n    ol.source.Zoomify.prototype.getTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getUrls',\n    ol.source.Zoomify.prototype.getUrls);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setTileLoadFunction',\n    ol.source.Zoomify.prototype.setTileLoadFunction);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setTileUrlFunction',\n    ol.source.Zoomify.prototype.setTileUrlFunction);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setUrl',\n    ol.source.Zoomify.prototype.setUrl);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setUrls',\n    ol.source.Zoomify.prototype.setUrls);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getTileGrid',\n    ol.source.Zoomify.prototype.getTileGrid);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'refresh',\n    ol.source.Zoomify.prototype.refresh);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getAttributions',\n    ol.source.Zoomify.prototype.getAttributions);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getLogo',\n    ol.source.Zoomify.prototype.getLogo);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getProjection',\n    ol.source.Zoomify.prototype.getProjection);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getState',\n    ol.source.Zoomify.prototype.getState);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setAttributions',\n    ol.source.Zoomify.prototype.setAttributions);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'get',\n    ol.source.Zoomify.prototype.get);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getKeys',\n    ol.source.Zoomify.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getProperties',\n    ol.source.Zoomify.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'set',\n    ol.source.Zoomify.prototype.set);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'setProperties',\n    ol.source.Zoomify.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'unset',\n    ol.source.Zoomify.prototype.unset);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'changed',\n    ol.source.Zoomify.prototype.changed);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'dispatchEvent',\n    ol.source.Zoomify.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'getRevision',\n    ol.source.Zoomify.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'on',\n    ol.source.Zoomify.prototype.on);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'once',\n    ol.source.Zoomify.prototype.once);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'un',\n    ol.source.Zoomify.prototype.un);\n\ngoog.exportProperty(\n    ol.source.Zoomify.prototype,\n    'unByKey',\n    ol.source.Zoomify.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.reproj.Tile.prototype,\n    'getTileCoord',\n    ol.reproj.Tile.prototype.getTileCoord);\n\ngoog.exportProperty(\n    ol.reproj.Tile.prototype,\n    'load',\n    ol.reproj.Tile.prototype.load);\n\ngoog.exportProperty(\n    ol.renderer.Layer.prototype,\n    'changed',\n    ol.renderer.Layer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.Layer.prototype,\n    'dispatchEvent',\n    ol.renderer.Layer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.Layer.prototype,\n    'getRevision',\n    ol.renderer.Layer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.Layer.prototype,\n    'on',\n    ol.renderer.Layer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.Layer.prototype,\n    'once',\n    ol.renderer.Layer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.Layer.prototype,\n    'un',\n    ol.renderer.Layer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.Layer.prototype,\n    'unByKey',\n    ol.renderer.Layer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.webgl.Layer.prototype,\n    'changed',\n    ol.renderer.webgl.Layer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.webgl.Layer.prototype,\n    'dispatchEvent',\n    ol.renderer.webgl.Layer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.webgl.Layer.prototype,\n    'getRevision',\n    ol.renderer.webgl.Layer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.webgl.Layer.prototype,\n    'on',\n    ol.renderer.webgl.Layer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.webgl.Layer.prototype,\n    'once',\n    ol.renderer.webgl.Layer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.webgl.Layer.prototype,\n    'un',\n    ol.renderer.webgl.Layer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.webgl.Layer.prototype,\n    'unByKey',\n    ol.renderer.webgl.Layer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.webgl.ImageLayer.prototype,\n    'changed',\n    ol.renderer.webgl.ImageLayer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.webgl.ImageLayer.prototype,\n    'dispatchEvent',\n    ol.renderer.webgl.ImageLayer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.webgl.ImageLayer.prototype,\n    'getRevision',\n    ol.renderer.webgl.ImageLayer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.webgl.ImageLayer.prototype,\n    'on',\n    ol.renderer.webgl.ImageLayer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.webgl.ImageLayer.prototype,\n    'once',\n    ol.renderer.webgl.ImageLayer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.webgl.ImageLayer.prototype,\n    'un',\n    ol.renderer.webgl.ImageLayer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.webgl.ImageLayer.prototype,\n    'unByKey',\n    ol.renderer.webgl.ImageLayer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.webgl.TileLayer.prototype,\n    'changed',\n    ol.renderer.webgl.TileLayer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.webgl.TileLayer.prototype,\n    'dispatchEvent',\n    ol.renderer.webgl.TileLayer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.webgl.TileLayer.prototype,\n    'getRevision',\n    ol.renderer.webgl.TileLayer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.webgl.TileLayer.prototype,\n    'on',\n    ol.renderer.webgl.TileLayer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.webgl.TileLayer.prototype,\n    'once',\n    ol.renderer.webgl.TileLayer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.webgl.TileLayer.prototype,\n    'un',\n    ol.renderer.webgl.TileLayer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.webgl.TileLayer.prototype,\n    'unByKey',\n    ol.renderer.webgl.TileLayer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.webgl.VectorLayer.prototype,\n    'changed',\n    ol.renderer.webgl.VectorLayer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.webgl.VectorLayer.prototype,\n    'dispatchEvent',\n    ol.renderer.webgl.VectorLayer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.webgl.VectorLayer.prototype,\n    'getRevision',\n    ol.renderer.webgl.VectorLayer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.webgl.VectorLayer.prototype,\n    'on',\n    ol.renderer.webgl.VectorLayer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.webgl.VectorLayer.prototype,\n    'once',\n    ol.renderer.webgl.VectorLayer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.webgl.VectorLayer.prototype,\n    'un',\n    ol.renderer.webgl.VectorLayer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.webgl.VectorLayer.prototype,\n    'unByKey',\n    ol.renderer.webgl.VectorLayer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.canvas.Layer.prototype,\n    'changed',\n    ol.renderer.canvas.Layer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.canvas.Layer.prototype,\n    'dispatchEvent',\n    ol.renderer.canvas.Layer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.canvas.Layer.prototype,\n    'getRevision',\n    ol.renderer.canvas.Layer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.canvas.Layer.prototype,\n    'on',\n    ol.renderer.canvas.Layer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.canvas.Layer.prototype,\n    'once',\n    ol.renderer.canvas.Layer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.canvas.Layer.prototype,\n    'un',\n    ol.renderer.canvas.Layer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.canvas.Layer.prototype,\n    'unByKey',\n    ol.renderer.canvas.Layer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.canvas.IntermediateCanvas.prototype,\n    'changed',\n    ol.renderer.canvas.IntermediateCanvas.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.canvas.IntermediateCanvas.prototype,\n    'dispatchEvent',\n    ol.renderer.canvas.IntermediateCanvas.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.canvas.IntermediateCanvas.prototype,\n    'getRevision',\n    ol.renderer.canvas.IntermediateCanvas.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.canvas.IntermediateCanvas.prototype,\n    'on',\n    ol.renderer.canvas.IntermediateCanvas.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.canvas.IntermediateCanvas.prototype,\n    'once',\n    ol.renderer.canvas.IntermediateCanvas.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.canvas.IntermediateCanvas.prototype,\n    'un',\n    ol.renderer.canvas.IntermediateCanvas.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.canvas.IntermediateCanvas.prototype,\n    'unByKey',\n    ol.renderer.canvas.IntermediateCanvas.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.canvas.ImageLayer.prototype,\n    'changed',\n    ol.renderer.canvas.ImageLayer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.canvas.ImageLayer.prototype,\n    'dispatchEvent',\n    ol.renderer.canvas.ImageLayer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.canvas.ImageLayer.prototype,\n    'getRevision',\n    ol.renderer.canvas.ImageLayer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.canvas.ImageLayer.prototype,\n    'on',\n    ol.renderer.canvas.ImageLayer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.canvas.ImageLayer.prototype,\n    'once',\n    ol.renderer.canvas.ImageLayer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.canvas.ImageLayer.prototype,\n    'un',\n    ol.renderer.canvas.ImageLayer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.canvas.ImageLayer.prototype,\n    'unByKey',\n    ol.renderer.canvas.ImageLayer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.canvas.TileLayer.prototype,\n    'changed',\n    ol.renderer.canvas.TileLayer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.canvas.TileLayer.prototype,\n    'dispatchEvent',\n    ol.renderer.canvas.TileLayer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.canvas.TileLayer.prototype,\n    'getRevision',\n    ol.renderer.canvas.TileLayer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.canvas.TileLayer.prototype,\n    'on',\n    ol.renderer.canvas.TileLayer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.canvas.TileLayer.prototype,\n    'once',\n    ol.renderer.canvas.TileLayer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.canvas.TileLayer.prototype,\n    'un',\n    ol.renderer.canvas.TileLayer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.canvas.TileLayer.prototype,\n    'unByKey',\n    ol.renderer.canvas.TileLayer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorLayer.prototype,\n    'changed',\n    ol.renderer.canvas.VectorLayer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorLayer.prototype,\n    'dispatchEvent',\n    ol.renderer.canvas.VectorLayer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorLayer.prototype,\n    'getRevision',\n    ol.renderer.canvas.VectorLayer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorLayer.prototype,\n    'on',\n    ol.renderer.canvas.VectorLayer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorLayer.prototype,\n    'once',\n    ol.renderer.canvas.VectorLayer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorLayer.prototype,\n    'un',\n    ol.renderer.canvas.VectorLayer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorLayer.prototype,\n    'unByKey',\n    ol.renderer.canvas.VectorLayer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorTileLayer.prototype,\n    'changed',\n    ol.renderer.canvas.VectorTileLayer.prototype.changed);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorTileLayer.prototype,\n    'dispatchEvent',\n    ol.renderer.canvas.VectorTileLayer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorTileLayer.prototype,\n    'getRevision',\n    ol.renderer.canvas.VectorTileLayer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorTileLayer.prototype,\n    'on',\n    ol.renderer.canvas.VectorTileLayer.prototype.on);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorTileLayer.prototype,\n    'once',\n    ol.renderer.canvas.VectorTileLayer.prototype.once);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorTileLayer.prototype,\n    'un',\n    ol.renderer.canvas.VectorTileLayer.prototype.un);\n\ngoog.exportProperty(\n    ol.renderer.canvas.VectorTileLayer.prototype,\n    'unByKey',\n    ol.renderer.canvas.VectorTileLayer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'type',\n    ol.render.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'target',\n    ol.render.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'preventDefault',\n    ol.render.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.render.Event.prototype,\n    'stopPropagation',\n    ol.render.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.pointer.PointerEvent.prototype,\n    'type',\n    ol.pointer.PointerEvent.prototype.type);\n\ngoog.exportProperty(\n    ol.pointer.PointerEvent.prototype,\n    'target',\n    ol.pointer.PointerEvent.prototype.target);\n\ngoog.exportProperty(\n    ol.pointer.PointerEvent.prototype,\n    'preventDefault',\n    ol.pointer.PointerEvent.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.pointer.PointerEvent.prototype,\n    'stopPropagation',\n    ol.pointer.PointerEvent.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'get',\n    ol.layer.Base.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getKeys',\n    ol.layer.Base.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getProperties',\n    ol.layer.Base.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'set',\n    ol.layer.Base.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'setProperties',\n    ol.layer.Base.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'unset',\n    ol.layer.Base.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'changed',\n    ol.layer.Base.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'dispatchEvent',\n    ol.layer.Base.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'getRevision',\n    ol.layer.Base.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'on',\n    ol.layer.Base.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'once',\n    ol.layer.Base.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'un',\n    ol.layer.Base.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.Base.prototype,\n    'unByKey',\n    ol.layer.Base.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getExtent',\n    ol.layer.Group.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getMaxResolution',\n    ol.layer.Group.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getMinResolution',\n    ol.layer.Group.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getOpacity',\n    ol.layer.Group.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getVisible',\n    ol.layer.Group.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getZIndex',\n    ol.layer.Group.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setExtent',\n    ol.layer.Group.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setMaxResolution',\n    ol.layer.Group.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setMinResolution',\n    ol.layer.Group.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setOpacity',\n    ol.layer.Group.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setVisible',\n    ol.layer.Group.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setZIndex',\n    ol.layer.Group.prototype.setZIndex);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'get',\n    ol.layer.Group.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getKeys',\n    ol.layer.Group.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getProperties',\n    ol.layer.Group.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'set',\n    ol.layer.Group.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'setProperties',\n    ol.layer.Group.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'unset',\n    ol.layer.Group.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'changed',\n    ol.layer.Group.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'dispatchEvent',\n    ol.layer.Group.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'getRevision',\n    ol.layer.Group.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'on',\n    ol.layer.Group.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'once',\n    ol.layer.Group.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'un',\n    ol.layer.Group.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.Group.prototype,\n    'unByKey',\n    ol.layer.Group.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getExtent',\n    ol.layer.Layer.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getMaxResolution',\n    ol.layer.Layer.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getMinResolution',\n    ol.layer.Layer.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getOpacity',\n    ol.layer.Layer.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getVisible',\n    ol.layer.Layer.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getZIndex',\n    ol.layer.Layer.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setExtent',\n    ol.layer.Layer.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setMaxResolution',\n    ol.layer.Layer.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setMinResolution',\n    ol.layer.Layer.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setOpacity',\n    ol.layer.Layer.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setVisible',\n    ol.layer.Layer.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setZIndex',\n    ol.layer.Layer.prototype.setZIndex);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'get',\n    ol.layer.Layer.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getKeys',\n    ol.layer.Layer.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getProperties',\n    ol.layer.Layer.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'set',\n    ol.layer.Layer.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'setProperties',\n    ol.layer.Layer.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'unset',\n    ol.layer.Layer.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'changed',\n    ol.layer.Layer.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'dispatchEvent',\n    ol.layer.Layer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'getRevision',\n    ol.layer.Layer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'on',\n    ol.layer.Layer.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'once',\n    ol.layer.Layer.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'un',\n    ol.layer.Layer.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.Layer.prototype,\n    'unByKey',\n    ol.layer.Layer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setMap',\n    ol.layer.Vector.prototype.setMap);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setSource',\n    ol.layer.Vector.prototype.setSource);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getExtent',\n    ol.layer.Vector.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getMaxResolution',\n    ol.layer.Vector.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getMinResolution',\n    ol.layer.Vector.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getOpacity',\n    ol.layer.Vector.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getVisible',\n    ol.layer.Vector.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getZIndex',\n    ol.layer.Vector.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setExtent',\n    ol.layer.Vector.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setMaxResolution',\n    ol.layer.Vector.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setMinResolution',\n    ol.layer.Vector.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setOpacity',\n    ol.layer.Vector.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setVisible',\n    ol.layer.Vector.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setZIndex',\n    ol.layer.Vector.prototype.setZIndex);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'get',\n    ol.layer.Vector.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getKeys',\n    ol.layer.Vector.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getProperties',\n    ol.layer.Vector.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'set',\n    ol.layer.Vector.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'setProperties',\n    ol.layer.Vector.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'unset',\n    ol.layer.Vector.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'changed',\n    ol.layer.Vector.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'dispatchEvent',\n    ol.layer.Vector.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'getRevision',\n    ol.layer.Vector.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'on',\n    ol.layer.Vector.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'once',\n    ol.layer.Vector.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'un',\n    ol.layer.Vector.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.Vector.prototype,\n    'unByKey',\n    ol.layer.Vector.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getSource',\n    ol.layer.Heatmap.prototype.getSource);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getStyle',\n    ol.layer.Heatmap.prototype.getStyle);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getStyleFunction',\n    ol.layer.Heatmap.prototype.getStyleFunction);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setStyle',\n    ol.layer.Heatmap.prototype.setStyle);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setMap',\n    ol.layer.Heatmap.prototype.setMap);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setSource',\n    ol.layer.Heatmap.prototype.setSource);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getExtent',\n    ol.layer.Heatmap.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getMaxResolution',\n    ol.layer.Heatmap.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getMinResolution',\n    ol.layer.Heatmap.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getOpacity',\n    ol.layer.Heatmap.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getVisible',\n    ol.layer.Heatmap.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getZIndex',\n    ol.layer.Heatmap.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setExtent',\n    ol.layer.Heatmap.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setMaxResolution',\n    ol.layer.Heatmap.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setMinResolution',\n    ol.layer.Heatmap.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setOpacity',\n    ol.layer.Heatmap.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setVisible',\n    ol.layer.Heatmap.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setZIndex',\n    ol.layer.Heatmap.prototype.setZIndex);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'get',\n    ol.layer.Heatmap.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getKeys',\n    ol.layer.Heatmap.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getProperties',\n    ol.layer.Heatmap.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'set',\n    ol.layer.Heatmap.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'setProperties',\n    ol.layer.Heatmap.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'unset',\n    ol.layer.Heatmap.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'changed',\n    ol.layer.Heatmap.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'dispatchEvent',\n    ol.layer.Heatmap.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'getRevision',\n    ol.layer.Heatmap.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'on',\n    ol.layer.Heatmap.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'once',\n    ol.layer.Heatmap.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'un',\n    ol.layer.Heatmap.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.Heatmap.prototype,\n    'unByKey',\n    ol.layer.Heatmap.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setMap',\n    ol.layer.Image.prototype.setMap);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setSource',\n    ol.layer.Image.prototype.setSource);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getExtent',\n    ol.layer.Image.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getMaxResolution',\n    ol.layer.Image.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getMinResolution',\n    ol.layer.Image.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getOpacity',\n    ol.layer.Image.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getVisible',\n    ol.layer.Image.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getZIndex',\n    ol.layer.Image.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setExtent',\n    ol.layer.Image.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setMaxResolution',\n    ol.layer.Image.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setMinResolution',\n    ol.layer.Image.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setOpacity',\n    ol.layer.Image.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setVisible',\n    ol.layer.Image.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setZIndex',\n    ol.layer.Image.prototype.setZIndex);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'get',\n    ol.layer.Image.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getKeys',\n    ol.layer.Image.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getProperties',\n    ol.layer.Image.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'set',\n    ol.layer.Image.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'setProperties',\n    ol.layer.Image.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'unset',\n    ol.layer.Image.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'changed',\n    ol.layer.Image.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'dispatchEvent',\n    ol.layer.Image.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'getRevision',\n    ol.layer.Image.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'on',\n    ol.layer.Image.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'once',\n    ol.layer.Image.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'un',\n    ol.layer.Image.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.Image.prototype,\n    'unByKey',\n    ol.layer.Image.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setMap',\n    ol.layer.Tile.prototype.setMap);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setSource',\n    ol.layer.Tile.prototype.setSource);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getExtent',\n    ol.layer.Tile.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getMaxResolution',\n    ol.layer.Tile.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getMinResolution',\n    ol.layer.Tile.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getOpacity',\n    ol.layer.Tile.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getVisible',\n    ol.layer.Tile.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getZIndex',\n    ol.layer.Tile.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setExtent',\n    ol.layer.Tile.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setMaxResolution',\n    ol.layer.Tile.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setMinResolution',\n    ol.layer.Tile.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setOpacity',\n    ol.layer.Tile.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setVisible',\n    ol.layer.Tile.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setZIndex',\n    ol.layer.Tile.prototype.setZIndex);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'get',\n    ol.layer.Tile.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getKeys',\n    ol.layer.Tile.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getProperties',\n    ol.layer.Tile.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'set',\n    ol.layer.Tile.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'setProperties',\n    ol.layer.Tile.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'unset',\n    ol.layer.Tile.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'changed',\n    ol.layer.Tile.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'dispatchEvent',\n    ol.layer.Tile.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'getRevision',\n    ol.layer.Tile.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'on',\n    ol.layer.Tile.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'once',\n    ol.layer.Tile.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'un',\n    ol.layer.Tile.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.Tile.prototype,\n    'unByKey',\n    ol.layer.Tile.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getSource',\n    ol.layer.VectorTile.prototype.getSource);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getStyle',\n    ol.layer.VectorTile.prototype.getStyle);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getStyleFunction',\n    ol.layer.VectorTile.prototype.getStyleFunction);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setStyle',\n    ol.layer.VectorTile.prototype.setStyle);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setMap',\n    ol.layer.VectorTile.prototype.setMap);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setSource',\n    ol.layer.VectorTile.prototype.setSource);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getExtent',\n    ol.layer.VectorTile.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getMaxResolution',\n    ol.layer.VectorTile.prototype.getMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getMinResolution',\n    ol.layer.VectorTile.prototype.getMinResolution);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getOpacity',\n    ol.layer.VectorTile.prototype.getOpacity);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getVisible',\n    ol.layer.VectorTile.prototype.getVisible);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getZIndex',\n    ol.layer.VectorTile.prototype.getZIndex);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setExtent',\n    ol.layer.VectorTile.prototype.setExtent);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setMaxResolution',\n    ol.layer.VectorTile.prototype.setMaxResolution);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setMinResolution',\n    ol.layer.VectorTile.prototype.setMinResolution);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setOpacity',\n    ol.layer.VectorTile.prototype.setOpacity);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setVisible',\n    ol.layer.VectorTile.prototype.setVisible);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setZIndex',\n    ol.layer.VectorTile.prototype.setZIndex);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'get',\n    ol.layer.VectorTile.prototype.get);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getKeys',\n    ol.layer.VectorTile.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getProperties',\n    ol.layer.VectorTile.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'set',\n    ol.layer.VectorTile.prototype.set);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'setProperties',\n    ol.layer.VectorTile.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'unset',\n    ol.layer.VectorTile.prototype.unset);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'changed',\n    ol.layer.VectorTile.prototype.changed);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'dispatchEvent',\n    ol.layer.VectorTile.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'getRevision',\n    ol.layer.VectorTile.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'on',\n    ol.layer.VectorTile.prototype.on);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'once',\n    ol.layer.VectorTile.prototype.once);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'un',\n    ol.layer.VectorTile.prototype.un);\n\ngoog.exportProperty(\n    ol.layer.VectorTile.prototype,\n    'unByKey',\n    ol.layer.VectorTile.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'get',\n    ol.interaction.Interaction.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'getKeys',\n    ol.interaction.Interaction.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'getProperties',\n    ol.interaction.Interaction.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'set',\n    ol.interaction.Interaction.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'setProperties',\n    ol.interaction.Interaction.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'unset',\n    ol.interaction.Interaction.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'changed',\n    ol.interaction.Interaction.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'dispatchEvent',\n    ol.interaction.Interaction.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'getRevision',\n    ol.interaction.Interaction.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'on',\n    ol.interaction.Interaction.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'once',\n    ol.interaction.Interaction.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'un',\n    ol.interaction.Interaction.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Interaction.prototype,\n    'unByKey',\n    ol.interaction.Interaction.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'getActive',\n    ol.interaction.DoubleClickZoom.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'getMap',\n    ol.interaction.DoubleClickZoom.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'setActive',\n    ol.interaction.DoubleClickZoom.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'get',\n    ol.interaction.DoubleClickZoom.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'getKeys',\n    ol.interaction.DoubleClickZoom.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'getProperties',\n    ol.interaction.DoubleClickZoom.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'set',\n    ol.interaction.DoubleClickZoom.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'setProperties',\n    ol.interaction.DoubleClickZoom.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'unset',\n    ol.interaction.DoubleClickZoom.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'changed',\n    ol.interaction.DoubleClickZoom.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'dispatchEvent',\n    ol.interaction.DoubleClickZoom.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'getRevision',\n    ol.interaction.DoubleClickZoom.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'on',\n    ol.interaction.DoubleClickZoom.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'once',\n    ol.interaction.DoubleClickZoom.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'un',\n    ol.interaction.DoubleClickZoom.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.DoubleClickZoom.prototype,\n    'unByKey',\n    ol.interaction.DoubleClickZoom.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'getActive',\n    ol.interaction.DragAndDrop.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'getMap',\n    ol.interaction.DragAndDrop.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'setActive',\n    ol.interaction.DragAndDrop.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'get',\n    ol.interaction.DragAndDrop.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'getKeys',\n    ol.interaction.DragAndDrop.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'getProperties',\n    ol.interaction.DragAndDrop.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'set',\n    ol.interaction.DragAndDrop.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'setProperties',\n    ol.interaction.DragAndDrop.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'unset',\n    ol.interaction.DragAndDrop.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'changed',\n    ol.interaction.DragAndDrop.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'dispatchEvent',\n    ol.interaction.DragAndDrop.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'getRevision',\n    ol.interaction.DragAndDrop.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'on',\n    ol.interaction.DragAndDrop.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'once',\n    ol.interaction.DragAndDrop.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'un',\n    ol.interaction.DragAndDrop.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.prototype,\n    'unByKey',\n    ol.interaction.DragAndDrop.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.Event.prototype,\n    'type',\n    ol.interaction.DragAndDrop.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.Event.prototype,\n    'target',\n    ol.interaction.DragAndDrop.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.Event.prototype,\n    'preventDefault',\n    ol.interaction.DragAndDrop.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.interaction.DragAndDrop.Event.prototype,\n    'stopPropagation',\n    ol.interaction.DragAndDrop.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'getActive',\n    ol.interaction.Pointer.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'getMap',\n    ol.interaction.Pointer.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'setActive',\n    ol.interaction.Pointer.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'get',\n    ol.interaction.Pointer.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'getKeys',\n    ol.interaction.Pointer.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'getProperties',\n    ol.interaction.Pointer.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'set',\n    ol.interaction.Pointer.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'setProperties',\n    ol.interaction.Pointer.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'unset',\n    ol.interaction.Pointer.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'changed',\n    ol.interaction.Pointer.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'dispatchEvent',\n    ol.interaction.Pointer.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'getRevision',\n    ol.interaction.Pointer.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'on',\n    ol.interaction.Pointer.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'once',\n    ol.interaction.Pointer.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'un',\n    ol.interaction.Pointer.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Pointer.prototype,\n    'unByKey',\n    ol.interaction.Pointer.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'getActive',\n    ol.interaction.DragBox.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'getMap',\n    ol.interaction.DragBox.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'setActive',\n    ol.interaction.DragBox.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'get',\n    ol.interaction.DragBox.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'getKeys',\n    ol.interaction.DragBox.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'getProperties',\n    ol.interaction.DragBox.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'set',\n    ol.interaction.DragBox.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'setProperties',\n    ol.interaction.DragBox.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'unset',\n    ol.interaction.DragBox.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'changed',\n    ol.interaction.DragBox.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'dispatchEvent',\n    ol.interaction.DragBox.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'getRevision',\n    ol.interaction.DragBox.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'on',\n    ol.interaction.DragBox.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'once',\n    ol.interaction.DragBox.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'un',\n    ol.interaction.DragBox.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.prototype,\n    'unByKey',\n    ol.interaction.DragBox.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.Event.prototype,\n    'type',\n    ol.interaction.DragBox.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.Event.prototype,\n    'target',\n    ol.interaction.DragBox.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.Event.prototype,\n    'preventDefault',\n    ol.interaction.DragBox.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.interaction.DragBox.Event.prototype,\n    'stopPropagation',\n    ol.interaction.DragBox.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'getActive',\n    ol.interaction.DragPan.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'getMap',\n    ol.interaction.DragPan.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'setActive',\n    ol.interaction.DragPan.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'get',\n    ol.interaction.DragPan.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'getKeys',\n    ol.interaction.DragPan.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'getProperties',\n    ol.interaction.DragPan.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'set',\n    ol.interaction.DragPan.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'setProperties',\n    ol.interaction.DragPan.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'unset',\n    ol.interaction.DragPan.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'changed',\n    ol.interaction.DragPan.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'dispatchEvent',\n    ol.interaction.DragPan.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'getRevision',\n    ol.interaction.DragPan.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'on',\n    ol.interaction.DragPan.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'once',\n    ol.interaction.DragPan.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'un',\n    ol.interaction.DragPan.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.DragPan.prototype,\n    'unByKey',\n    ol.interaction.DragPan.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'getActive',\n    ol.interaction.DragRotate.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'getMap',\n    ol.interaction.DragRotate.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'setActive',\n    ol.interaction.DragRotate.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'get',\n    ol.interaction.DragRotate.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'getKeys',\n    ol.interaction.DragRotate.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'getProperties',\n    ol.interaction.DragRotate.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'set',\n    ol.interaction.DragRotate.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'setProperties',\n    ol.interaction.DragRotate.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'unset',\n    ol.interaction.DragRotate.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'changed',\n    ol.interaction.DragRotate.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'dispatchEvent',\n    ol.interaction.DragRotate.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'getRevision',\n    ol.interaction.DragRotate.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'on',\n    ol.interaction.DragRotate.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'once',\n    ol.interaction.DragRotate.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'un',\n    ol.interaction.DragRotate.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.DragRotate.prototype,\n    'unByKey',\n    ol.interaction.DragRotate.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'getActive',\n    ol.interaction.DragRotateAndZoom.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'getMap',\n    ol.interaction.DragRotateAndZoom.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'setActive',\n    ol.interaction.DragRotateAndZoom.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'get',\n    ol.interaction.DragRotateAndZoom.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'getKeys',\n    ol.interaction.DragRotateAndZoom.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'getProperties',\n    ol.interaction.DragRotateAndZoom.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'set',\n    ol.interaction.DragRotateAndZoom.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'setProperties',\n    ol.interaction.DragRotateAndZoom.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'unset',\n    ol.interaction.DragRotateAndZoom.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'changed',\n    ol.interaction.DragRotateAndZoom.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'dispatchEvent',\n    ol.interaction.DragRotateAndZoom.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'getRevision',\n    ol.interaction.DragRotateAndZoom.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'on',\n    ol.interaction.DragRotateAndZoom.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'once',\n    ol.interaction.DragRotateAndZoom.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'un',\n    ol.interaction.DragRotateAndZoom.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.DragRotateAndZoom.prototype,\n    'unByKey',\n    ol.interaction.DragRotateAndZoom.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'getGeometry',\n    ol.interaction.DragZoom.prototype.getGeometry);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'getActive',\n    ol.interaction.DragZoom.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'getMap',\n    ol.interaction.DragZoom.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'setActive',\n    ol.interaction.DragZoom.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'get',\n    ol.interaction.DragZoom.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'getKeys',\n    ol.interaction.DragZoom.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'getProperties',\n    ol.interaction.DragZoom.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'set',\n    ol.interaction.DragZoom.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'setProperties',\n    ol.interaction.DragZoom.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'unset',\n    ol.interaction.DragZoom.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'changed',\n    ol.interaction.DragZoom.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'dispatchEvent',\n    ol.interaction.DragZoom.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'getRevision',\n    ol.interaction.DragZoom.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'on',\n    ol.interaction.DragZoom.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'once',\n    ol.interaction.DragZoom.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'un',\n    ol.interaction.DragZoom.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.DragZoom.prototype,\n    'unByKey',\n    ol.interaction.DragZoom.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'getActive',\n    ol.interaction.Draw.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'getMap',\n    ol.interaction.Draw.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'setActive',\n    ol.interaction.Draw.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'get',\n    ol.interaction.Draw.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'getKeys',\n    ol.interaction.Draw.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'getProperties',\n    ol.interaction.Draw.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'set',\n    ol.interaction.Draw.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'setProperties',\n    ol.interaction.Draw.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'unset',\n    ol.interaction.Draw.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'changed',\n    ol.interaction.Draw.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'dispatchEvent',\n    ol.interaction.Draw.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'getRevision',\n    ol.interaction.Draw.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'on',\n    ol.interaction.Draw.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'once',\n    ol.interaction.Draw.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'un',\n    ol.interaction.Draw.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Draw.prototype,\n    'unByKey',\n    ol.interaction.Draw.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Draw.Event.prototype,\n    'type',\n    ol.interaction.Draw.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.interaction.Draw.Event.prototype,\n    'target',\n    ol.interaction.Draw.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.interaction.Draw.Event.prototype,\n    'preventDefault',\n    ol.interaction.Draw.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.interaction.Draw.Event.prototype,\n    'stopPropagation',\n    ol.interaction.Draw.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'getActive',\n    ol.interaction.Extent.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'getMap',\n    ol.interaction.Extent.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'setActive',\n    ol.interaction.Extent.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'get',\n    ol.interaction.Extent.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'getKeys',\n    ol.interaction.Extent.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'getProperties',\n    ol.interaction.Extent.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'set',\n    ol.interaction.Extent.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'setProperties',\n    ol.interaction.Extent.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'unset',\n    ol.interaction.Extent.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'changed',\n    ol.interaction.Extent.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'dispatchEvent',\n    ol.interaction.Extent.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'getRevision',\n    ol.interaction.Extent.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'on',\n    ol.interaction.Extent.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'once',\n    ol.interaction.Extent.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'un',\n    ol.interaction.Extent.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Extent.prototype,\n    'unByKey',\n    ol.interaction.Extent.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Extent.Event.prototype,\n    'type',\n    ol.interaction.Extent.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.interaction.Extent.Event.prototype,\n    'target',\n    ol.interaction.Extent.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.interaction.Extent.Event.prototype,\n    'preventDefault',\n    ol.interaction.Extent.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.interaction.Extent.Event.prototype,\n    'stopPropagation',\n    ol.interaction.Extent.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'getActive',\n    ol.interaction.KeyboardPan.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'getMap',\n    ol.interaction.KeyboardPan.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'setActive',\n    ol.interaction.KeyboardPan.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'get',\n    ol.interaction.KeyboardPan.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'getKeys',\n    ol.interaction.KeyboardPan.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'getProperties',\n    ol.interaction.KeyboardPan.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'set',\n    ol.interaction.KeyboardPan.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'setProperties',\n    ol.interaction.KeyboardPan.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'unset',\n    ol.interaction.KeyboardPan.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'changed',\n    ol.interaction.KeyboardPan.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'dispatchEvent',\n    ol.interaction.KeyboardPan.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'getRevision',\n    ol.interaction.KeyboardPan.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'on',\n    ol.interaction.KeyboardPan.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'once',\n    ol.interaction.KeyboardPan.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'un',\n    ol.interaction.KeyboardPan.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardPan.prototype,\n    'unByKey',\n    ol.interaction.KeyboardPan.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'getActive',\n    ol.interaction.KeyboardZoom.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'getMap',\n    ol.interaction.KeyboardZoom.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'setActive',\n    ol.interaction.KeyboardZoom.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'get',\n    ol.interaction.KeyboardZoom.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'getKeys',\n    ol.interaction.KeyboardZoom.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'getProperties',\n    ol.interaction.KeyboardZoom.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'set',\n    ol.interaction.KeyboardZoom.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'setProperties',\n    ol.interaction.KeyboardZoom.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'unset',\n    ol.interaction.KeyboardZoom.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'changed',\n    ol.interaction.KeyboardZoom.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'dispatchEvent',\n    ol.interaction.KeyboardZoom.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'getRevision',\n    ol.interaction.KeyboardZoom.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'on',\n    ol.interaction.KeyboardZoom.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'once',\n    ol.interaction.KeyboardZoom.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'un',\n    ol.interaction.KeyboardZoom.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.KeyboardZoom.prototype,\n    'unByKey',\n    ol.interaction.KeyboardZoom.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'getActive',\n    ol.interaction.Modify.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'getMap',\n    ol.interaction.Modify.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'setActive',\n    ol.interaction.Modify.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'get',\n    ol.interaction.Modify.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'getKeys',\n    ol.interaction.Modify.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'getProperties',\n    ol.interaction.Modify.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'set',\n    ol.interaction.Modify.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'setProperties',\n    ol.interaction.Modify.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'unset',\n    ol.interaction.Modify.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'changed',\n    ol.interaction.Modify.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'dispatchEvent',\n    ol.interaction.Modify.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'getRevision',\n    ol.interaction.Modify.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'on',\n    ol.interaction.Modify.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'once',\n    ol.interaction.Modify.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'un',\n    ol.interaction.Modify.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Modify.prototype,\n    'unByKey',\n    ol.interaction.Modify.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Modify.Event.prototype,\n    'type',\n    ol.interaction.Modify.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.interaction.Modify.Event.prototype,\n    'target',\n    ol.interaction.Modify.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.interaction.Modify.Event.prototype,\n    'preventDefault',\n    ol.interaction.Modify.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.interaction.Modify.Event.prototype,\n    'stopPropagation',\n    ol.interaction.Modify.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'getActive',\n    ol.interaction.MouseWheelZoom.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'getMap',\n    ol.interaction.MouseWheelZoom.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'setActive',\n    ol.interaction.MouseWheelZoom.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'get',\n    ol.interaction.MouseWheelZoom.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'getKeys',\n    ol.interaction.MouseWheelZoom.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'getProperties',\n    ol.interaction.MouseWheelZoom.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'set',\n    ol.interaction.MouseWheelZoom.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'setProperties',\n    ol.interaction.MouseWheelZoom.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'unset',\n    ol.interaction.MouseWheelZoom.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'changed',\n    ol.interaction.MouseWheelZoom.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'dispatchEvent',\n    ol.interaction.MouseWheelZoom.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'getRevision',\n    ol.interaction.MouseWheelZoom.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'on',\n    ol.interaction.MouseWheelZoom.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'once',\n    ol.interaction.MouseWheelZoom.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'un',\n    ol.interaction.MouseWheelZoom.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.MouseWheelZoom.prototype,\n    'unByKey',\n    ol.interaction.MouseWheelZoom.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'getActive',\n    ol.interaction.PinchRotate.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'getMap',\n    ol.interaction.PinchRotate.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'setActive',\n    ol.interaction.PinchRotate.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'get',\n    ol.interaction.PinchRotate.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'getKeys',\n    ol.interaction.PinchRotate.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'getProperties',\n    ol.interaction.PinchRotate.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'set',\n    ol.interaction.PinchRotate.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'setProperties',\n    ol.interaction.PinchRotate.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'unset',\n    ol.interaction.PinchRotate.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'changed',\n    ol.interaction.PinchRotate.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'dispatchEvent',\n    ol.interaction.PinchRotate.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'getRevision',\n    ol.interaction.PinchRotate.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'on',\n    ol.interaction.PinchRotate.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'once',\n    ol.interaction.PinchRotate.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'un',\n    ol.interaction.PinchRotate.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.PinchRotate.prototype,\n    'unByKey',\n    ol.interaction.PinchRotate.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'getActive',\n    ol.interaction.PinchZoom.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'getMap',\n    ol.interaction.PinchZoom.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'setActive',\n    ol.interaction.PinchZoom.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'get',\n    ol.interaction.PinchZoom.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'getKeys',\n    ol.interaction.PinchZoom.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'getProperties',\n    ol.interaction.PinchZoom.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'set',\n    ol.interaction.PinchZoom.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'setProperties',\n    ol.interaction.PinchZoom.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'unset',\n    ol.interaction.PinchZoom.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'changed',\n    ol.interaction.PinchZoom.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'dispatchEvent',\n    ol.interaction.PinchZoom.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'getRevision',\n    ol.interaction.PinchZoom.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'on',\n    ol.interaction.PinchZoom.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'once',\n    ol.interaction.PinchZoom.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'un',\n    ol.interaction.PinchZoom.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.PinchZoom.prototype,\n    'unByKey',\n    ol.interaction.PinchZoom.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getActive',\n    ol.interaction.Select.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getMap',\n    ol.interaction.Select.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'setActive',\n    ol.interaction.Select.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'get',\n    ol.interaction.Select.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getKeys',\n    ol.interaction.Select.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getProperties',\n    ol.interaction.Select.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'set',\n    ol.interaction.Select.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'setProperties',\n    ol.interaction.Select.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'unset',\n    ol.interaction.Select.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'changed',\n    ol.interaction.Select.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'dispatchEvent',\n    ol.interaction.Select.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'getRevision',\n    ol.interaction.Select.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'on',\n    ol.interaction.Select.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'once',\n    ol.interaction.Select.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'un',\n    ol.interaction.Select.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Select.prototype,\n    'unByKey',\n    ol.interaction.Select.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Select.Event.prototype,\n    'type',\n    ol.interaction.Select.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.interaction.Select.Event.prototype,\n    'target',\n    ol.interaction.Select.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.interaction.Select.Event.prototype,\n    'preventDefault',\n    ol.interaction.Select.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.interaction.Select.Event.prototype,\n    'stopPropagation',\n    ol.interaction.Select.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'getActive',\n    ol.interaction.Snap.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'getMap',\n    ol.interaction.Snap.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'setActive',\n    ol.interaction.Snap.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'get',\n    ol.interaction.Snap.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'getKeys',\n    ol.interaction.Snap.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'getProperties',\n    ol.interaction.Snap.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'set',\n    ol.interaction.Snap.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'setProperties',\n    ol.interaction.Snap.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'unset',\n    ol.interaction.Snap.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'changed',\n    ol.interaction.Snap.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'dispatchEvent',\n    ol.interaction.Snap.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'getRevision',\n    ol.interaction.Snap.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'on',\n    ol.interaction.Snap.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'once',\n    ol.interaction.Snap.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'un',\n    ol.interaction.Snap.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Snap.prototype,\n    'unByKey',\n    ol.interaction.Snap.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'getActive',\n    ol.interaction.Translate.prototype.getActive);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'getMap',\n    ol.interaction.Translate.prototype.getMap);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'setActive',\n    ol.interaction.Translate.prototype.setActive);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'get',\n    ol.interaction.Translate.prototype.get);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'getKeys',\n    ol.interaction.Translate.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'getProperties',\n    ol.interaction.Translate.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'set',\n    ol.interaction.Translate.prototype.set);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'setProperties',\n    ol.interaction.Translate.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'unset',\n    ol.interaction.Translate.prototype.unset);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'changed',\n    ol.interaction.Translate.prototype.changed);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'dispatchEvent',\n    ol.interaction.Translate.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'getRevision',\n    ol.interaction.Translate.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'on',\n    ol.interaction.Translate.prototype.on);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'once',\n    ol.interaction.Translate.prototype.once);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'un',\n    ol.interaction.Translate.prototype.un);\n\ngoog.exportProperty(\n    ol.interaction.Translate.prototype,\n    'unByKey',\n    ol.interaction.Translate.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.interaction.Translate.Event.prototype,\n    'type',\n    ol.interaction.Translate.Event.prototype.type);\n\ngoog.exportProperty(\n    ol.interaction.Translate.Event.prototype,\n    'target',\n    ol.interaction.Translate.Event.prototype.target);\n\ngoog.exportProperty(\n    ol.interaction.Translate.Event.prototype,\n    'preventDefault',\n    ol.interaction.Translate.Event.prototype.preventDefault);\n\ngoog.exportProperty(\n    ol.interaction.Translate.Event.prototype,\n    'stopPropagation',\n    ol.interaction.Translate.Event.prototype.stopPropagation);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'get',\n    ol.geom.Geometry.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'getKeys',\n    ol.geom.Geometry.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'getProperties',\n    ol.geom.Geometry.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'set',\n    ol.geom.Geometry.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'setProperties',\n    ol.geom.Geometry.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'unset',\n    ol.geom.Geometry.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'changed',\n    ol.geom.Geometry.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'dispatchEvent',\n    ol.geom.Geometry.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'getRevision',\n    ol.geom.Geometry.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'on',\n    ol.geom.Geometry.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'once',\n    ol.geom.Geometry.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'un',\n    ol.geom.Geometry.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.Geometry.prototype,\n    'unByKey',\n    ol.geom.Geometry.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getClosestPoint',\n    ol.geom.SimpleGeometry.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'intersectsCoordinate',\n    ol.geom.SimpleGeometry.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getExtent',\n    ol.geom.SimpleGeometry.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'rotate',\n    ol.geom.SimpleGeometry.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'scale',\n    ol.geom.SimpleGeometry.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'simplify',\n    ol.geom.SimpleGeometry.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'transform',\n    ol.geom.SimpleGeometry.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'get',\n    ol.geom.SimpleGeometry.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getKeys',\n    ol.geom.SimpleGeometry.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getProperties',\n    ol.geom.SimpleGeometry.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'set',\n    ol.geom.SimpleGeometry.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'setProperties',\n    ol.geom.SimpleGeometry.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'unset',\n    ol.geom.SimpleGeometry.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'changed',\n    ol.geom.SimpleGeometry.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'dispatchEvent',\n    ol.geom.SimpleGeometry.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'getRevision',\n    ol.geom.SimpleGeometry.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'on',\n    ol.geom.SimpleGeometry.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'once',\n    ol.geom.SimpleGeometry.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'un',\n    ol.geom.SimpleGeometry.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.SimpleGeometry.prototype,\n    'unByKey',\n    ol.geom.SimpleGeometry.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getFirstCoordinate',\n    ol.geom.Circle.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getLastCoordinate',\n    ol.geom.Circle.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getLayout',\n    ol.geom.Circle.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'rotate',\n    ol.geom.Circle.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'scale',\n    ol.geom.Circle.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getClosestPoint',\n    ol.geom.Circle.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'intersectsCoordinate',\n    ol.geom.Circle.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getExtent',\n    ol.geom.Circle.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'simplify',\n    ol.geom.Circle.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'get',\n    ol.geom.Circle.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getKeys',\n    ol.geom.Circle.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getProperties',\n    ol.geom.Circle.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'set',\n    ol.geom.Circle.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'setProperties',\n    ol.geom.Circle.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'unset',\n    ol.geom.Circle.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'changed',\n    ol.geom.Circle.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'dispatchEvent',\n    ol.geom.Circle.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'getRevision',\n    ol.geom.Circle.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'on',\n    ol.geom.Circle.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'once',\n    ol.geom.Circle.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'un',\n    ol.geom.Circle.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.Circle.prototype,\n    'unByKey',\n    ol.geom.Circle.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'getClosestPoint',\n    ol.geom.GeometryCollection.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'intersectsCoordinate',\n    ol.geom.GeometryCollection.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'getExtent',\n    ol.geom.GeometryCollection.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'rotate',\n    ol.geom.GeometryCollection.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'scale',\n    ol.geom.GeometryCollection.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'simplify',\n    ol.geom.GeometryCollection.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'transform',\n    ol.geom.GeometryCollection.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'get',\n    ol.geom.GeometryCollection.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'getKeys',\n    ol.geom.GeometryCollection.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'getProperties',\n    ol.geom.GeometryCollection.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'set',\n    ol.geom.GeometryCollection.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'setProperties',\n    ol.geom.GeometryCollection.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'unset',\n    ol.geom.GeometryCollection.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'changed',\n    ol.geom.GeometryCollection.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'dispatchEvent',\n    ol.geom.GeometryCollection.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'getRevision',\n    ol.geom.GeometryCollection.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'on',\n    ol.geom.GeometryCollection.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'once',\n    ol.geom.GeometryCollection.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'un',\n    ol.geom.GeometryCollection.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.GeometryCollection.prototype,\n    'unByKey',\n    ol.geom.GeometryCollection.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getFirstCoordinate',\n    ol.geom.LinearRing.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getLastCoordinate',\n    ol.geom.LinearRing.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getLayout',\n    ol.geom.LinearRing.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'rotate',\n    ol.geom.LinearRing.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'scale',\n    ol.geom.LinearRing.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getClosestPoint',\n    ol.geom.LinearRing.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'intersectsCoordinate',\n    ol.geom.LinearRing.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getExtent',\n    ol.geom.LinearRing.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'simplify',\n    ol.geom.LinearRing.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'transform',\n    ol.geom.LinearRing.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'get',\n    ol.geom.LinearRing.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getKeys',\n    ol.geom.LinearRing.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getProperties',\n    ol.geom.LinearRing.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'set',\n    ol.geom.LinearRing.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'setProperties',\n    ol.geom.LinearRing.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'unset',\n    ol.geom.LinearRing.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'changed',\n    ol.geom.LinearRing.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'dispatchEvent',\n    ol.geom.LinearRing.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'getRevision',\n    ol.geom.LinearRing.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'on',\n    ol.geom.LinearRing.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'once',\n    ol.geom.LinearRing.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'un',\n    ol.geom.LinearRing.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.LinearRing.prototype,\n    'unByKey',\n    ol.geom.LinearRing.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getFirstCoordinate',\n    ol.geom.LineString.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getLastCoordinate',\n    ol.geom.LineString.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getLayout',\n    ol.geom.LineString.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'rotate',\n    ol.geom.LineString.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'scale',\n    ol.geom.LineString.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getClosestPoint',\n    ol.geom.LineString.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'intersectsCoordinate',\n    ol.geom.LineString.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getExtent',\n    ol.geom.LineString.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'simplify',\n    ol.geom.LineString.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'transform',\n    ol.geom.LineString.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'get',\n    ol.geom.LineString.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getKeys',\n    ol.geom.LineString.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getProperties',\n    ol.geom.LineString.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'set',\n    ol.geom.LineString.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'setProperties',\n    ol.geom.LineString.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'unset',\n    ol.geom.LineString.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'changed',\n    ol.geom.LineString.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'dispatchEvent',\n    ol.geom.LineString.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'getRevision',\n    ol.geom.LineString.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'on',\n    ol.geom.LineString.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'once',\n    ol.geom.LineString.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'un',\n    ol.geom.LineString.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.LineString.prototype,\n    'unByKey',\n    ol.geom.LineString.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getFirstCoordinate',\n    ol.geom.MultiLineString.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getLastCoordinate',\n    ol.geom.MultiLineString.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getLayout',\n    ol.geom.MultiLineString.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'rotate',\n    ol.geom.MultiLineString.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'scale',\n    ol.geom.MultiLineString.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getClosestPoint',\n    ol.geom.MultiLineString.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'intersectsCoordinate',\n    ol.geom.MultiLineString.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getExtent',\n    ol.geom.MultiLineString.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'simplify',\n    ol.geom.MultiLineString.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'transform',\n    ol.geom.MultiLineString.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'get',\n    ol.geom.MultiLineString.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getKeys',\n    ol.geom.MultiLineString.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getProperties',\n    ol.geom.MultiLineString.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'set',\n    ol.geom.MultiLineString.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'setProperties',\n    ol.geom.MultiLineString.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'unset',\n    ol.geom.MultiLineString.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'changed',\n    ol.geom.MultiLineString.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'dispatchEvent',\n    ol.geom.MultiLineString.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'getRevision',\n    ol.geom.MultiLineString.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'on',\n    ol.geom.MultiLineString.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'once',\n    ol.geom.MultiLineString.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'un',\n    ol.geom.MultiLineString.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.MultiLineString.prototype,\n    'unByKey',\n    ol.geom.MultiLineString.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getFirstCoordinate',\n    ol.geom.MultiPoint.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getLastCoordinate',\n    ol.geom.MultiPoint.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getLayout',\n    ol.geom.MultiPoint.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'rotate',\n    ol.geom.MultiPoint.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'scale',\n    ol.geom.MultiPoint.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getClosestPoint',\n    ol.geom.MultiPoint.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'intersectsCoordinate',\n    ol.geom.MultiPoint.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getExtent',\n    ol.geom.MultiPoint.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'simplify',\n    ol.geom.MultiPoint.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'transform',\n    ol.geom.MultiPoint.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'get',\n    ol.geom.MultiPoint.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getKeys',\n    ol.geom.MultiPoint.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getProperties',\n    ol.geom.MultiPoint.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'set',\n    ol.geom.MultiPoint.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'setProperties',\n    ol.geom.MultiPoint.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'unset',\n    ol.geom.MultiPoint.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'changed',\n    ol.geom.MultiPoint.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'dispatchEvent',\n    ol.geom.MultiPoint.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'getRevision',\n    ol.geom.MultiPoint.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'on',\n    ol.geom.MultiPoint.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'once',\n    ol.geom.MultiPoint.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'un',\n    ol.geom.MultiPoint.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.MultiPoint.prototype,\n    'unByKey',\n    ol.geom.MultiPoint.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getFirstCoordinate',\n    ol.geom.MultiPolygon.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getLastCoordinate',\n    ol.geom.MultiPolygon.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getLayout',\n    ol.geom.MultiPolygon.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'rotate',\n    ol.geom.MultiPolygon.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'scale',\n    ol.geom.MultiPolygon.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getClosestPoint',\n    ol.geom.MultiPolygon.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'intersectsCoordinate',\n    ol.geom.MultiPolygon.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getExtent',\n    ol.geom.MultiPolygon.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'simplify',\n    ol.geom.MultiPolygon.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'transform',\n    ol.geom.MultiPolygon.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'get',\n    ol.geom.MultiPolygon.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getKeys',\n    ol.geom.MultiPolygon.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getProperties',\n    ol.geom.MultiPolygon.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'set',\n    ol.geom.MultiPolygon.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'setProperties',\n    ol.geom.MultiPolygon.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'unset',\n    ol.geom.MultiPolygon.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'changed',\n    ol.geom.MultiPolygon.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'dispatchEvent',\n    ol.geom.MultiPolygon.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'getRevision',\n    ol.geom.MultiPolygon.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'on',\n    ol.geom.MultiPolygon.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'once',\n    ol.geom.MultiPolygon.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'un',\n    ol.geom.MultiPolygon.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.MultiPolygon.prototype,\n    'unByKey',\n    ol.geom.MultiPolygon.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getFirstCoordinate',\n    ol.geom.Point.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getLastCoordinate',\n    ol.geom.Point.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getLayout',\n    ol.geom.Point.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'rotate',\n    ol.geom.Point.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'scale',\n    ol.geom.Point.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getClosestPoint',\n    ol.geom.Point.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'intersectsCoordinate',\n    ol.geom.Point.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getExtent',\n    ol.geom.Point.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'simplify',\n    ol.geom.Point.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'transform',\n    ol.geom.Point.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'get',\n    ol.geom.Point.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getKeys',\n    ol.geom.Point.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getProperties',\n    ol.geom.Point.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'set',\n    ol.geom.Point.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'setProperties',\n    ol.geom.Point.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'unset',\n    ol.geom.Point.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'changed',\n    ol.geom.Point.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'dispatchEvent',\n    ol.geom.Point.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'getRevision',\n    ol.geom.Point.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'on',\n    ol.geom.Point.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'once',\n    ol.geom.Point.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'un',\n    ol.geom.Point.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.Point.prototype,\n    'unByKey',\n    ol.geom.Point.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getFirstCoordinate',\n    ol.geom.Polygon.prototype.getFirstCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getLastCoordinate',\n    ol.geom.Polygon.prototype.getLastCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getLayout',\n    ol.geom.Polygon.prototype.getLayout);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'rotate',\n    ol.geom.Polygon.prototype.rotate);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'scale',\n    ol.geom.Polygon.prototype.scale);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getClosestPoint',\n    ol.geom.Polygon.prototype.getClosestPoint);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'intersectsCoordinate',\n    ol.geom.Polygon.prototype.intersectsCoordinate);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getExtent',\n    ol.geom.Polygon.prototype.getExtent);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'simplify',\n    ol.geom.Polygon.prototype.simplify);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'transform',\n    ol.geom.Polygon.prototype.transform);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'get',\n    ol.geom.Polygon.prototype.get);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getKeys',\n    ol.geom.Polygon.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getProperties',\n    ol.geom.Polygon.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'set',\n    ol.geom.Polygon.prototype.set);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'setProperties',\n    ol.geom.Polygon.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'unset',\n    ol.geom.Polygon.prototype.unset);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'changed',\n    ol.geom.Polygon.prototype.changed);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'dispatchEvent',\n    ol.geom.Polygon.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'getRevision',\n    ol.geom.Polygon.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'on',\n    ol.geom.Polygon.prototype.on);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'once',\n    ol.geom.Polygon.prototype.once);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'un',\n    ol.geom.Polygon.prototype.un);\n\ngoog.exportProperty(\n    ol.geom.Polygon.prototype,\n    'unByKey',\n    ol.geom.Polygon.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.format.GML.prototype,\n    'readFeatures',\n    ol.format.GML.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.GML2.prototype,\n    'readFeatures',\n    ol.format.GML2.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.format.GML3.prototype,\n    'readFeatures',\n    ol.format.GML3.prototype.readFeatures);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'get',\n    ol.control.Control.prototype.get);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'getKeys',\n    ol.control.Control.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'getProperties',\n    ol.control.Control.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'set',\n    ol.control.Control.prototype.set);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'setProperties',\n    ol.control.Control.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'unset',\n    ol.control.Control.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'changed',\n    ol.control.Control.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'dispatchEvent',\n    ol.control.Control.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'getRevision',\n    ol.control.Control.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'on',\n    ol.control.Control.prototype.on);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'once',\n    ol.control.Control.prototype.once);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'un',\n    ol.control.Control.prototype.un);\n\ngoog.exportProperty(\n    ol.control.Control.prototype,\n    'unByKey',\n    ol.control.Control.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'getMap',\n    ol.control.Attribution.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'setMap',\n    ol.control.Attribution.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'setTarget',\n    ol.control.Attribution.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'get',\n    ol.control.Attribution.prototype.get);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'getKeys',\n    ol.control.Attribution.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'getProperties',\n    ol.control.Attribution.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'set',\n    ol.control.Attribution.prototype.set);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'setProperties',\n    ol.control.Attribution.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'unset',\n    ol.control.Attribution.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'changed',\n    ol.control.Attribution.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'dispatchEvent',\n    ol.control.Attribution.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'getRevision',\n    ol.control.Attribution.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'on',\n    ol.control.Attribution.prototype.on);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'once',\n    ol.control.Attribution.prototype.once);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'un',\n    ol.control.Attribution.prototype.un);\n\ngoog.exportProperty(\n    ol.control.Attribution.prototype,\n    'unByKey',\n    ol.control.Attribution.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'getMap',\n    ol.control.FullScreen.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'setMap',\n    ol.control.FullScreen.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'setTarget',\n    ol.control.FullScreen.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'get',\n    ol.control.FullScreen.prototype.get);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'getKeys',\n    ol.control.FullScreen.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'getProperties',\n    ol.control.FullScreen.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'set',\n    ol.control.FullScreen.prototype.set);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'setProperties',\n    ol.control.FullScreen.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'unset',\n    ol.control.FullScreen.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'changed',\n    ol.control.FullScreen.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'dispatchEvent',\n    ol.control.FullScreen.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'getRevision',\n    ol.control.FullScreen.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'on',\n    ol.control.FullScreen.prototype.on);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'once',\n    ol.control.FullScreen.prototype.once);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'un',\n    ol.control.FullScreen.prototype.un);\n\ngoog.exportProperty(\n    ol.control.FullScreen.prototype,\n    'unByKey',\n    ol.control.FullScreen.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'getMap',\n    ol.control.MousePosition.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'setMap',\n    ol.control.MousePosition.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'setTarget',\n    ol.control.MousePosition.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'get',\n    ol.control.MousePosition.prototype.get);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'getKeys',\n    ol.control.MousePosition.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'getProperties',\n    ol.control.MousePosition.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'set',\n    ol.control.MousePosition.prototype.set);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'setProperties',\n    ol.control.MousePosition.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'unset',\n    ol.control.MousePosition.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'changed',\n    ol.control.MousePosition.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'dispatchEvent',\n    ol.control.MousePosition.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'getRevision',\n    ol.control.MousePosition.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'on',\n    ol.control.MousePosition.prototype.on);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'once',\n    ol.control.MousePosition.prototype.once);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'un',\n    ol.control.MousePosition.prototype.un);\n\ngoog.exportProperty(\n    ol.control.MousePosition.prototype,\n    'unByKey',\n    ol.control.MousePosition.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'getMap',\n    ol.control.OverviewMap.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'setMap',\n    ol.control.OverviewMap.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'setTarget',\n    ol.control.OverviewMap.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'get',\n    ol.control.OverviewMap.prototype.get);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'getKeys',\n    ol.control.OverviewMap.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'getProperties',\n    ol.control.OverviewMap.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'set',\n    ol.control.OverviewMap.prototype.set);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'setProperties',\n    ol.control.OverviewMap.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'unset',\n    ol.control.OverviewMap.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'changed',\n    ol.control.OverviewMap.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'dispatchEvent',\n    ol.control.OverviewMap.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'getRevision',\n    ol.control.OverviewMap.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'on',\n    ol.control.OverviewMap.prototype.on);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'once',\n    ol.control.OverviewMap.prototype.once);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'un',\n    ol.control.OverviewMap.prototype.un);\n\ngoog.exportProperty(\n    ol.control.OverviewMap.prototype,\n    'unByKey',\n    ol.control.OverviewMap.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'getMap',\n    ol.control.Rotate.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'setMap',\n    ol.control.Rotate.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'setTarget',\n    ol.control.Rotate.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'get',\n    ol.control.Rotate.prototype.get);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'getKeys',\n    ol.control.Rotate.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'getProperties',\n    ol.control.Rotate.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'set',\n    ol.control.Rotate.prototype.set);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'setProperties',\n    ol.control.Rotate.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'unset',\n    ol.control.Rotate.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'changed',\n    ol.control.Rotate.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'dispatchEvent',\n    ol.control.Rotate.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'getRevision',\n    ol.control.Rotate.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'on',\n    ol.control.Rotate.prototype.on);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'once',\n    ol.control.Rotate.prototype.once);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'un',\n    ol.control.Rotate.prototype.un);\n\ngoog.exportProperty(\n    ol.control.Rotate.prototype,\n    'unByKey',\n    ol.control.Rotate.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'getMap',\n    ol.control.ScaleLine.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'setMap',\n    ol.control.ScaleLine.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'setTarget',\n    ol.control.ScaleLine.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'get',\n    ol.control.ScaleLine.prototype.get);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'getKeys',\n    ol.control.ScaleLine.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'getProperties',\n    ol.control.ScaleLine.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'set',\n    ol.control.ScaleLine.prototype.set);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'setProperties',\n    ol.control.ScaleLine.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'unset',\n    ol.control.ScaleLine.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'changed',\n    ol.control.ScaleLine.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'dispatchEvent',\n    ol.control.ScaleLine.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'getRevision',\n    ol.control.ScaleLine.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'on',\n    ol.control.ScaleLine.prototype.on);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'once',\n    ol.control.ScaleLine.prototype.once);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'un',\n    ol.control.ScaleLine.prototype.un);\n\ngoog.exportProperty(\n    ol.control.ScaleLine.prototype,\n    'unByKey',\n    ol.control.ScaleLine.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'getMap',\n    ol.control.Zoom.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'setMap',\n    ol.control.Zoom.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'setTarget',\n    ol.control.Zoom.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'get',\n    ol.control.Zoom.prototype.get);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'getKeys',\n    ol.control.Zoom.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'getProperties',\n    ol.control.Zoom.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'set',\n    ol.control.Zoom.prototype.set);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'setProperties',\n    ol.control.Zoom.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'unset',\n    ol.control.Zoom.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'changed',\n    ol.control.Zoom.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'dispatchEvent',\n    ol.control.Zoom.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'getRevision',\n    ol.control.Zoom.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'on',\n    ol.control.Zoom.prototype.on);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'once',\n    ol.control.Zoom.prototype.once);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'un',\n    ol.control.Zoom.prototype.un);\n\ngoog.exportProperty(\n    ol.control.Zoom.prototype,\n    'unByKey',\n    ol.control.Zoom.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'getMap',\n    ol.control.ZoomSlider.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'setMap',\n    ol.control.ZoomSlider.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'setTarget',\n    ol.control.ZoomSlider.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'get',\n    ol.control.ZoomSlider.prototype.get);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'getKeys',\n    ol.control.ZoomSlider.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'getProperties',\n    ol.control.ZoomSlider.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'set',\n    ol.control.ZoomSlider.prototype.set);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'setProperties',\n    ol.control.ZoomSlider.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'unset',\n    ol.control.ZoomSlider.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'changed',\n    ol.control.ZoomSlider.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'dispatchEvent',\n    ol.control.ZoomSlider.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'getRevision',\n    ol.control.ZoomSlider.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'on',\n    ol.control.ZoomSlider.prototype.on);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'once',\n    ol.control.ZoomSlider.prototype.once);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'un',\n    ol.control.ZoomSlider.prototype.un);\n\ngoog.exportProperty(\n    ol.control.ZoomSlider.prototype,\n    'unByKey',\n    ol.control.ZoomSlider.prototype.unByKey);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'getMap',\n    ol.control.ZoomToExtent.prototype.getMap);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'setMap',\n    ol.control.ZoomToExtent.prototype.setMap);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'setTarget',\n    ol.control.ZoomToExtent.prototype.setTarget);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'get',\n    ol.control.ZoomToExtent.prototype.get);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'getKeys',\n    ol.control.ZoomToExtent.prototype.getKeys);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'getProperties',\n    ol.control.ZoomToExtent.prototype.getProperties);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'set',\n    ol.control.ZoomToExtent.prototype.set);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'setProperties',\n    ol.control.ZoomToExtent.prototype.setProperties);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'unset',\n    ol.control.ZoomToExtent.prototype.unset);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'changed',\n    ol.control.ZoomToExtent.prototype.changed);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'dispatchEvent',\n    ol.control.ZoomToExtent.prototype.dispatchEvent);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'getRevision',\n    ol.control.ZoomToExtent.prototype.getRevision);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'on',\n    ol.control.ZoomToExtent.prototype.on);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'once',\n    ol.control.ZoomToExtent.prototype.once);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'un',\n    ol.control.ZoomToExtent.prototype.un);\n\ngoog.exportProperty(\n    ol.control.ZoomToExtent.prototype,\n    'unByKey',\n    ol.control.ZoomToExtent.prototype.unByKey);\nol.VERSION = 'v3.20.1';\nOPENLAYERS.ol = ol;\n\n  return OPENLAYERS.ol;\n}));\n","var map;\nvar extent;\nvar overlays = [];\nvar vectorSource = new ol.source.Vector();\nvar lastClick;\nvar popupOverlay;\nvar vectorLayer;\nvar id = null;\nvar userPositionMarker = null;\nvar lockViewToPosition = true;\nvar gps = false;\nvar gpsLocation = null;\nvar featureStyle = new ol.style.Style({\n    stroke: new ol.style.Stroke({\n        color: 'rgb(153,39,208)',\n        lineDash: [4, 8]\n    }),\n    fill: new ol.style.Fill({\n        color: 'rgba(153,39,208,.03)'\n    })\n});\nvar mapClickFunction = function(evt) {\n    var pos = ol.proj.transform(evt[\"coordinate\"], 'EPSG:3857', 'EPSG:4326');\n    lastClick = pos;\n    getNearest(pos[0], pos[1]);\n};\nvar moveFunction = function() {\n    var q = $(\"#search input[name=q]\").val();\n    if (q !== \"\" && $(\"#search input[name=q]\").attr(\"data-move-search\") === \"\") {\n        updateMapExtent();\n        var q = $(\"#search input[name=q]\").val();\n        q = encodeURI(q);\n        $(\"#clearInput\").html(\"<img src=\\\"/img/ajax-loader.gif\\\" />\");\n        var url = '/' + q + '/' + encodeURI(extent[0]) + '/' + encodeURI(extent[1]) + '/' + encodeURI(extent[2]) + '/' + encodeURI(extent[3] + '/' + false + '/50');\n        $.getScript(url);\n    }\n};\nvar clearInputFunction = function() {\n    $(\"#search input[name=q]\").val('');\n    $(\"#search input[name=q]\").focus();\n    clearPOIS();\n    $.each(overlays, function(index, value) {\n        map.removeOverlay(value);\n        $(\"#popup-closer\").click();\n    });\n    deinitResults();\n    $(\"#clearInput\").off();\n};\n$(document).ready(function() {\n    // Initialize the Map\n    initMap();\n    if(getPosition){\n        checkGPS(startApplication);\n    }else{\n        startApplication();\n    }\n    $(\"#closer\").click(function() {\n        toggleResults();\n    });\n    map.on('singleclick', mapClickFunction);\n    $(window).resize(function() {\n        updateResultsPosition();\n        updateCloserPosition();\n        updateMapSize();\n    });\n    $(\"#follow-location > span.button\").click(function() {\n        followLocation();\n    });\n    $(\"#lock-location > span.button\").click(function() {\n        toggleViewLock();\n    });\n});\n\nfunction updateMapExtent() {\n    var tmpExtent = map.getView().calculateExtent([$(\"#map\").width(), $(\"#map\").height()]);\n    extent = ol.proj.transform([tmpExtent[0], tmpExtent[1]], 'EPSG:3857', 'EPSG:4326').concat(ol.proj.transform([tmpExtent[2], tmpExtent[3]], 'EPSG:3857', 'EPSG:4326'));\n}\n\nfunction numberWithPoints(x) {\n    return x.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \".\");\n}\n\nfunction deinitSearchBox() {\n    $(\"#search\").addClass(\"hidden\");\n}\n\nfunction initStartNavigation() {\n    $(\"#clearInput\").html('<a href=\"/route/start/foot\" target=\"_self\"><img src=\"/img/navigation-arrow.svg\" height=\"20px\"></a>');\n    $(\"#clearInput\").off();\n    $(\"#clearInput\").attr(\"title\", \"Routenplaner starten\");\n}\n\nfunction initClearInput() {\n    $(\"#clearInput\").html('<span class=\"font-bold\">X</span>');\n    $(\"#clearInput\").off();\n    $(\"#clearInput\").click(clearInputFunction);\n    $(\"#clearInput\").attr(\"title\", \"Sucheingabe löschen\");\n}\n\nfunction toggleResults(status) {\n    if (status === undefined) {\n        status = $(\"#results\").attr(\"data-status\");\n    } else if (status !== \"in\" && status !== \"out\") {\n        status = \"in\";\n    }\n    if (status === \"in\") {\n        $(\"#closer\").html(\"<\");\n        $(\"#results\").attr(\"data-status\", \"out\");\n        $(\"#closer\").attr(\"title\", \"Ergebnisse ausklappen\");\n        updateResultsPosition();\n        updateCloserPosition();\n    } else {\n        $(\"#closer\").html(\">\");\n        $(\"#results\").attr(\"data-status\", \"in\");\n        $(\"#closer\").attr(\"title\", \"Ergebnisse einklappen\");\n        updateResultsPosition();\n        updateCloserPosition();\n    }\n    updateMapSize();\n}\n\nfunction updateMapSize() {\n    var resultsWidth = parseInt($(\"#results\").width());\n    if ($(\"#results\").hasClass(\"hidden\")) {\n        resultsWidth = 0;\n    }\n    $(\"#search input[name=q]\").attr(\"data-move-search\", \"false\");\n    var displayWidth = $(window).width();\n    // Change Map Width\n    $(\"#map\").width(displayWidth - resultsWidth);\n    var navBarHeight = $(\"nav\").height();\n    if($(\"nav\").hasClass(\"hidden\")){\n        navBarHeight = 0;\n    }\n    var displayHeight = $(window).height();\n    // Change The Map Height\n    // It's possible that the <main> element has a max-height defined\n    if($(\"main\").css(\"max-height\") !== \"none\"){\n        $(\"#map\").height($(\"main\").css(\"max-height\"));\n    }else{\n        $(\"#map\").css(\"margin-top\", navBarHeight);\n        $(\"#map\").height(displayHeight - navBarHeight);\n    }\n\n    map.updateSize();\n    setTimeout(function() {\n        $(\"#search input[name=q]\").attr(\"data-move-search\", \"\");\n    }, 1500);\n}\n\nfunction updateResultsPosition() {\n    if ($(\"#results\").attr(\"data-status\") === \"out\") {\n        $(\"#results\").addClass(\"hidden\");\n    } else {\n        $(\"#results\").removeClass(\"hidden\");\n    }\n}\n\nfunction updateCloserPosition() {\n    if($(\"#closer\").hasClass(\"hidden\")){\n        $(\"#closer\").removeClass(\"hidden\");\n    }\n    if ($(\"#results\").attr(\"data-status\") === \"out\") {\n        $(\"#closer\").css(\"right\", \"0px\");\n    } else {\n        var screenWidth = $(window).width();\n        var resultsWidth = $(\"#results\").width() - 1;\n        var closerWidth = $(\"#closer\").width();\n        if (screenWidth > (resultsWidth + closerWidth)) {\n            $(\"#closer\").css(\"right\", resultsWidth + \"px\");\n        } else {\n            $(\"#closer\").css(\"right\", (resultsWidth - closerWidth) + \"px\");\n        }\n\n        var top = 0;\n        if(!$(\"nav\").hasClass(\"hidden\")){\n            top = $(\"nav\").height();\n        }\n        $(\"#closer\").css(\"top\", top);\n    }\n}\n\nfunction adjustView(results) {\n    if (results.length <= 0) return;\n    var minPosition = [];\n    var maxPosition = [];\n    for (var i = 0; i < results.length; i++) {\n        if (typeof minPosition[0] === 'undefined' || minPosition[0] > parseFloat(results[i][\"lon\"])) {\n            minPosition[0] = parseFloat(results[i][\"lon\"]);\n        }\n        if (typeof minPosition[0] === 'undefined' || (typeof results[i][\"boundingbox\"] !== 'undefined' && minPosition[0] > parseFloat(results[i][\"boundingbox\"][2]))) {\n            minPosition[0] = parseFloat(results[i][\"boundingbox\"][2]);\n        }\n        if (typeof minPosition[1] === 'undefined' || minPosition[1] > parseFloat(results[i][\"lat\"])) {\n            minPosition[1] = parseFloat(results[i][\"lat\"]);\n        }\n        if (typeof minPosition[1] === 'undefined' || (typeof results[i][\"boundingbox\"] !== 'undefined' && minPosition[1] > parseFloat(results[i][\"boundingbox\"][0]))) {\n            minPosition[1] = parseFloat(results[i][\"boundingbox\"][0]);\n        }\n        if (typeof maxPosition[0] === 'undefined' || maxPosition[0] < parseFloat(results[i][\"lon\"])) {\n            maxPosition[0] = parseFloat(results[i][\"lon\"]);\n        }\n        if (typeof maxPosition[0] === 'undefined' || (typeof results[i][\"boundingbox\"] !== 'undefined' && maxPosition[0] < parseFloat(results[i][\"boundingbox\"][3]))) {\n            maxPosition[0] = parseFloat(results[i][\"boundingbox\"][3]);\n        }\n        if (typeof maxPosition[1] === 'undefined' || maxPosition[1] < parseFloat(results[i][\"lat\"])) {\n            maxPosition[1] = parseFloat(results[i][\"lat\"]);\n        }\n        if (typeof maxPosition[1] === 'undefined' || (typeof results[i][\"boundingbox\"] !== 'undefined' && maxPosition[1] < parseFloat(results[i][\"boundingbox\"][1]))) {\n            maxPosition[1] = parseFloat(results[i][\"boundingbox\"][1]);\n        }\n        if (typeof results[i][\"type\"] !== 'undefined' && (results[i][\"type\"] === 'city' || results[i][\"type\"] === 'administrative' || results[i][\"type\"] === 'river')) {\n            break;\n        }\n    }\n    minPosition = ol.proj.transform(minPosition, 'EPSG:4326', 'EPSG:3857');\n    maxPosition = ol.proj.transform(maxPosition, 'EPSG:4326', 'EPSG:3857');\n    map.getView().fit([minPosition[0], minPosition[1], maxPosition[0], maxPosition[1]], map.getSize());\n    updateMapExtent();\n}\n/**\n * Parsesan OSM-Address-Object for the Road-Name\n * @param {Array} address\n * @return {String} roadname\n */\nfunction getRoad(address) {\n    var road = \"\";\n    if (typeof address[\"road\"] !== 'undefined') {\n        road = address[\"road\"];\n    } else if (typeof address[\"pedestrian\"] !== 'undefined') {\n        road = address[\"pedestrian\"];\n    } else if (typeof address[\"path\"] !== 'undefined') {\n        road = address[\"path\"];\n    } else if (typeof address[\"footway\"] !== 'undefined') {\n        road = address[\"footway\"];\n    }\n    return road;\n}\n/**\n * Parse an OSM-Address-Object for the House Number\n * @param {Array} address\n * @return {String} Housenumber\n */\nfunction getHouseNumber(address) {\n    var house_number = typeof address[\"house_number\"] !== 'undefined' ? address[\"house_number\"] : \"\";\n    return house_number;\n}\n/**\n * Parse an OSM-Address-Object for the City (including Zip-Code)\n * @param {Array} address\n * @return {String} City\n */\nfunction getCity(address) {\n    var city = typeof address[\"postcode\"] !== 'undefined' ? address[\"postcode\"] + \" \" : \"\";\n    if (typeof address[\"city\"] !== \"undefined\") {\n        city += address[\"city\"];\n    } else if (typeof address[\"town\"] !== \"undefined\") {\n        city += address[\"town\"];\n    } else if (typeof address[\"village\"] !== \"undefined\") {\n        city += address[\"village\"];\n    }\n    return city;\n}\n\nfunction adjustViewBoundingBox(minpos, maxpos) {\n    minPosition = ol.proj.transform(minpos, 'EPSG:4326', 'EPSG:3857');\n    maxPosition = ol.proj.transform(maxpos, 'EPSG:4326', 'EPSG:3857');\n    map.getView().fit([minPosition[0], minPosition[1], maxPosition[0], maxPosition[1]], map.getSize());\n    updateMapExtent();\n}\n/*\n * This Function takes an array of Positions and adjusts the view of the map so everything is visible\n * @param positions{Array} - Array with Position Objects ([lon,lat])\n */\nfunction adjustViewPosList(positions) {\n    var minpos = [null, null];\n    var maxpos = [null, null];\n    $.each(positions, function(index, value) {\n        if(value === \"\"){\n            return;\n        }\n        if (minpos[0] === null || value[0] < minpos[0]) {\n            minpos[0] = value[0];\n        }\n        if (maxpos[0] === null || value[0] > maxpos[0]) {\n            maxpos[0] = value[0];\n        }\n        if (minpos[1] === null || value[1] < minpos[1]) {\n            minpos[1] = value[1];\n        }\n        if (maxpos[1] === null || value[1] > maxpos[1]) {\n            maxpos[1] = value[1];\n        }\n    });\n    adjustViewBoundingBox(minpos, maxpos);\n}\n\nfunction clearPOIS() {\n    // Remove All Existing Overlays\n    $.each(overlays, function(index, value) {\n        map.removeOverlay(value);\n    });\n    map.removeLayer(vectorLayer);\n    vectorSource = new ol.source.Vector();\n    // Remove Existing Results\n    $(\"#results > .result\").remove();\n    $(\"#results > h4\").remove();\n    overlays = [];\n}\n\nfunction centerMap(longitude, latitude) {\n    var point = ol.proj.transform([longitude, latitude], 'EPSG:4326', 'EPSG:3857')\n    map.getView().setCenter(point);\n}\n/**\n * Fügt einen Marker auf die Karte hinzu\n * Parameter:\n *  el: HTML-Code für das Element, welches den Marker definiert\n *  pos: Position, auf der sich der Marker befinden soll int[2] (Lat, Long)\n **/\nfunction addMarker(el, pos) {\n    var overlay = new ol.Overlay({\n        position: pos,\n        element: el.get(0),\n        offset: [-12, -45],\n        stopEvent: false,\n    });\n    map.addOverlay(overlay);\n    return overlay;\n}\n\nfunction toggleGpsWarning(){\n    $(\"#gps-error\").addClass(\"visible-xs\");\n    $(\"#gps-error\").removeClass(\"hidden\");\n    setTimeout(function(){\n        $(\"#gps-error\").addClass(\"hidden\");\n        $(\"#gps-error\").removeClass(\"visible-xs\");\n    }, 5000);\n}\n\nfunction checkGPS(callback) {\n\n    if (navigator.geolocation) {\n        navigator.geolocation.getCurrentPosition(function(position){\n            if(position.coords.accuracy > 500){\n                gps = false;\n                toggleGPSLocator(false);\n                lon = parseFloat(position.coords.longitude);\n                lat = parseFloat(position.coords.latitude);\n                gpsLocation = [lon, lat];\n                toggleGpsWarning();\n            }else{\n                gps = gps = true;\n                lon = parseFloat(position.coords.longitude);\n                lat = parseFloat(position.coords.latitude);\n                gpsLocation = [lon, lat];\n                toggleGPSLocator(true);\n            }\n            if(gpsLocation !== null){\n                map.getView().setCenter(ol.proj.transform(gpsLocation, 'EPSG:4326', 'EPSG:3857'));\n                map.getView().setZoom(12);\n            }\n            if(typeof callback === \"function\"){\n                callback();\n            }\n        }, function(error){\n            gps = false;\n            toggleGPSLocator(false);\n            toggleGpsWarning();\n            if(typeof callback === \"function\"){\n                callback();\n            }\n        });\n    } else {\n        gps = false;\n        toggleGPSLocator(false);\n        toggleGpsWarning();\n        if(typeof callback === \"function\"){\n            callback();\n        }\n    }\n}\n\nfunction startApplication(){\n    if(typeof start === \"function\"){\n        start();\n    }\n}\n\nfunction toggleGPSLocator(visible){\n    if(visible){\n        $(\"#location-tool\").removeClass(\"hidden\");\n    }else{\n        $(\"#location-tool\").addClass(\"hidden\");\n    }\n}\n\nfunction followLocation() {\n    // Element to be displayed at the user-location\n    var el = $('<span id=\"user-position\" class=\"glyphicon glyphicon-record\" style=\"color: #2881cc;\"></span>');\n    if (lockViewToPosition) $(\"#lock-location\").addClass(\"active\");\n    else $(\"#lock-location\").removeClass(\"active\");\n    if (id === null) {\n        id = navigator.geolocation.watchPosition(function(position) {\n            // Remove possibly existing User-Location Marker:\n            if (userPositionMarker !== null) {\n                map.removeLayer(userPositionMarker);\n                userPositionMarker = null;\n            }\n            // Create User Position\n            var point_geom = new ol.geom.Point(ol.proj.transform([position.coords.longitude, position.coords.latitude], 'EPSG:4326', 'EPSG:3857'));\n            var point_feature = new ol.Feature({\n                name: \"Position\",\n                geometry: point_geom\n            });\n            // Create the accuracy Circle:\n            var circle = new ol.geom.Circle(ol.proj.transform([position.coords.longitude, position.coords.latitude], 'EPSG:4326', 'EPSG:3857'), position.coords.accuracy);\n            var accuracy_feature = new ol.Feature({\n                name: \"Accuracy\",\n                geometry: circle\n            });\n            userPositionMarker = new ol.layer.Vector({\n                source: new ol.source.Vector({\n                    features: [point_feature, accuracy_feature]\n                })\n            });\n            map.addLayer(userPositionMarker);\n            if (lockViewToPosition) {\n                // Fit the Extent of the Map to Fit the new Features Exactly\n                map.getView().fit(userPositionMarker.getSource().getExtent(), map.getSize());\n            }\n            // Change the color of the Icon so the user knows that the position is tracked:\n            $(\"#follow-location\").addClass(\"active\");\n        }, function(error) {}, options);\n        // Show the Lock View to Position Button\n        $(\"#lock-location\").removeClass(\"hidden\");\n        $(\"#lock-location > span.info\").fadeOut(2000);\n    } else {\n        map.removeLayer(userPositionMarker);\n        userPositionMarker = null;\n        navigator.geolocation.clearWatch(id);\n        id = null;\n        // Clear the color of the Icon so the user knows that the position is no longer tracked\n        $(\"#follow-location\").removeClass(\"active\");\n        // Hide the lock View to Position Button\n        $(\"#lock-location\").addClass(\"hidden\");\n        $(\"#lock-location > span.info\").css(\"display\", \"\");\n    }\n}\n\nfunction updateCurrentLocation(callback) {\n    var lon = \"\";\n    var lat = \"\";\n    if (gps) {\n        navigator.geolocation.getCurrentPosition(function(position) {\n            lon = parseFloat(position.coords.longitude);\n            lat = parseFloat(position.coords.latitude);\n            gpsLocation = [lon, lat];\n            if(typeof callback === \"function\"){\n                callback();\n            }\n        }, function(error) {\n            checkGPS(callback);\n        });\n\n        \n    } else {\n        return null;\n    }\n}\n\nfunction toggleViewLock() {\n    if (lockViewToPosition) {\n        lockViewToPosition = false;\n        $(\"#lock-location\").removeClass(\"active\");\n        $(\"#lock-location > span.info\").html(\"Ansicht freigegeben\");\n        $(\"#lock-location > span.info\").css(\"display\", \"\");\n        $(\"#lock-location > span.info\").fadeOut(2000);\n    } else {\n        lockViewToPosition = true;\n        $(\"#lock-location\").addClass(\"active\");\n        $(\"#lock-location > span.info\").html(\"Ansicht zentriert\");\n        $(\"#lock-location > span.info\").css(\"display\", \"\");\n        $(\"#lock-location > span.info\").fadeOut(2000);\n    }\n}\n\nfunction createPopup(lon, lat, html) {\n    var pos = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326', 'EPSG:3857');\n    $(\"#popup-content\").html(html);\n    popupOverlay.setPosition(pos);\n}","\n\n$(document).ready(function() {\n    initStartNavigation();\n    if (boundings) {\n        adjustViewBoundingBox(minPos, maxPos);\n    }\n    $(\"#search input[name=q]\").on(\"keydown\", function(event) {\n        if (event.which == 13) $(\"#doSearch\").click();\n    });\n    $(\"#doSearch\").click(function() {\n        updateMapExtent();\n        var q = $(\"#search input[name=q]\").val();\n        q = encodeURI(q);\n        $(\"#clearInput\").html(\"<img src=\\\"/img/ajax-loader.gif\\\" />\");\n        var url = '/' + q + '/' + encodeURI(extent[0]) + '/' + encodeURI(extent[1]) + '/' + encodeURI(extent[2]) + '/' + encodeURI(extent[3]);\n        $.getScript(url).fail(function(jqxhr, settings, exception) {\n            console.log(exception);\n        });\n        $(\"#search input[name=q]\").blur();\n    });\n});\n\nfunction initMap() {\n    popupOverlay = new ol.Overlay( /** @type {olx.OverlayOptions} */ ({\n        element: document.getElementById(\"popup\"),\n        autoPan: true,\n        autoPanAnimation: {\n            duration: 250\n        }\n    }));\n    map = new ol.Map({\n        layers: [\n            new ol.layer.Tile({\n                preload: Infinity,\n                source: new ol.source.OSM({\n                    attributions: [\n                        new ol.Attribution({\n                            html: '<a href=\"https://metager.de/impressum\">Impressum</a>'\n                        }),\n                        new ol.Attribution({\n                            html: 'All search results &copy; ' + '<a href=\"http://nominatim.openstreetmap.org/\">Nominatim</a>'\n                        }),\n                        ol.source.OSM.ATTRIBUTION,\n                    ],\n                    url: 'https://maps.metager.de/osm_tiles/{z}/{x}/{y}.png'\n                })\n            })\n        ],\n        target: 'map',\n        controls: ol.control.defaults({\n            attributionOptions: /** @type {olx.control.AttributionOptions} */ ({\n                collapsible: true\n            })\n        }),\n        overlays: [popupOverlay],\n        view: new ol.View({\n            maxZoom: 18,\n            minZoom: 6,\n            center: ol.proj.transform(\n                [10.06897, 51.37247], 'EPSG:4326', 'EPSG:3857'),\n            zoom: 6\n        }),\n        loadTilesWhileAnimating: true,\n        loadTilesWhileInteracting: true\n    });\n    map.addControl(new ol.control.ZoomSlider());\n    $(\"#popup-closer\").click(function() {\n        popupOverlay.setPosition(undefined);\n        $(this).blur();\n        return false;\n    });\n}\n/**\n * This function sends a request to our Nominatim instance and evaluates the given coordinates to an adress\n * @param {Float} lon\n * @param {Float} lat\n * @return {Array} adress\n */\nfunction getNearest(lon, lat) {\n    var url = \"https://maps.metager.de/nominatim/reverse.php?format=json&lat=\" + lat + \"&lon=\" + lon + \"&zoom=18\";\n    // Send the Request\n    $.get(url, function(data) {\n        if (typeof data !== \"undefined\" && typeof data[\"address\"] !== \"undefined\") {\n            // Success we have an address\n            var address = data[\"address\"];\n\n            var road = getRoad(address);\n            var house_number = getHouseNumber(address);\n            var city = getCity(address);\n            var id = data[\"place_id\"];\n\n            var url = \"\";\n            if(gps){\n                url = \"/route/start/foot/gps;\"+lon+\",\"+lat;\n            }else{\n                url = \"/route/start/foot/\"+lon+\",\"+lat;\n            }\n\n            var popup = $(\"\\\n                <div class=\\\"result col-xs-12\\\">\\\n                    <p class=\\\"address\\\">\" + road + \" \" + house_number + \"</p>\\\n                    <p class=\\\"city\\\">\" + city + \"</p>\\\n                    <p class=\\\"address\\\">Longitude: \" + lon + \"</p>\\\n                    <p class=\\\"address\\\">Latitude: \" + lat + \"</p>\\\n                    <a href=\\\"https://maps.metager.de/nominatim/details.php?place_id=\" + id + \"\\\" target=\\\"_blank\\\" class=\\\"btn btn-default btn-xs\\\">Details</a>\\\n                    <a href=\\\"\"+url+\"\\\" class=\\\"btn btn-default btn-xs\\\">Route berechnen</a>\\\n                    </div>\");\n\n            // And now we can show the Popup where the user clicked\n            createPopup(lon, lat, popup);\n        }\n    });\n}\n\nfunction deinitResults() {\n    toggleResults(\"out\");\n    $(\"#results\").addClass(\"hidden\");\n    $(\"#closer\").addClass(\"hidden\");\n    $(\"#results\").html(\"\");\n    updateMapSize();\n    initStartNavigation();\n}"]}