pyopencl 2025.1__cp313-cp313-win_amd64.whl → 2025.2.2__cp313-cp313-win_amd64.whl
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.
Potentially problematic release.
This version of pyopencl might be problematic. Click here for more details.
- pyopencl/__init__.py +582 -997
- pyopencl/_cl.cp313-win_amd64.pyd +0 -0
- pyopencl/_cl.pyi +2006 -0
- pyopencl/_cluda.py +3 -0
- pyopencl/_monkeypatch.py +1063 -0
- pyopencl/_mymako.py +3 -0
- pyopencl/algorithm.py +29 -24
- pyopencl/array.py +300 -255
- pyopencl/bitonic_sort.py +5 -2
- pyopencl/bitonic_sort_templates.py +3 -0
- pyopencl/cache.py +5 -5
- pyopencl/capture_call.py +31 -8
- pyopencl/characterize/__init__.py +26 -19
- pyopencl/characterize/performance.py +3 -0
- pyopencl/clmath.py +2 -0
- pyopencl/clrandom.py +3 -0
- pyopencl/cltypes.py +67 -2
- pyopencl/compyte/.basedpyright/baseline.json +1272 -0
- pyopencl/compyte/array.py +36 -9
- pyopencl/compyte/dtypes.py +61 -29
- pyopencl/compyte/pyproject.toml +17 -22
- pyopencl/elementwise.py +13 -10
- pyopencl/invoker.py +13 -17
- pyopencl/ipython_ext.py +2 -0
- pyopencl/py.typed +0 -0
- pyopencl/reduction.py +72 -43
- pyopencl/scan.py +31 -30
- pyopencl/tools.py +128 -90
- pyopencl/typing.py +57 -0
- pyopencl/version.py +2 -0
- {pyopencl-2025.1.dist-info → pyopencl-2025.2.2.dist-info}/METADATA +11 -10
- pyopencl-2025.2.2.dist-info/RECORD +47 -0
- {pyopencl-2025.1.dist-info → pyopencl-2025.2.2.dist-info}/WHEEL +1 -1
- pyopencl-2025.1.dist-info/RECORD +0 -42
- {pyopencl-2025.1.dist-info → pyopencl-2025.2.2.dist-info}/licenses/LICENSE +0 -0
pyopencl/bitonic_sort.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
__copyright__ = """
|
|
2
5
|
Copyright (c) 2011, Eric Bainville
|
|
3
6
|
Copyright (c) 2015, Ilya Efimoff
|
|
@@ -35,7 +38,7 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
35
38
|
|
|
36
39
|
from functools import reduce
|
|
37
40
|
from operator import mul
|
|
38
|
-
from typing import ClassVar
|
|
41
|
+
from typing import ClassVar
|
|
39
42
|
|
|
40
43
|
from mako.template import Template
|
|
41
44
|
|
|
@@ -64,7 +67,7 @@ class BitonicSort:
|
|
|
64
67
|
.. automethod:: __call__
|
|
65
68
|
"""
|
|
66
69
|
|
|
67
|
-
kernels_srcs: ClassVar[
|
|
70
|
+
kernels_srcs: ClassVar[dict[str, str]] = {
|
|
68
71
|
"B2": _tmpl.ParallelBitonic_B2,
|
|
69
72
|
"B4": _tmpl.ParallelBitonic_B4,
|
|
70
73
|
"B8": _tmpl.ParallelBitonic_B8,
|
pyopencl/cache.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""PyOpenCL compiler cache."""
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
__copyright__ = "Copyright (C) 2011 Andreas Kloeckner"
|
|
@@ -28,7 +29,6 @@ import os
|
|
|
28
29
|
import re
|
|
29
30
|
import sys
|
|
30
31
|
from dataclasses import dataclass
|
|
31
|
-
from typing import List, Optional, Tuple
|
|
32
32
|
|
|
33
33
|
import pyopencl._cl as _cl
|
|
34
34
|
|
|
@@ -339,8 +339,8 @@ def retrieve_from_cache(cache_dir, cache_key):
|
|
|
339
339
|
|
|
340
340
|
@dataclass(frozen=True)
|
|
341
341
|
class _SourceInfo:
|
|
342
|
-
dependencies:
|
|
343
|
-
log:
|
|
342
|
+
dependencies: list[tuple[str, ...]]
|
|
343
|
+
log: str | None
|
|
344
344
|
|
|
345
345
|
|
|
346
346
|
def _create_built_program_from_source_cached(ctx, src, options_bytes,
|
|
@@ -373,7 +373,7 @@ def _create_built_program_from_source_cached(ctx, src, options_bytes,
|
|
|
373
373
|
binaries = []
|
|
374
374
|
to_be_built_indices = []
|
|
375
375
|
logs = []
|
|
376
|
-
for i, (_device, cache_key) in enumerate(zip(devices, cache_keys)):
|
|
376
|
+
for i, (_device, cache_key) in enumerate(zip(devices, cache_keys, strict=True)):
|
|
377
377
|
cache_result = retrieve_from_cache(cache_dir, cache_key)
|
|
378
378
|
|
|
379
379
|
if cache_result is None:
|
|
@@ -391,7 +391,7 @@ def _create_built_program_from_source_cached(ctx, src, options_bytes,
|
|
|
391
391
|
|
|
392
392
|
message = (75*"="+"\n").join(
|
|
393
393
|
f"Build on {dev} succeeded, but said:\n\n{log}"
|
|
394
|
-
for dev, log in zip(devices, logs)
|
|
394
|
+
for dev, log in zip(devices, logs, strict=True)
|
|
395
395
|
if log is not None and log.strip())
|
|
396
396
|
|
|
397
397
|
if message:
|
pyopencl/capture_call.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
__copyright__ = "Copyright (C) 2013 Andreas Kloeckner"
|
|
2
5
|
|
|
3
6
|
__license__ = """
|
|
@@ -21,6 +24,8 @@ THE SOFTWARE.
|
|
|
21
24
|
"""
|
|
22
25
|
|
|
23
26
|
|
|
27
|
+
from typing import TYPE_CHECKING, TextIO, cast
|
|
28
|
+
|
|
24
29
|
import numpy as np
|
|
25
30
|
|
|
26
31
|
from pytools.py_codegen import Indentation, PythonCodeGenerator
|
|
@@ -28,9 +33,26 @@ from pytools.py_codegen import Indentation, PythonCodeGenerator
|
|
|
28
33
|
import pyopencl as cl
|
|
29
34
|
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from numpy.typing import DTypeLike
|
|
38
|
+
|
|
39
|
+
from pyopencl.typing import KernelArg, WaitList
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def capture_kernel_call(
|
|
43
|
+
kernel: cl.Kernel,
|
|
44
|
+
output_file: str | TextIO,
|
|
45
|
+
queue: cl.CommandQueue,
|
|
46
|
+
g_size: tuple[int, ...],
|
|
47
|
+
l_size: tuple[int, ...] | None,
|
|
48
|
+
*args: KernelArg,
|
|
49
|
+
wait_for: WaitList = None, # pyright: ignore[reportUnusedParameter]
|
|
50
|
+
g_times_l: bool = False,
|
|
51
|
+
allow_empty_ndrange: bool = False,
|
|
52
|
+
global_offset: tuple[int, ...] | None = None,
|
|
53
|
+
) -> None:
|
|
32
54
|
try:
|
|
33
|
-
source = kernel._source
|
|
55
|
+
source = cast("str | None", kernel._source) # pyright: ignore[reportAttributeAccessIssue]
|
|
34
56
|
except AttributeError as err:
|
|
35
57
|
raise RuntimeError("cannot capture call, kernel source not available") from err
|
|
36
58
|
|
|
@@ -55,7 +77,7 @@ def capture_kernel_call(kernel, output_file, queue, g_size, l_size, *args, **kwa
|
|
|
55
77
|
|
|
56
78
|
# {{{ invocation
|
|
57
79
|
|
|
58
|
-
arg_data = []
|
|
80
|
+
arg_data: list[tuple[str, memoryview | bytearray]] = []
|
|
59
81
|
|
|
60
82
|
cg("")
|
|
61
83
|
cg("")
|
|
@@ -65,7 +87,7 @@ def capture_kernel_call(kernel, output_file, queue, g_size, l_size, *args, **kwa
|
|
|
65
87
|
cg("queue = cl.CommandQueue(ctx)")
|
|
66
88
|
cg("")
|
|
67
89
|
|
|
68
|
-
kernel_args = []
|
|
90
|
+
kernel_args: list[str] = []
|
|
69
91
|
|
|
70
92
|
for i, arg in enumerate(args):
|
|
71
93
|
if isinstance(arg, cl.Buffer):
|
|
@@ -101,22 +123,23 @@ def capture_kernel_call(kernel, output_file, queue, g_size, l_size, *args, **kwa
|
|
|
101
123
|
|
|
102
124
|
cg("")
|
|
103
125
|
|
|
104
|
-
g_times_l = kwargs.get("g_times_l", False)
|
|
105
126
|
if g_times_l:
|
|
127
|
+
assert l_size is not None
|
|
106
128
|
dim = max(len(g_size), len(l_size))
|
|
107
129
|
l_size = l_size + (1,) * (dim-len(l_size))
|
|
108
130
|
g_size = g_size + (1,) * (dim-len(g_size))
|
|
109
131
|
g_size = tuple(
|
|
110
|
-
gs*ls for gs, ls in zip(g_size, l_size))
|
|
132
|
+
gs*ls for gs, ls in zip(g_size, l_size, strict=True))
|
|
111
133
|
|
|
112
|
-
global_offset = kwargs.get("global_offset", None)
|
|
113
134
|
if global_offset is not None:
|
|
114
135
|
kernel_args.append("global_offset=%s" % repr(global_offset))
|
|
136
|
+
if allow_empty_ndrange:
|
|
137
|
+
kernel_args.append("allow_empty_ndrange=%s" % repr(allow_empty_ndrange))
|
|
115
138
|
|
|
116
139
|
cg("prg = cl.Program(ctx, CODE).build()")
|
|
117
140
|
cg("knl = prg.%s" % kernel.function_name)
|
|
118
141
|
if hasattr(kernel, "_scalar_arg_dtypes"):
|
|
119
|
-
def strify_dtype(d):
|
|
142
|
+
def strify_dtype(d: DTypeLike):
|
|
120
143
|
if d is None:
|
|
121
144
|
return "None"
|
|
122
145
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
__copyright__ = "Copyright (C) 2009 Andreas Kloeckner"
|
|
2
5
|
|
|
3
6
|
__license__ = """
|
|
@@ -20,7 +23,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
20
23
|
THE SOFTWARE.
|
|
21
24
|
"""
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
|
|
27
|
+
from typing import cast
|
|
24
28
|
|
|
25
29
|
from pytools import memoize
|
|
26
30
|
|
|
@@ -32,14 +36,14 @@ class CLCharacterizationWarning(UserWarning):
|
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
@memoize
|
|
35
|
-
def has_double_support(dev):
|
|
39
|
+
def has_double_support(dev: cl.Device):
|
|
36
40
|
for ext in dev.extensions.split(" "):
|
|
37
41
|
if ext == "cl_khr_fp64":
|
|
38
42
|
return True
|
|
39
43
|
return False
|
|
40
44
|
|
|
41
45
|
|
|
42
|
-
def has_amd_double_support(dev):
|
|
46
|
+
def has_amd_double_support(dev: cl.Device):
|
|
43
47
|
""""Fix to allow incomplete amd double support in low end boards"""
|
|
44
48
|
|
|
45
49
|
for ext in dev.extensions.split(" "):
|
|
@@ -48,7 +52,10 @@ def has_amd_double_support(dev):
|
|
|
48
52
|
return False
|
|
49
53
|
|
|
50
54
|
|
|
51
|
-
def reasonable_work_group_size_multiple(
|
|
55
|
+
def reasonable_work_group_size_multiple(
|
|
56
|
+
dev: cl.Device,
|
|
57
|
+
ctx: cl.Context | None = None
|
|
58
|
+
):
|
|
52
59
|
try:
|
|
53
60
|
return dev.warp_size_nv
|
|
54
61
|
except Exception:
|
|
@@ -63,12 +70,12 @@ def reasonable_work_group_size_multiple(dev, ctx=None):
|
|
|
63
70
|
}
|
|
64
71
|
""")
|
|
65
72
|
prg.build()
|
|
66
|
-
return prg.knl.get_work_group_info(
|
|
73
|
+
return cast("int", prg.knl.get_work_group_info(
|
|
67
74
|
cl.kernel_work_group_info.PREFERRED_WORK_GROUP_SIZE_MULTIPLE,
|
|
68
|
-
dev)
|
|
75
|
+
dev))
|
|
69
76
|
|
|
70
77
|
|
|
71
|
-
def nv_compute_capability(dev):
|
|
78
|
+
def nv_compute_capability(dev: cl.Device):
|
|
72
79
|
"""If *dev* is an Nvidia GPU :class:`pyopencl.Device`, return a tuple
|
|
73
80
|
*(major, minor)* indicating the device's compute capability.
|
|
74
81
|
"""
|
|
@@ -80,7 +87,7 @@ def nv_compute_capability(dev):
|
|
|
80
87
|
return None
|
|
81
88
|
|
|
82
89
|
|
|
83
|
-
def usable_local_mem_size(dev, nargs=None):
|
|
90
|
+
def usable_local_mem_size(dev: cl.Device, nargs: int | None = None):
|
|
84
91
|
"""Return an estimate of the usable local memory size.
|
|
85
92
|
:arg nargs: Number of 32-bit arguments passed.
|
|
86
93
|
"""
|
|
@@ -101,7 +108,7 @@ def usable_local_mem_size(dev, nargs=None):
|
|
|
101
108
|
return usable_local_mem_size
|
|
102
109
|
|
|
103
110
|
|
|
104
|
-
def simultaneous_work_items_on_local_access(dev):
|
|
111
|
+
def simultaneous_work_items_on_local_access(dev: cl.Device):
|
|
105
112
|
"""Return the number of work items that access local
|
|
106
113
|
memory simultaneously and thereby may conflict with
|
|
107
114
|
each other.
|
|
@@ -136,12 +143,12 @@ def simultaneous_work_items_on_local_access(dev):
|
|
|
136
143
|
return 16
|
|
137
144
|
|
|
138
145
|
|
|
139
|
-
def local_memory_access_granularity(dev):
|
|
146
|
+
def local_memory_access_granularity(dev: cl.Device):
|
|
140
147
|
"""Return the number of bytes per bank in local memory."""
|
|
141
148
|
return 4
|
|
142
149
|
|
|
143
150
|
|
|
144
|
-
def local_memory_bank_count(dev):
|
|
151
|
+
def local_memory_bank_count(dev: cl.Device):
|
|
145
152
|
"""Return the number of banks present in local memory.
|
|
146
153
|
"""
|
|
147
154
|
nv_compute_cap = nv_compute_capability(dev)
|
|
@@ -219,7 +226,7 @@ def why_not_local_access_conflict_free(dev, itemsize,
|
|
|
219
226
|
idx = []
|
|
220
227
|
left_over_idx = work_item_id
|
|
221
228
|
for axis, (ax_size, ax_stor_size) in enumerate(
|
|
222
|
-
zip(array_shape, array_stored_shape)):
|
|
229
|
+
zip(array_shape, array_stored_shape, strict=True)):
|
|
223
230
|
|
|
224
231
|
if axis >= work_item_axis:
|
|
225
232
|
left_over_idx, ax_idx = divmod(left_over_idx, ax_size)
|
|
@@ -258,7 +265,7 @@ def why_not_local_access_conflict_free(dev, itemsize,
|
|
|
258
265
|
return 1, None
|
|
259
266
|
|
|
260
267
|
|
|
261
|
-
def get_fast_inaccurate_build_options(dev):
|
|
268
|
+
def get_fast_inaccurate_build_options(dev: cl.Device):
|
|
262
269
|
"""Return a list of flags valid on device *dev* that enable fast, but
|
|
263
270
|
potentially inaccurate floating point math.
|
|
264
271
|
"""
|
|
@@ -269,7 +276,7 @@ def get_fast_inaccurate_build_options(dev):
|
|
|
269
276
|
return result
|
|
270
277
|
|
|
271
278
|
|
|
272
|
-
def get_simd_group_size(dev, type_size):
|
|
279
|
+
def get_simd_group_size(dev: cl.Device, type_size: int):
|
|
273
280
|
"""Return an estimate of how many work items will be executed across SIMD
|
|
274
281
|
lanes. This returns the size of what Nvidia calls a warp and what AMD calls
|
|
275
282
|
a wavefront.
|
|
@@ -323,8 +330,8 @@ def get_simd_group_size(dev, type_size):
|
|
|
323
330
|
|
|
324
331
|
def get_pocl_version(
|
|
325
332
|
platform: cl.Platform,
|
|
326
|
-
fallback_value:
|
|
327
|
-
) ->
|
|
333
|
+
fallback_value: tuple[int, int] | None = None
|
|
334
|
+
) -> tuple[int, int] | None:
|
|
328
335
|
if platform.name != "Portable Computing Language":
|
|
329
336
|
return None
|
|
330
337
|
|
|
@@ -342,12 +349,12 @@ def get_pocl_version(
|
|
|
342
349
|
return (int(ver_match.group(1)), int(ver_match.group(2)))
|
|
343
350
|
|
|
344
351
|
|
|
345
|
-
_CHECK_FOR_POCL_ARG_COUNT_BUG_CACHE:
|
|
352
|
+
_CHECK_FOR_POCL_ARG_COUNT_BUG_CACHE: dict[cl.Device, bool] = {}
|
|
346
353
|
|
|
347
354
|
|
|
348
355
|
def _check_for_pocl_arg_count_bug(
|
|
349
356
|
dev: cl.Device,
|
|
350
|
-
ctx:
|
|
357
|
+
ctx: cl.Context | None = None) -> bool:
|
|
351
358
|
try:
|
|
352
359
|
return _CHECK_FOR_POCL_ARG_COUNT_BUG_CACHE[dev]
|
|
353
360
|
except KeyError:
|
|
@@ -437,7 +444,7 @@ def has_fine_grain_system_svm_atomics(dev):
|
|
|
437
444
|
# }}}
|
|
438
445
|
|
|
439
446
|
|
|
440
|
-
def has_src_build_cache(dev: cl.Device) ->
|
|
447
|
+
def has_src_build_cache(dev: cl.Device) -> bool | None:
|
|
441
448
|
"""
|
|
442
449
|
Return *True* if *dev* has internal support for caching builds from source,
|
|
443
450
|
*False* if it doesn't, and *None* if unknown.
|
pyopencl/clmath.py
CHANGED
pyopencl/clrandom.py
CHANGED
pyopencl/cltypes.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
__copyright__ = "Copyright (C) 2016 Jonathan Mackenzie"
|
|
2
5
|
|
|
3
6
|
__license__ = """
|
|
@@ -19,6 +22,7 @@ THE SOFTWARE.
|
|
|
19
22
|
"""
|
|
20
23
|
|
|
21
24
|
import warnings
|
|
25
|
+
from typing import Any
|
|
22
26
|
|
|
23
27
|
import numpy as np
|
|
24
28
|
|
|
@@ -89,10 +93,11 @@ def _create_vector_types():
|
|
|
89
93
|
except NotImplementedError:
|
|
90
94
|
try:
|
|
91
95
|
dtype = np.dtype([((n, title), base_type)
|
|
92
|
-
for (n, title)
|
|
96
|
+
for (n, title)
|
|
97
|
+
in zip(names, titles, strict=True)])
|
|
93
98
|
except TypeError:
|
|
94
99
|
dtype = np.dtype([(n, base_type) for (n, title)
|
|
95
|
-
in zip(names, titles)])
|
|
100
|
+
in zip(names, titles, strict=True)])
|
|
96
101
|
|
|
97
102
|
get_or_register_dtype(name, dtype)
|
|
98
103
|
|
|
@@ -134,4 +139,64 @@ vec_types, vec_type_to_scalar_and_count = _create_vector_types()
|
|
|
134
139
|
|
|
135
140
|
# }}}
|
|
136
141
|
|
|
142
|
+
char2: np.dtype[Any]
|
|
143
|
+
char3: np.dtype[Any]
|
|
144
|
+
char4: np.dtype[Any]
|
|
145
|
+
char8: np.dtype[Any]
|
|
146
|
+
char16: np.dtype[Any]
|
|
147
|
+
|
|
148
|
+
uchar2: np.dtype[Any]
|
|
149
|
+
uchar3: np.dtype[Any]
|
|
150
|
+
uchar4: np.dtype[Any]
|
|
151
|
+
uchar8: np.dtype[Any]
|
|
152
|
+
uchar16: np.dtype[Any]
|
|
153
|
+
|
|
154
|
+
short2: np.dtype[Any]
|
|
155
|
+
short3: np.dtype[Any]
|
|
156
|
+
short4: np.dtype[Any]
|
|
157
|
+
short8: np.dtype[Any]
|
|
158
|
+
short16: np.dtype[Any]
|
|
159
|
+
|
|
160
|
+
ushort2: np.dtype[Any]
|
|
161
|
+
ushort3: np.dtype[Any]
|
|
162
|
+
ushort4: np.dtype[Any]
|
|
163
|
+
ushort8: np.dtype[Any]
|
|
164
|
+
ushort16: np.dtype[Any]
|
|
165
|
+
|
|
166
|
+
int2: np.dtype[Any]
|
|
167
|
+
int3: np.dtype[Any]
|
|
168
|
+
int4: np.dtype[Any]
|
|
169
|
+
int8: np.dtype[Any]
|
|
170
|
+
int16: np.dtype[Any]
|
|
171
|
+
|
|
172
|
+
uint2: np.dtype[Any]
|
|
173
|
+
uint3: np.dtype[Any]
|
|
174
|
+
uint4: np.dtype[Any]
|
|
175
|
+
uint8: np.dtype[Any]
|
|
176
|
+
uint16: np.dtype[Any]
|
|
177
|
+
|
|
178
|
+
long2: np.dtype[Any]
|
|
179
|
+
long3: np.dtype[Any]
|
|
180
|
+
long4: np.dtype[Any]
|
|
181
|
+
long8: np.dtype[Any]
|
|
182
|
+
long16: np.dtype[Any]
|
|
183
|
+
|
|
184
|
+
ulong2: np.dtype[Any]
|
|
185
|
+
ulong3: np.dtype[Any]
|
|
186
|
+
ulong4: np.dtype[Any]
|
|
187
|
+
ulong8: np.dtype[Any]
|
|
188
|
+
ulong16: np.dtype[Any]
|
|
189
|
+
|
|
190
|
+
float2: np.dtype[Any]
|
|
191
|
+
float3: np.dtype[Any]
|
|
192
|
+
float4: np.dtype[Any]
|
|
193
|
+
float8: np.dtype[Any]
|
|
194
|
+
float16: np.dtype[Any]
|
|
195
|
+
|
|
196
|
+
double2: np.dtype[Any]
|
|
197
|
+
double3: np.dtype[Any]
|
|
198
|
+
double4: np.dtype[Any]
|
|
199
|
+
double8: np.dtype[Any]
|
|
200
|
+
double16: np.dtype[Any]
|
|
201
|
+
|
|
137
202
|
# vim: foldmethod=marker
|