Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
73c87cd
Add format-selection decision framework page and case studies
emmanuelmathot Aug 3, 2026
7e37124
Link cng-formats-benchmark as the quantitative enabler
emmanuelmathot Aug 3, 2026
cd12599
Reframe the second size lesson around overviews and indexes
emmanuelmathot Aug 3, 2026
0d3e0d2
Expand ecosystem maturity with an explicit scale and the Zarr/GeoZarr…
emmanuelmathot Aug 4, 2026
69e2a2f
Update .gitignore to exclude Quarto notebook files and enhance clarit…
emmanuelmathot Aug 4, 2026
ef5b027
Enhance decision framework documentation by clarifying intent categor…
emmanuelmathot Aug 4, 2026
37a076d
Update decision-framework/index.qmd
emmanuelmathot Aug 5, 2026
ae6dbd5
Update decision-framework/index.qmd
emmanuelmathot Aug 5, 2026
6904983
Update decision-framework/index.qmd
emmanuelmathot Aug 5, 2026
4413be7
Refine decision framework by clarifying the two-stage process for for…
emmanuelmathot Aug 5, 2026
fc422dc
Enhance decision framework documentation by adding key terms and clar…
emmanuelmathot Aug 5, 2026
b9a385e
Clarify terminology and references in decision framework documentatio…
emmanuelmathot Aug 5, 2026
c0b8e41
Clarify decision framework by refining terminology and adding detaile…
emmanuelmathot Aug 5, 2026
a579973
Refine decision framework documentation by clarifying the interpretat…
emmanuelmathot Aug 5, 2026
f908d81
Enhance decision framework by expanding format family options for dat…
emmanuelmathot Aug 6, 2026
559c35f
Clarify decision framework by distinguishing between size and shape o…
emmanuelmathot Aug 6, 2026
a9ae111
Clarify terminology in decision framework by correcting pluralization…
emmanuelmathot Aug 6, 2026
2edda05
Clarify decision framework terminology by updating "unlock this" to "…
emmanuelmathot Aug 10, 2026
5a3443c
Clarify virtualization limitations in decision framework by updating …
emmanuelmathot Aug 10, 2026
dda3e36
Enhance decision framework by adding a repackage option for existing …
emmanuelmathot Aug 10, 2026
f5d684b
Clarify processing intent in decision framework by enhancing descript…
emmanuelmathot Aug 10, 2026
d9ac010
Update decision-framework/index.qmd
emmanuelmathot Aug 10, 2026
5bd680d
link
emmanuelmathot Aug 10, 2026
94bdb55
Update decision-framework/case-studies.qmd
emmanuelmathot Aug 10, 2026
b2d7ebf
Enhance decision framework documentation by adding access pattern def…
emmanuelmathot Aug 10, 2026
cba7555
Refine case studies in decision framework by adding detailed intent, …
emmanuelmathot Aug 10, 2026
f4e3bf3
Clarify the precedent of HDF5 in the decision framework by detailing …
emmanuelmathot Aug 10, 2026
45d16ca
Enhance case study on spatial indexing by clarifying the three-dimens…
emmanuelmathot Aug 10, 2026
e7fc113
Refine case study on GeoParquet and FlatGeobuf by clarifying download…
emmanuelmathot Aug 10, 2026
754932e
Update decision-framework/index.qmd
emmanuelmathot Aug 10, 2026
d8bc1ac
Update decision-framework/case-studies.qmd
emmanuelmathot Aug 10, 2026
35ecb16
Update decision-framework/case-studies.qmd
emmanuelmathot Aug 10, 2026
c58814f
Clarify product description and virtualization conditions for large i…
emmanuelmathot Aug 10, 2026
55aeb64
Add clarification on data control factors in decision framework
emmanuelmathot Aug 10, 2026
79187c0
Refine definition of "Access pattern" for clarity in glossary and dec…
emmanuelmathot Aug 10, 2026
01e395b
Update decision-framework/case-studies.qmd
emmanuelmathot Aug 10, 2026
eb6b7c3
Update decision-framework/case-studies.qmd
emmanuelmathot Aug 10, 2026
13820f5
Update decision-framework/index.qmd
emmanuelmathot Aug 10, 2026
f92d87e
Update decision-framework/case-studies.qmd
emmanuelmathot Aug 10, 2026
c665686
Update decision-framework/index.qmd
emmanuelmathot Aug 10, 2026
30bba09
Update decision-framework/index.qmd
emmanuelmathot Aug 10, 2026
ad1686f
Clarify example of object-size policy in storage backend section
emmanuelmathot Aug 10, 2026
b9b1327
Clarify the role of shape in format selection and its impact on perfo…
emmanuelmathot Aug 10, 2026
0008534
Clarify terminology by replacing "spine" with "framework" in decision…
emmanuelmathot Aug 10, 2026
5df3ade
Update decision-framework/index.qmd
emmanuelmathot Aug 10, 2026
afb32a0
Clarify terminology by replacing "backend" with "object store" in dec…
emmanuelmathot Aug 10, 2026
1323fa3
Update decision-framework/index.qmd
emmanuelmathot Aug 10, 2026
de216a8
Update decision-framework/case-studies.qmd
emmanuelmathot Aug 10, 2026
315dcc2
Clarify benchmark examples and terminology in case studies section
emmanuelmathot Aug 10, 2026
d142f07
Clarify GeoZarr store description and timing numbers in case studies …
emmanuelmathot Aug 10, 2026
8e04630
Remove benchmark caveat from GeoZarr case study for clarity
emmanuelmathot Aug 10, 2026
3405a29
Update decision-framework/index.qmd
emmanuelmathot Aug 21, 2026
ae41b39
Add clarification on Sentinel-2 multiscale dimensions and enhance ter…
emmanuelmathot Aug 27, 2026
2ad4bee
Clarify decision framework stages and object size policies in documen…
emmanuelmathot Sep 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ __pycache__/
.ipynb_checkpoints

/.luarc.json

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ authors:
family-names: "Barron"
- given-names: "Zachary"
family-names: "Deziel"
- given-names: "Emmanuel"
family-names: "Mathot"
- given-names: "Max"
family-names: "Jones"
- given-names: "Brianna"
Expand Down
9 changes: 9 additions & 0 deletions _quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ website:
text: Welcome
- href: overview.qmd
text: Overview Slides
# NOTE for @abarciauskas-bgse: proposed nav placement only.
# Placed before "Formats" so a reader can pick a format family before
# diving into a format page. Final position depends on the Track-3 site
# redesign - please confirm or move (and rename the path if needed).
- section: Choosing a Format
href: decision-framework/index.qmd
contents:
- decision-framework/index.qmd
- decision-framework/case-studies.qmd
- section: Formats
contents:
- section: Cloud Optimized GeoTIFFs (COG)
Expand Down
4 changes: 3 additions & 1 deletion _thankyous.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ This guide has been made possible through the support of:
[![](./images/thankyous-devseed-logo.png){fig-alt="Development Seed Logo" fig-align="left" width=40%}](https://developmentseed.org)

[![](./images/thankyous-cng-logo.png){fig-alt="Cloud-Native Geospatial Forum" fig-align="left" width=40%}](https://cloudnativegeo.org)
:::
:::

The [Format Selection Decision Framework](./decision-framework/index.qmd) and its case studies were contributed from a study for the [Centre National d'Études Spatiales (CNES)](https://cnes.fr/), and use public [Copernicus](https://www.copernicus.eu/) and [NASA](https://www.earthdata.nasa.gov/) mission data.
147 changes: 147 additions & 0 deletions decision-framework/case-studies.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: "Decision Framework Case Studies"
subtitle: "Six products run through the framework, five of them backed by measurements"
---

Each case study below runs a real product through the [decision framework](index.qmd). It shows where the product lands and why. Five of the six are backed by **measured benchmark results**.

Read each case in two parts:
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

1. **The path through the spine**: the control fork, the topology gate, then intent, the object-size lever, and maturity.
2. **What the measurement showed.**
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

The examples use public Copernicus and NASA missions. The [CNES Datalake](https://cnes.fr/en/projects/centre-de-calcul) appears as one worked example of a tiered object store. It is not the only kind of backend, and its tier numbers are not a general rule.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

::: {.callout-important}
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved
## The recurring lesson
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

**Going cloud-optimized is rarely smaller than the source you started from.**
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

What it buys you is partial access, a spatial index, or a level of detail. Where two cloud-optimized candidates *do* differ in size, the cause is usually the **codec**, not the format.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do these thresholds work -- is the mean object size per bucket or some other grouping unit? And you don't have a choice, if you have mean objects of 32 MB or smaller, all those objects are in warm storage and if you have mean object size of greater than 32 MB its in cold storage? Or just greater than 100MB? Then what happens inbetween 32 and 100 MB?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I realise our wording cause the confusion. "Sorts data into tiers" makes the process sound automatic and it is not the case.

The Datalake is an in-house S3 service with a lifecycle policy that moves data between disk and tape. Each tier has a recommended minimum mean object size: about 32 MB for disk, and about 100 MB for tape. The check is mechanical. The system divides the total volume by the object count, then compares the result to the floor for the tier.

  • A larger mean object size makes your data eligible for more tiers. It never moves your data to a colder tier.
  • Between 32 MB and 100 MB, the data is suitable for disk but not for tape.
    Below 32 MB is the failure case. The penalty is not the tier. Too many small objects fill the object index table before the disk capacity is full. The Datalake then cannot supply its pooled volume to any project, even when much disk space remains.
  • That last point is the real motivation, and it is much stronger than "tiers", so I will rewrite the paragraph around it. In CNES, floors are advisory, not enforced.

A second element explains much of the gap: **the extra bytes are the feature.** Overviews, levels of detail, and spatial indexes are structures the source file did not carry at all. They add volume, and they are exactly what buys fast display and cheap subsetting. The COG in case 1 is about 30 % larger than the delivered archive mostly because it carries overviews, and the row-group index in case 4 is the whole point of the conversion.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved
:::

::: {.callout-note}
The numbers below are first measurements on a representative unit per mission, meaning one scene, one tile, or a few granules. They are illustrative, not a published benchmark. Two of the six cases have re-runs pending, and each one says so.

They were produced with [`cng-formats-benchmark`](https://github.com/developmentseed/cng-formats-benchmark), an open-source harness that measures object-size distribution, write, read, and display per format. You can describe your own datasets in its config files and reproduce this shape of comparison on your own data. See [Optional: make it quantitative](index.qmd#optional-make-it-quantitative).
:::

## 1. Per-scene optical raster: COG vs GeoZarr for visualization and distribution

**Product:** Sentinel-2 L2A. **Topology:** 2D raster per scene. **Source format:** geoTiff in a `.zip`. **Candidate set:** `{COG, GeoZarr}`.

**[Intent](index.qmd#intent).** Distribution and visualization. Both are served per scene, which is why this case does not need a cube.

**The path.** Existing data, and the producer operates the processing chain, so this is a free choice. The topology opens `{COG, GeoZarr}` and the [intent](index.qmd#intent) decides between them. Per-scene **distribution and visualization** favors COG. **Time-series analysis** favors a GeoZarr cube. The [grouping lever](index.qmd#the-object-size-and-grouping-lever) is COG internal tiling, or a scene-size Zarr shard.

**Measured, one scene.** Both layouts cleared the warm tier. COG came to 2625.7 MiB in 28 objects. A scene-size GeoZarr shard came to 1975.6 MiB in 26 objects, about 25 % smaller. That gap is the **codec**, Deflate against ZSTD, not the format. Against the 2023.7 MiB delivered `.zip`, the GeoZarr store is about source size (−2 %) and the COG is larger (+30 %), because the COG carries overviews.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

**[Interpretation encoding](index.qmd#interpretation-encoding) is a real differentiator here.** The source reflectance is stored as scaled integers, and the nodata fill is left undeclared. COG puts the scale, the offset, and the nodata in side metadata that readers honor unevenly. Zarr v3 can carry all three as first-class array properties, using the `scale_offset` codec and a declared fill value, so every reader recovers the same physical value.

**Where it lands.** COG per scene for distribution and visualization.

For temporal analysis GeoZarr is the right target, but **the arm measured here does not yet deliver it.** What was written is a scene-size store: one scene, so there is no time dimension to exploit. It proves the container and the encoding, because it comes out at roughly source size and it carries the scale, offset, and nodata correctly. A time-series query against it still has to open one store per date, which is the same fan-out the COG layout has.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

The temporal benefit appears only once many scenes are concatenated along time into a single cube. That is the regime measured in [case 2](#case-time-cube), and it is a collection-level layout decision, not something a scene-size store can give you. Read the per-scene store as a building block and the cube as the product.

The associated masking product, which is written as many small GeoTIFFs, is a clear anti-pattern to fix at the source.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels out of context and why its a clear anti-pattern is not really explained, so we should probably just remove this sentence.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right that the sentence was not very clear. I would prefer to fix it than to delete it, because the finding is real and it connects to the object-size lever.


## 2. Raster time-cube: GeoZarr, with COG as the alternative {#case-time-cube}

**Product:** Sentinel-1 RTC. **Topology:** 2D raster over time. **Source format:** geoTiff in a `.zip`. **Candidate set:** `{COG, GeoZarr}`.

**[Intent](index.qmd#intent).** Advanced analysis and visualization lead, with distribution close behind but weighted a little lower. The analysis half is what separates this case from case 1: it is asked over time, not per scene, and that is what pulls the answer to a cube.

**The path.** Existing data, reprocessable, so a free choice. A year of RTC over a region is naturally a `time × y × x × pol` cube. On a Zarr cube, a time-series slice or an area-of-interest subset is one range-addressable query. Across thousands of per-timestamp COGs, the same request becomes a large fan-out. Sharding reconciles fine-grained chunk access with the backend's preference for large objects.

**Measured, one tile and confirmed at area scale.** COG came to 728 MiB per tile and a scene-size GeoZarr shard to 545 MiB. Both cleared the cold tier. GeoZarr is again about 25 % smaller, and again this is the codec: Deflate at 3.70x against ZSTD at 4.98x. The result held over a 16-tile block, at 16498 MiB for COG and 12344 MiB for GeoZarr. Against the 496 MiB delivered `.zip` both are larger, COG by 47 % and GeoZarr by 10 %. Cloud-optimized costs storage here, and buys the range access that the opaque zip cannot give at all.

::: {.callout-warning}
## A benchmark caveat, not a format verdict

The GeoZarr store read and displayed much slower than the COG, but it was written **with no multiscale overview pyramid**. A store without multiscales is not a faithful GeoZarr, and the missing pyramid is the reason a tile server has to downsample full-resolution chunks on request. The slow read is also in large part a reader effect, from the library used rather than the format.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

Both issues are being fixed for the final campaign, so that display is compared on equal terms. Treat the timing numbers from this arm as provisional.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved
:::

## 3. Point cloud: netCDF to COPC

**Product:** SWOT L2_HR Pixel Cloud. **Topology:** point cloud. **Source format:** netCDF. **Candidate set:** `{COPC, GeoParquet}`.

**[Intent](index.qmd#intent).** Distribution, visualization, and data fusion. The fusion intent is the one that matters most here: these points get combined with other water products, so a reader has to recover the same physical value per point and subset the same area cheaply. That is what makes the missing spatial index in the source a real cost rather than an inconvenience.

**The path.** Existing data, reprocessable, so a free choice. The point-cloud topology gives COPC, which is a clustered octree inside a LAZ file. The netCDF source has no spatial index and no level of detail, so reading a small geographic subset means scanning the whole granule.

**Measured, content-complete, three granules.** A COPC carrying all per-point variables was about 16 % **smaller** than the source netCDF. This is the one clear size win among the cases, and it comes from the codec: LASzip at 3.72x against netCDF Deflate at 2.56x. Each granule cleared the tier on its own.

The real gain is what the netCDF lacks:

- A **spatial index**. A bounding-box query reads only the overlapping octree nodes.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved
- A **level of detail**. Octree levels 0 to 11 are the point-cloud analogue of COG overviews.

::: {.callout-caution}
An earlier measurement on this product looked like a 97 % size saving. It had dropped most of the per-point variables. Size comparisons must be like for like on content.
:::

**Where it lands.** COPC. The cloud-optimized value is partial access plus level of detail, with a modest size win on top. GeoParquet is the alternative where columnar analytics dominate.

## 4. Vector and tabular: shapefile to GeoParquet

**Product:** SWOT L2_HR Lake Single Pass. **Topology:** vector and tabular. **Source format:** shapefile. **Candidate set:** `{GeoParquet, FlatGeobuf}`.

**[Intent](index.qmd#intent).** Distribution, download, and data fusion. Note that visualization is *absent* from this mix, and download is present. That combination is why the answer is not automatically the columnar option: download rewards a single streamable file, which is FlatGeobuf's strength, while fusion rewards cheap joins on a fixed schema, which is GeoParquet's. The fusion weight is what settles it.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

**The path.** Existing data, reprocessable, so a free choice. This is a fixed-schema tabular product, with a lake id, a reach id, water-surface elevation, area, and more. That is the native fit for GeoParquet, with its columns, row groups, and spatial partitioning. A sparse Zarr store would add complexity with no gain.

**Measured, two passes.** GeoParquet came to 17.8 MiB per pass, about 14 % **larger** than the 31.1 MiB zipped shapefile. This surprised reviewers, who expected a binary columnar format to be smaller. The likely cause is the default row-group codec, and it is under investigation.

Each pass sits below the warm-tier floor. The lever is therefore **aggregation across passes**: concatenate first, then size the row groups. A one-for-one transcode of each pass would leave the object-size problem in place. The gain over the shapefile is the bounding-box row-group index, not the size.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit hard to digest without knowing what passes are and more about the data, but maybe that is unavoidable in order to provide a succinct case study. Are there multiple passes per shapefile or is it one per shapefile? Does each pass constitute one Geoparquet row or many?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. One pass is one overflight, and the mission delivers one shapefile per pass. But LakeSP Prior reports the whole prior lake database on every pass, not only the lakes that pass observed, so about 78 % of the rows describe a lake with no observation and carry a NULL geometry. Many rows per pass, and most of them empty. The GeoParquet output keeps the same rows. That fact also drives the aggregation lever: concatenating passes stacks these row sets, and the row groups are sized after that.

I had this wrong in the text and will correct it


**Where it lands.** GeoParquet, with pass-level aggregation. FlatGeobuf is the single-file streaming alternative.

## 5. Small N-D grid: the aggregation regime

**Product:** SWOT L2_HR Raster. **Topology:** N-D grid. **Source format:** geoTiff. **Candidate set:** `{GeoZarr, COG}`.

**[Intent](index.qmd#intent).** Distribution and download, with data fusion against the other SWOT products, and some visualization. This mix is provisional and still to be confirmed with the product owner.

**The path.** Existing data, reprocessable, so a free choice. A 100 m raster granule covers a small tile, about 160 km across.

**Measured, single variable, so not yet like for like.** On the primary water-surface-elevation variable, COG came to 4.3 MiB per granule and a GeoZarr shard to 0.8 MiB on average, because sharding fragments at this size. Both sit far below the warm-tier floor, so the lever is **aggregation**, and at this small size **COG is the cleaner carrier**: one tiled object that also holds overviews. An all-variable re-run is needed before quoting a size, for the same reason as case 3.

The natural aggregation unit is a spatial mosaic, per grid zone and per orbit cycle. That turns a wall of tiny granules into one range-addressable object.

**Where it lands.** COG for the small raster, plus collection-level aggregation. GeoZarr is the alternative to compare once the pyramid and all variables are in place.

This case is the counterpart to cases 1 and 2. There, one large band already clears the tier, so you group *within* a product. Here the products are small, so you group *above* a single product.

## 6. Existing archive to a virtual store

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add an actual example from NASA here, we have many now.


**Topology:** any. **Candidate set:** a virtual Zarr store.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

This case has no benchmark. It illustrates the "existing data, cannot reprocess" branch of the control fork.

An immutable archive, for example HDF5 or netCDF that you cannot reprocess, can be surfaced as a virtual Zarr store with [VirtualiZarr, Kerchunk, or Icechunk](../zarr/virtual-zarr.qmd). This gives range-based access without rewriting the data.

The result is more limited than a native store. Chunk sizes are whatever the source chose, you cannot add overviews, and you inherit the source's codec. It is still much better than whole-file download, and it is often the only option available.

This case is also where the ["unlock this"](index.qmd#dead-ends-are-unlock-this) framing matters. If the source cannot even be virtualized, name what is missing rather than declaring the case impossible.
Comment thread
emmanuelmathot marked this conversation as resolved.
Resolved

## Summary

| Case | Topology | Lands on | Size against source | Main gain |
| --- | --- | --- | --- | --- |
| 1. Optical scene | 2D raster | COG per scene; a cube needs cross-scene aggregation | COG +30 %, GeoZarr −2 % | Partial access, encoding |
| 2. SAR time-cube | Raster over time | GeoZarr v3 sharded | COG +47 %, GeoZarr +10 % | One query instead of a fan-out |
| 3. Pixel cloud | Point cloud | COPC | −16 % | Spatial index, level of detail |
| 4. Lake vector | Vector, tabular | GeoParquet, aggregated | +14 % | Row-group bbox index |
| 5. Small raster grid | N-D grid | COG, plus aggregation | Re-run pending | Fewer, larger objects |
| 6. Frozen archive | Any | Virtual Zarr | No rewrite | Range access with no reprocessing |

Read the size column together with the recurring lesson at the top of this page. Only one case got smaller, and that case got smaller because of its codec.

## Acknowledgements

These case studies come from a study for the [Centre National d'Études Spatiales (CNES)](https://cnes.fr/), carried out by [Development Seed](https://developmentseed.org/). They use public Copernicus and NASA mission data. The measurements were produced with [`cng-formats-benchmark`](https://github.com/developmentseed/cng-formats-benchmark), which is maintained separately from this guide so that its methodological choices stay debatable in their own right. See [Our Supporters](../contributing.qmd#thank-you-to-our-supporters).
Loading
Loading