jablonka.czprosek.czf

czfgmap

Subversion Repositories:
[/] [index.php] - Blame information for rev 8

 

Line No. Rev Author Line
15simandl<?php
2//<!-- Copyright (C) 2008 Petr Simandl www.simandl.cz -->
3//<!-- This file is part of CZFGmap. -->
4//<!-- -->
5//<!-- CZFGmap is free software: you can redistribute it and/or modify -->
6//<!-- it under the terms of the GNU General Public License as published by -->
7//<!-- the Free Software Foundation, either version 3 of the License, or -->
8//<!-- (at your option) any later version. -->
9//<!-- -->
10//<!-- CZFGmap is distributed in the hope that it will be useful, -->
11//<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
12//<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
13//<!-- GNU General Public License for more details. -->
14//<!-- -->
15//<!-- You should have received a copy of the GNU General Public License -->
16//<!-- along with CZFGmap. If not, see <http://www.gnu.org/licenses/>. -->
17 
18error_reporting(7);
19 
20include("../forum/globalmap.php");
21 
22switch (@$_SERVER['SERVER_NAME']) {
23 case "connected.czf":
24 $GMapKey="ABQIAAAAvGTA14kOdSvtr3t8EjKUdxQ2n1pNbYRLwYPuGT94C-0un95jGhSkgS0a3LnGa2MzRepHicK08lDDmg";
25 break;
26 case "mapa.prosek.czf":
27 $GMapKey="ABQIAAAAlZ9uhPay2OYt2xmaN84g0BTYUdkyQZ68wktXWB9o4y2agzv8zxRyBxtFdIbLe18hmqHTwiWPXl7VxA";
28 break;
29 default:
30 $GMapKey="ABQIAAAAlZ9uhPay2OYt2xmaN84g0BTYUdkyQZ68wktXWB9o4y2agzv8zxRyBxtFdIbLe18hmqHTwiWPXl7VxA";
31}
32 
33echo '
341simandl<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
35 
36 
37<html xmlns="http://www.w3.org/1999/xhtml">
38 <head>
39 <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
403simandl <title>CZFGmap</title>
411simandl <META name="AUTHOR" content="Petr Simandl, www.simandl.cz">
42 <META name="LICENSE" content="GNU General Public License">
43 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
44 <link REL="SHORTCUT ICON" HREF="favicon.ico">
45 <style type="text/css">
46 @import url("http://www.google.com/uds/css/gsearch.css");
47 @import url("http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css");
48 @import "czfgmap.css";
49 }
50 </style>
515simandl <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key='.$GMapKey.'"
521simandl type="text/javascript"></script>
53 <script src="http://www.google.com/uds/api?file=uds.js&amp;v=1.0" type="text/javascript"></script>
54 <script src="http://www.google.com/uds/solutions/localsearch/gmlocalsearch.js" type="text/javascript"></script>
55 <script type="text/javascript">
56 
57 //### Globalni promenne #################################
58 var CurrentDatabase = "czfmutf";
59 var NodeLimit = "200";
60 var NodeOrder = "ASC";
61 var NodeSortBy = "name";
62 var Where = "";
63 var LoadedNodes = new Array();
64 var map;
658simandl var NodeIcon = new Array();
66 var DatabaseNodeTables = new Array();
671simandl var AutoFetchMode = true;
68 var AutoClearMode = true;
69 var NumLoadedNodes = 0;
70 var NumAddedNodes = 0;
71 var NumLoadedLinks = 0;
72 var NumAddedLinks = 0;
73 var NumVisibleLinks = 0;
74 var NumInVisibleLinks = 0;
758simandl var PtA = new Array();
76 var PtB = new Array();
77 var PtC = new Array();
78 var PtPt = 1;
79 var PtNum = 0;
803simandl 
818simandl var LinkColType = new Array();
824simandl LinkColType["00000001"] = "#00aa00";
833simandl LinkColType["00000001"] = "#00FF00";
84 var LinkColTypeWifiBackbone = "#fafa00";
85 LinkColType["00000002"] = "#be0000";
86 LinkColType["00000006"] = "#ff5050";
87 LinkColType["00000003"] = "#64c8ff";
88 LinkColType["00000004"] = "#dc00dc";
89 LinkColType["00000007"] = "#c8c8c8";
90 LinkColType["00000008"] = "#ffffff";
91 LinkColType["00000009"] = "#fa8000";
92 LinkColType["00000099"] = "#0000fa";
93 var LinkColTypeNA = "#78783c";
94 LinkColType["00000005"] = "#00fafa";
951simandl 
96 //nacteni ikon pro nody
97 var NodeType = [0,1,9,10,98,99];
98 var NodeState = [1,9,10,40,79,80,90];
99 for (type in NodeType) {
100 for (state in NodeState) {
101 i = 10000 + NodeType[type]*100 + NodeState[state];
102 NodeIcon[i] = new GIcon();
1035simandl NodeIcon[i].image = "./images/node/node-" + NodeType[type] + "-" + NodeState[state] + ".png";
1041simandl NodeIcon[i].iconSize = new GSize(15,15);
105 NodeIcon[i].iconAnchor = new GPoint(7,7);
106 NodeIcon[i].shadowSize = new GSize(22,20);
107 NodeIcon[i].infoWindowAnchor = new GPoint(5,1);
108 }
109 }
110 
111 //### Uvodni funkce #################################
112 function load() {
113 if (GBrowserIsCompatible()) {
1145simandl map = new GMap2(document.getElementById("map"),{draggableCursor: \'crosshair\', draggingCursor: \'pointer\'});
1151simandl map.addControl(new GLargeMapControl());
116 map.addControl(new GMapTypeControl());
117 map.addControl(new GOverviewMapControl());
118 map.setCenter(new GLatLng(50.123567, 14.496258), 15);
119 map.enableScrollWheelZoom();
120 map.addControl(new GScaleControl());
121 
122 map.addControl(new google.maps.LocalSearch(), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10,20)));
123 //tohle zajisti znovunacteni nodu po presunu
124 GEvent.addListener(map, "moveend", HandleMapMoveEnd);
125 
1262simandl //ziskani souradnic po kliknuti
1278simandl GEvent.addListener(map, \'click\', function(overlay, point) { if(point) { HandleNextPoint(point) }} );
1282simandl 
1291simandl //tohle zajisti vypis pri startu
130 var center = map.getCenter();
131 document.getElementById("souradnice").innerHTML = CurrentDatabase + "<br>Souradnice stredu:" + center.toString() + "<br>Rozsah: " + map.getBounds()+"<br>Zvetseni: " + map.getZoom();
132 
133 //tohle zajisti prubezny vypis
134 GEvent.addListener(map, "moveend", function() {
135 var center = map.getCenter();
136 document.getElementById("souradnice").innerHTML = CurrentDatabase + " " + map.getBounds().getSouthWest().lat() + "<br>Souradnice stredu: " + center.toString() + "<br>Rozsah: " + map.getBounds()+"<br>Zvetseni: " + map.getZoom();
137 });
138 
139 document.getElementById("AutoFetchModeCheckButton").checked = true;
140 document.getElementById("AutoClearModeCheckButton").checked = true;
141 document.getElementById("NodeLimitSelectBox").value = NodeLimit;
142 document.getElementById("databaze").innerHTML = CurrentDatabase;
143 
144 //prvotni zobrazeni
145 ClearOverlayAndData();
146 NodeLayer();
1474simandl 
148 var pts = new Array();
149 
150// pts.push (new GLatLng(50.120771, 14.486246));
151 pts.push (new GLatLng(50.118212, 14.484079));
152 pts.push (new GLatLng(50.118707, 14.491160));
153 
1541simandl }
155 }
156 
157 //### Ostatni funkce ###########################
158 
159 function NodeLayer() {
160 //body se berou z databaze pomoci php skriptu ktery dela jen inteface a generuje xml
161 Where = "";
162 GDownloadUrl("mapa_genxml.php?db="+CurrentDatabase
163 +"&latmin="+map.getBounds().getSouthWest().lat()
164 +"&latmax="+map.getBounds().getNorthEast().lat()
165 +"&lonmin="+map.getBounds().getSouthWest().lng()
166 +"&lonmax="+map.getBounds().getNorthEast().lng()
167 +"&sortby="+NodeSortBy
168 +"&limit="+NodeLimit
169 +"&order="+NodeOrder
170 +"&where="+Where
171 +"&zoom="+map.getZoom()
172 , function(data) {
173 var xml = GXml.parse(data);
174 var nodes = xml.documentElement.getElementsByTagName("node");
175 for (var i = 0; i < nodes.length; i++) {
176 var id = nodes[i].getAttribute("id");
177 //zobrazime jen nove nody
178 if (! LoadedNodes[id]) {
179 var name = nodes[i].getAttribute("name");
180 var address = nodes[i].getAttribute("address");
181 var type = 10000 + nodes[i].getAttribute("type")*100 + nodes[i].getAttribute("status")*1;
182 var point = new GLatLng(parseFloat(nodes[i].getAttribute("lat")),
183 parseFloat(nodes[i].getAttribute("lng")));
184 var marker = CreateMarker(point, name, address, type, id);
185 map.addOverlay(marker);
186 LoadedNodes[id]=point;
187 NumAddedNodes = NumAddedNodes + 1;
188 }
189 }
190 document.getElementById("NumNodes").innerHTML = "Nacteno " + NumAddedNodes + " nodu";
191 
192 var links = xml.documentElement.getElementsByTagName("link");
193 for (var i = 0; i < links.length; i++) {
194 var id1 = links[i].getAttribute("id1");
195 var id2 = links[i].getAttribute("id2");
196 //nacteme jen pokud jde o novy link
197 if (! LoadedLinks[id1+"x"+id2] && ! LoadedLinks[id2+"x"+id1]) {
198 var backbone = links[i].getAttribute("backbone");
199 var inplanning = links[i].getAttribute("inplanning");
200 var type = links[i].getAttribute("type");
201 var status = links[i].getAttribute("status");
202 
203 //zobrazi se jen pokud jsou k dispozici oba nody
204 if ( LoadedNodes[id1] && LoadedNodes[id2]) {
2053simandl var LinkSize = (backbone * 2);
2064simandl var LinkColBg = "#000000";
2076simandl var LinkColBgOpacity = 1;
208 var LinkColOpacity = 1;
2094simandl var LinkStyle = "solid";
210 
211 if (inplanning == 1) {
212 LinkColBgOpacity = 0.1;
2135simandl LinkColOpacity = 0.2;
2144simandl LinkColBg = "#0000FF";
215 LinkStyle = "dash";
216 }
217// DebugPrint(":"+ inplanning + ":");
218 
219 var Linepts = new Array();
220 Linepts = [LoadedNodes[id1],LoadedNodes[id2]];
221 LineLength = Math.round(GetLineLength(Linepts[0].lat(), Linepts[0].lng(), Linepts[1].lat(), Linepts[1].lng()));
222 
2231simandl var polyOptions = {geodesic:false};
2245simandl var polyline = new GPolyline([LoadedNodes[id1],LoadedNodes[id2]], LinkColBg, 3 + LinkSize, LinkColBgOpacity, polyOptions);
225 map.addOverlay(polyline);
2264simandl 
2273simandl var LinkColTypeAct = LinkColTypeNA;
228 if ( LinkColType[type]) {
229 LinkColTypeAct = LinkColType[type];
230 }
2312simandl 
2325simandl LoadedLinks[id1+"x"+id2] = new GPolyline([LoadedNodes[id1],LoadedNodes[id2]], LinkColTypeAct, 1 + LinkSize, LinkColOpacity, polyOptions);
2334simandl map.addOverlay(LoadedLinks[id1+"x"+id2]);
234 
2351simandl NumVisibleLinks = NumVisibleLinks + 1;
236 } else {
237 //zde se pokusime donahrat nod ktery nam chybi
238 
239 
240 NumInVisibleLinks = NumInVisibleLinks + 1;
241 }
242 
2434simandl// LoadedLinks[id1+"x"+id2]=polyline;
244 
2451simandl NumAddedLinks = NumAddedLinks + 1;
246 }
247 }
248 document.getElementById("NumLinks").innerHTML = "Nacteno " + NumAddedLinks + " linku a zobrazeno " + NumVisibleLinks + " linku a " + NumInVisibleLinks + " nezobrazeno.";
249 });
250 }
251 
252 //##############################
2538simandl function HandleNextPoint(point) {
254 var Distance = 0;
255 
256 document.getElementById("NodeCoordinates").innerHTML = (point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
257 
258 if ( PtPt == 1 ) {
259 document.getElementById("NodeCoordinatesA").innerHTML = (\'A \'+point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
260 PtA = point;
261 }
262 if ( PtPt == 2 ) {
263 document.getElementById("NodeCoordinatesB").innerHTML = (\'B \'+point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
264 PtB = point;
265 }
266 if ( PtPt == 3 ) {
267 document.getElementById("NodeCoordinatesC").innerHTML = (\'C \'+point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
268 PtC = point;
269 }
270 
271 
272 PtPt = PtPt + 1;
273 if ( PtPt > 3 ) { PtPt = 1; }
274 PtNum = PtNum + 1;
275 
276// document.getElementById("NodeDistanceBC").innerHTML = (\'C \'+point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
277// document.getElementById("NodeDistanceABC").innerHTML = (\'ss\');
278 if ( PtNum > 1 ) {
279 Distance = Math.round(GetLineLength(PtA.lat(), PtA.lng(), PtB.lat(), PtB.lng()));
280 document.getElementById("NodeDistanceAB").innerHTML = Distance;
281 document.getElementById("NodeDistanceBA").innerHTML = Distance;
282 }
283 if ( PtNum > 2 ) {
284 Distance = Math.round(GetLineLength(PtC.lat(), PtC.lng(), PtB.lat(), PtB.lng()));
285 document.getElementById("NodeDistanceBC").innerHTML = Distance;
286 document.getElementById("NodeDistanceCB").innerHTML = Distance;
287 document.getElementById("NodeDistanceABC").innerHTML = 1 * Distance + 1 * document.getElementById("NodeDistanceBA").innerHTML;
288 Distance = Math.round(GetLineLength(PtC.lat(), PtC.lng(), PtA.lat(), PtA.lng()));
289 document.getElementById("NodeDistanceAC").innerHTML = Distance;
290 document.getElementById("NodeDistanceCA").innerHTML = Distance;
291 
292 }
293 
294 document.getElementById("NodeAngleACB").innerHTML = (point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
295 document.getElementById("NodeAngleBAC").innerHTML = (point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
296 document.getElementById("NodeAngleCBA").innerHTML = (point.y.toFixed(6)+\'x\'+point.x.toFixed(6));
297 
298 
299 }
300 
301 //##############################
3024simandl function GetLineLength(Lat1, Lon1, Lat2, Lon2) {
303 var R = 6371; // km
304 var dLat = (Lat2-Lat1) * Math.PI / 180;
305 var dLon = (Lon2-Lon1) * Math.PI / 180;
306 var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
307 Math.cos(Lat1 * Math.PI / 180) * Math.cos(Lat2 * Math.PI / 180) *
308 Math.sin(dLon/2) * Math.sin(dLon/2);
309 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
310 var LineLength = 1000 * R * c;
311 return LineLength;
312 }
313 
314 //##############################
3151simandl function HandleMapMoveEnd() {
316 if (AutoFetchMode) {
317 ClearOverlayAndData();
318 FetchOverlayAndData();
319 }
320 document.getElementById("status").innerHTML = "Po presunu mame celkem " + NumAddedNodes + " nodu";
321 }
322 
323 //##############################
324 function CreateMarker(point, name, address, type, id) {
325 var marker = new GMarker(point, {draggable: true, bounce: true, icon: NodeIcon[type]});
326 var html = "<b>" + id + " " + name + "</b> <br/>" + address +" <br/>" + type;
327 GEvent.addListener(marker, "dragstart", function() {
328 map.closeInfoWindow();
329 });
3305simandl GEvent.addListener(marker, \'click\', function() {
3311simandl marker.openInfoWindowHtml(html);
332 });
333 return marker;
334 }
335 
336 //##############################
337 function SwitchDatabase(NewDatabase) {
338 CurrentDatabase = NewDatabase;
339 document.getElementById("souradnice").innerHTML = CurrentDatabase;
340 ClearOverlayAndData();
341 FetchOverlayAndData();
342 document.getElementById("status").innerHTML = "Databaze zmenena na "+CurrentDatabase;
343 document.getElementById("databaze").innerHTML = CurrentDatabase;
344 }
345 
346 //##############################
347 function ChangeNodeLimit(NewNodeLimit) {
348 NodeLimit = NewNodeLimit;
349 FetchOverlayAndData();
350 document.getElementById("status").innerHTML = "Limit zmenen na "+NewNodeLimit;
351 }
352 
353 //##############################
3544simandl function DebugPrint(Text) {
355 document.getElementById("debug").innerHTML = document.getElementById("debug").innerHTML + Text;
356 }
357 
358 //##############################
3591simandl function Fetch() {
360 NodeLayer();
361 document.getElementById("status").innerHTML = "Nacteno";
362 }
363 
364 //##############################
365 function FetchOverlayAndData() {
366 if (AutoFetchMode) {
367 Fetch();
368 };
369 }
370 
371 //##############################
372 function ClearOverlayAndData() {
373 if (AutoClearMode) {
374 Clear();
375 };
376 }
377 
378 //##############################
379 function Clear() {
380 document.getElementById("status").innerHTML = "Smazano " + NumAddedNodes + " nodu";
381 map.clearOverlays();
382 LoadedNodes=Array();
383 LoadedLinks=Array();
384 NumAddedNodes=0;
385 document.getElementById("NumNodes").innerHTML = "Nacteno " + NumAddedNodes + " nodu";
386 LoadedLinks=Array();
387 NumAddedLinks=0;
388 NumVisibleLinks=0;
3895simandl NumInVisibleLinks=0;
3901simandl document.getElementById("NumLinks").innerHTML = "Nacteno " + NumAddedLinks + " linku";
391 }
392 
393 //##############################
394 function ToggleAutoFetchMode(NewAutoFetchMode) {
395 AutoFetchMode = NewAutoFetchMode;
396 if (AutoFetchMode) {
397 document.getElementById("status").innerHTML = "Automaticke nacitani zapnuto.";
398 }
399 else {
400 document.getElementById("status").innerHTML = "Automaticke nacitani vypnuto.";
401 }
402 }
403 
404 //##############################
405 function ToggleAutoClearMode(NewAutoClearMode) {
406 AutoClearMode = NewAutoClearMode;
407 if (AutoClearMode) {
408 document.getElementById("status").innerHTML = "Automaticke mazani zapnuto.";
409 }
410 else {
411 document.getElementById("status").innerHTML = "Automaticke mazani vypnuto.";
412 }
413 }
414 
415 </script>
416 </head>
417 
418 <body onload="load()" onunload="GUnload()">
419 <table>
420 <tr>
421 <td>
422 <div id="map" style="width: 800px; height: 600px"></div>
423 </td>
424 
425 <td valign="top">
4265simandl <div id="UserInfo">';
427 
428 echo "Prihlasen jako:<br>";
429 echo $bbuserinfo['username']."&nbsp;";
430 echo $bbuserinfo['userid']."&nbsp;";
431 echo $bbuserinfo['mapperms']."&nbsp;";
432 echo $_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']."&nbsp;";
433 
434 echo '</div>
4351simandl Prepnout databazi:
436 <div id="databaze">0</div>
4375simandl <input type="button" value="ajax" onClick="SwitchDatabase(\'ajax\');"/>
438 <input type="button" value="czfmutf" onClick="SwitchDatabase(\'czfmutf\');"/>
439 <input type="button" value="gendb" onClick="SwitchDatabase(\'gendb\');"/>
4401simandl <br>
441 <div id="NumNodes">0</div>
442 <div id="NumLinks">0</div>
443 <input type="button" value="Nacist ted" onClick="Fetch();"/>
444 <input type="button" value="Smazat ted" onClick="Clear();"/>
445 <br>
446 Automaticke nacitani:
447 <input id="AutoFetchModeCheckButton" type="checkBox" onclick="ToggleAutoFetchMode(this.checked)">
448 <br>
449 Automaticke mazani:
450 <input id="AutoClearModeCheckButton" type="checkBox" onclick="ToggleAutoClearMode(this.checked)">
451 <br>
452 Limit nodu:
453 <select id="NodeLimitSelectBox" onchange="ChangeNodeLimit(this.value)">
454 <option value="0">0</option>
455 <option value="30" selected="selected">30</option>
456 <option value="60">60</option>
457 <option value="200">200</option>
458 <option value="500">500</option>
459 <option value="1000">1000</option>
460 </select>
4618simandl <table border="1">
462 <tr>
463 <td>
464 <div id="NodeDistanceABC">ABC</div>
465 </td>
466 <td>
467 A
468 </td>
469 <td>
470 B
471 </td>
472 <td>
473 C
474 </td>
475 </tr>
476 <tr>
477 <td>
478 <div id="NodeCoordinatesA">A</div>
479 </td>
480 <td>
481 <div id="NodeAngleACB">ACB</div>
482 </td>
483 <td>
484 <div id="NodeDistanceAB">AB</div>
485 </td>
486 <td>
487 <div id="NodeDistanceAC">AC</div>
488 </td>
489 </tr>
490 <tr>
491 <td>
492 <div id="NodeCoordinatesB">B</div>
493 </td>
494 <td>
495 <div id="NodeDistanceBA">BA</div>
496 </td>
497 <td>
498 <div id="NodeAngleBAC">BAC</div>
499 </td>
500 <td>
501 <div id="NodeDistanceBC">BC</div>
502 </td>
503 </tr>
504 <tr>
505 <td>
506 <div id="NodeCoordinatesC">C</div>
507 </td>
508 <td>
509 <div id="NodeDistanceCA">CA</div>
510 </td>
511 <td>
512 <div id="NodeDistanceCB">CB</div>
513 </td>
514 <td>
515 <div id="NodeAngleCBA">BAC</div>
516 </td>
517 </tr>
518 </table>
5193simandl 
5201simandl </td>
521 </tr>
522 
523 <tr>
524 <td colspan=2>
525 
5264simandl <div id="debug"></div>
5271simandl <div id="status">Hotovo!</div>
528 <div id="data"></div>
5292simandl <div id="NodeCoordinates">aaa</div>
5301simandl <div id="souradnice">Souradnice stredu:<br>Rozsah:<br>Zvetseni:</div>
5314simandl <a href="http://code.google.com/apis/maps/documentation/examples/">http://code.google.com/apis/maps/documentation/examples/</a>
5321simandl <br>
5334simandl <a href="http://code.google.com/apis/kml/documentation/kml_tut.html">http://code.google.com/apis/kml/documentation/kml_tut.html</a>
534 <br>
535 <a href="http://mapki.com/wiki/Knowledge_Base">http://mapki.com/wiki/Knowledge_Base</a>
536 <br>
537 <a href="http://www.bdcc.co.uk/Gmaps/BdccGmapBits.htm">http://www.bdcc.co.uk/Gmaps/BdccGmapBits.htm</a>
538 <br>
5395simandl http://www.czfree.net/forum/showthread.php?postid=197732#post197732
5401simandl </td>
541 </tr>
542 
543 <tr>
544 <td colspan=2>
545 <br>
546 CZFGmap (c) Petr Simandl - GNU General Public License
547 <br>
548 <a href="http://websvn.prosek.czf/">websvn.prosek.czf</a>
549 </td>
550 </tr>
551 
552 </table>
553 
554 </body>
555</html>
5565simandl';
557?>

Powered by WebSVN 2.2.1