libsim Versione 7.1.11
|
◆ arrayof_georef_coord_array_import()
Import an array of georef_coord_array objects from a file in ESRI/Shapefile format. The this argument is an uninitialised arrayof_georef_coord_array, every element of which, thisarray(n), is of type georef_coord_array and, on return, will contain information from the n-th shape of the file. Topology information and possible polygon parts are imported as well, while no projection information, even if available, is imported. An error condition while opening the file can be detected by checking .NOT.ASSOCIATED(thisarray), while an error reading shape n can be detected by checking .NOT.c_e(thisarray(n)).
Definizione alla linea 1121 del file georef_coord_class.F90. 1122! Copyright (C) 2010 ARPA-SIM <urpsim@smr.arpa.emr.it>
1123! authors:
1124! Davide Cesari <dcesari@arpa.emr.it>
1125! Paolo Patruno <ppatruno@arpa.emr.it>
1126
1127! This program is free software; you can redistribute it and/or
1128! modify it under the terms of the GNU General Public License as
1129! published by the Free Software Foundation; either version 2 of
1130! the License, or (at your option) any later version.
1131
1132! This program is distributed in the hope that it will be useful,
1133! but WITHOUT ANY WARRANTY; without even the implied warranty of
1134! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1135! GNU General Public License for more details.
1136
1137! You should have received a copy of the GNU General Public License
1138! along with this program. If not, see <http://www.gnu.org/licenses/>.
1139#include "config.h"
1140
1158USE geo_proj_class
1159#ifdef HAVE_SHAPELIB
1160USE shapelib
1161#endif
1162IMPLICIT NONE
1163
1169 PRIVATE
1170 DOUBLE PRECISION :: x=dmiss, y=dmiss
1172
1175
1181 PRIVATE
1182 INTEGER,ALLOCATABLE :: parts(:)
1183 TYPE(georef_coord),ALLOCATABLE :: coord(:)
1184 INTEGER :: topo=imiss
1185 TYPE(geo_proj) :: proj
1186 TYPE(georef_coord) :: bbox(2)=(/georef_coord_miss, georef_coord_miss/)
1187 LOGICAL :: bbox_updated=.false.
1189
1190INTEGER,PARAMETER :: georef_coord_array_point = 1
1191INTEGER,PARAMETER :: georef_coord_array_arc = 3
1192INTEGER,PARAMETER :: georef_coord_array_polygon = 5
1193INTEGER,PARAMETER :: georef_coord_array_multipoint = 8
1194
1195
1200 MODULE PROCEDURE georef_coord_delete, georef_coord_array_delete
1201END INTERFACE
1202
1205 MODULE PROCEDURE georef_coord_c_e, georef_coord_array_c_e
1206END INTERFACE
1207
1210 MODULE PROCEDURE georef_coord_getval, georef_coord_proj_getval, georef_coord_array_getval
1211END INTERFACE
1212
1213INTERFACE compute_bbox
1214 MODULE PROCEDURE georef_coord_array_compute_bbox
1215END INTERFACE
1216
1218INTERFACE OPERATOR (==)
1219 MODULE PROCEDURE georef_coord_eq
1220END INTERFACE
1221
1223INTERFACE OPERATOR (/=)
1224 MODULE PROCEDURE georef_coord_ne
1225END INTERFACE
1226
1229INTERFACE OPERATOR (>=)
1230 MODULE PROCEDURE georef_coord_ge
1231END INTERFACE
1232
1235INTERFACE OPERATOR (<=)
1236 MODULE PROCEDURE georef_coord_le
1237END INTERFACE
1238
1239#ifdef HAVE_SHAPELIB
1240
1242INTERFACE import
1243 MODULE PROCEDURE arrayof_georef_coord_array_import
1244END INTERFACE
1245
1249 MODULE PROCEDURE arrayof_georef_coord_array_export
1250END INTERFACE
1251#endif
1252
1256 MODULE PROCEDURE georef_coord_read_unit, georef_coord_vect_read_unit
1257END INTERFACE
1258
1262 MODULE PROCEDURE georef_coord_write_unit, georef_coord_vect_write_unit
1263END INTERFACE
1264
1267 MODULE PROCEDURE georef_coord_inside, georef_coord_inside_rectang
1268END INTERFACE
1269
1272 MODULE PROCEDURE georef_coord_dist
1273END INTERFACE
1274
1275#define ARRAYOF_ORIGTYPE TYPE(georef_coord_array)
1276#define ARRAYOF_TYPE arrayof_georef_coord_array
1277!define ARRAYOF_ORIGEQ 0
1278#define ARRAYOF_ORIGDESTRUCTOR(x) CALL delete(x)
1279#include "arrayof_pre.F90"
1280! from arrayof
1282
1283PRIVATE
1285 georef_coord_array, georef_coord_array_point, georef_coord_array_arc, &
1286 georef_coord_array_polygon, georef_coord_array_multipoint, &
1288#ifdef HAVE_SHAPELIB
1290#endif
1292 georef_coord_new, georef_coord_array_new
1293
1294CONTAINS
1295
1296#include "arrayof_post.F90"
1297
1298! ===================
1299! == georef_coord ==
1300! ===================
1304FUNCTION georef_coord_new(x, y) RESULT(this)
1305DOUBLE PRECISION,INTENT(in),OPTIONAL :: x
1306DOUBLE PRECISION,INTENT(in),OPTIONAL :: y
1307TYPE(georef_coord) :: this
1308
1311
1312END FUNCTION georef_coord_new
1313
1314
1315SUBROUTINE georef_coord_delete(this)
1316TYPE(georef_coord),INTENT(inout) :: this
1317
1318this%x = dmiss
1319this%y = dmiss
1320
1321END SUBROUTINE georef_coord_delete
1322
1323
1324ELEMENTAL FUNCTION georef_coord_c_e(this) RESULT (res)
1325TYPE(georef_coord),INTENT(in) :: this
1326LOGICAL :: res
1327
1328res = .NOT. this == georef_coord_miss
1329
1330END FUNCTION georef_coord_c_e
1331
1332
1339ELEMENTAL SUBROUTINE georef_coord_getval(this, x, y)
1340TYPE(georef_coord),INTENT(in) :: this
1341DOUBLE PRECISION,INTENT(out),OPTIONAL :: x
1342DOUBLE PRECISION,INTENT(out),OPTIONAL :: y
1343
1344IF (PRESENT(x)) x = this%x
1345IF (PRESENT(y)) y = this%y
1346
1347END SUBROUTINE georef_coord_getval
1348
1349
1358ELEMENTAL SUBROUTINE georef_coord_proj_getval(this, proj, x, y, lon, lat)
1359TYPE(georef_coord),INTENT(in) :: this
1360TYPE(geo_proj),INTENT(in) :: proj
1361DOUBLE PRECISION,INTENT(out),OPTIONAL :: x
1362DOUBLE PRECISION,INTENT(out),OPTIONAL :: y
1363DOUBLE PRECISION,INTENT(out),OPTIONAL :: lon
1364DOUBLE PRECISION,INTENT(out),OPTIONAL :: lat
1365
1366DOUBLE PRECISION :: llon, llat
1367
1368IF (PRESENT(x)) x = this%x
1369IF (PRESENT(y)) y = this%y
1370IF (PRESENT(lon) .OR. present(lat)) THEN
1372 IF (PRESENT(lon)) lon = llon
1373 IF (PRESENT(lat)) lat = llat
1374ENDIF
1375
1376END SUBROUTINE georef_coord_proj_getval
1377
1378
1379! document and improve
1380ELEMENTAL FUNCTION getlat(this)
1381TYPE(georef_coord),INTENT(in) :: this ! oggetto di cui restituire latitudine
1382DOUBLE PRECISION :: getlat ! latitudine geografica
1383
1384getlat = this%y ! change!!!
1385
1386END FUNCTION getlat
1387
1388! document and improve
1389ELEMENTAL FUNCTION getlon(this)
1390TYPE(georef_coord),INTENT(in) :: this ! oggetto di cui restituire latitudine
1391DOUBLE PRECISION :: getlon ! longitudine geografica
1392
1393getlon = this%x ! change!!!
1394
1395END FUNCTION getlon
1396
1397
1398ELEMENTAL FUNCTION georef_coord_eq(this, that) RESULT(res)
1399TYPE(georef_coord),INTENT(IN) :: this, that
1400LOGICAL :: res
1401
1402res = (this%x == that%x .AND. this%y == that%y)
1403
1404END FUNCTION georef_coord_eq
1405
1406
1407ELEMENTAL FUNCTION georef_coord_ge(this, that) RESULT(res)
1408TYPE(georef_coord),INTENT(IN) :: this, that
1409LOGICAL :: res
1410
1411res = (this%x >= that%x .AND. this%y >= that%y)
1412
1413END FUNCTION georef_coord_ge
1414
1415
1416ELEMENTAL FUNCTION georef_coord_le(this, that) RESULT(res)
1417TYPE(georef_coord),INTENT(IN) :: this, that
1418LOGICAL :: res
1419
1420res = (this%x <= that%x .AND. this%y <= that%y)
1421
1422END FUNCTION georef_coord_le
1423
1424
1425ELEMENTAL FUNCTION georef_coord_ne(this, that) RESULT(res)
1426TYPE(georef_coord),INTENT(IN) :: this, that
1427LOGICAL :: res
1428
1429res = .NOT.(this == that)
1430
1431END FUNCTION georef_coord_ne
1432
1433
1439SUBROUTINE georef_coord_read_unit(this, unit)
1440TYPE(georef_coord),INTENT(out) :: this
1441INTEGER, INTENT(in) :: unit
1442
1443CALL georef_coord_vect_read_unit((/this/), unit)
1444
1445END SUBROUTINE georef_coord_read_unit
1446
1447
1453SUBROUTINE georef_coord_vect_read_unit(this, unit)
1454TYPE(georef_coord) :: this(:)
1455INTEGER, INTENT(in) :: unit
1456
1457CHARACTER(len=40) :: form
1458INTEGER :: i
1459
1460INQUIRE(unit, form=form)
1461IF (form == 'FORMATTED') THEN
1462 read(unit,*) (this(i)%x,this(i)%y, i=1,SIZE(this))
1463!TODO bug gfortran compiler !
1464!missing values are unredeable when formatted
1465ELSE
1466 READ(unit) (this(i)%x,this(i)%y, i=1,SIZE(this))
1467ENDIF
1468
1469END SUBROUTINE georef_coord_vect_read_unit
1470
1471
1476SUBROUTINE georef_coord_write_unit(this, unit)
1477TYPE(georef_coord),INTENT(in) :: this
1478INTEGER, INTENT(in) :: unit
1479
1480CALL georef_coord_vect_write_unit((/this/), unit)
1481
1482END SUBROUTINE georef_coord_write_unit
1483
1484
1489SUBROUTINE georef_coord_vect_write_unit(this, unit)
1490TYPE(georef_coord),INTENT(in) :: this(:)
1491INTEGER, INTENT(in) :: unit
1492
1493CHARACTER(len=40) :: form
1494INTEGER :: i
1495
1496INQUIRE(unit, form=form)
1497IF (form == 'FORMATTED') THEN
1498 WRITE(unit,*) (this(i)%x,this(i)%y, i=1,SIZE(this))
1499!TODO bug gfortran compiler !
1500!missing values are unredeable when formatted
1501ELSE
1502 WRITE(unit) (this(i)%x,this(i)%y, i=1,SIZE(this))
1503ENDIF
1504
1505END SUBROUTINE georef_coord_vect_write_unit
1506
1507
1510FUNCTION georef_coord_dist(this, that) RESULT(dist)
1512TYPE(georef_coord), INTENT (IN) :: this
1513TYPE(georef_coord), INTENT (IN) :: that
1514DOUBLE PRECISION :: dist
1515
1516DOUBLE PRECISION :: x,y
1517! Distanza approssimata, valida per piccoli angoli
1518
1519x = (this%x-that%x)*cos(((this%y+this%y)/2.)*degrad)
1520y = (this%y-that%y)
1521dist = sqrt(x**2 + y**2)*degrad*rearth
1522
1523END FUNCTION georef_coord_dist
1524
1525
1531FUNCTION georef_coord_inside_rectang(this, coordmin, coordmax) RESULT(res)
1532TYPE(georef_coord),INTENT(IN) :: this
1533TYPE(georef_coord),INTENT(IN) :: coordmin
1534TYPE(georef_coord),INTENT(IN) :: coordmax
1535LOGICAL :: res
1536
1537res = (this >= coordmin .AND. this <= coordmax)
1538
1539END FUNCTION georef_coord_inside_rectang
1540
1541
1542! ========================
1543! == georef_coord_array ==
1544! ========================
1550FUNCTION georef_coord_array_new(x, y, topo, proj) RESULT(this)
1551DOUBLE PRECISION,INTENT(in),OPTIONAL :: x(:)
1552DOUBLE PRECISION,INTENT(in),OPTIONAL :: y(:)
1553INTEGER,INTENT(in),OPTIONAL :: topo
1554TYPE(geo_proj),INTENT(in),OPTIONAL :: proj
1555TYPE(georef_coord_array) :: this
1556
1557INTEGER :: lsize
1558
1559IF (PRESENT(x) .AND. PRESENT(y)) THEN
1560 lsize = min(SIZE(x), SIZE(y))
1561 ALLOCATE(this%coord(lsize))
1562 this%coord(1:lsize)%x = x(1:lsize)
1563 this%coord(1:lsize)%y = y(1:lsize)
1564ENDIF
1565this%topo = optio_l(topo)
1567
1568END FUNCTION georef_coord_array_new
1569
1570
1571SUBROUTINE georef_coord_array_delete(this)
1572TYPE(georef_coord_array),INTENT(inout) :: this
1573
1574TYPE(georef_coord_array) :: lobj
1575
1576this = lobj
1577
1578END SUBROUTINE georef_coord_array_delete
1579
1580
1581ELEMENTAL FUNCTION georef_coord_array_c_e(this) RESULT (res)
1582TYPE(georef_coord_array),INTENT(in) :: this
1583LOGICAL :: res
1584
1585res = ALLOCATED(this%coord)
1586
1587END FUNCTION georef_coord_array_c_e
1588
1589
1594SUBROUTINE georef_coord_array_getval(this, x, y, topo, proj)
1595TYPE(georef_coord_array),INTENT(in) :: this
1596DOUBLE PRECISION,OPTIONAL,ALLOCATABLE,INTENT(out) :: x(:)
1597DOUBLE PRECISION,OPTIONAL,ALLOCATABLE,INTENT(out) :: y(:)
1598! allocatable per vedere di nascosto l'effetto che fa
1599INTEGER,OPTIONAL,INTENT(out) :: topo
1600TYPE(geo_proj),OPTIONAL,INTENT(out) :: proj
1601
1602
1603IF (PRESENT(x)) THEN
1604 IF (ALLOCATED(this%coord)) THEN
1605 x = this%coord%x
1606 ENDIF
1607ENDIF
1608IF (PRESENT(y)) THEN
1609 IF (ALLOCATED(this%coord)) THEN
1610 y = this%coord%y
1611 ENDIF
1612ENDIF
1613IF (PRESENT(topo)) topo = this%topo
1615
1616END SUBROUTINE georef_coord_array_getval
1617
1618
1624SUBROUTINE georef_coord_array_compute_bbox(this)
1625TYPE(georef_coord_array),INTENT(inout) :: this
1626
1627IF (ALLOCATED(this%coord)) THEN
1628 this%bbox(1)%x = minval(this%coord(:)%x)
1629 this%bbox(1)%y = minval(this%coord(:)%y)
1630 this%bbox(2)%x = maxval(this%coord(:)%x)
1631 this%bbox(2)%y = maxval(this%coord(:)%y)
1632 this%bbox_updated = .true.
1633ENDIF
1634
1635END SUBROUTINE georef_coord_array_compute_bbox
1636
1637#ifdef HAVE_SHAPELIB
1638! internal method for importing a single shape
1639SUBROUTINE georef_coord_array_import(this, shphandle, nshp)
1640TYPE(georef_coord_array),INTENT(OUT) :: this
1641TYPE(shpfileobject),INTENT(INOUT) :: shphandle
1642INTEGER,INTENT(IN) :: nshp
1643
1644TYPE(shpobject) :: shpobj
1645
1646! read shape object
1647shpobj = shpreadobject(shphandle, nshp)
1648IF (.NOT.shpisnull(shpobj)) THEN
1649! import it in georef_coord object
1650 this = georef_coord_array_new(x=dble(shpobj%padfx), y=dble(shpobj%padfy), &
1651 topo=shpobj%nshptype)
1652 IF (shpobj%nparts > 1 .AND. ASSOCIATED(shpobj%panpartstart)) THEN
1653 this%parts = shpobj%panpartstart(:) ! automatic f95 allocation
1654 ELSE IF (ALLOCATED(this%parts)) THEN
1655 DEALLOCATE(this%parts)
1656 ENDIF
1657 CALL shpdestroyobject(shpobj)
1658 CALL compute_bbox(this)
1659ENDIF
1660
1661
1662END SUBROUTINE georef_coord_array_import
1663
1664
1665! internal method for exporting a single shape
1666SUBROUTINE georef_coord_array_export(this, shphandle, nshp)
1667TYPE(georef_coord_array),INTENT(in) :: this
1668TYPE(shpfileobject),INTENT(inout) :: shphandle
1669INTEGER,INTENT(IN) :: nshp ! index of shape to write starting from 0, -1 to append
1670
1671INTEGER :: i
1672TYPE(shpobject) :: shpobj
1673
1674IF (ALLOCATED(this%coord)) THEN
1675 IF (ALLOCATED(this%parts)) THEN
1676 shpobj = shpcreateobject(this%topo, -1, SIZE(this%parts), this%parts, &
1677 this%parts, SIZE(this%coord), this%coord(:)%x, this%coord(:)%y)
1678 ELSE
1679 shpobj = shpcreatesimpleobject(this%topo, SIZE(this%coord), &
1680 this%coord(:)%x, this%coord(:)%y)
1681 ENDIF
1682ELSE
1683 RETURN
1684ENDIF
1685
1686IF (.NOT.shpisnull(shpobj)) THEN
1687 i = shpwriteobject(shphandle, nshp, shpobj)
1688 CALL shpdestroyobject(shpobj)
1689ENDIF
1690
1691END SUBROUTINE georef_coord_array_export
1692
1693
1704SUBROUTINE arrayof_georef_coord_array_import(this, shpfile)
1705TYPE(arrayof_georef_coord_array),INTENT(out) :: this
1706CHARACTER(len=*),INTENT(in) :: shpfile
1707
1708REAL(kind=fp_d) :: minb(4), maxb(4)
1709INTEGER :: i, ns, shptype, dbfnf, dbfnr
1710TYPE(shpfileobject) :: shphandle
1711
1712shphandle = shpopen(trim(shpfile), 'rb')
1713IF (shpfileisnull(shphandle)) THEN
1714 ! log here
1715 CALL raise_error()
1716 RETURN
1717ENDIF
1718
1719! get info about file
1720CALL shpgetinfo(shphandle, ns, shptype, minb, maxb, dbfnf, dbfnr)
1721IF (ns > 0) THEN ! allocate and read the object
1723 DO i = 1, ns
1724 CALL georef_coord_array_import(this%array(i), shphandle=shphandle, nshp=i-1)
1725 ENDDO
1726ENDIF
1727
1728CALL shpclose(shphandle)
1729! pack object to save memory
1731
1732END SUBROUTINE arrayof_georef_coord_array_import
1733
1734
1740SUBROUTINE arrayof_georef_coord_array_export(this, shpfile)
1741TYPE(arrayof_georef_coord_array),INTENT(in) :: this
1742CHARACTER(len=*),INTENT(in) :: shpfile
1743
1744INTEGER :: i
1745TYPE(shpfileobject) :: shphandle
1746
1747IF (this%arraysize > 0) THEN
1748 shphandle = shpcreate(trim(shpfile), this%array(1)%topo)
1749ELSE
1750 shphandle = shpcreate(trim(shpfile), georef_coord_array_polygon)
1751ENDIF
1752IF (shpfileisnull(shphandle)) THEN
1753 ! log here
1754 CALL raise_error()
1755 RETURN
1756ENDIF
1757
1758DO i = 1, this%arraysize
1759 CALL georef_coord_array_export(this%array(i), shphandle=shphandle, nshp=i-1)
1760ENDDO
1761
1762CALL shpclose(shphandle)
1763
1764END SUBROUTINE arrayof_georef_coord_array_export
1765#endif
1766
1778FUNCTION georef_coord_inside(this, poly) RESULT(inside)
1779TYPE(georef_coord), INTENT(IN) :: this
1780TYPE(georef_coord_array), INTENT(IN) :: poly
1781LOGICAL :: inside
1782
1783INTEGER :: i
1784
1785inside = .false.
1787IF (.NOT.ALLOCATED(poly%coord)) RETURN
1788! if outside bounding box stop here
1789IF (poly%bbox_updated) THEN
1790 IF (.NOT.georef_coord_inside_rectang(this, poly%bbox(1), poly%bbox(2))) RETURN
1791ENDIF
1792
1793IF (ALLOCATED(poly%parts)) THEN
1794 DO i = 1, SIZE(poly%parts)-1
1796 poly%coord(poly%parts(i)+1:poly%parts(i+1))%x, &
1797 poly%coord(poly%parts(i)+1:poly%parts(i+1))%y)
1798 ENDDO
1799 IF (SIZE(poly%parts) > 0) THEN ! safety check
1801 poly%coord(poly%parts(i)+1:)%x, &
1802 poly%coord(poly%parts(i)+1:)%y)
1803 ENDIF
1804
1805ELSE
1806 IF (SIZE(poly%coord) < 1) RETURN ! safety check
1807 inside = pointinpoly(this%x, this%y, &
1808 poly%coord(:)%x, poly%coord(:)%y)
1809ENDIF
1810
1811CONTAINS
1812
1813FUNCTION pointinpoly(x, y, px, py)
1814DOUBLE PRECISION, INTENT(in) :: x, y, px(:), py(:)
1815LOGICAL :: pointinpoly
1816
1817INTEGER :: i, j, starti
1818
1819pointinpoly = .false.
1820
1821IF (px(1) == px(SIZE(px)) .AND. py(1) == py(SIZE(px))) THEN ! closed polygon
1822 starti = 2
1823 j = 1
1824ELSE ! unclosed polygon
1825 starti = 1
1826 j = SIZE(px)
1827ENDIF
1828DO i = starti, SIZE(px)
1829 IF ((py(i) <= y .AND. y < py(j)) .OR. &
1830 (py(j) <= y .AND. y < py(i))) THEN
1831 IF (x < (px(j) - px(i)) * (y - py(i)) / (py(j) - py(i)) + px(i)) THEN
1832 pointinpoly = .NOT. pointinpoly
1833 ENDIF
1834 ENDIF
1835 j = i
1836ENDDO
1837
1838END FUNCTION pointinpoly
1839
1840END FUNCTION georef_coord_inside
1841
1842
1843
Compute forward coordinate transformation from geographical system to projected system. Definition: geo_proj_class.F90:295 Compute backward coordinate transformation from projected system to geographical system. Definition: geo_proj_class.F90:301 Quick method to append an element to the array. Definition: georef_coord_class.F90:401 Compute the distance in m between two points. Definition: georef_coord_class.F90:344 Export an array of georef_coord_array objects to a file in ESRI/Shapefile format. Definition: georef_coord_class.F90:321 Methods for returning the value of object members. Definition: georef_coord_class.F90:282 Import an array of georef_coord_array objects from a file in ESRI/Shapefile format. Definition: georef_coord_class.F90:315 Method for inserting elements of the array at a desired position. Definition: georef_coord_class.F90:392 Determine whether a point lies inside a polygon or a rectangle. Definition: georef_coord_class.F90:339 Method for packing the array object reducing at a minimum the memory occupation, without destroying i... Definition: georef_coord_class.F90:424 Read a single georef_coord object or an array of georef_coord objects from a Fortran FORMATTED or UNF... Definition: georef_coord_class.F90:328 Method for removing elements of the array at a desired position. Definition: georef_coord_class.F90:407 Write a single georef_coord object or an array of georef_coord objects to a Fortran FORMATTED or UNFO... Definition: georef_coord_class.F90:334 Generic subroutine for checking OPTIONAL parameters. Definition: optional_values.f90:36 This module defines objects describing georeferenced sparse points possibly with topology and project... Definition: georef_coord_class.F90:227 Definitions of constants and functions for working with missing values. Definition: missing_values.f90:50 Module for quickly interpreting the OPTIONAL parameters passed to a subprogram. Definition: optional_values.f90:28 Derived type defining a one-dimensional array of georeferenced points with an associated topology (is... Definition: georef_coord_class.F90:253 Derive type defining a single georeferenced point, either in geodetic or in projected coordinates. Definition: georef_coord_class.F90:241 |