eodash_catalog 0.0.17__tar.gz → 0.0.19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of eodash_catalog might be problematic. Click here for more details.

Files changed (33) hide show
  1. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/.bumpversion.cfg +1 -1
  2. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/PKG-INFO +1 -1
  3. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/__about__.py +1 -1
  4. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/endpoints.py +53 -29
  5. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/generate_indicators.py +28 -26
  6. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/stac_handling.py +5 -4
  7. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/test_generate.py +4 -2
  8. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-layers/baselayers.yaml +1 -2
  9. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-layers/overlays.yaml +2 -3
  10. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/.github/workflows/ci.yml +0 -0
  11. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/.github/workflows/python-publish.yml +0 -0
  12. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/.gitignore +0 -0
  13. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/.vscode/extensions.json +0 -0
  14. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/.vscode/settings.json +0 -0
  15. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/LICENSE.txt +0 -0
  16. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/README.md +0 -0
  17. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/pyproject.toml +0 -0
  18. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/requirements.txt +0 -0
  19. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/ruff.toml +0 -0
  20. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/__init__.py +0 -0
  21. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/duration.py +0 -0
  22. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/sh_endpoint.py +0 -0
  23. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/thumbnails.py +0 -0
  24. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/src/eodash_catalog/utils.py +0 -0
  25. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/__init__.py +0 -0
  26. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/test-data/regional_forecast.json +0 -0
  27. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-catalogs/testing.yaml +0 -0
  28. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-collections/test_CROPOMAT1.yaml +0 -0
  29. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-collections/test_see_solar_energy.yaml +0 -0
  30. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-collections/test_tif_demo_1.yaml +0 -0
  31. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-collections/test_tif_demo_2.yaml +0 -0
  32. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-collections/test_wms_no_time.yaml +0 -0
  33. {eodash_catalog-0.0.17 → eodash_catalog-0.0.19}/tests/testing-indicators/test_indicator.yaml +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.0.17
2
+ current_version = 0.0.19
3
3
  commit = True
4
4
  tag = True
5
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)\.(?P<build>\d+))?
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: eodash_catalog
3
- Version: 0.0.17
3
+ Version: 0.0.19
4
4
  Summary: This package is intended to help create a compatible STAC catalog for the eodash dashboard client. It supports configuration of multiple endpoint types for information extraction.
5
5
  Project-URL: Documentation, https://github.com/eodash/eodash_catalog#readme
6
6
  Project-URL: Issues, https://github.com/eodash/eodash_catalog/issues
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2024-present Daniel Santillan <daniel.santillan@eox.at>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- __version__ = "0.0.17"
4
+ __version__ = "0.0.19"
@@ -136,6 +136,8 @@ def handle_STAC_based_endpoint(
136
136
  link.extra_fields["latlng"] = latlng
137
137
  link.extra_fields["name"] = location["Name"]
138
138
  add_example_info(collection, collection_config, endpoint_config, catalog_config)
139
+ # eodash v4 compatibility
140
+ add_visualization_info(collection, collection_config, endpoint_config)
139
141
  if "OverwriteBBox" in location:
140
142
  collection.extent.spatial = SpatialExtent(
141
143
  [
@@ -160,7 +162,8 @@ def handle_STAC_based_endpoint(
160
162
  headers=headers,
161
163
  bbox=bbox,
162
164
  )
163
-
165
+ # eodash v4 compatibility
166
+ add_visualization_info(root_collection, collection_config, endpoint_config)
164
167
  add_example_info(root_collection, collection_config, endpoint_config, catalog_config)
165
168
  return root_collection
166
169
 
@@ -306,6 +309,8 @@ def handle_collection_only(
306
309
  link = collection.add_item(item)
307
310
  link.extra_fields["datetime"] = t
308
311
  add_collection_information(catalog_config, collection, collection_config)
312
+ # eodash v4 compatibility
313
+ add_visualization_info(collection, collection_config, endpoint_config)
309
314
  return collection
310
315
 
311
316
 
@@ -359,6 +364,8 @@ def handle_SH_WMS_endpoint(
359
364
  for c_child in root_collection.get_children():
360
365
  if isinstance(c_child, Collection):
361
366
  root_collection.extent.spatial.bboxes.append(c_child.extent.spatial.bboxes[0])
367
+ # eodash v4 compatibility
368
+ add_visualization_info(root_collection, collection_config, endpoint_config)
362
369
  return root_collection
363
370
 
364
371
 
@@ -512,7 +519,10 @@ def handle_WMS_endpoint(
512
519
  )
513
520
  # optionally filter time results
514
521
  if query := endpoint_config.get("Query"):
515
- datetime_query = [times[0], times[-1]]
522
+ datetime_query = [
523
+ parser.isoparse(times[0]).replace(tzinfo=timezone.utc),
524
+ parser.isoparse(times[-1]).replace(tzinfo=timezone.utc),
525
+ ]
516
526
  if start := query.get("Start"):
517
527
  datetime_query[0] = parser.isoparse(start).replace(tzinfo=timezone.utc)
518
528
  if end := query.get("End"):
@@ -549,6 +559,8 @@ def handle_WMS_endpoint(
549
559
  endpoint_config["OverwriteBBox"],
550
560
  ]
551
561
  )
562
+ # eodash v4 compatibility
563
+ add_visualization_info(collection, collection_config, endpoint_config)
552
564
  add_collection_information(catalog_config, collection, collection_config)
553
565
  return collection
554
566
 
@@ -576,6 +588,9 @@ def add_visualization_info(
576
588
  file_url: str | None = None,
577
589
  time: str | None = None,
578
590
  ) -> None:
591
+ extra_fields: dict[str, list[str] | dict[str, str]] = {}
592
+ if "Attribution" in endpoint_config:
593
+ extra_fields["attribution"] = endpoint_config["Attribution"]
579
594
  # add extension reference
580
595
  if endpoint_config["Name"] == "Sentinel Hub" or endpoint_config["Name"] == "Sentinel Hub WMS":
581
596
  instanceId = os.getenv("SH_INSTANCE_ID")
@@ -585,10 +600,12 @@ def add_visualization_info(
585
600
  # special handling for custom environment
586
601
  # (will take SH_INSTANCE_ID_{env_id}) as ENV VAR
587
602
  instanceId = os.getenv(f"SH_INSTANCE_ID_{env_id}")
588
- extra_fields: dict[str, list[str] | dict[str, str]] = {
589
- "wms:layers": [endpoint_config["LayerId"]],
590
- "role": ["data"],
591
- }
603
+ extra_fields.update(
604
+ {
605
+ "wms:layers": [endpoint_config["LayerId"]],
606
+ "role": ["data"],
607
+ }
608
+ )
592
609
  if time is not None:
593
610
  if endpoint_config["Name"] == "Sentinel Hub WMS":
594
611
  # SH WMS for public collections needs time interval, we use full day here
@@ -609,19 +626,19 @@ def add_visualization_info(
609
626
  )
610
627
  )
611
628
  elif endpoint_config["Name"] == "WMS":
612
- extra_fields = {
613
- "wms:layers": [endpoint_config["LayerId"]],
614
- "role": ["data"],
615
- }
629
+ extra_fields.update(
630
+ {
631
+ "wms:layers": [endpoint_config["LayerId"]],
632
+ "role": ["data"],
633
+ }
634
+ )
616
635
  if time is not None:
617
636
  extra_fields["wms:dimensions"] = {
618
637
  "TIME": time,
619
638
  }
620
639
  if "Styles" in endpoint_config:
621
640
  extra_fields["wms:styles"] = endpoint_config["Styles"]
622
- media_type = "image/jpeg"
623
- if "MediaType" in endpoint_config:
624
- media_type = endpoint_config["MediaType"]
641
+ media_type = endpoint_config.get("MediaType", "image/jpeg")
625
642
  endpoint_url = endpoint_config["EndPoint"]
626
643
  # custom replacing of all ENV VARS present as template in URL as {VAR}
627
644
  endpoint_url = replace_with_env_variables(endpoint_url)
@@ -637,9 +654,9 @@ def add_visualization_info(
637
654
  elif endpoint_config["Name"] == "JAXA_WMTS_PALSAR":
638
655
  target_url = "{}".format(endpoint_config.get("EndPoint"))
639
656
  # custom time just for this special case as a default for collection wmts
640
- extra_fields = {
641
- "wmts:layer": endpoint_config.get("LayerId", "").replace("{time}", time or "2017")
642
- }
657
+ extra_fields.update(
658
+ {"wmts:layer": endpoint_config.get("LayerId", "").replace("{time}", time or "2017")}
659
+ )
643
660
  stac_object.add_link(
644
661
  Link(
645
662
  rel="wmts",
@@ -680,14 +697,17 @@ def add_visualization_info(
680
697
  target=target_url,
681
698
  media_type="image/png",
682
699
  title="xcube tiles",
700
+ extra_fields=extra_fields,
683
701
  )
684
702
  )
685
- elif endpoint_config["Type"] == "WMTSCapabilities":
703
+ elif endpoint_config.get("Type") == "WMTSCapabilities":
686
704
  target_url = "{}".format(endpoint_config.get("EndPoint"))
687
- extra_fields = {
688
- "wmts:layer": endpoint_config.get("LayerId", ""),
689
- "role": ["data"],
690
- }
705
+ extra_fields.update(
706
+ {
707
+ "wmts:layer": endpoint_config.get("LayerId", ""),
708
+ "role": ["data"],
709
+ }
710
+ )
691
711
  dimensions = {}
692
712
  if time is not None:
693
713
  dimensions["time"] = time
@@ -717,6 +737,7 @@ def add_visualization_info(
717
737
  target=target_url,
718
738
  media_type="image/png",
719
739
  title=collection_config["Name"],
740
+ extra_fields=extra_fields,
720
741
  )
721
742
  )
722
743
  elif endpoint_config["Name"] == "GeoDB Vector Tiles":
@@ -728,20 +749,23 @@ def add_visualization_info(
728
749
  endpoint_config["Database"],
729
750
  endpoint_config["CollectionId"],
730
751
  )
752
+ extra_fields.update(
753
+ {
754
+ "description": collection_config["Title"],
755
+ "parameters": endpoint_config["Parameters"],
756
+ "matchKey": endpoint_config["MatchKey"],
757
+ "timeKey": endpoint_config["TimeKey"],
758
+ "source": endpoint_config["Source"],
759
+ "role": ["data"],
760
+ }
761
+ )
731
762
  stac_object.add_link(
732
763
  Link(
733
764
  rel="xyz",
734
765
  target=target_url,
735
766
  media_type="application/pbf",
736
767
  title=collection_config["Name"],
737
- extra_fields={
738
- "description": collection_config["Title"],
739
- "parameters": endpoint_config["Parameters"],
740
- "matchKey": endpoint_config["MatchKey"],
741
- "timeKey": endpoint_config["TimeKey"],
742
- "source": endpoint_config["Source"],
743
- "role": ["data"],
744
- },
768
+ extra_fields=extra_fields,
745
769
  )
746
770
  )
747
771
  else:
@@ -88,6 +88,8 @@ def process_catalog_file(file_path: str, options: Options):
88
88
  )
89
89
  else:
90
90
  print(f"Warning: neither collection nor indicator found for {collection}")
91
+ if "MapProjection" in catalog_config:
92
+ catalog.extra_fields["eodash:mapProjection"] = catalog_config["MapProjection"]
91
93
 
92
94
  strategy = TemplateLayoutStrategy(item_template="${collection}/${year}")
93
95
  # expecting that the catalog will be hosted online, self url should correspond to that
@@ -196,64 +198,64 @@ def process_collection_file(
196
198
  with open(file_path) as f:
197
199
  collection_config: dict = yaml.load(f, Loader=SafeLoader)
198
200
  if "Resources" in collection_config:
199
- for resource in collection_config["Resources"]:
201
+ for endpoint_config in collection_config["Resources"]:
200
202
  collection = None
201
- if resource["Name"] == "Sentinel Hub":
203
+ if endpoint_config["Name"] == "Sentinel Hub":
202
204
  collection = handle_SH_endpoint(
203
- catalog_config, resource, collection_config, catalog, options
205
+ catalog_config, endpoint_config, collection_config, catalog, options
204
206
  )
205
- elif resource["Name"] == "Sentinel Hub WMS":
207
+ elif endpoint_config["Name"] == "Sentinel Hub WMS":
206
208
  collection = handle_SH_WMS_endpoint(
207
- catalog_config, resource, collection_config, catalog
209
+ catalog_config, endpoint_config, collection_config, catalog
208
210
  )
209
- elif resource["Name"] == "GeoDB":
211
+ elif endpoint_config["Name"] == "GeoDB":
210
212
  collection = handle_GeoDB_endpoint(
211
- catalog_config, resource, collection_config, catalog
213
+ catalog_config, endpoint_config, collection_config, catalog
212
214
  )
213
- elif resource["Name"] == "VEDA":
215
+ elif endpoint_config["Name"] == "VEDA":
214
216
  collection = handle_VEDA_endpoint(
215
- catalog_config, resource, collection_config, catalog, options
217
+ catalog_config, endpoint_config, collection_config, catalog, options
216
218
  )
217
- elif resource["Name"] == "marinedatastore":
219
+ elif endpoint_config["Name"] == "marinedatastore":
218
220
  collection = handle_WMS_endpoint(
219
- catalog_config, resource, collection_config, catalog, wmts=True
221
+ catalog_config, endpoint_config, collection_config, catalog, wmts=True
220
222
  )
221
- elif resource["Name"] == "xcube":
223
+ elif endpoint_config["Name"] == "xcube":
222
224
  collection = handle_xcube_endpoint(
223
- catalog_config, resource, collection_config, catalog
225
+ catalog_config, endpoint_config, collection_config, catalog
224
226
  )
225
- elif resource["Name"] == "WMS":
227
+ elif endpoint_config["Name"] == "WMS":
226
228
  collection = handle_WMS_endpoint(
227
- catalog_config, resource, collection_config, catalog
229
+ catalog_config, endpoint_config, collection_config, catalog
228
230
  )
229
- elif resource["Name"] == "JAXA_WMTS_PALSAR":
231
+ elif endpoint_config["Name"] == "JAXA_WMTS_PALSAR":
230
232
  # somewhat one off creation of individual WMTS layers as individual items
231
233
  collection = handle_WMS_endpoint(
232
- catalog_config, resource, collection_config, catalog, wmts=True
234
+ catalog_config, endpoint_config, collection_config, catalog, wmts=True
233
235
  )
234
- elif resource["Name"] == "Collection-only":
236
+ elif endpoint_config["Name"] == "Collection-only":
235
237
  collection = handle_collection_only(
236
- catalog_config, resource, collection_config, catalog
238
+ catalog_config, endpoint_config, collection_config, catalog
237
239
  )
238
- elif resource["Name"] == "Custom-Endpoint":
240
+ elif endpoint_config["Name"] == "Custom-Endpoint":
239
241
  collection = handle_custom_endpoint(
240
242
  catalog_config,
241
- resource,
243
+ endpoint_config,
242
244
  collection_config,
243
245
  catalog,
244
246
  )
245
- elif resource["Name"] in ["COG source", "GeoJSON source"]:
247
+ elif endpoint_config["Name"] in ["COG source", "GeoJSON source"]:
246
248
  collection = handle_raw_source(
247
- catalog_config, resource, collection_config, catalog
249
+ catalog_config, endpoint_config, collection_config, catalog
248
250
  )
249
251
  else:
250
252
  raise ValueError("Type of Resource is not supported")
251
253
  if collection:
252
254
  add_single_item_if_collection_empty(collection)
253
- add_projection_info(resource, collection)
254
- add_to_catalog(collection, catalog, resource, collection_config)
255
+ add_projection_info(endpoint_config, collection)
256
+ add_to_catalog(collection, catalog, endpoint_config, collection_config)
255
257
  else:
256
- raise Exception(f"No collection was generated for resource {resource}")
258
+ raise Exception(f"No collection was generated for resource {endpoint_config}")
257
259
  elif "Subcollections" in collection_config:
258
260
  # if no endpoint is specified we check for definition of subcollections
259
261
  parent_collection = get_or_create_collection(
@@ -112,7 +112,8 @@ def create_web_map_link(layer_config: dict, role: str) -> Link:
112
112
  extra_fields["wmts:layer"] = layer_config["layer"]
113
113
  if "dimensions" in layer_config:
114
114
  extra_fields["wmts:dimensions"] = layer_config["dimensions"]
115
-
115
+ if "Attribution" in layer_config:
116
+ extra_fields["attribution"] = layer_config["Attribution"]
116
117
  wml = Link(
117
118
  rel=layer_config["protocol"],
118
119
  target=layer_config["url"],
@@ -347,7 +348,7 @@ def add_base_overlay_info(
347
348
  collection.add_link(create_web_map_link(layer, role="overlay"))
348
349
 
349
350
 
350
- def add_extra_fields(stac_object: Collection | Catalog | Link, collection_config: dict) -> None:
351
+ def add_extra_fields(stac_object: Collection | Link, collection_config: dict) -> None:
351
352
  if "yAxis" in collection_config:
352
353
  stac_object.extra_fields["yAxis"] = collection_config["yAxis"]
353
354
  if "Themes" in collection_config:
@@ -379,7 +380,7 @@ def add_extra_fields(stac_object: Collection | Catalog | Link, collection_config
379
380
  if "Other" in collection_config["DataSource"]:
380
381
  stac_object.extra_fields["otherSources"] = collection_config["DataSource"]["Other"]
381
382
  if "MapProjection" in collection_config:
382
- stac_object.extra_fields["mapProjection"] = collection_config["MapProjection"]
383
+ stac_object.extra_fields["eodash:mapProjection"] = collection_config["MapProjection"]
383
384
 
384
385
 
385
386
  def get_collection_times_from_config(endpoint_config: dict) -> list[str]:
@@ -416,6 +417,6 @@ def add_projection_info(
416
417
  # so we are taking over the DataProjection as is and deal with it in the eodash client
417
418
  # in a non-standard compliant way
418
419
  # https://github.com/proj4js/proj4js/issues/400
419
- stac_object.extra_fields["proj4_def"] = proj
420
+ stac_object.extra_fields["eodash:proj4_def"] = proj
420
421
  else:
421
422
  raise Exception(f"Incorrect type of proj definition {proj}")
@@ -100,7 +100,7 @@ def test_indicator_map_projection_added(catalog_output_folder):
100
100
  with open(os.path.join(root_collection_path, "collection.json")) as fp:
101
101
  indicator_json = json.load(fp)
102
102
  # test that collection has map projection defined
103
- assert indicator_json["mapProjection"] == 3035
103
+ assert indicator_json["eodash:mapProjection"] == 3035
104
104
 
105
105
 
106
106
  def test_baselayers_and_overlays_added(catalog_output_folder):
@@ -120,6 +120,8 @@ def test_baselayers_and_overlays_added(catalog_output_folder):
120
120
  ]
121
121
  assert len(baselayer_links) == 1
122
122
  assert len(overlay_links) == 1
123
+ # test that attribution gets passed to a link dict
124
+ assert "attribution" in baselayer_links[0]
123
125
 
124
126
 
125
127
  def test_geojson_dataset_handled(catalog_output_folder):
@@ -184,4 +186,4 @@ def test_baselayer_with_custom_projection_added(catalog_output_folder):
184
186
  # overwrites default_baselayers, so there is just 1
185
187
  assert len(baselayer_links) == 1
186
188
  # test that custom proj4 definition is added to link
187
- assert baselayer_links[0]["proj4_def"]["name"] == "ORTHO:680500"
189
+ assert baselayer_links[0]["eodash:proj4_def"]["name"] == "ORTHO:680500"
@@ -2,6 +2,5 @@
2
2
  name: EOxCloudless 2022
3
3
  url: '//s2maps-tiles.eu/wmts/1.0.0/s2cloudless-2022_3857/default/g/{z}/{y}/{x}.jpeg'
4
4
  media_type: image/jpeg
5
- attribution: '{ EOxCloudless 2022: <a xmlns:dct="http://purl.org/dc/terms/" href="//s2maps.eu" target="_blank" property="dct:title">Sentinel-2 cloudless - s2maps.eu</a> by <a xmlns:cc="http://creativecommons.org/ns#" href="//eox.at" target="_blank" property="cc:attributionName" rel="cc:attributionURL">EOX IT Services GmbH</a> (Contains modified Copernicus Sentinel data 2022) }'
6
- maxNativeZoom: 17
5
+ Attribution: '{ EOxCloudless 2022: <a xmlns:dct="http://purl.org/dc/terms/" href="//s2maps.eu" target="_blank" property="dct:title">Sentinel-2 cloudless - s2maps.eu</a> by <a xmlns:cc="http://creativecommons.org/ns#" href="//eox.at" target="_blank" property="cc:attributionName" rel="cc:attributionURL">EOX IT Services GmbH</a> (Contains modified Copernicus Sentinel data 2022) }'
7
6
  protocol: 'xyz'
@@ -1,7 +1,6 @@
1
1
  - id: overlay_bright
2
2
  name: 'Overlay labels'
3
3
  url: '//s2maps-tiles.eu/wmts/1.0.0/overlay_base_bright_3857/default/g/{z}/{y}/{x}.png'
4
- attribution: '{ Overlay: Data &copy; <a href="http://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors, Made with Natural Earth, Rendering &copy; <a href="//eox.at" target="_blank">EOX</a> }'
4
+ Attribution: '{ Overlay: Data &copy; <a href="http://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors, Made with Natural Earth, Rendering &copy; <a href="//eox.at" target="_blank">EOX</a> }'
5
5
  visible: true
6
- maxNativeZoom: 14
7
- protocol: 'xyz'
6
+ protocol: 'xyz'