shapely 1.0.4__tar.gz → 1.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. {Shapely-1.0.4 → Shapely-1.0.5}/CHANGES.txt +6 -0
  2. {Shapely-1.0.4 → Shapely-1.0.5}/PKG-INFO +1 -1
  3. {Shapely-1.0.4 → Shapely-1.0.5}/Shapely.egg-info/PKG-INFO +1 -1
  4. {Shapely-1.0.4 → Shapely-1.0.5}/Shapely.egg-info/SOURCES.txt +2 -0
  5. {Shapely-1.0.4 → Shapely-1.0.5}/manual/manual.txt +35 -7
  6. {Shapely-1.0.4 → Shapely-1.0.5}/setup.py +1 -1
  7. {Shapely-1.0.4 → Shapely-1.0.5}/setup_windows.py +1 -1
  8. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/__init__.py +0 -1
  9. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/base.py +46 -2
  10. Shapely-1.0.5/shapely/geometry/collection.py +38 -0
  11. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/geo.py +4 -1
  12. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/linestring.py +21 -7
  13. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/polygon.py +4 -2
  14. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/iterops.py +2 -2
  15. Shapely-1.0.5/shapely/ops.py +29 -0
  16. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/predicates.py +2 -2
  17. {Shapely-1.0.4 → Shapely-1.0.5}/tests/Polygon.txt +6 -0
  18. Shapely-1.0.5/tests/polygonize.txt +29 -0
  19. Shapely-1.0.4/shapely/geometry/collection.py +0 -24
  20. {Shapely-1.0.4 → Shapely-1.0.5}/CREDITS.txt +0 -0
  21. {Shapely-1.0.4 → Shapely-1.0.5}/HISTORY.txt +0 -0
  22. {Shapely-1.0.4 → Shapely-1.0.5}/LICENSE.txt +0 -0
  23. {Shapely-1.0.4 → Shapely-1.0.5}/README.txt +0 -0
  24. {Shapely-1.0.4 → Shapely-1.0.5}/Shapely.egg-info/dependency_links.txt +0 -0
  25. {Shapely-1.0.4 → Shapely-1.0.5}/Shapely.egg-info/requires.txt +0 -0
  26. {Shapely-1.0.4 → Shapely-1.0.5}/Shapely.egg-info/top_level.txt +0 -0
  27. {Shapely-1.0.4 → Shapely-1.0.5}/examples/geoms.py +0 -0
  28. {Shapely-1.0.4 → Shapely-1.0.5}/examples/world.py +0 -0
  29. {Shapely-1.0.4 → Shapely-1.0.5}/manual/style.css +0 -0
  30. {Shapely-1.0.4 → Shapely-1.0.5}/setup.cfg +0 -0
  31. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/__init__.py +0 -0
  32. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/multilinestring.py +0 -0
  33. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/multipoint.py +0 -0
  34. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/multipolygon.py +0 -0
  35. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/point.py +0 -0
  36. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geometry/proxy.py +0 -0
  37. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/geos.py +0 -0
  38. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/kml.py +0 -0
  39. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/topology.py +0 -0
  40. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/wkb.py +0 -0
  41. {Shapely-1.0.4 → Shapely-1.0.5}/shapely/wkt.py +0 -0
  42. {Shapely-1.0.4 → Shapely-1.0.5}/tests/Array.txt +0 -0
  43. {Shapely-1.0.4 → Shapely-1.0.5}/tests/GeoInterface.txt +0 -0
  44. {Shapely-1.0.4 → Shapely-1.0.5}/tests/IterOps.txt +0 -0
  45. {Shapely-1.0.4 → Shapely-1.0.5}/tests/LineString.txt +0 -0
  46. {Shapely-1.0.4 → Shapely-1.0.5}/tests/MultiLineString.txt +0 -0
  47. {Shapely-1.0.4 → Shapely-1.0.5}/tests/MultiPoint.txt +0 -0
  48. {Shapely-1.0.4 → Shapely-1.0.5}/tests/MultiPolygon.txt +0 -0
  49. {Shapely-1.0.4 → Shapely-1.0.5}/tests/Operations.txt +0 -0
  50. {Shapely-1.0.4 → Shapely-1.0.5}/tests/Persist.txt +0 -0
  51. {Shapely-1.0.4 → Shapely-1.0.5}/tests/Point.txt +0 -0
  52. {Shapely-1.0.4 → Shapely-1.0.5}/tests/Predicates.txt +0 -0
  53. {Shapely-1.0.4 → Shapely-1.0.5}/tests/__init__.py +0 -0
  54. {Shapely-1.0.4 → Shapely-1.0.5}/tests/attribute-chains.txt +0 -0
  55. {Shapely-1.0.4 → Shapely-1.0.5}/tests/binascii_hex.txt +0 -0
  56. {Shapely-1.0.4 → Shapely-1.0.5}/tests/invalid_intersection.txt +0 -0
  57. {Shapely-1.0.4 → Shapely-1.0.5}/tests/rungrind.dist +0 -0
  58. {Shapely-1.0.4 → Shapely-1.0.5}/tests/test_doctests.py +0 -0
  59. {Shapely-1.0.4 → Shapely-1.0.5}/tests/test_threads.py +0 -0
  60. {Shapely-1.0.4 → Shapely-1.0.5}/tests/valgrind-python.supp +0 -0
@@ -1,5 +1,11 @@
1
1
  All tickets are children of http://trac.gispython.org/projects/PCL/ticket/
2
2
 
3
+ 1.0.5 (2008-05-20)
4
+ ------------------
5
+ - Added access to GEOS polygonizer function.
6
+ - Raise exception when insufficient coordinate tuples are passed to LinearRing
7
+ constructor (#164).
8
+
3
9
  1.0.4 (2008-05-01)
4
10
  ------------------
5
11
  - Disentangle Python and topological equality (#163).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: Shapely
3
- Version: 1.0.4
3
+ Version: 1.0.5
4
4
  Summary: Geospatial geometries, predicates, and operations
5
5
  Home-page: http://trac.gispython.org/projects/PCL/wiki/Shapely
6
6
  Author: Sean Gillies
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: Shapely
3
- Version: 1.0.4
3
+ Version: 1.0.5
4
4
  Summary: Geospatial geometries, predicates, and operations
5
5
  Home-page: http://trac.gispython.org/projects/PCL/wiki/Shapely
6
6
  Author: Sean Gillies
@@ -18,6 +18,7 @@ shapely/__init__.py
18
18
  shapely/geos.py
19
19
  shapely/iterops.py
20
20
  shapely/kml.py
21
+ shapely/ops.py
21
22
  shapely/predicates.py
22
23
  shapely/topology.py
23
24
  shapely/wkb.py
@@ -49,6 +50,7 @@ tests/__init__.py
49
50
  tests/attribute-chains.txt
50
51
  tests/binascii_hex.txt
51
52
  tests/invalid_intersection.txt
53
+ tests/polygonize.txt
52
54
  tests/rungrind.dist
53
55
  tests/test_doctests.py
54
56
  tests/test_threads.py
@@ -4,16 +4,15 @@ The Shapely Manual
4
4
 
5
5
  :Author: Sean Gillies
6
6
  :address: sgillies@frii.com
7
- http://zcologia.com/sgillies
8
-
9
- :revision: 1.0
10
- :date: 2 January 2008
11
-
12
- :copyright: This work is licensed under a `Creative Commons Attribution 3.0 United States License`__.
7
+ :revision: 1.0.5
8
+ :date: 20 May 2008
9
+ :copyright: This work is licensed under a `Creative Commons Attribution 3.0
10
+ United States License`__.
13
11
 
14
12
  .. __: http://creativecommons.org/licenses/by/3.0/us/
15
13
 
16
- :abstract: This document describes the Shapely Python package for programming with geospatial geometries.
14
+ :abstract: This document describes the Shapely Python package for programming
15
+ with geospatial geometries.
17
16
 
18
17
  .. sectnum::
19
18
 
@@ -342,6 +341,32 @@ not:
342
341
  <shapely.geometry.polygon.Polygon object at ...>
343
342
 
344
343
 
344
+ Other Operations
345
+ ----------------
346
+
347
+ Polygonization
348
+ ++++++++++++++
349
+
350
+ shapely.ops.polygonize(lines) : iterator
351
+ Returns an iterator over polygons constructed from the *lines* iterator. The
352
+ elements of *lines* may be Shapely geometries, objects that provide the geo
353
+ interface, or Numpy arrays or Python sequences shaped like LineStrings.
354
+
355
+ .. code-block:: python
356
+
357
+ >>> from shapely.ops import polygonize
358
+ >>> lines = [
359
+ ... ((0, 0), (1, 1)),
360
+ ... ((0, 0), (0, 1)),
361
+ ... ((0, 1), (1, 1)),
362
+ ... ((1, 1), (1, 0)),
363
+ ... ((1, 0), (0, 0))
364
+ ... ]
365
+ >>> result = polygonize(lines)
366
+ >>> list(result.geoms)
367
+ [<shapely.geometry.polygon.Polygon object at ...>, <shapely.geometry.polygon.Polygon object at ...>]
368
+
369
+
345
370
  Unary Spatial Predicates
346
371
  ------------------------
347
372
 
@@ -798,6 +823,9 @@ Or a simple placemark-type object:
798
823
  >>> list(shape.coords)
799
824
  [(0.0, 0.0)]
800
825
 
826
+ If you want to copy coordinate data to a new geometry, use the
827
+ *shapely.geometry.shape* function instead.
828
+
801
829
  .. _Python geo interface: http://trac.gispython.org/projects/PCL/wiki/PythonGeoInterface
802
830
 
803
831
 
@@ -11,7 +11,7 @@ if version_info[:2] < (2,5):
11
11
  readme_text = file('README.txt', 'rb').read()
12
12
 
13
13
  setup(name = 'Shapely',
14
- version = '1.0.4',
14
+ version = '1.0.5',
15
15
  description = 'Geospatial geometries, predicates, and operations',
16
16
  license = 'BSD',
17
17
  keywords = 'geometry topology',
@@ -11,7 +11,7 @@ if version_info[:2] < (2,5):
11
11
  readme_text = file('README.txt', 'rb').read()
12
12
 
13
13
  setup(name = 'Shapely',
14
- version = '1.0.3',
14
+ version = '1.0.5',
15
15
  description = 'Geospatial geometries, predicates, and operations',
16
16
  license = 'BSD',
17
17
  keywords = 'geometry topology',
@@ -6,4 +6,3 @@ from multipoint import MultiPoint, asMultiPoint
6
6
  from multilinestring import MultiLineString, asMultiLineString
7
7
  from multipolygon import MultiPolygon, asMultiPolygon
8
8
  from collection import GeometryCollection
9
-
@@ -207,11 +207,29 @@ class GeometrySequence(object):
207
207
  max = l
208
208
 
209
209
 
210
+ class HeterogeneousGeometrySequence(GeometrySequence):
211
+
212
+ def __init__(self, parent):
213
+ self.__p__ = parent
214
+ self._geom = parent._geom
215
+ self._ndim = parent._ndim
216
+
217
+ def next(self):
218
+ if self._index < self.__len__():
219
+ sub = lgeos.GEOSGetGeometryN(self._geom, self._index)
220
+ g = geom_factory(sub)
221
+ g._owned = True
222
+ self._index += 1
223
+ return g
224
+ else:
225
+ raise StopIteration
226
+
227
+
210
228
  def exceptNull(func):
211
229
  """Decorator which helps avoid GEOS operations on null pointers."""
212
230
  def wrapper(*args, **kwargs):
213
231
  # self is the first arg
214
- if args[0]._geom is None:
232
+ if not args[0]._geom:
215
233
  raise ValueError, "Null geometry supports no operations"
216
234
  return func(*args, **kwargs)
217
235
  return wrapper
@@ -220,7 +238,7 @@ def exceptEitherNull(func):
220
238
  """Decorator which avoids GEOS operations on one or more null pointers."""
221
239
  def wrapper(*args, **kwargs):
222
240
  # self is the first arg
223
- if args[0]._geom is None or args[1]._geom is None:
241
+ if not args[0]._geom or not args[1]._geom:
224
242
  raise ValueError, "Null geometry supports no operations"
225
243
  return func(*args, **kwargs)
226
244
  return wrapper
@@ -459,3 +477,29 @@ class BaseGeometry(object):
459
477
 
460
478
  return (minx, miny, maxx, maxy)
461
479
 
480
+
481
+ class BaseMultiPartGeometry(BaseGeometry):
482
+
483
+ @property
484
+ def ctypes(self):
485
+ raise NotImplementedError, \
486
+ "Multi-part geometries have no ctypes representations"
487
+
488
+ @property
489
+ def __array_interface__(self):
490
+ """Provide the Numpy array protocol."""
491
+ raise NotImplementedError, \
492
+ "Multi-part geometries do not themselves provide the array interface"
493
+
494
+ def _get_coords(self):
495
+ raise NotImplementedError, \
496
+ "Sub-geometries may have coordinate sequences, but collections do not"
497
+
498
+ def _set_coords(self, ob):
499
+ raise NotImplementedError, \
500
+ "Sub-geometries may have coordinate sequences, but collections do not"
501
+
502
+ @property
503
+ def coords(self):
504
+ raise NotImplementedError, \
505
+ "Multi-part geometries do not provide a coordinate sequence"
@@ -0,0 +1,38 @@
1
+ """
2
+ Geometry collections.
3
+ """
4
+
5
+ from shapely.geometry.base import BaseMultiPartGeometry
6
+ from shapely.geometry.base import HeterogeneousGeometrySequence, exceptNull
7
+
8
+
9
+ class GeometryCollection(BaseMultiPartGeometry):
10
+
11
+ """A geometry collection.
12
+ """
13
+
14
+ def __init__(self):
15
+ BaseMultiPartGeometry.__init__(self)
16
+
17
+ @property
18
+ def __geo_interface__(self):
19
+ geometries = []
20
+ for geom in self.geoms:
21
+ geometries.append(geom.__geo_interface__)
22
+ return dict(type='GeometryCollection', geometries=geometries)
23
+
24
+ @property
25
+ @exceptNull
26
+ def geoms(self):
27
+ return HeterogeneousGeometrySequence(self)
28
+
29
+
30
+ # Test runner
31
+ def _test():
32
+ import doctest
33
+ doctest.testmod()
34
+
35
+
36
+ if __name__ == "__main__":
37
+ _test()
38
+
@@ -43,7 +43,10 @@ def asShape(context):
43
43
  else:
44
44
  ob = context
45
45
 
46
- geom_type = ob.get("type").lower()
46
+ try:
47
+ geom_type = ob.get("type").lower()
48
+ except AttributeError:
49
+ raise ValueError, "Context does not provide geo interface"
47
50
 
48
51
  if geom_type == "point":
49
52
  return asPoint(ob["coordinates"])
@@ -16,8 +16,12 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
16
16
  array = ob.__array_interface__
17
17
  assert len(array['shape']) == 2
18
18
  m = array['shape'][0]
19
- n = array['shape'][1]
20
- assert m >= 2
19
+ if m < 2:
20
+ raise ValueError, "LineStrings must have at least 2 coordinate tuples"
21
+ try:
22
+ n = array['shape'][1]
23
+ except IndexError:
24
+ raise ValueError, "Input %s is the wrong shape for a LineString" % str(ob)
21
25
  assert n == 2 or n == 3
22
26
 
23
27
  # Make pointer to the coordinate array
@@ -42,8 +46,11 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
42
46
  dy = c_double(cp[n*i+1])
43
47
  dz = None
44
48
  if n == 3:
45
- dz = c_double(cp[n*i+2])
46
-
49
+ try:
50
+ dz = c_double(cp[n*i+2])
51
+ except IndexError:
52
+ raise ValueError, "Inconsistent coordinate dimensionality"
53
+
47
54
  # Because of a bug in the GEOS C API,
48
55
  # always set X before Y
49
56
  lgeos.GEOSCoordSeq_setX(cs, i, dx)
@@ -54,8 +61,12 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
54
61
  except AttributeError:
55
62
  # Fall back on list
56
63
  m = len(ob)
57
- n = len(ob[0])
58
- assert m >= 2
64
+ if m < 2:
65
+ raise ValueError, "LineStrings must have at least 2 coordinate tuples"
66
+ try:
67
+ n = len(ob[0])
68
+ except TypeError:
69
+ raise ValueError, "Input %s is the wrong shape for a LineString" % str(ob)
59
70
  assert n == 2 or n == 3
60
71
 
61
72
  # Create a coordinate sequence
@@ -75,7 +86,10 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
75
86
  dy = c_double(coords[1])
76
87
  dz = None
77
88
  if n == 3:
78
- dz = c_double(coords[2])
89
+ try:
90
+ dz = c_double(coords[2])
91
+ except IndexError:
92
+ raise ValueError, "Inconsistent coordinate dimensionality"
79
93
 
80
94
  # Because of a bug in the GEOS C API,
81
95
  # always set X before Y
@@ -17,7 +17,8 @@ def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
17
17
  assert len(array['shape']) == 2
18
18
  m = array['shape'][0]
19
19
  n = array['shape'][1]
20
- assert m >= 2
20
+ if m < 3:
21
+ raise ValueError, "A LinearRing must have at least 3 coordinate tuples"
21
22
  assert n == 2 or n == 3
22
23
 
23
24
  # Make pointer to the coordinate array
@@ -76,7 +77,8 @@ def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
76
77
  # Fall back on list
77
78
  m = len(ob)
78
79
  n = len(ob[0])
79
- assert m >= 2
80
+ if m < 3:
81
+ raise ValueError, "A LinearRing must have at least 3 coordinate tuples"
80
82
  assert (n == 2 or n == 3)
81
83
 
82
84
  # Add closing coordinates if not provided
@@ -1,4 +1,5 @@
1
1
  """
2
+ Iterative forms of operations.
2
3
  """
3
4
 
4
5
  from ctypes import c_char_p, c_size_t
@@ -36,7 +37,7 @@ class BinaryPredicateIterator(object):
36
37
  except TypeError:
37
38
  this_geom = item
38
39
  ob = this_geom
39
- if this_geom._geom is None:
40
+ if not this_geom._geom:
40
41
  raise ValueError, "Null geometry supports no operations"
41
42
  retval = self.fn(geom._geom, this_geom._geom)
42
43
  if retval == 2:
@@ -53,4 +54,3 @@ within = BinaryPredicateIterator(lgeos.GEOSWithin)
53
54
  contains = BinaryPredicateIterator(lgeos.GEOSContains)
54
55
  overlaps = BinaryPredicateIterator(lgeos.GEOSOverlaps)
55
56
  equals = BinaryPredicateIterator(lgeos.GEOSEquals)
56
-
@@ -0,0 +1,29 @@
1
+ from shapely.geos import lgeos
2
+ from shapely.geometry.base import geom_factory, BaseGeometry
3
+ from shapely.geometry import asShape, asLineString
4
+ from ctypes import byref, c_void_p
5
+
6
+ def shapeup(ob):
7
+ if isinstance(ob, BaseGeometry):
8
+ return ob
9
+ else:
10
+ try:
11
+ return asShape(ob)
12
+ except ValueError:
13
+ return asLineString(ob)
14
+
15
+ def polygonize(iterator):
16
+ """Creates polygons from a list of LineString objects.
17
+ """
18
+ lines = [shapeup(ob) for ob in iterator]
19
+ geom_array_type = c_void_p * len(lines)
20
+ geom_array = geom_array_type()
21
+ for i, line in enumerate(lines):
22
+ geom_array[i] = line._geom
23
+ product = lgeos.GEOSPolygonize(byref(geom_array), len(lines))
24
+ collection = geom_factory(product)
25
+ for g in collection.geoms:
26
+ clone = lgeos.GEOSGeom_clone(g._geom)
27
+ g = geom_factory(clone)
28
+ g._owned = False
29
+ yield g
@@ -27,7 +27,7 @@ class BinaryPredicate(object):
27
27
  return self
28
28
 
29
29
  def __call__(self, other):
30
- if self.context._geom is None or other._geom is None:
30
+ if not self.context._geom or not other._geom:
31
31
  raise ValueError, "Null geometry supports no operations"
32
32
  return bool(self.fn(self.context._geom, other._geom))
33
33
 
@@ -49,7 +49,7 @@ class UnaryPredicate(object):
49
49
  self.fn.errcheck = errcheck
50
50
 
51
51
  def __get__(self, obj, objtype=None):
52
- if obj._geom is None:
52
+ if not obj._geom:
53
53
  raise ValueError, "Null geometry supports no operations"
54
54
  return bool(self.fn(obj._geom))
55
55
 
@@ -139,4 +139,10 @@ Check that we can set coordinates of a null geometry
139
139
  >>> print r_null.length # doctest: +ELLIPSIS
140
140
  3.414...
141
141
 
142
+ Error handling
143
+ --------------
142
144
 
145
+ >>> p = Polygon([[1,2], [2, 3]])
146
+ Traceback (most recent call last):
147
+ ...
148
+ ValueError: A LinearRing must have at least 3 coordinate tuples
@@ -0,0 +1,29 @@
1
+ Polygonizing
2
+ ============
3
+
4
+ >>> from shapely.geometry import LineString, Point
5
+ >>> from shapely.ops import polygonize
6
+ >>> lines = [
7
+ ... LineString(((0, 0), (1, 1))),
8
+ ... LineString(((0, 0), (0, 1))),
9
+ ... LineString(((0, 1), (1, 1))),
10
+ ... LineString(((1, 1), (1, 0))),
11
+ ... LineString(((1, 0), (0, 0))),
12
+ ... LineString(((5, 5), (6, 6))),
13
+ ... Point(0, 0),
14
+ ... ]
15
+ >>> result = polygonize(lines)
16
+ >>> list(result)
17
+ [<shapely.geometry.polygon.Polygon object at ...>, <shapely.geometry.polygon.Polygon object at ...>]
18
+
19
+ >>> lines2 = [
20
+ ... ((0, 0), (1, 1)),
21
+ ... ((0, 0), (0, 1)),
22
+ ... ((0, 1), (1, 1)),
23
+ ... ((1, 1), (1, 0)),
24
+ ... ((1, 0), (0, 0)),
25
+ ... ((5, 5), (6, 6)),
26
+ ... ]
27
+ >>> result2 = polygonize(lines2)
28
+ >>> list(result2)
29
+ [<shapely.geometry.polygon.Polygon object at ...>, <shapely.geometry.polygon.Polygon object at ...>]
@@ -1,24 +0,0 @@
1
- """
2
- Geometry collections.
3
- """
4
-
5
- from shapely.geometry.base import BaseGeometry
6
-
7
- class GeometryCollection(BaseGeometry):
8
-
9
- """A geometry collection.
10
- """
11
-
12
- def __init__(self):
13
- BaseGeometry.__init__(self)
14
-
15
-
16
- # Test runner
17
- def _test():
18
- import doctest
19
- doctest.testmod()
20
-
21
-
22
- if __name__ == "__main__":
23
- _test()
24
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes