kolaslab commited on
Commit
3eaa1f4
·
verified ·
1 Parent(s): fd6d094

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +227 -180
index.html CHANGED
@@ -3,7 +3,6 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <title>Global SDR Network Monitor</title>
6
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" />
7
  <style>
8
  body {
9
  margin: 0;
@@ -67,9 +66,9 @@
67
  }
68
 
69
  #map {
70
- height: calc(100vh - 40px);
71
- border-radius: 8px;
72
  background: #111;
 
 
73
  }
74
 
75
  .signal-strength {
@@ -81,9 +80,10 @@
81
 
82
  .signal-bar {
83
  height: 100%;
84
- background: linear-gradient(to right, #00ff00, #00ff00);
85
  width: 0%;
86
  transition: width 0.3s ease-in-out;
 
87
  border-radius: 2px;
88
  }
89
 
@@ -92,79 +92,24 @@
92
  border-left: 3px solid #0f0;
93
  padding: 8px;
94
  margin: 5px 0;
 
95
  border-radius: 0 4px 4px 0;
96
  }
97
 
98
- .leaflet-tile-pane {
99
- filter: invert(1) hue-rotate(180deg);
100
- }
101
-
102
- .leaflet-container {
103
- background: #111 !important;
104
- }
105
-
106
- .leaflet-control-attribution {
107
- background: #222 !important;
108
- color: #666 !important;
109
- }
110
-
111
- .leaflet-popup-content-wrapper,
112
- .leaflet-popup-tip {
113
- background: #222 !important;
114
- color: #0f0 !important;
115
- }
116
-
117
- .station-marker {
118
- border: 2px solid #0f0;
119
- border-radius: 50%;
120
- width: 8px;
121
- height: 8px;
122
- background: transparent;
123
- }
124
-
125
- .station-range {
126
- stroke: #0f0;
127
- stroke-width: 1;
128
- fill: #0f0;
129
- fill-opacity: 0.1;
130
- }
131
-
132
  .signal-line {
133
- stroke: #0f0;
134
- stroke-width: 2px;
135
- stroke-opacity: 0.5;
 
136
  pointer-events: none;
 
137
  animation: signalPulse 2s infinite;
138
  }
139
 
140
  @keyframes signalPulse {
141
- 0% { stroke-opacity: 0.4; }
142
- 50% { stroke-opacity: 0.1; }
143
- 100% { stroke-opacity: 0.4; }
144
- }
145
-
146
- .target-marker {
147
- width: 6px;
148
- height: 6px;
149
- background: #ff0;
150
- border-radius: 50%;
151
- border: 1px solid #fff;
152
- }
153
-
154
- /* Make signal lines more visible */
155
- .leaflet-overlay-pane path {
156
- stroke: #0f0 !important;
157
- stroke-opacity: 0.4 !important;
158
- stroke-width: 2px !important;
159
- animation: signalPulse 2s infinite;
160
- }
161
-
162
- .custom-tooltip {
163
- background: #111 !important;
164
- border: 1px solid #0f0 !important;
165
- border-radius: 4px !important;
166
- padding: 5px !important;
167
- color: #0f0 !important;
168
  }
169
  </style>
170
  </head>
@@ -178,12 +123,11 @@
178
  <div id="detections"></div>
179
  </div>
180
 
181
- <div id="map"></div>
182
  </div>
183
 
184
- <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
185
  <script>
186
- // Global SDR stations data
187
  const sdrStations = [
188
  // Europe
189
  {
@@ -382,47 +326,22 @@
382
 
383
  class RadarSystem {
384
  constructor() {
 
 
385
  this.targets = new Set();
386
- this.markers = new Map();
387
- this.signalLines = new Map();
388
- this.initializeMap();
389
  this.renderReceivers();
390
  this.startTracking();
391
  }
392
 
393
- initializeMap() {
394
- this.map = L.map('map', {
395
- center: [20, 0],
396
- zoom: 3,
397
- preferCanvas: true,
398
- worldCopyJump: true
399
- });
400
-
401
- L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
402
- maxZoom: 19,
403
- attribution: '© OpenStreetMap contributors'
404
- }).addTo(this.map);
405
-
406
- sdrStations.forEach(station => {
407
- const marker = L.circleMarker(station.location, {
408
- radius: 5,
409
- color: '#0f0',
410
- fillColor: '#0f0',
411
- fillOpacity: 1
412
- }).addTo(this.map);
413
-
414
- const range = L.circle(station.location, {
415
- radius: station.range * 1000,
416
- className: 'station-range'
417
- }).addTo(this.map);
418
-
419
- marker.bindTooltip(`
420
- ${station.name}<br>
421
- Frequency: ${station.frequency}<br>
422
- Range: ${station.range}km
423
- `, {
424
- className: 'custom-tooltip'
425
- });
426
  });
427
  }
428
 
@@ -445,9 +364,23 @@
445
  `).join('');
446
  }
447
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  generateTarget() {
 
449
  const station = sdrStations[Math.floor(Math.random() * sdrStations.length)];
450
- const range = 5;
 
451
  return {
452
  type: Math.random() > 0.7 ? 'aircraft' : 'vehicle',
453
  position: {
@@ -462,65 +395,138 @@
462
  };
463
  }
464
 
465
- updateTargets() {
466
- // Clear existing signals and markers
467
- this.signalLines.forEach(line => this.map.removeLayer(line));
468
- this.signalLines.clear();
469
- this.markers.forEach(marker => this.map.removeLayer(marker));
470
- this.markers.clear();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
 
472
- // Add new markers and signal lines for current targets
473
- this.targets.forEach(target => {
474
- // Create target marker
475
- const marker = L.circleMarker([target.position.lat, target.position.lon], {
476
- radius: 5,
477
- color: target.type === 'aircraft' ? '#ff0' : '#0ff',
478
- fillColor: target.type === 'aircraft' ? '#ff0' : '#0ff',
479
- fillOpacity: 1,
480
- weight: 2
481
- }).addTo(this.map);
482
-
483
- // Enhanced tooltip
484
- marker.bindTooltip(`
485
- <div style="color: #0f0;">
486
- <strong>${target.id}</strong><br>
487
- ${target.type === 'aircraft' ? '✈️' : '🚗'} ${target.type.toUpperCase()}<br>
488
- Speed: ${target.speed.toFixed(0)} kts<br>
489
- ${target.type === 'aircraft' ? `Altitude: ${target.altitude.toFixed(0)} ft<br>` : ''}
490
- Signal: ${(target.signalStrength * 100).toFixed(0)}%
491
- </div>
492
- `, {
493
- className: 'custom-tooltip'
494
- });
 
 
 
 
 
 
 
 
495
 
496
- this.markers.set(target.id, marker);
 
 
 
 
 
497
 
498
- // Draw signal lines to nearby active stations
 
 
 
 
499
  sdrStations.forEach(station => {
500
- if (station.active) {
501
- const distance = this.map.distance(
502
- [target.position.lat, target.position.lon],
503
- station.location
504
- ) / 1000;
505
-
506
- if (distance <= station.range) {
507
- const signalStrength = Math.max(0.1, 1 - (distance / station.range));
 
 
 
 
 
 
 
 
 
508
 
509
- const line = L.polyline([
510
- [target.position.lat, target.position.lon],
511
- station.location
512
- ], {
513
- color: '#00ff00',
514
- opacity: signalStrength * 0.8,
515
- weight: 2,
516
- dashArray: '5, 10',
517
- className: 'signal-line'
518
- }).addTo(this.map);
519
-
520
- this.signalLines.set(`${target.id}-${station.name}`, line);
521
  }
522
  }
523
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
524
  });
525
  }
526
 
@@ -531,8 +537,8 @@
531
  <div class="detection">
532
  ${target.type === 'aircraft' ? '✈️' : '🚗'}
533
  <strong>${target.id}</strong><br>
534
- Speed: ${target.speed.toFixed(0)} kts
535
- ${target.type === 'aircraft' ? `<br>Alt: ${target.altitude.toFixed(0)} ft` : ''}
536
  <br>Signal: ${(target.signalStrength * 100).toFixed(0)}%
537
  </div>
538
  `).join('');
@@ -541,24 +547,25 @@
541
  updateSignalStrengths() {
542
  sdrStations.forEach(station => {
543
  const bar = document.querySelector(`#rx-${station.url.split(':')[0]} .signal-bar`);
544
- if (bar) {
545
- // Calculate actual signal strength based on nearby targets
546
  let maxSignalStrength = 0;
547
  this.targets.forEach(target => {
548
- const distance = this.map.distance(
549
- [target.position.lat, target.position.lon],
550
- station.location
551
- ) / 1000;
552
 
553
- if (distance <= station.range) {
554
- const strength = Math.max(0.1, 1 - (distance / station.range));
 
 
 
 
 
555
  maxSignalStrength = Math.max(maxSignalStrength, strength);
556
  }
557
  });
558
 
559
- // Add some random fluctuation
560
  const baseStrength = maxSignalStrength * 100;
561
- const fluctuation = Math.random() * 20 - 10; // ±10%
562
  const finalStrength = Math.max(10, Math.min(100, baseStrength + fluctuation));
563
 
564
  bar.style.width = `${finalStrength}%`;
@@ -567,20 +574,60 @@
567
  });
568
  }
569
 
570
- startTracking() {
571
  setInterval(() => {
572
- // Add/remove targets
573
  if(Math.random() < 0.1 && this.targets.size < 20) {
574
- this.targets.add(this.generateTarget());
575
- }
576
- if(Math.random() < 0.1 && this.targets.size > 0) {
577
- this.targets.delete(Array.from(this.targets)[0]);
578
  }
579
 
580
- this.updateTargets();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  this.updateDetections();
582
  this.updateSignalStrengths();
583
- }, 100);
584
  }
585
  }
586
 
@@ -590,4 +637,4 @@
590
  });
591
  </script>
592
  </body>
593
- </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <title>Global SDR Network Monitor</title>
 
6
  <style>
7
  body {
8
  margin: 0;
 
66
  }
67
 
68
  #map {
 
 
69
  background: #111;
70
+ border-radius: 8px;
71
+ height: calc(100vh - 40px);
72
  }
73
 
74
  .signal-strength {
 
80
 
81
  .signal-bar {
82
  height: 100%;
83
+ background: linear-gradient(to right, #0f0, #00ff00);
84
  width: 0%;
85
  transition: width 0.3s ease-in-out;
86
+ box-shadow: 0 0 5px #0f0;
87
  border-radius: 2px;
88
  }
89
 
 
92
  border-left: 3px solid #0f0;
93
  padding: 8px;
94
  margin: 5px 0;
95
+ font-size: 12px;
96
  border-radius: 0 4px 4px 0;
97
  }
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  .signal-line {
100
+ position: absolute;
101
+ background: linear-gradient(90deg, rgba(0,255,0,0.4) 0%, rgba(0,255,0,0) 100%);
102
+ height: 2px;
103
+ transform-origin: 0 0;
104
  pointer-events: none;
105
+ opacity: 0.7;
106
  animation: signalPulse 2s infinite;
107
  }
108
 
109
  @keyframes signalPulse {
110
+ 0% { opacity: 0.7; }
111
+ 50% { opacity: 0.3; }
112
+ 100% { opacity: 0.7; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
  </style>
115
  </head>
 
123
  <div id="detections"></div>
124
  </div>
125
 
126
+ <canvas id="map"></canvas>
127
  </div>
128
 
 
129
  <script>
130
+ // Global SDR stations data with all 23 stations
131
  const sdrStations = [
132
  // Europe
133
  {
 
326
 
327
  class RadarSystem {
328
  constructor() {
329
+ this.canvas = document.getElementById('map');
330
+ this.ctx = this.canvas.getContext('2d');
331
  this.targets = new Set();
332
+ this.signalLines = new Set();
333
+ this.setupCanvas();
 
334
  this.renderReceivers();
335
  this.startTracking();
336
  }
337
 
338
+ setupCanvas() {
339
+ this.canvas.width = this.canvas.offsetWidth;
340
+ this.canvas.height = this.canvas.offsetHeight;
341
+
342
+ window.addEventListener('resize', () => {
343
+ this.canvas.width = this.canvas.offsetWidth;
344
+ this.canvas.height = this.canvas.offsetHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  });
346
  }
347
 
 
364
  `).join('');
365
  }
366
 
367
+ latLongToXY(lat, lon) {
368
+ // Adjusted scale for global view
369
+ const centerLat = 20; // Moved center point south for better global coverage
370
+ const centerLon = 0; // Centered on prime meridian
371
+ const scale = 30; // Reduced scale to show more of the world
372
+
373
+ const x = (lon - centerLon) * scale + this.canvas.width/2;
374
+ const y = (centerLat - lat) * scale + this.canvas.height/2;
375
+
376
+ return {x, y};
377
+ }
378
+
379
  generateTarget() {
380
+ // Select random station as center point for target generation
381
  const station = sdrStations[Math.floor(Math.random() * sdrStations.length)];
382
+ const range = 5; // Degrees of latitude/longitude range for target generation
383
+
384
  return {
385
  type: Math.random() > 0.7 ? 'aircraft' : 'vehicle',
386
  position: {
 
395
  };
396
  }
397
 
398
+ drawBackground() {
399
+ this.ctx.fillStyle = '#111';
400
+ this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
401
+
402
+ // Enhanced grid with better visibility
403
+ this.ctx.strokeStyle = '#1a1a1a';
404
+ this.ctx.lineWidth = 1;
405
+
406
+ for(let i = 0; i < this.canvas.width; i += 50) {
407
+ this.ctx.beginPath();
408
+ this.ctx.moveTo(i, 0);
409
+ this.ctx.lineTo(i, this.canvas.height);
410
+ this.ctx.stroke();
411
+ }
412
+
413
+ for(let i = 0; i < this.canvas.height; i += 50) {
414
+ this.ctx.beginPath();
415
+ this.ctx.moveTo(0, i);
416
+ this.ctx.lineTo(this.canvas.width, i);
417
+ this.ctx.stroke();
418
+ }
419
+ }
420
 
421
+ drawStations() {
422
+ sdrStations.forEach(station => {
423
+ const pos = this.latLongToXY(station.location[0], station.location[1]);
424
+
425
+ // Draw coverage area with gradient
426
+ const gradient = this.ctx.createRadialGradient(
427
+ pos.x, pos.y, station.range / 2
428
+ );
429
+ gradient.addColorStop(0, `rgba(0,255,0,${station.active ? 0.2 : 0.05})`);
430
+ gradient.addColorStop(1, 'rgba(0,255,0,0)');
431
+
432
+ // Draw enhanced coverage radius with gradient
433
+ this.ctx.beginPath();
434
+ this.ctx.arc(pos.x, pos.y, station.range / 2, 0, Math.PI * 2);
435
+ this.ctx.fillStyle = gradient;
436
+ this.ctx.fill();
437
+ this.ctx.strokeStyle = `rgba(0,255,0,${station.active ? 0.4 : 0.1})`;
438
+ this.ctx.stroke();
439
+
440
+ // Draw improved station point with glow effect
441
+ this.ctx.beginPath();
442
+ this.ctx.arc(pos.x, pos.y, 4, 0, Math.PI * 2);
443
+ this.ctx.fillStyle = station.active ? '#0f0' : '#f00';
444
+ this.ctx.fill();
445
+
446
+ if(station.active) {
447
+ this.ctx.beginPath();
448
+ this.ctx.arc(pos.x, pos.y, 6, 0, Math.PI * 2);
449
+ this.ctx.strokeStyle = 'rgba(0,255,0,0.5)';
450
+ this.ctx.stroke();
451
+ }
452
 
453
+ // Draw enhanced station label
454
+ this.ctx.fillStyle = '#0f0';
455
+ this.ctx.font = 'bold 10px monospace';
456
+ this.ctx.fillText(station.name, pos.x + 10, pos.y + 4);
457
+ });
458
+ }
459
 
460
+ drawTargets() {
461
+ this.targets.forEach(target => {
462
+ const pos = this.latLongToXY(target.position.lat, target.position.lon);
463
+
464
+ // Draw enhanced signal connections to stations
465
  sdrStations.forEach(station => {
466
+ if(station.active) {
467
+ const stationPos = this.latLongToXY(station.location[0], station.location[1]);
468
+
469
+ // Calculate distance for signal strength
470
+ const dx = pos.x - stationPos.x;
471
+ const dy = pos.y - stationPos.y;
472
+ const distance = Math.sqrt(dx * dx + dy * dy);
473
+ const maxDistance = station.range / 2;
474
+ const signalStrength = Math.max(0.1, 1 - (distance / maxDistance));
475
+
476
+ if (distance <= maxDistance) {
477
+ // Create gradient for signal line
478
+ const gradient = this.ctx.createLinearGradient(
479
+ stationPos.x, stationPos.y, pos.x, pos.y
480
+ );
481
+ gradient.addColorStop(0, `rgba(0,255,0,${signalStrength * 0.7})`);
482
+ gradient.addColorStop(1, 'rgba(0,255,0,0)');
483
 
484
+ // Draw animated signal line
485
+ this.ctx.beginPath();
486
+ this.ctx.moveTo(stationPos.x, stationPos.y);
487
+ this.ctx.lineTo(pos.x, pos.y);
488
+ this.ctx.strokeStyle = gradient;
489
+ this.ctx.lineWidth = 2;
490
+ this.ctx.setLineDash([5, 15]);
491
+ this.ctx.stroke();
492
+ this.ctx.setLineDash([]);
 
 
 
493
  }
494
  }
495
  });
496
+
497
+ // Draw enhanced target with glow effect
498
+ const targetGlow = this.ctx.createRadialGradient(
499
+ pos.x, pos.y, 2,
500
+ pos.x, pos.y, 8
501
+ );
502
+ const targetColor = target.type === 'aircraft' ?
503
+ ['rgba(255,255,0,0.8)', 'rgba(255,255,0,0)'] :
504
+ ['rgba(0,255,255,0.8)', 'rgba(0,255,255,0)'];
505
+
506
+ targetGlow.addColorStop(0, targetColor[0]);
507
+ targetGlow.addColorStop(1, targetColor[1]);
508
+
509
+ this.ctx.beginPath();
510
+ this.ctx.arc(pos.x, pos.y, 8, 0, Math.PI * 2);
511
+ this.ctx.fillStyle = targetGlow;
512
+ this.ctx.fill();
513
+
514
+ // Draw target point
515
+ this.ctx.beginPath();
516
+ this.ctx.arc(pos.x, pos.y, 4, 0, Math.PI * 2);
517
+ this.ctx.fillStyle = target.type === 'aircraft' ? '#ff0' : '#0ff';
518
+ this.ctx.fill();
519
+
520
+ // Draw improved target info with background
521
+ const info = `${target.id} • ${target.speed.toFixed(0)}kts • ${target.altitude.toFixed(0)}ft`;
522
+ this.ctx.font = 'bold 10px monospace';
523
+ const textWidth = this.ctx.measureText(info).width;
524
+
525
+ this.ctx.fillStyle = 'rgba(0,0,0,0.7)';
526
+ this.ctx.fillRect(pos.x + 10, pos.y - 8, textWidth + 4, 16);
527
+
528
+ this.ctx.fillStyle = target.type === 'aircraft' ? '#ff0' : '#0ff';
529
+ this.ctx.fillText(info, pos.x + 12, pos.y + 4);
530
  });
531
  }
532
 
 
537
  <div class="detection">
538
  ${target.type === 'aircraft' ? '✈️' : '🚗'}
539
  <strong>${target.id}</strong><br>
540
+ Speed: ${target.speed.toFixed(0)}kts
541
+ ${target.type === 'aircraft' ? `<br>Alt: ${target.altitude.toFixed(0)}ft` : ''}
542
  <br>Signal: ${(target.signalStrength * 100).toFixed(0)}%
543
  </div>
544
  `).join('');
 
547
  updateSignalStrengths() {
548
  sdrStations.forEach(station => {
549
  const bar = document.querySelector(`#rx-${station.url.split(':')[0]} .signal-bar`);
550
+ if(bar) {
 
551
  let maxSignalStrength = 0;
552
  this.targets.forEach(target => {
553
+ const stationPos = this.latLongToXY(station.location[0], station.location[1]);
554
+ const targetPos = this.latLongToXY(target.position.lat, target.position.lon);
 
 
555
 
556
+ const dx = targetPos.x - stationPos.x;
557
+ const dy = targetPos.y - stationPos.y;
558
+ const distance = Math.sqrt(dx * dx + dy * dy);
559
+ const maxDistance = station.range / 2;
560
+
561
+ if (distance <= maxDistance) {
562
+ const strength = Math.max(0.1, 1 - (distance / maxDistance));
563
  maxSignalStrength = Math.max(maxSignalStrength, strength);
564
  }
565
  });
566
 
 
567
  const baseStrength = maxSignalStrength * 100;
568
+ const fluctuation = Math.random() * 20 - 10;
569
  const finalStrength = Math.max(10, Math.min(100, baseStrength + fluctuation));
570
 
571
  bar.style.width = `${finalStrength}%`;
 
574
  });
575
  }
576
 
577
+ startTracking() {
578
  setInterval(() => {
 
579
  if(Math.random() < 0.1 && this.targets.size < 20) {
580
+ const newTarget = this.generateTarget();
581
+ newTarget.createdAt = Date.now();
582
+ this.targets.add(newTarget);
 
583
  }
584
 
585
+ // Remove old targets
586
+ const currentTime = Date.now();
587
+ Array.from(this.targets).forEach(target => {
588
+ if(currentTime - target.createdAt > 10000) { // 10초 후 제거
589
+ this.targets.delete(target);
590
+ }
591
+ });
592
+
593
+ // Signal strength calculation
594
+ sdrStations.forEach(station => {
595
+ const bar = document.querySelector(`#rx-${station.url.split(':')[0]} .signal-bar`);
596
+ if(bar) {
597
+ let maxSignalStrength = 0;
598
+ this.targets.forEach(target => {
599
+ const stationPos = this.latLongToXY(station.location[0], station.location[1]);
600
+ const targetPos = this.latLongToXY(target.position.lat, target.position.lon);
601
+
602
+ const dx = targetPos.x - stationPos.x;
603
+ const dy = targetPos.y - stationPos.y;
604
+ const distance = Math.sqrt(dx * dx + dy * dy);
605
+ const maxDistance = station.range / 2;
606
+
607
+ if (distance <= maxDistance) {
608
+ const strength = Math.max(0.1, 1 - (distance / maxDistance));
609
+ maxSignalStrength = Math.max(maxSignalStrength, strength);
610
+ }
611
+ });
612
+
613
+ // Add random fluctuation to signal strength
614
+ const baseStrength = maxSignalStrength * 100;
615
+ const fluctuation = Math.random() * 20 - 10;
616
+ const finalStrength = Math.max(10, Math.min(100, baseStrength + fluctuation));
617
+
618
+ bar.style.width = `${finalStrength}%`;
619
+ bar.style.boxShadow = maxSignalStrength > 0.5 ? '0 0 10px #0f0' : 'none';
620
+ bar.style.opacity = maxSignalStrength > 0 ? 1 : 0.3;
621
+ }
622
+ });
623
+
624
+ // Update display
625
+ this.drawBackground();
626
+ this.drawStations();
627
+ this.drawTargets();
628
  this.updateDetections();
629
  this.updateSignalStrengths();
630
+ }, 50); // 50ms interval for smooth animation
631
  }
632
  }
633
 
 
637
  });
638
  </script>
639
  </body>
640
+ </html>