Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ __pycache__
images
examples/debug
examples/release


webapp/data/*
31 changes: 31 additions & 0 deletions webapp/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Road Network Visualization with OpenStreetMap</title>

<!-- Leaflet CSS and JS -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

<!-- D3.js -->
<script src="https://d3js.org/d3.v7.min.js"></script>

<link rel="stylesheet" href="styles.css" />
</head>
<body>

<!-- Map container -->
<div id="map"></div>

<!-- Slider for time step -->
<div class="slider-container">
<label for="timeSlider">Time Step:</label>
<input type="range" id="timeSlider" min="0" step="300" value="0" />
<span id="timeLabel">Time Step: 0</span>
</div>

<script src="script.js"></script>
</body>
</html>
223 changes: 223 additions & 0 deletions webapp/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// Initialize the Leaflet map
const baseZoom = 13;

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const map = L.map('map').setView([44.4949, 11.3426], baseZoom); // Centered on Bologna, Italy

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

// Add OpenStreetMap tile layer with inverted grayscale effect
const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a>'
}).addTo(map);
tileLayer.getContainer().style.filter = 'grayscale(100%) invert(100%)';

// Create an overlay for D3 visualizations
L.svg().addTo(map);
const overlay = d3.select(map.getPanes().overlayPane).select("svg");

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const g = overlay.append("g").attr("class", "leaflet-zoom-hide");

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

let nodes, edges, densities;

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
let timeStep = 0;

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

// Load CSV data for nodes, edges, and densities
Promise.all([
d3.dsv(";", "./data/nodes.csv", parseNodes),
d3.dsv(";", "./data/edges.csv", parseEdges),
d3.dsv(";", "./data/densities.csv", parseDensity)
]).then(([nodesData, edgesData, densityData]) => {

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
nodes = nodesData;
edges = edgesData;
densities = densityData;

// console.log("Nodes:", nodes);
// console.log("Edges:", edges);
// console.log("Densities:", densities);

if (!nodes.length || !edges.length || !densities.length) {
console.error("Missing CSV data.");
return;
}

// Create a map of nodes keyed by their id for quick lookup
const nodeMap = new Map(nodes.map(d => [d.id, d]));

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

// Filter out edges whose nodes do not exist
edges = edges.filter(d => nodeMap.has(d.u) && nodeMap.has(d.v));

// Create a color scale for density values using three color stops
const colorScale = d3.scaleLinear()

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
.domain([0, 0.5, 1])
.range(["green", "yellow", "red"]);

// Function to project geographic coordinates into Leaflet's layer point coordinates
function project(d) {
return map.latLngToLayerPoint([d.lat, d.lon]);
}

// D3 line generator to draw paths
const lineGenerator = d3.line()

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
.x(d => d[0])
.y(d => d[1]);

// Draw edges as SVG paths
const link = g.selectAll("path")

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
.data(edges)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-dasharray", d =>
d.name.toLowerCase().includes("autostrada") ? "4,4" : "none"
)
.style("pointer-events", "all")
.style("cursor", "pointer")
.on("click", function(event, d) {
const densityData = densities.find(row => row.time === timeStep);

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const densityValue = densityData ? densityData.densities[edges.indexOf(d)] : "N/A";

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
alert(`Edge ID: ${d.id} - from ${d.source_id} to ${d.target_id}.\n\nDensity at time step ${timeStep}: ${densityValue}`);
});


// Draw nodes as SVG circles
const node = g.selectAll("circle")

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
.data(nodes)
.enter()
.append("circle")
.attr("fill", "blue")
.style("cursor", "pointer")
.on("click", function(event, d) {
alert(`Node ID: ${d.id}`);
});

// Function to update node and edge positions, and color edges based on density
function update() {
// Project nodes to current map coordinates
nodes.forEach(d => d.projected = project(d));

// Update edge paths
link.attr("d", d => {
if (d.geometry && d.geometry.length > 0) {
const projectedCoords = d.geometry.map(pt => {

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const point = map.latLngToLayerPoint([pt.lat, pt.lon]);

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
return [point.lat, point.lon];
});
return lineGenerator(projectedCoords);
} else {
// Fallback: draw a straight line between the two nodes
const start = project(nodeMap.get(d.source_id));

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const end = project(nodeMap.get(d.target_id));

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
return lineGenerator([[start.lon, start.lat], [end.lon, end.lat]]);
}
});

// Update node positions
node.attr("cx", d => d.projected.lon)
.attr("cy", d => d.projected.lat);


// Update node radius based on zoom level
function updateNodeRadius() {
const zoomLevel = map.getZoom();

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const radiusScale = 3 + (zoomLevel - baseZoom);

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
node.attr("r", radiusScale);
}
// Update edge stroke width based on zoom level
function updateEdgeStrokeWidth() {
const zoomLevel = map.getZoom();

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const strokeWidthScale = 3 + (zoomLevel - baseZoom);

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
link.attr("stroke-width", strokeWidthScale);
}

// Add event listener to map
map.on('zoomend', function() {
updateNodeRadius();
updateEdgeStrokeWidth();
});

// Initial render (default zoom level)
updateNodeRadius();
updateEdgeStrokeWidth();

updateDensityVisualization();
}

map.on("zoomend", update);
update(); // Initial render

// Update edge colors based on the current time step density data
function updateDensityVisualization() {
const currentDensityRow = densities.find(d => d.time === timeStep);

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
if (!currentDensityRow) {
console.error("No density data for time step:", timeStep);
return;
}
const currentDensities = currentDensityRow.densities;

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

// For each edge, update the stroke color based on its density value
edges.forEach((edge, index) => {
let density = currentDensities[index];

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
if (density === undefined || isNaN(density)) {
console.warn(`Edge index ${index} has invalid density. Defaulting to 0.`);
density = 0;
}
const color = colorScale(density);

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
link.filter((d, i) => i === index)
.attr("stroke", color);
});
}

// Set up the time slider based on the density data's maximum time value
const maxTimeStep = d3.max(densities, d => d.time);

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const timeSlider = document.getElementById('timeSlider');

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
const timeLabel = document.getElementById('timeLabel');

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
// Round up max to the nearest 300 for step consistency
timeSlider.max = Math.ceil(maxTimeStep / 300) * 300;
timeSlider.step = 300;
timeLabel.textContent = `Time Step: ${timeStep}`;

// Update the visualization when the slider value changes
timeSlider.addEventListener('input', function() {
timeStep = parseInt(timeSlider.value);
timeLabel.textContent = `Time Step: ${timeStep}`;
update();
});
}).catch(error => {
console.error("Error loading CSV files:", error);
});

// Parsing function for nodes CSV
function parseNodes(d) {
return {
id: d.id,
x: +d.lon, // Longitude
y: +d.lat // Latitude
};
}

// Parsing function for edges CSV, including geometry parsing
function parseEdges(d) {
let geometry = [];
if (d.geometry) {
const coordsStr = d.geometry.replace(/^LINESTRING\s*\(/, '').replace(/\)$/, '');
geometry = coordsStr.split(",").map(coordStr => {
const coords = coordStr.trim().split(/\s+/);
return { x: +coords[0], y: +coords[1] };
});
}
return {
osm_id: d.id,
u: d.source,
v: d.target,
name: d.name,
geometry: geometry
};
}

// Parsing function for density CSV
function parseDensity(d) {
const time = +d.time;
const densities = Object.keys(d)
.filter(key => key !== 'time')
.map(key => {
const val = d[key] ? d[key].trim() : "";
return val === "" ? 0 : +val;
});
return { time, densities };
}
46 changes: 46 additions & 0 deletions webapp/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
body, html {

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected newline after "," (selector-list-comma-newline-after) Warning

Expected newline after "," (selector-list-comma-newline-after)

Check warning

Code scanning / Csslint (reported by Codacy)

Rule doesn't have all its properties in alphabetical order. Warning

Rule doesn't have all its properties in alphabetical order.
margin: 0;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
padding: 0;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
width: 100%;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
height: 100%;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
}

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Stylelint (reported by Codacy)

Unexpected whitespace at end of line (no-eol-whitespace) Warning

Unexpected whitespace at end of line (no-eol-whitespace)
/* Fullscreen map */

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)
#map {

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check notice

Code scanning / Csslint (reported by Codacy)

Don't use IDs in selectors. Note

Don't use IDs in selectors.

Check warning

Code scanning / Csslint (reported by Codacy)

Rule doesn't have all its properties in alphabetical order. Warning

Rule doesn't have all its properties in alphabetical order.
width: 100%;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
height: 100vh;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
position: absolute;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
top: 0;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
left: 0;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
}

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Stylelint (reported by Codacy)

Unexpected whitespace at end of line (no-eol-whitespace) Warning

Unexpected whitespace at end of line (no-eol-whitespace)
/* Slider container */

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)
.slider-container {

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Csslint (reported by Codacy)

Rule doesn't have all its properties in alphabetical order. Warning

Rule doesn't have all its properties in alphabetical order.
position: absolute;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
bottom: 20px;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
left: 50%;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
transform: translateX(-50%);

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
z-index: 1000;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
width: 80%;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
padding: 10px;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)

Check notice

Code scanning / Csslint (reported by Codacy)

Using width with padding can sometimes make elements larger than you expect. Note

Using width with padding can sometimes make elements larger than you expect.
background: rgba(255, 255, 255, 0.8);

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)

Check notice

Code scanning / Csslint (reported by Codacy)

Fallback background (hex or RGB) should precede RGBA background. Note

Fallback background (hex or RGB) should precede RGBA background.
}

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Stylelint (reported by Codacy)

Unexpected whitespace at end of line (no-eol-whitespace) Warning

Unexpected whitespace at end of line (no-eol-whitespace)
.slider-container input {

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)
width: 100%;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
}

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Stylelint (reported by Codacy)

Unexpected whitespace at end of line (no-eol-whitespace) Warning

Unexpected whitespace at end of line (no-eol-whitespace)
/* SVG container on top of Leaflet */

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)
.leaflet-overlay-pane svg {

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)
position: absolute;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
}

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)
.leaflet-zoom-hide {

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected empty line before rule (rule-empty-line-before) Warning

Expected empty line before rule (rule-empty-line-before)
pointer-events: auto;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
}

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Stylelint (reported by Codacy)

Unexpected whitespace at end of line (no-eol-whitespace) Warning

Unexpected whitespace at end of line (no-eol-whitespace)
circle {

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)
fill: black;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
stroke: white;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
stroke-width: 1;

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 2 spaces (indentation) Warning

Expected indentation of 2 spaces (indentation)
}

Check warning

Code scanning / Stylelint (reported by Codacy)

Expected indentation of 0 spaces (indentation) Warning

Expected indentation of 0 spaces (indentation)

Check warning

Code scanning / Stylelint (reported by Codacy)

Unexpected whitespace at end of line (no-eol-whitespace) Warning

Unexpected whitespace at end of line (no-eol-whitespace)

Check warning

Code scanning / Stylelint (reported by Codacy)

Unexpected missing end-of-source newline (no-missing-end-of-source-newline) Warning

Unexpected missing end-of-source newline (no-missing-end-of-source-newline)
Loading