666 lines
24 KiB
HTML
666 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SDG Network Viz 2: Environmental Indicators Network</title>
|
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 20px;
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
border-radius: 12px;
|
|
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.header {
|
|
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
|
|
color: white;
|
|
padding: 30px;
|
|
text-align: center;
|
|
}
|
|
|
|
.header h1 {
|
|
margin: 0 0 10px 0;
|
|
font-size: 2.5em;
|
|
font-weight: 300;
|
|
}
|
|
|
|
.header p {
|
|
margin: 0;
|
|
opacity: 0.9;
|
|
font-size: 1.1em;
|
|
}
|
|
|
|
#network {
|
|
background: #f8f9fa;
|
|
position: relative;
|
|
}
|
|
|
|
.controls {
|
|
padding: 20px 30px;
|
|
background: #ecf0f1;
|
|
border-bottom: 2px solid #bdc3c7;
|
|
display: flex;
|
|
gap: 20px;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.controls label {
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
}
|
|
|
|
.controls select, .controls button {
|
|
padding: 8px 16px;
|
|
border: 2px solid #3498db;
|
|
border-radius: 6px;
|
|
background: white;
|
|
color: #2c3e50;
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.controls button {
|
|
background: #3498db;
|
|
color: white;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.controls button:hover {
|
|
background: #2980b9;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
.controls select:hover {
|
|
border-color: #2980b9;
|
|
}
|
|
|
|
.legend {
|
|
padding: 20px 30px;
|
|
background: white;
|
|
border-top: 2px solid #ecf0f1;
|
|
}
|
|
|
|
.legend h3 {
|
|
margin: 0 0 15px 0;
|
|
color: #2c3e50;
|
|
font-size: 1.3em;
|
|
}
|
|
|
|
.legend-section {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.legend-section h4 {
|
|
margin: 0 0 10px 0;
|
|
color: #34495e;
|
|
font-size: 1em;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.legend-items {
|
|
display: flex;
|
|
gap: 20px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.legend-color {
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 50%;
|
|
border: 2px solid #34495e;
|
|
}
|
|
|
|
.legend-size {
|
|
border-radius: 50%;
|
|
border: 2px solid #34495e;
|
|
background: #95a5a6;
|
|
}
|
|
|
|
.tooltip {
|
|
position: absolute;
|
|
background: rgba(44, 62, 80, 0.95);
|
|
color: white;
|
|
padding: 12px 16px;
|
|
border-radius: 8px;
|
|
pointer-events: none;
|
|
font-size: 13px;
|
|
line-height: 1.6;
|
|
opacity: 0;
|
|
transition: opacity 0.3s;
|
|
max-width: 300px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
|
|
z-index: 1000;
|
|
}
|
|
|
|
.tooltip.visible {
|
|
opacity: 1;
|
|
}
|
|
|
|
.tooltip strong {
|
|
color: #3498db;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.links line {
|
|
stroke-opacity: 0.6;
|
|
}
|
|
|
|
.nodes circle {
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.nodes circle:hover {
|
|
stroke-width: 4px;
|
|
filter: brightness(1.2);
|
|
}
|
|
|
|
.nodes text {
|
|
pointer-events: none;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-shadow: 1px 1px 2px white, -1px -1px 2px white;
|
|
}
|
|
|
|
.footer {
|
|
padding: 25px 30px;
|
|
background: #34495e;
|
|
color: white;
|
|
line-height: 1.8;
|
|
}
|
|
|
|
.footer h3 {
|
|
margin: 0 0 10px 0;
|
|
color: #3498db;
|
|
font-size: 1.2em;
|
|
}
|
|
|
|
.footer p {
|
|
margin: 5px 0;
|
|
}
|
|
|
|
.footer strong {
|
|
color: #ecf0f1;
|
|
}
|
|
|
|
.loading {
|
|
text-align: center;
|
|
padding: 40px;
|
|
font-size: 1.2em;
|
|
color: #7f8c8d;
|
|
}
|
|
|
|
.spinner {
|
|
border: 4px solid #ecf0f1;
|
|
border-top: 4px solid #3498db;
|
|
border-radius: 50%;
|
|
width: 40px;
|
|
height: 40px;
|
|
animation: spin 1s linear infinite;
|
|
margin: 20px auto;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>Environmental Indicators Network</h1>
|
|
<p>Climate & Environment Data from World Bank Open Data API</p>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<label for="yearSelect">Year:</label>
|
|
<select id="yearSelect">
|
|
<option value="2020">2020</option>
|
|
<option value="2019">2019</option>
|
|
<option value="2018">2018</option>
|
|
<option value="2017">2017</option>
|
|
<option value="2016">2016</option>
|
|
</select>
|
|
|
|
<label for="regionSelect">Region Focus:</label>
|
|
<select id="regionSelect">
|
|
<option value="all">All Regions</option>
|
|
<option value="asia">Asia & Pacific</option>
|
|
<option value="europe">Europe & Central Asia</option>
|
|
<option value="africa">Africa</option>
|
|
<option value="americas">Americas</option>
|
|
</select>
|
|
|
|
<button id="resetBtn">Reset View</button>
|
|
</div>
|
|
|
|
<div id="network">
|
|
<div class="loading">
|
|
<div class="spinner"></div>
|
|
Loading environmental data from World Bank API...
|
|
</div>
|
|
</div>
|
|
|
|
<div class="legend">
|
|
<h3>Legend</h3>
|
|
<div class="legend-section">
|
|
<h4>Node Colors (Indicator Categories)</h4>
|
|
<div class="legend-items" id="colorLegend"></div>
|
|
</div>
|
|
<div class="legend-section">
|
|
<h4>Node Sizes (Data Magnitude)</h4>
|
|
<div class="legend-items">
|
|
<div class="legend-item">
|
|
<div class="legend-size" style="width: 10px; height: 10px;"></div>
|
|
<span>Low values</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<div class="legend-size" style="width: 18px; height: 18px;"></div>
|
|
<span>Medium values</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<div class="legend-size" style="width: 26px; height: 26px;"></div>
|
|
<span>High values</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="legend-section">
|
|
<h4>Edge Width (Correlation Strength)</h4>
|
|
<div class="legend-items">
|
|
<div class="legend-item">
|
|
<svg width="60" height="4"><line x1="0" y1="2" x2="60" y2="2" stroke="#95a5a6" stroke-width="1"/></svg>
|
|
<span>Weak correlation</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<svg width="60" height="6"><line x1="0" y1="3" x2="60" y2="3" stroke="#95a5a6" stroke-width="3"/></svg>
|
|
<span>Moderate correlation</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<svg width="60" height="8"><line x1="0" y1="4" x2="60" y2="4" stroke="#95a5a6" stroke-width="5"/></svg>
|
|
<span>Strong correlation</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<h3>Data Source & Learning Documentation</h3>
|
|
<p><strong>API Source:</strong> World Bank Open Data API (https://api.worldbank.org/v2/)</p>
|
|
<p><strong>Indicators:</strong> CO2 Emissions (EN.ATM.CO2E.PC), Forest Area (AG.LND.FRST.ZS), Renewable Energy (EG.FEC.RNEW.ZS), Access to Electricity (EG.ELC.ACCS.ZS), PM2.5 Air Pollution (EN.ATM.PM25.MC.M3)</p>
|
|
<p><strong>Web Learning Source:</strong> https://d3-graph-gallery.com/network.html</p>
|
|
<p><strong>Techniques Applied:</strong></p>
|
|
<ul style="margin: 5px 0; padding-left: 20px;">
|
|
<li><strong>Color Scales:</strong> d3.scaleOrdinal() with d3.schemeCategory10 for categorical indicator types</li>
|
|
<li><strong>Node Sizing:</strong> d3.scaleLinear() for proportional sizing based on data magnitude (5-25px range)</li>
|
|
<li><strong>Force Simulation:</strong> Multi-body forces, link forces, collision detection, and centering</li>
|
|
<li><strong>Visual Encodings:</strong> Size encodes value, color encodes category, edge width encodes correlation strength</li>
|
|
<li><strong>Edge Styling:</strong> Curved paths with variable stroke-width based on relationship strength</li>
|
|
<li><strong>Interactivity:</strong> Drag simulation, hover tooltips with rich data, zoom/pan behavior</li>
|
|
</ul>
|
|
<p><strong>Network Structure:</strong> Countries as nodes, environmental indicator correlations as edges. Nodes sized by normalized indicator values, colored by indicator category, connected when indicators show regional correlations.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tooltip" id="tooltip"></div>
|
|
|
|
<script>
|
|
// Configuration
|
|
const width = 1400;
|
|
const height = 800;
|
|
|
|
// Color scale for indicator categories (d3.scaleOrdinal learned from web source)
|
|
const colorScale = d3.scaleOrdinal()
|
|
.domain(['Climate', 'Energy', 'Forest', 'Pollution', 'Other'])
|
|
.range(['#e74c3c', '#f39c12', '#27ae60', '#8e44ad', '#3498db']);
|
|
|
|
// Node size scale (d3.scaleLinear learned from web source)
|
|
const sizeScale = d3.scaleLinear()
|
|
.domain([0, 100])
|
|
.range([5, 25]);
|
|
|
|
// Edge width scale
|
|
const edgeWidthScale = d3.scaleLinear()
|
|
.domain([0, 1])
|
|
.range([1, 5]);
|
|
|
|
// Environmental indicators from World Bank API
|
|
const indicators = [
|
|
{ code: 'EN.ATM.CO2E.PC', name: 'CO2 Emissions (metric tons per capita)', category: 'Climate' },
|
|
{ code: 'AG.LND.FRST.ZS', name: 'Forest Area (% of land)', category: 'Forest' },
|
|
{ code: 'EG.FEC.RNEW.ZS', name: 'Renewable Energy (% of total)', category: 'Energy' },
|
|
{ code: 'EG.ELC.ACCS.ZS', name: 'Access to Electricity (% of population)', category: 'Energy' },
|
|
{ code: 'EN.ATM.PM25.MC.M3', name: 'PM2.5 Air Pollution (μg/m³)', category: 'Pollution' }
|
|
];
|
|
|
|
// Selected countries for network
|
|
const countries = [
|
|
{ code: 'USA', name: 'United States', region: 'americas' },
|
|
{ code: 'CHN', name: 'China', region: 'asia' },
|
|
{ code: 'IND', name: 'India', region: 'asia' },
|
|
{ code: 'BRA', name: 'Brazil', region: 'americas' },
|
|
{ code: 'DEU', name: 'Germany', region: 'europe' },
|
|
{ code: 'GBR', name: 'United Kingdom', region: 'europe' },
|
|
{ code: 'JPN', name: 'Japan', region: 'asia' },
|
|
{ code: 'ZAF', name: 'South Africa', region: 'africa' },
|
|
{ code: 'KEN', name: 'Kenya', region: 'africa' },
|
|
{ code: 'AUS', name: 'Australia', region: 'asia' },
|
|
{ code: 'CAN', name: 'Canada', region: 'americas' },
|
|
{ code: 'FRA', name: 'France', region: 'europe' },
|
|
{ code: 'IDN', name: 'Indonesia', region: 'asia' },
|
|
{ code: 'MEX', name: 'Mexico', region: 'americas' },
|
|
{ code: 'NGA', name: 'Nigeria', region: 'africa' }
|
|
];
|
|
|
|
// Create color legend
|
|
const colorLegend = d3.select('#colorLegend');
|
|
colorScale.domain().forEach(category => {
|
|
const item = colorLegend.append('div')
|
|
.attr('class', 'legend-item');
|
|
item.append('div')
|
|
.attr('class', 'legend-color')
|
|
.style('background-color', colorScale(category));
|
|
item.append('span').text(category);
|
|
});
|
|
|
|
// Tooltip
|
|
const tooltip = d3.select('#tooltip');
|
|
|
|
// Main data fetching and visualization
|
|
async function fetchIndicatorData(indicatorCode, year) {
|
|
const countryCodes = countries.map(c => c.code).join(';');
|
|
const url = `https://api.worldbank.org/v2/country/${countryCodes}/indicator/${indicatorCode}?date=${year}&format=json&per_page=100`;
|
|
|
|
try {
|
|
const response = await fetch(url);
|
|
const data = await response.json();
|
|
return data[1] || []; // World Bank API returns [metadata, data]
|
|
} catch (error) {
|
|
console.error(`Error fetching ${indicatorCode}:`, error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async function buildNetworkData(year) {
|
|
// Fetch all indicator data
|
|
const allData = {};
|
|
|
|
for (const indicator of indicators) {
|
|
const data = await fetchIndicatorData(indicator.code, year);
|
|
allData[indicator.code] = data;
|
|
}
|
|
|
|
// Build nodes (countries with their indicator values)
|
|
const nodes = [];
|
|
const countryData = {};
|
|
|
|
countries.forEach(country => {
|
|
const nodeData = {
|
|
id: country.code,
|
|
name: country.name,
|
|
region: country.region,
|
|
indicators: {}
|
|
};
|
|
|
|
indicators.forEach(indicator => {
|
|
const countryIndicator = allData[indicator.code].find(d => d.countryiso3code === country.code);
|
|
if (countryIndicator && countryIndicator.value !== null) {
|
|
nodeData.indicators[indicator.code] = {
|
|
value: countryIndicator.value,
|
|
name: indicator.name,
|
|
category: indicator.category
|
|
};
|
|
}
|
|
});
|
|
|
|
// Calculate average indicator value for node sizing
|
|
const values = Object.values(nodeData.indicators).map(i => i.value);
|
|
nodeData.avgValue = values.length > 0 ? d3.mean(values) : 0;
|
|
|
|
// Assign primary category based on most significant indicator
|
|
const primaryIndicator = Object.entries(nodeData.indicators)
|
|
.sort((a, b) => b[1].value - a[1].value)[0];
|
|
nodeData.category = primaryIndicator ? primaryIndicator[1].category : 'Other';
|
|
|
|
nodes.push(nodeData);
|
|
countryData[country.code] = nodeData;
|
|
});
|
|
|
|
// Build edges (correlations between countries based on similar indicator patterns)
|
|
const links = [];
|
|
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
const node1 = nodes[i];
|
|
const node2 = nodes[j];
|
|
|
|
// Calculate correlation based on shared indicators
|
|
const sharedIndicators = Object.keys(node1.indicators).filter(
|
|
k => node2.indicators[k] !== undefined
|
|
);
|
|
|
|
if (sharedIndicators.length >= 2) {
|
|
// Simple correlation: inverse of average difference
|
|
const differences = sharedIndicators.map(k => {
|
|
const v1 = node1.indicators[k].value;
|
|
const v2 = node2.indicators[k].value;
|
|
return Math.abs(v1 - v2) / Math.max(v1, v2, 1);
|
|
});
|
|
|
|
const avgDiff = d3.mean(differences);
|
|
const correlation = Math.max(0, 1 - avgDiff);
|
|
|
|
// Only add edges with meaningful correlation
|
|
if (correlation > 0.3) {
|
|
links.push({
|
|
source: node1.id,
|
|
target: node2.id,
|
|
strength: correlation,
|
|
sharedCount: sharedIndicators.length
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return { nodes, links };
|
|
}
|
|
|
|
function createVisualization(data) {
|
|
// Clear existing visualization
|
|
d3.select('#network').html('');
|
|
|
|
// Create SVG with zoom behavior
|
|
const svg = d3.select('#network')
|
|
.append('svg')
|
|
.attr('width', width)
|
|
.attr('height', height)
|
|
.attr('viewBox', [0, 0, width, height]);
|
|
|
|
// Add zoom behavior
|
|
const g = svg.append('g');
|
|
|
|
const zoom = d3.zoom()
|
|
.scaleExtent([0.5, 3])
|
|
.on('zoom', (event) => {
|
|
g.attr('transform', event.transform);
|
|
});
|
|
|
|
svg.call(zoom);
|
|
|
|
// Force simulation (learned from web source)
|
|
const simulation = d3.forceSimulation(data.nodes)
|
|
.force('link', d3.forceLink(data.links)
|
|
.id(d => d.id)
|
|
.distance(100)
|
|
.strength(d => d.strength * 0.5))
|
|
.force('charge', d3.forceManyBody()
|
|
.strength(-400))
|
|
.force('center', d3.forceCenter(width / 2, height / 2))
|
|
.force('collision', d3.forceCollide()
|
|
.radius(d => sizeScale(d.avgValue) + 5));
|
|
|
|
// Draw edges (curved paths for visual appeal)
|
|
const link = g.append('g')
|
|
.attr('class', 'links')
|
|
.selectAll('path')
|
|
.data(data.links)
|
|
.join('path')
|
|
.attr('stroke', '#95a5a6')
|
|
.attr('stroke-width', d => edgeWidthScale(d.strength))
|
|
.attr('fill', 'none')
|
|
.attr('opacity', 0.6);
|
|
|
|
// Draw nodes
|
|
const node = g.append('g')
|
|
.attr('class', 'nodes')
|
|
.selectAll('g')
|
|
.data(data.nodes)
|
|
.join('g')
|
|
.call(drag(simulation));
|
|
|
|
// Node circles with color scale and size scale
|
|
node.append('circle')
|
|
.attr('r', d => sizeScale(d.avgValue))
|
|
.attr('fill', d => colorScale(d.category))
|
|
.attr('stroke', '#2c3e50')
|
|
.attr('stroke-width', 2);
|
|
|
|
// Node labels
|
|
node.append('text')
|
|
.attr('dx', d => sizeScale(d.avgValue) + 5)
|
|
.attr('dy', 4)
|
|
.text(d => d.name)
|
|
.attr('fill', '#2c3e50');
|
|
|
|
// Hover interactions
|
|
node.on('mouseover', function(event, d) {
|
|
d3.select(this).select('circle')
|
|
.attr('stroke-width', 4);
|
|
|
|
// Create rich tooltip content
|
|
let tooltipHTML = `<strong>${d.name}</strong><br>`;
|
|
tooltipHTML += `Region: ${d.region}<br>`;
|
|
tooltipHTML += `Category: ${d.category}<br><br>`;
|
|
tooltipHTML += `<strong>Environmental Indicators:</strong><br>`;
|
|
|
|
Object.entries(d.indicators).forEach(([code, info]) => {
|
|
tooltipHTML += `• ${info.name}: ${info.value.toFixed(2)}<br>`;
|
|
});
|
|
|
|
tooltip.html(tooltipHTML)
|
|
.style('left', (event.pageX + 10) + 'px')
|
|
.style('top', (event.pageY - 10) + 'px')
|
|
.classed('visible', true);
|
|
})
|
|
.on('mouseout', function() {
|
|
d3.select(this).select('circle')
|
|
.attr('stroke-width', 2);
|
|
|
|
tooltip.classed('visible', false);
|
|
});
|
|
|
|
// Update positions on simulation tick
|
|
simulation.on('tick', () => {
|
|
link.attr('d', d => {
|
|
// Curved path for edges
|
|
const dx = d.target.x - d.source.x;
|
|
const dy = d.target.y - d.source.y;
|
|
const dr = Math.sqrt(dx * dx + dy * dy) * 2;
|
|
return `M${d.source.x},${d.source.y}A${dr},${dr} 0 0,1 ${d.target.x},${d.target.y}`;
|
|
});
|
|
|
|
node.attr('transform', d => `translate(${d.x},${d.y})`);
|
|
});
|
|
}
|
|
|
|
// Drag behavior for nodes
|
|
function drag(simulation) {
|
|
function dragstarted(event) {
|
|
if (!event.active) simulation.alphaTarget(0.3).restart();
|
|
event.subject.fx = event.subject.x;
|
|
event.subject.fy = event.subject.y;
|
|
}
|
|
|
|
function dragged(event) {
|
|
event.subject.fx = event.x;
|
|
event.subject.fy = event.y;
|
|
}
|
|
|
|
function dragended(event) {
|
|
if (!event.active) simulation.alphaTarget(0);
|
|
event.subject.fx = null;
|
|
event.subject.fy = null;
|
|
}
|
|
|
|
return d3.drag()
|
|
.on('start', dragstarted)
|
|
.on('drag', dragged)
|
|
.on('end', dragended);
|
|
}
|
|
|
|
// Initialize visualization
|
|
let currentData = null;
|
|
|
|
async function loadData() {
|
|
const year = document.getElementById('yearSelect').value;
|
|
const data = await buildNetworkData(year);
|
|
currentData = data;
|
|
createVisualization(data);
|
|
}
|
|
|
|
// Event listeners
|
|
document.getElementById('yearSelect').addEventListener('change', loadData);
|
|
|
|
document.getElementById('regionSelect').addEventListener('change', () => {
|
|
const region = document.getElementById('regionSelect').value;
|
|
if (!currentData) return;
|
|
|
|
let filteredData;
|
|
if (region === 'all') {
|
|
filteredData = currentData;
|
|
} else {
|
|
const filteredNodes = currentData.nodes.filter(n => n.region === region);
|
|
const nodeIds = new Set(filteredNodes.map(n => n.id));
|
|
const filteredLinks = currentData.links.filter(l =>
|
|
nodeIds.has(l.source.id || l.source) && nodeIds.has(l.target.id || l.target)
|
|
);
|
|
filteredData = { nodes: filteredNodes, links: filteredLinks };
|
|
}
|
|
|
|
createVisualization(filteredData);
|
|
});
|
|
|
|
document.getElementById('resetBtn').addEventListener('click', () => {
|
|
document.getElementById('yearSelect').value = '2020';
|
|
document.getElementById('regionSelect').value = 'all';
|
|
loadData();
|
|
});
|
|
|
|
// Load initial data
|
|
loadData();
|
|
</script>
|
|
</body>
|
|
</html>
|