ansys-pyensight-core 0.8.11__py3-none-any.whl → 0.8.13__py3-none-any.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 ansys-pyensight-core might be problematic. Click here for more details.
- ansys/pyensight/core/common.py +216 -216
- ansys/pyensight/core/deep_pixel_view.html +10 -10
- ansys/pyensight/core/ensight_grpc.py +432 -432
- ansys/pyensight/core/libuserd.py +1953 -1945
- ansys/pyensight/core/locallauncher.py +2 -0
- ansys/pyensight/core/renderable.py +853 -844
- ansys/pyensight/core/session.py +1820 -1820
- ansys/pyensight/core/utils/dsg_server.py +1085 -912
- ansys/pyensight/core/utils/export.py +584 -584
- ansys/pyensight/core/utils/omniverse.py +362 -362
- ansys/pyensight/core/utils/omniverse_cli.py +520 -481
- ansys/pyensight/core/utils/omniverse_dsg_server.py +882 -690
- ansys/pyensight/core/utils/omniverse_glb_server.py +631 -279
- ansys/pyensight/core/utils/parts.py +1199 -1199
- ansys/pyensight/core/utils/variables.py +1 -1
- {ansys_pyensight_core-0.8.11.dist-info → ansys_pyensight_core-0.8.13.dist-info}/METADATA +11 -9
- ansys_pyensight_core-0.8.13.dist-info/RECORD +36 -0
- {ansys_pyensight_core-0.8.11.dist-info → ansys_pyensight_core-0.8.13.dist-info}/WHEEL +1 -1
- ansys_pyensight_core-0.8.11.dist-info/RECORD +0 -36
- {ansys_pyensight_core-0.8.11.dist-info → ansys_pyensight_core-0.8.13.dist-info}/LICENSE +0 -0
ansys/pyensight/core/common.py
CHANGED
|
@@ -1,216 +1,216 @@
|
|
|
1
|
-
""" This module provides a list of common utilities shared between different PyEnSight modules."""
|
|
2
|
-
|
|
3
|
-
import random
|
|
4
|
-
import re
|
|
5
|
-
import socket
|
|
6
|
-
import time
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
|
|
8
|
-
|
|
9
|
-
from ansys.pyensight.core import enshell_grpc
|
|
10
|
-
import urllib3
|
|
11
|
-
|
|
12
|
-
try:
|
|
13
|
-
from simple_upload_server.client import Client
|
|
14
|
-
|
|
15
|
-
simple_upload_server_is_available = True # pragma: no cover
|
|
16
|
-
except Exception:
|
|
17
|
-
simple_upload_server_is_available = False
|
|
18
|
-
|
|
19
|
-
if TYPE_CHECKING:
|
|
20
|
-
from docker import DockerClient
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def find_unused_ports(count: int, avoid: Optional[List[int]] = None) -> Optional[List[int]]:
|
|
24
|
-
"""Find "count" unused ports on the host system
|
|
25
|
-
|
|
26
|
-
A port is considered unused if it does not respond to a "connect" attempt. Walk
|
|
27
|
-
the ports from 'start' to 'end' looking for unused ports and avoiding any ports
|
|
28
|
-
in the 'avoid' list. Stop once the desired number of ports have been
|
|
29
|
-
found. If an insufficient number of ports were found, return None.
|
|
30
|
-
|
|
31
|
-
Parameters
|
|
32
|
-
----------
|
|
33
|
-
count: int :
|
|
34
|
-
Number of unused ports to find
|
|
35
|
-
avoid: Optional[List[int]] :
|
|
36
|
-
An optional list of ports not to check
|
|
37
|
-
|
|
38
|
-
Returns
|
|
39
|
-
-------
|
|
40
|
-
The detected ports or None on failure
|
|
41
|
-
|
|
42
|
-
"""
|
|
43
|
-
if avoid is None:
|
|
44
|
-
avoid = []
|
|
45
|
-
ports = list()
|
|
46
|
-
|
|
47
|
-
# pick a starting port number
|
|
48
|
-
start = random.randint(1024, 64000)
|
|
49
|
-
# We will scan for 65530 ports unless end is specified
|
|
50
|
-
port_mod = 65530
|
|
51
|
-
end = start + port_mod - 1
|
|
52
|
-
# walk the "virtual" port range
|
|
53
|
-
for base_port in range(start, end + 1):
|
|
54
|
-
# Map to physical port range
|
|
55
|
-
# There have been some issues with 65534+ so we stop at 65530
|
|
56
|
-
port = base_port % port_mod
|
|
57
|
-
# port 0 is special
|
|
58
|
-
if port == 0: # pragma: no cover
|
|
59
|
-
continue # pragma: no cover
|
|
60
|
-
# avoid admin ports
|
|
61
|
-
if port < 1024: # pragma: no cover
|
|
62
|
-
continue # pragma: no cover
|
|
63
|
-
# are we supposed to skip this one?
|
|
64
|
-
if port in avoid: # pragma: no cover
|
|
65
|
-
continue # pragma: no cover
|
|
66
|
-
# is anyone listening?
|
|
67
|
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
68
|
-
result = sock.connect_ex(("127.0.0.1", port))
|
|
69
|
-
if result != 0:
|
|
70
|
-
ports.append(port)
|
|
71
|
-
else:
|
|
72
|
-
sock.close() # pragma: no cover
|
|
73
|
-
if len(ports) >= count:
|
|
74
|
-
return ports
|
|
75
|
-
# in case we failed...
|
|
76
|
-
if len(ports) < count: # pragma: no cover
|
|
77
|
-
return None # pragma: no cover
|
|
78
|
-
return ports # pragma: no cover
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def get_host_port(uri: str) -> Tuple[str, int]:
|
|
82
|
-
"""Get the host port for the input uri
|
|
83
|
-
|
|
84
|
-
Parameters
|
|
85
|
-
----------
|
|
86
|
-
|
|
87
|
-
uri: str
|
|
88
|
-
The Uri to inspect
|
|
89
|
-
|
|
90
|
-
Returns
|
|
91
|
-
-------
|
|
92
|
-
(tuple):
|
|
93
|
-
A tuple containing the host and the port of the input uri
|
|
94
|
-
"""
|
|
95
|
-
parse_results = urllib3.util.parse_url(uri)
|
|
96
|
-
port = (
|
|
97
|
-
parse_results.port
|
|
98
|
-
if parse_results.port
|
|
99
|
-
else (443 if re.search("^https|wss$", parse_results.scheme) else None)
|
|
100
|
-
)
|
|
101
|
-
return (parse_results.host, port)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def get_file_service(pim_instance: Any) -> Optional[Any]: # pragma: no cover
|
|
105
|
-
"""Get the file service object for the input pim instance.
|
|
106
|
-
|
|
107
|
-
Parameters
|
|
108
|
-
----------
|
|
109
|
-
|
|
110
|
-
pim_instance:
|
|
111
|
-
the PIM instance to get the service from.
|
|
112
|
-
|
|
113
|
-
Returns
|
|
114
|
-
-------
|
|
115
|
-
|
|
116
|
-
pim_file_service:
|
|
117
|
-
the PIM file service object
|
|
118
|
-
"""
|
|
119
|
-
if simple_upload_server_is_available is False:
|
|
120
|
-
return None
|
|
121
|
-
if pim_instance is None:
|
|
122
|
-
return None
|
|
123
|
-
|
|
124
|
-
if "http-simple-upload-server" in pim_instance.services:
|
|
125
|
-
pim_file_service = Client(
|
|
126
|
-
token="token",
|
|
127
|
-
url=pim_instance.services["http-simple-upload-server"].uri,
|
|
128
|
-
headers=pim_instance.services["http-simple-upload-server"].headers,
|
|
129
|
-
)
|
|
130
|
-
return pim_file_service
|
|
131
|
-
return None
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def populate_service_host_port( # pragma: no cover
|
|
135
|
-
pim_instance: Any, service_host_port: Dict[str, Tuple[str, int]], webui: bool = False
|
|
136
|
-
) -> Dict[str, Tuple[str, int]]:
|
|
137
|
-
"""Populate the service host port dictionary with the services available in the PIM instance.
|
|
138
|
-
|
|
139
|
-
Parameters
|
|
140
|
-
----------
|
|
141
|
-
pim_instance:
|
|
142
|
-
the PIM instance to get the servicea from.
|
|
143
|
-
service_host_port: dict
|
|
144
|
-
the dictionary to be updated with the services from the PIM instance
|
|
145
|
-
webui: bool
|
|
146
|
-
if True retrieve also the webUI service
|
|
147
|
-
|
|
148
|
-
Returns
|
|
149
|
-
-------
|
|
150
|
-
service_host_port: dict
|
|
151
|
-
the dictionary updated with the services from the PIM instance
|
|
152
|
-
"""
|
|
153
|
-
if not set(("grpc_private", "http", "ws")).issubset(pim_instance.services):
|
|
154
|
-
raise RuntimeError(
|
|
155
|
-
"If channel is specified, the PIM instance must have a list of length 3 "
|
|
156
|
-
+ "containing the appropriate service URIs. It does not."
|
|
157
|
-
)
|
|
158
|
-
service_host_port["grpc_private"] = get_host_port(pim_instance.services["grpc_private"].uri)
|
|
159
|
-
service_host_port["http"] = get_host_port(pim_instance.services["http"].uri)
|
|
160
|
-
service_host_port["ws"] = get_host_port(pim_instance.services["ws"].uri)
|
|
161
|
-
service_host_port["grpc"] = ("127.0.0.1", -1)
|
|
162
|
-
if webui:
|
|
163
|
-
service_host_port["webui"] = get_host_port(pim_instance.services["webui"].uri)
|
|
164
|
-
return service_host_port
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def launch_enshell_interface(
|
|
168
|
-
enshell_grpc_channel: Any, grpc_port: int, timeout: float
|
|
169
|
-
) -> enshell_grpc.EnShellGRPC:
|
|
170
|
-
"""Launch the EnShell gRPC Interface.
|
|
171
|
-
|
|
172
|
-
Parameters
|
|
173
|
-
----------
|
|
174
|
-
enshell_grpc_channel:
|
|
175
|
-
An eventual gRPC channel already available, like in the PIM case
|
|
176
|
-
grpc_port: int
|
|
177
|
-
the gRPC port to connect to
|
|
178
|
-
timeout: float
|
|
179
|
-
a timeout to wait for the gRPC connection
|
|
180
|
-
|
|
181
|
-
Returns
|
|
182
|
-
-------
|
|
183
|
-
enshell: enshell_grpc.EnShellGRPC
|
|
184
|
-
the enshell gRPC interface
|
|
185
|
-
"""
|
|
186
|
-
if enshell_grpc_channel: # pragma: no cover
|
|
187
|
-
enshell = enshell_grpc.EnShellGRPC() # pragma: no cover
|
|
188
|
-
enshell.connect_existing_channel(enshell_grpc_channel) # pragma: no cover
|
|
189
|
-
else:
|
|
190
|
-
enshell = enshell_grpc.EnShellGRPC(port=grpc_port)
|
|
191
|
-
time_start = time.time()
|
|
192
|
-
while time.time() - time_start < timeout: # pragma: no cover
|
|
193
|
-
if enshell.is_connected():
|
|
194
|
-
break
|
|
195
|
-
try:
|
|
196
|
-
enshell.connect(timeout=timeout)
|
|
197
|
-
except OSError: # pragma: no cover
|
|
198
|
-
pass # pragma: no cover
|
|
199
|
-
return enshell
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def pull_image(docker_client: "DockerClient", image_name: str) -> None:
|
|
203
|
-
"""Pull the input docker image using the input Docker Client
|
|
204
|
-
|
|
205
|
-
Parameters
|
|
206
|
-
----------
|
|
207
|
-
docker_client: DockerClient
|
|
208
|
-
the current DockerClient to pull the image with
|
|
209
|
-
image_name: str
|
|
210
|
-
the image to pull
|
|
211
|
-
"""
|
|
212
|
-
try:
|
|
213
|
-
if docker_client is not None: # pragma: no cover
|
|
214
|
-
docker_client.images.pull(image_name)
|
|
215
|
-
except Exception:
|
|
216
|
-
raise RuntimeError(f"Can't pull Docker image: {image_name}")
|
|
1
|
+
""" This module provides a list of common utilities shared between different PyEnSight modules."""
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
import re
|
|
5
|
+
import socket
|
|
6
|
+
import time
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
from ansys.pyensight.core import enshell_grpc
|
|
10
|
+
import urllib3
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from simple_upload_server.client import Client
|
|
14
|
+
|
|
15
|
+
simple_upload_server_is_available = True # pragma: no cover
|
|
16
|
+
except Exception:
|
|
17
|
+
simple_upload_server_is_available = False
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from docker import DockerClient
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def find_unused_ports(count: int, avoid: Optional[List[int]] = None) -> Optional[List[int]]:
|
|
24
|
+
"""Find "count" unused ports on the host system
|
|
25
|
+
|
|
26
|
+
A port is considered unused if it does not respond to a "connect" attempt. Walk
|
|
27
|
+
the ports from 'start' to 'end' looking for unused ports and avoiding any ports
|
|
28
|
+
in the 'avoid' list. Stop once the desired number of ports have been
|
|
29
|
+
found. If an insufficient number of ports were found, return None.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
count: int :
|
|
34
|
+
Number of unused ports to find
|
|
35
|
+
avoid: Optional[List[int]] :
|
|
36
|
+
An optional list of ports not to check
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
The detected ports or None on failure
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
if avoid is None:
|
|
44
|
+
avoid = []
|
|
45
|
+
ports = list()
|
|
46
|
+
|
|
47
|
+
# pick a starting port number
|
|
48
|
+
start = random.randint(1024, 64000)
|
|
49
|
+
# We will scan for 65530 ports unless end is specified
|
|
50
|
+
port_mod = 65530
|
|
51
|
+
end = start + port_mod - 1
|
|
52
|
+
# walk the "virtual" port range
|
|
53
|
+
for base_port in range(start, end + 1):
|
|
54
|
+
# Map to physical port range
|
|
55
|
+
# There have been some issues with 65534+ so we stop at 65530
|
|
56
|
+
port = base_port % port_mod
|
|
57
|
+
# port 0 is special
|
|
58
|
+
if port == 0: # pragma: no cover
|
|
59
|
+
continue # pragma: no cover
|
|
60
|
+
# avoid admin ports
|
|
61
|
+
if port < 1024: # pragma: no cover
|
|
62
|
+
continue # pragma: no cover
|
|
63
|
+
# are we supposed to skip this one?
|
|
64
|
+
if port in avoid: # pragma: no cover
|
|
65
|
+
continue # pragma: no cover
|
|
66
|
+
# is anyone listening?
|
|
67
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
68
|
+
result = sock.connect_ex(("127.0.0.1", port))
|
|
69
|
+
if result != 0:
|
|
70
|
+
ports.append(port)
|
|
71
|
+
else:
|
|
72
|
+
sock.close() # pragma: no cover
|
|
73
|
+
if len(ports) >= count:
|
|
74
|
+
return ports
|
|
75
|
+
# in case we failed...
|
|
76
|
+
if len(ports) < count: # pragma: no cover
|
|
77
|
+
return None # pragma: no cover
|
|
78
|
+
return ports # pragma: no cover
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_host_port(uri: str) -> Tuple[str, int]:
|
|
82
|
+
"""Get the host port for the input uri
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
|
|
87
|
+
uri: str
|
|
88
|
+
The Uri to inspect
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
(tuple):
|
|
93
|
+
A tuple containing the host and the port of the input uri
|
|
94
|
+
"""
|
|
95
|
+
parse_results = urllib3.util.parse_url(uri)
|
|
96
|
+
port = (
|
|
97
|
+
parse_results.port
|
|
98
|
+
if parse_results.port
|
|
99
|
+
else (443 if re.search("^https|wss$", parse_results.scheme) else None)
|
|
100
|
+
)
|
|
101
|
+
return (parse_results.host, port)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_file_service(pim_instance: Any) -> Optional[Any]: # pragma: no cover
|
|
105
|
+
"""Get the file service object for the input pim instance.
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
|
|
110
|
+
pim_instance:
|
|
111
|
+
the PIM instance to get the service from.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
|
|
116
|
+
pim_file_service:
|
|
117
|
+
the PIM file service object
|
|
118
|
+
"""
|
|
119
|
+
if simple_upload_server_is_available is False:
|
|
120
|
+
return None
|
|
121
|
+
if pim_instance is None:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
if "http-simple-upload-server" in pim_instance.services:
|
|
125
|
+
pim_file_service = Client(
|
|
126
|
+
token="token",
|
|
127
|
+
url=pim_instance.services["http-simple-upload-server"].uri,
|
|
128
|
+
headers=pim_instance.services["http-simple-upload-server"].headers,
|
|
129
|
+
)
|
|
130
|
+
return pim_file_service
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def populate_service_host_port( # pragma: no cover
|
|
135
|
+
pim_instance: Any, service_host_port: Dict[str, Tuple[str, int]], webui: bool = False
|
|
136
|
+
) -> Dict[str, Tuple[str, int]]:
|
|
137
|
+
"""Populate the service host port dictionary with the services available in the PIM instance.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
pim_instance:
|
|
142
|
+
the PIM instance to get the servicea from.
|
|
143
|
+
service_host_port: dict
|
|
144
|
+
the dictionary to be updated with the services from the PIM instance
|
|
145
|
+
webui: bool
|
|
146
|
+
if True retrieve also the webUI service
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
service_host_port: dict
|
|
151
|
+
the dictionary updated with the services from the PIM instance
|
|
152
|
+
"""
|
|
153
|
+
if not set(("grpc_private", "http", "ws")).issubset(pim_instance.services):
|
|
154
|
+
raise RuntimeError(
|
|
155
|
+
"If channel is specified, the PIM instance must have a list of length 3 "
|
|
156
|
+
+ "containing the appropriate service URIs. It does not."
|
|
157
|
+
)
|
|
158
|
+
service_host_port["grpc_private"] = get_host_port(pim_instance.services["grpc_private"].uri)
|
|
159
|
+
service_host_port["http"] = get_host_port(pim_instance.services["http"].uri)
|
|
160
|
+
service_host_port["ws"] = get_host_port(pim_instance.services["ws"].uri)
|
|
161
|
+
service_host_port["grpc"] = ("127.0.0.1", -1)
|
|
162
|
+
if webui:
|
|
163
|
+
service_host_port["webui"] = get_host_port(pim_instance.services["webui"].uri)
|
|
164
|
+
return service_host_port
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def launch_enshell_interface(
|
|
168
|
+
enshell_grpc_channel: Any, grpc_port: int, timeout: float
|
|
169
|
+
) -> enshell_grpc.EnShellGRPC:
|
|
170
|
+
"""Launch the EnShell gRPC Interface.
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
enshell_grpc_channel:
|
|
175
|
+
An eventual gRPC channel already available, like in the PIM case
|
|
176
|
+
grpc_port: int
|
|
177
|
+
the gRPC port to connect to
|
|
178
|
+
timeout: float
|
|
179
|
+
a timeout to wait for the gRPC connection
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
enshell: enshell_grpc.EnShellGRPC
|
|
184
|
+
the enshell gRPC interface
|
|
185
|
+
"""
|
|
186
|
+
if enshell_grpc_channel: # pragma: no cover
|
|
187
|
+
enshell = enshell_grpc.EnShellGRPC() # pragma: no cover
|
|
188
|
+
enshell.connect_existing_channel(enshell_grpc_channel) # pragma: no cover
|
|
189
|
+
else:
|
|
190
|
+
enshell = enshell_grpc.EnShellGRPC(port=grpc_port)
|
|
191
|
+
time_start = time.time()
|
|
192
|
+
while time.time() - time_start < timeout: # pragma: no cover
|
|
193
|
+
if enshell.is_connected():
|
|
194
|
+
break
|
|
195
|
+
try:
|
|
196
|
+
enshell.connect(timeout=timeout)
|
|
197
|
+
except OSError: # pragma: no cover
|
|
198
|
+
pass # pragma: no cover
|
|
199
|
+
return enshell
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def pull_image(docker_client: "DockerClient", image_name: str) -> None:
|
|
203
|
+
"""Pull the input docker image using the input Docker Client
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
docker_client: DockerClient
|
|
208
|
+
the current DockerClient to pull the image with
|
|
209
|
+
image_name: str
|
|
210
|
+
the image to pull
|
|
211
|
+
"""
|
|
212
|
+
try:
|
|
213
|
+
if docker_client is not None: # pragma: no cover
|
|
214
|
+
docker_client.images.pull(image_name)
|
|
215
|
+
except Exception:
|
|
216
|
+
raise RuntimeError(f"Can't pull Docker image: {image_name}")
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<link rel="stylesheet" type="text/css" href="/bootstrap.min.cssOPTIONAL_QUERY"/>
|
|
5
5
|
|
|
6
|
-
<script src='/
|
|
6
|
+
<script src='/jqueryJQUERY_VERSION.min.jsOPTIONAL_QUERY'></script>
|
|
7
7
|
<script src='/geotiff.jsOPTIONAL_QUERY'></script>
|
|
8
8
|
<script src='/geotiff_nexus.jsOPTIONAL_QUERY'></script>
|
|
9
9
|
<script src="/bootstrap.min.jsOPTIONAL_QUERY"></script>
|
|
@@ -76,15 +76,15 @@
|
|
|
76
76
|
<div style="margin: 0 auto; display:flex; justify-content:center;">
|
|
77
77
|
<!-- tooltip parent for img --->
|
|
78
78
|
<div id="probe_display_ITEMID"
|
|
79
|
-
data-
|
|
80
|
-
data-
|
|
81
|
-
data-
|
|
82
|
-
data-
|
|
83
|
-
data-
|
|
84
|
-
data-
|
|
85
|
-
data-
|
|
86
|
-
data-
|
|
87
|
-
data-
|
|
79
|
+
data-BS_PREFIXtoggle="tooltip"
|
|
80
|
+
data-BS_PREFIXplacement="bottom"
|
|
81
|
+
data-BS_PREFIXfallbackPlacement="['top', 'right']"
|
|
82
|
+
data-BS_PREFIXhtml="true"
|
|
83
|
+
data-BS_PREFIXcontainer="body"
|
|
84
|
+
data-BS_PREFIXboundary="viewport"
|
|
85
|
+
data-BS_PREFIXanimation="false"
|
|
86
|
+
data-BS_PREFIXtrigger="manual"
|
|
87
|
+
data-BS_PREFIXtitle='<span class="f-1r">
|
|
88
88
|
<span>X, Y : <span id="probe_xy_ITEMID">0, 0</span></span>
|
|
89
89
|
<br>
|
|
90
90
|
<span id="probe_result_ITEMID"></span>
|