diff --git a/CMakeLists.txt b/CMakeLists.txt index c1bb08e..4493ef7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ cmake_minimum_required(VERSION 3.16) -project(robot_monitoring VERSION 2.6.0) +project(robot_monitoring VERSION 2.7.5) add_subdirectory(xbot2_gui) diff --git a/proto/generic.proto b/proto/generic.proto new file mode 100644 index 0000000..95675fb --- /dev/null +++ b/proto/generic.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +import "jointstate.proto"; +import "text.proto"; +import "process_output.proto"; +import "theora_packet.proto"; + +message Message { + + int32 seq = 1; + JointState jointstate = 2; + Text text = 3; + ProcessOutput process_output = 4; + TheoraPacket theora_packet = 5; + +} diff --git a/proto/jointstate.proto b/proto/jointstate.proto new file mode 100644 index 0000000..9b3cbe4 --- /dev/null +++ b/proto/jointstate.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +message FloatArray { + repeated float value = 1; +} + +message JointState { + + repeated float linkPos = 1; + repeated float motPos = 2; + repeated float linkVel = 3; + repeated float motVel = 4; + repeated float tor = 5; + repeated float motorTemp = 6; + repeated float driverTemp = 7; + + repeated float posRef = 8; + repeated float velRef = 9; + repeated float torRef = 10; + repeated float k = 11; + repeated float d = 12; + + map aux = 13; + + float vbatt = 14; + float ibatt = 15; +} diff --git a/proto/process_output.proto b/proto/process_output.proto new file mode 100644 index 0000000..07ba237 --- /dev/null +++ b/proto/process_output.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +message ProcessOutput { + + string name = 1; + string out = 2; + string err = 3; +} diff --git a/proto/text.proto b/proto/text.proto new file mode 100644 index 0000000..8e1b38f --- /dev/null +++ b/proto/text.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; + +message Text { + + string text = 1; +} diff --git a/proto/theora_packet.proto b/proto/theora_packet.proto new file mode 100644 index 0000000..c201690 --- /dev/null +++ b/proto/theora_packet.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +message TheoraPacket { + string stream_name = 1; + bytes data = 2; + int32 b_o_s = 3; + int32 e_o_s = 4; + int32 granulepos = 5; + int32 packetno = 6; +} + diff --git a/proto/update_proto.bash b/proto/update_proto.bash new file mode 100644 index 0000000..ee72b64 --- /dev/null +++ b/proto/update_proto.bash @@ -0,0 +1 @@ +protoc *.proto --python_out=../server/src/xbot2_gui_server/proto diff --git a/server/setup.cfg b/server/setup.cfg index a0d9d96..69bca08 100644 --- a/server/setup.cfg +++ b/server/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = xbot2_gui_server -version = 2.6.0 +version = 2.7.3 author = Arturo Laurenzi author_email = arturo.laurenzi@iit.it description = Backend for XBot2 QML GUI @@ -23,6 +23,7 @@ python_requires = >=3.8 install_requires = aiohttp asyncudp + protobuf>=5.29.0,<5.29.9 [options.packages.find] @@ -31,3 +32,4 @@ where = src [options.entry_points] console_scripts = xbot2_gui_server = xbot2_gui_server.main:main + xbot2_gui = xbot2_gui_server.xbot2_gui:main diff --git a/server/src/xbot2_gui_server/cosecosecose.py b/server/src/xbot2_gui_server/cosecosecose.py new file mode 100644 index 0000000..f62ceca --- /dev/null +++ b/server/src/xbot2_gui_server/cosecosecose.py @@ -0,0 +1,5 @@ +from ecat_repl.stuff import read_sdo, set_uri + +set_uri('amax-5580.local:5555') +an = read_sdo(['Assigned_name'], [1])[1]['Assigned_name'] +print(an) \ No newline at end of file diff --git a/server/src/xbot2_gui_server/ecat.py b/server/src/xbot2_gui_server/ecat.py index 1a73c45..a3459df 100644 --- a/server/src/xbot2_gui_server/ecat.py +++ b/server/src/xbot2_gui_server/ecat.py @@ -100,6 +100,13 @@ async def get_sdo_list(self, req: web.Request): print('cache is empty, refreshing') self.ctx.update_cache() + for id in ids: + if id not in self.ctx.sdo_dict.keys(): + print(f'esc id {id} not found in cache, refreshing...') + await utils.to_thread(self.ctx.update_cache) + print('...done') + break + # fill sdo list sdos = [] for id in ids: diff --git a/server/src/xbot2_gui_server/joint_states.py b/server/src/xbot2_gui_server/joint_states.py index d0a25fb..90c6745 100644 --- a/server/src/xbot2_gui_server/joint_states.py +++ b/server/src/xbot2_gui_server/joint_states.py @@ -9,6 +9,7 @@ import rospy +from sensor_msgs.msg import JointState as StdJointState from xbot_msgs.msg import JointState, Fault, JointCommand, CustomState from std_msgs.msg import Float32 from urdf_parser_py import urdf as urdf_parser @@ -16,7 +17,7 @@ from .server import ServerBase from . import utils -# from .proto import joint_states_pb2 +from .proto import jointstate_pb2, generic_pb2 ## limit float precision in json serialization class RoundingFloat(float): @@ -40,6 +41,7 @@ def __init__(self, srv: ServerBase, config=dict()) -> None: self.srv.schedule_task(self.run()) self.srv.register_ws_coroutine(self.handle_ws_msg) self.srv.add_route('GET', '/joint_states/info', self.get_joint_info_handler, 'get_joint_info') + self.srv.add_route('GET', '/joint_states/grippers', self.get_grippers_handler, 'get_grippers') self.srv.add_route('GET', '/joint_states/urdf', self.get_urdf_handler, 'get_urdf') self.srv.add_route('GET', '/joint_states/connected', self.robot_connected_handler, 'get_connected') self.srv.add_route('PUT', '/joint_command/goto/{joint_name}', self.command_handler, 'command') @@ -76,6 +78,11 @@ def __init__(self, srv: ServerBase, config=dict()) -> None: self.cmd_guard = JointStateHandler.CommandGuard(self.command_acquire, self.command_release) self.cmd_should_stop = True + # grippers + self.gripper_state_sub = dict() + self.gripper_cmd_pub = dict() + self.gripper_state_msg = dict() + # config self.rate = config.get('rate', 30.0) @@ -101,7 +108,11 @@ def on_aux_recv(self, msg: CustomState, aux: list): if not math.isnan(msg.value[i]): aux[i] = msg.value[i] - + + def on_gripper_state_recv(self, msg: StdJointState, gname): + self.gripper_state_msg[gname] = msg + + @utils.handle_exceptions async def get_urdf_handler(self, request: web.Request): print('retrieving robot description..') @@ -184,6 +195,43 @@ async def get_joint_info_handler(self, request: web.Request): return web.Response(text=json.dumps(joint_info)) + @utils.handle_exceptions + async def get_grippers_handler(self, req: web.Request): + + # get topic names from ros master + topic_name_type_list = await utils.to_thread(rospy.get_published_topics) + + # filter /xbotcore/gripper/GRIPPERNAME/state + gripper_names = set() + for tname, ttype in topic_name_type_list: + print(tname, ttype) + if ttype != 'sensor_msgs/JointState': + continue + tokens = tname.strip('/').split('/') + if len(tokens) == 4 and tokens[1] == 'gripper' and tokens[3] == 'state': + gripper_names.add(tokens[2]) + + # register topics + for gname in gripper_names: + state = f'xbotcore/gripper/{gname}/state' + cmd = f'xbotcore/gripper/{gname}/command' + self.gripper_state_msg[gname] = None + self.gripper_state_sub[gname] = rospy.Subscriber(state, StdJointState, + self.on_gripper_state_recv, gname, queue_size=1) + self.gripper_cmd_pub[gname] = rospy.Publisher(cmd, StdJointState, queue_size=1) + print(f'connecting to gripper {gname}...') + + + # reply + res = { + 'success': True, + 'message': '', + 'gripper_names': sorted(list(gripper_names)) + } + + return web.Response(text=json.dumps(res)) + + async def run(self): t0 = time.time() @@ -207,30 +255,48 @@ async def run(self): # check js received if self.msg is None: continue - - # convert to dict - js_msg_to_send = self.js_msg_to_dict(self.msg) - - # test: avoid sending names to save bw - del js_msg_to_send['name'] - - # add pow data and seq id - js_msg_to_send['vbatt'] = self.vbatt - js_msg_to_send['iload'] = self.iload - js_msg_to_send['seq'] = self.js_seq - self.js_seq += 1 - - # serialize msg to json - js_str = json.dumps(js_msg_to_send) - # send to all connected clients - await self.srv.udp_send_to_all(js_str) + # pb js + # TBD aux support + try: + msgpb = generic_pb2.Message() + msgpb.jointstate.linkPos.extend(self.msg.link_position) + msgpb.jointstate.motPos.extend(self.msg.motor_position) + msgpb.jointstate.motVel.extend(self.msg.motor_velocity) + msgpb.jointstate.velRef.extend(self.msg.velocity_reference) + msgpb.jointstate.torRef.extend(self.msg.effort_reference) + msgpb.jointstate.tor.extend(self.msg.effort) + msgpb.jointstate.posRef.extend(self.msg.position_reference) + msgpb.jointstate.k.extend(self.msg.stiffness) + msgpb.jointstate.d.extend(self.msg.damping) + msgpb.jointstate.motorTemp.extend(self.msg.temperature_motor) + msgpb.jointstate.driverTemp.extend(self.msg.temperature_driver) + msgpb.jointstate.vbatt = self.vbatt + msgpb.jointstate.ibatt = self.iload + await self.srv.udp_send_to_all(msgpb) + except Exception as e: + # print traceback + import traceback + traceback.print_exc() + # clear to avoid sending duplicates self.msg = None for v in self.aux_map.values(): v.clear() + # grippers + for gname, gmsg in self.gripper_state_msg.items(): + if gmsg is None: + continue + gmsg = { + 'type': 'gripper_state', + 'q': gmsg.position[0], + 'tau': gmsg.effort + } + await self.srv.ws_send_to_all(json.dumps(gmsg)) + self.gripper_state_msg[gname] = None + def command_acquire(self): if self.cmd_busy: @@ -376,6 +442,7 @@ def js_msg_to_dict(self, msg: JointState): async def handle_ws_msg(self, msg, proto, ws): + if msg['type'] == 'joint_cmd': cmdmsg = JointCommand() cmdmsg.name = msg['joint_names'] @@ -388,3 +455,12 @@ async def handle_ws_msg(self, msg, proto, ws): else: raise ValueError(f'unknown control mode {msg["ctrl"]}') self.cmd_pub.publish(cmdmsg) + + if msg['type'] == 'gripper_cmd': + cmdmsg = StdJointState() + gname = msg['name'] + if msg['action'] == 'open': + cmdmsg.position = [0.0] + elif msg['action'] == 'close': + cmdmsg.effort = [msg['effort']] + self.gripper_cmd_pub[gname].publish(cmdmsg) diff --git a/server/src/xbot2_gui_server/launcher.py b/server/src/xbot2_gui_server/launcher.py index fe678ee..9affe48 100644 --- a/server/src/xbot2_gui_server/launcher.py +++ b/server/src/xbot2_gui_server/launcher.py @@ -13,6 +13,8 @@ from .server import ServerBase from . import utils +from .proto import generic_pb2, process_output_pb2 + class Launcher: def __init__(self, srv: ServerBase, config=dict()) -> None: @@ -172,8 +174,7 @@ async def run(self): for p in self.get_process_names(): msg = { - 'type': 'proc', - 'content': 'status', + 'type': 'proc_status', 'name': p, 'status': status[p] } @@ -210,17 +211,12 @@ def create_proc_printer(self, process): ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + @utils.print_exceptions async def printer(l: str): - - msg = { - 'type': 'proc', - 'content': 'output', - 'name': process, - 'stdout': ansi_escape.sub('', l.strip()), - 'stderr': '', - } - - msg_str = json.dumps(msg) + + pbmsg = generic_pb2.Message() + pbmsg.process_output.name = process + pbmsg.process_output.out = ansi_escape.sub('', l.strip()) # throttle logic if time.time() - self.proc_stdout_prev_time > 1.0: @@ -234,13 +230,12 @@ async def printer(l: str): # too much data: send once, then skip for the rest of the window duration if self.proc_stdout_bytes*8/1000 > self.proc_stdout_max_kbps: # kbps -> Bps if self.proc_stdout_enabled: - msg['stdout'] = f'[launcher] process exceeding max output bandwith (max_bw = {self.proc_stdout_max_kbps}) over a 1 sec window' - msg_str = json.dumps(msg) + pbmsg.process_output.out = f'[launcher] process exceeding max output bandwith (max_bw = {self.proc_stdout_max_kbps}) over a 1 sec window' self.proc_stdout_enabled = False else: return - await self.srv.ws_send_to_all(msg_str) + await self.srv.ws_send_to_all(pbmsg) return printer @@ -314,10 +309,10 @@ async def on_launcher_event(proc, text): 'stderr': '', } - msg_str = json.dumps(msg) - - await self.srv.ws_send_to_all(msg_str) - + pbmsg = generic_pb2.Message() + pbmsg.process_output.name = 'launcher' + pbmsg.process_output.out = f'[{proc}] {text}' + await self.srv.ws_send_to_all(pbmsg) return await exe.execute_process(process=process, cfg=self.cfg, @@ -328,18 +323,10 @@ async def on_launcher_event(proc, text): async def kill(self, process, graceful=True): async def on_launcher_event(proc, text): - - msg = { - 'type': 'proc', - 'content': 'output', - 'name': 'launcher', - 'stdout': f'[{proc}] {text}', - 'stderr': '', - } - - msg_str = json.dumps(msg) - - await self.srv.ws_send_to_all(msg_str) + pbmsg = generic_pb2.Message() + pbmsg.process_output.name = 'launcher' + pbmsg.process_output.out = f'[{proc}] {text}' + await self.srv.ws_send_to_all(pbmsg) return await exe.kill(process=process, cfg=self.cfg, @@ -348,4 +335,4 @@ async def on_launcher_event(proc, text): - \ No newline at end of file + diff --git a/server/src/xbot2_gui_server/launcher_config.yaml b/server/src/xbot2_gui_server/launcher_config.yaml index 947dab2..36ed6e3 100644 --- a/server/src/xbot2_gui_server/launcher_config.yaml +++ b/server/src/xbot2_gui_server/launcher_config.yaml @@ -4,7 +4,7 @@ context: verbose_flag: '' roscore: - cmd: ros1; roscore + cmd: roscore ecat: cmd: watch ls @@ -13,7 +13,7 @@ wait_ecat_online: cmd: watch ls xbot2: - cmd: ros1; xbot2-core --hw dummy -C $(rospack find kyon_config)/kyon_basic.yaml + cmd: xbot2-core --hw dummy -C $(rospack find kyon_config)/kyon_basic.yaml variants: verbose: params: @@ -21,7 +21,7 @@ xbot2: ready_check: timeout 3 rostopic echo /xbotcore/status -n 1 prova1: - cmd: watch ls + cmd: rostopic echo /xbotcore/statistics prova2: - cmd: watch ls \ No newline at end of file + cmd: rostopic echo /xbotcore/joint_states diff --git a/server/src/xbot2_gui_server/main.py b/server/src/xbot2_gui_server/main.py index 1dac34e..f74b667 100644 --- a/server/src/xbot2_gui_server/main.py +++ b/server/src/xbot2_gui_server/main.py @@ -94,9 +94,9 @@ def load_extension(module_name, class_name, srv, config): ('xbot2_gui_server.theora_video', 'TheoraVideoHandler'), ('xbot2_gui_server.launcher', 'Launcher'), ('xbot2_gui_server.cartesian', 'CartesianHandler'), - ('xbot2_gui_server.speech', 'SpeechHandler'), + # ('xbot2_gui_server.speech', 'SpeechHandler'), ('xbot2_gui_server.visual', 'VisualHandler'), - ('xbot2_gui_server.concert', 'ConcertHandler'), + # ('xbot2_gui_server.concert', 'ConcertHandler'), ('xbot2_gui_server.ecat', 'EcatHandler'), ('xbot2_gui_server.horizon', 'HorizonHandler'), ('xbot2_gui_server.dashboard', 'DashboardHandler'), diff --git a/server/src/xbot2_gui_server/main.py.orig b/server/src/xbot2_gui_server/main.py.orig new file mode 100644 index 0000000..1ab2218 --- /dev/null +++ b/server/src/xbot2_gui_server/main.py.orig @@ -0,0 +1,172 @@ +import os, sys +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.dirname(SCRIPT_DIR)) + +from .server import Xbot2WebServer +import yaml, json +import sys +import importlib +import rospy +import logging +import argparse +from aiohttp import web +import asyncio + +def main(): + + # cli + parser = argparse.ArgumentParser(description='A modern UI for the Xbot2 framework, written in Qt6 / QML') + parser.add_argument('config', type=str, nargs='?', help='path to config file') + parser.add_argument('--port', '-p', type=int, default=8080, help='port for the UI server (it must be available on both TCP and UDP)') + parser.add_argument('--launch-ui', '-u', action='store_true', help='run the UI frontend') + args = parser.parse_args() + + # set verbose logging level + logging.basicConfig(level=logging.INFO, force=True) + + # load config + if len(sys.argv) > 1: + cfgpath = sys.argv[1] + cfg = yaml.safe_load(open(cfgpath, 'r').read()) + else: + cfgpath = __file__ + cfg = dict() + + # create server + srv = Xbot2WebServer() + srv.cfgpath = cfgpath + + # load default extensions + extensions = [] + + # task that load all extensions after waiting for ros master + async def load_extensions(): + + while True: + try: + await srv.log('waiting for ros master') + rospy.get_master().getPid() + break + except Exception as e: + await asyncio.sleep(1.0) + + await srv.log('ros master is alive') + + # init rospy node + rospy.init_node('xbot2_gui_server', disable_signals=True) + + # wasm ui + from .webui import WebUiHandler + ext = WebUiHandler(srv, cfg.get('webui', {})) + extensions.append(ext) + + # joint states + from .joint_states import JointStateHandler + ext = JointStateHandler(srv, cfg.get('joint_states', {})) + extensions.append(ext) + + # joint device + from .joint_device import JointDeviceHandler + ext = JointDeviceHandler(srv, cfg.get('joint_device', {})) + extensions.append(ext) + + # plugin + from .plugin import PluginHandler + ext = PluginHandler(srv, cfg.get('plugin', {})) + extensions.append(ext) + + # theora video + from .theora_video import TheoraVideoHandler + ext = TheoraVideoHandler(srv, cfg.get('theora_video', {})) + extensions.append(ext) +<<<<<<< Updated upstream + except KeyError: + pass + except ModuleNotFoundError: + pass +======= + + # cartesian + try: + from .cartesian import CartesianHandler + ext = CartesianHandler(srv, cfg.get('cartesian', {})) + extensions.append(ext) + except ModuleNotFoundError: + pass + + # visual + from .visual import VisualHandler + ext = VisualHandler(srv, cfg.get('visual', {})) + extensions.append(ext) + + # concert + if 'concert' in cfg.keys(): + from .concert import ConcertHandler + ext = ConcertHandler(srv, cfg.get('concert', {})) + extensions.append(ext) + + # ecat + if 'ecat' in cfg.keys(): + from .ecat import EcatHandler + ext = EcatHandler(srv, cfg.get('ecat', {})) + extensions.append(ext) + + # horizon + if 'horizon' in cfg.keys(): + from .horizon import HorizonHandler + ext = HorizonHandler(srv, cfg.get('horizon', {})) + extensions.append(ext) + + # launcher + try: + from .launcher import Launcher + ext = Launcher(srv, cfg.get('launcher', {})) + extensions.append(ext) + except ModuleNotFoundError: + pass + + # schedule extension loading task + srv.schedule_task(load_extensions()) +>>>>>>> Stashed changes + + # parse requested pages + requested_pages = cfg.get('requested_pages', []) + for e in extensions: + try: + requested_pages += e.requested_pages + except: + pass + + async def requested_pages_handler(req): + return web.Response(text=json.dumps({'requested_pages': requested_pages})) + + srv.add_route('GET', '/requested_pages', requested_pages_handler, 'requested_pages_handler') + + # run ui client if required + async def run_ui(): + + proc = await asyncio.create_subprocess_shell( + f'/home/alaurenzi/code/next_ui/build-robot_monitoring-Desktop_Qt_6_6_0_GCC_64bit-RelWithDebInfo/xbot2_gui/xbot2_gui -p {args.port}', + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.STDOUT, + stdin=asyncio.subprocess.PIPE) + + while True: + l = await proc.stdout.readline() + if len(l) == 0: + retcode = await proc.wait() + print(f'[ui] process exited with {retcode}') + exit(retcode) + l = l.decode() + print('[ui]', l, end='') + + if args.launch_ui: + srv.schedule_task(run_ui()) + + # run server + srv.run_server(port=args.port) + + +if __name__ == '__main__': + main() + diff --git a/server/src/xbot2_gui_server/proto/__init__.py b/server/src/xbot2_gui_server/proto/__init__.py new file mode 100644 index 0000000..2e56dac --- /dev/null +++ b/server/src/xbot2_gui_server/proto/__init__.py @@ -0,0 +1,4 @@ +# add current folder to python path +import sys +import os +sys.path.append(os.path.dirname(__file__)) \ No newline at end of file diff --git a/server/src/xbot2_gui_server/proto/generic_pb2.py b/server/src/xbot2_gui_server/proto/generic_pb2.py new file mode 100644 index 0000000..cd98530 --- /dev/null +++ b/server/src/xbot2_gui_server/proto/generic_pb2.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: generic.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +import jointstate_pb2 as jointstate__pb2 +import text_pb2 as text__pb2 +import process_output_pb2 as process__output__pb2 +import theora_packet_pb2 as theora__packet__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rgeneric.proto\x1a\x10jointstate.proto\x1a\ntext.proto\x1a\x14process_output.proto\x1a\x13theora_packet.proto\"\x9a\x01\n\x07Message\x12\x0b\n\x03seq\x18\x01 \x01(\x05\x12\x1f\n\njointstate\x18\x02 \x01(\x0b\x32\x0b.JointState\x12\x13\n\x04text\x18\x03 \x01(\x0b\x32\x05.Text\x12&\n\x0eprocess_output\x18\x04 \x01(\x0b\x32\x0e.ProcessOutput\x12$\n\rtheora_packet\x18\x05 \x01(\x0b\x32\r.TheoraPacketb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'generic_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _MESSAGE._serialized_start=91 + _MESSAGE._serialized_end=245 +# @@protoc_insertion_point(module_scope) diff --git a/server/src/xbot2_gui_server/proto/jointstate_pb2.py b/server/src/xbot2_gui_server/proto/jointstate_pb2.py new file mode 100644 index 0000000..b6b7055 --- /dev/null +++ b/server/src/xbot2_gui_server/proto/jointstate_pb2.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: jointstate.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10jointstate.proto\"\x1b\n\nFloatArray\x12\r\n\x05value\x18\x01 \x03(\x02\"\xc2\x02\n\nJointState\x12\x0f\n\x07linkPos\x18\x01 \x03(\x02\x12\x0e\n\x06motPos\x18\x02 \x03(\x02\x12\x0f\n\x07linkVel\x18\x03 \x03(\x02\x12\x0e\n\x06motVel\x18\x04 \x03(\x02\x12\x0b\n\x03tor\x18\x05 \x03(\x02\x12\x11\n\tmotorTemp\x18\x06 \x03(\x02\x12\x12\n\ndriverTemp\x18\x07 \x03(\x02\x12\x0e\n\x06posRef\x18\x08 \x03(\x02\x12\x0e\n\x06velRef\x18\t \x03(\x02\x12\x0e\n\x06torRef\x18\n \x03(\x02\x12\t\n\x01k\x18\x0b \x03(\x02\x12\t\n\x01\x64\x18\x0c \x03(\x02\x12!\n\x03\x61ux\x18\r \x03(\x0b\x32\x14.JointState.AuxEntry\x12\r\n\x05vbatt\x18\x0e \x01(\x02\x12\r\n\x05ibatt\x18\x0f \x01(\x02\x1a\x37\n\x08\x41uxEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1a\n\x05value\x18\x02 \x01(\x0b\x32\x0b.FloatArray:\x02\x38\x01\x62\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'jointstate_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _JOINTSTATE_AUXENTRY._options = None + _JOINTSTATE_AUXENTRY._serialized_options = b'8\001' + _FLOATARRAY._serialized_start=20 + _FLOATARRAY._serialized_end=47 + _JOINTSTATE._serialized_start=50 + _JOINTSTATE._serialized_end=372 + _JOINTSTATE_AUXENTRY._serialized_start=317 + _JOINTSTATE_AUXENTRY._serialized_end=372 +# @@protoc_insertion_point(module_scope) diff --git a/server/src/xbot2_gui_server/proto/process_output_pb2.py b/server/src/xbot2_gui_server/proto/process_output_pb2.py new file mode 100644 index 0000000..8ed2205 --- /dev/null +++ b/server/src/xbot2_gui_server/proto/process_output_pb2.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: process_output.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14process_output.proto\"7\n\rProcessOutput\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03out\x18\x02 \x01(\t\x12\x0b\n\x03\x65rr\x18\x03 \x01(\tb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'process_output_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _PROCESSOUTPUT._serialized_start=24 + _PROCESSOUTPUT._serialized_end=79 +# @@protoc_insertion_point(module_scope) diff --git a/server/src/xbot2_gui_server/proto/text_pb2.py b/server/src/xbot2_gui_server/proto/text_pb2.py new file mode 100644 index 0000000..0fffd92 --- /dev/null +++ b/server/src/xbot2_gui_server/proto/text_pb2.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: text.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ntext.proto\"\x14\n\x04Text\x12\x0c\n\x04text\x18\x01 \x01(\tb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'text_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _TEXT._serialized_start=14 + _TEXT._serialized_end=34 +# @@protoc_insertion_point(module_scope) diff --git a/server/src/xbot2_gui_server/proto/theora_packet_pb2.py b/server/src/xbot2_gui_server/proto/theora_packet_pb2.py new file mode 100644 index 0000000..44a3668 --- /dev/null +++ b/server/src/xbot2_gui_server/proto/theora_packet_pb2.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: theora_packet.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13theora_packet.proto\"u\n\x0cTheoraPacket\x12\x13\n\x0bstream_name\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\r\n\x05\x62_o_s\x18\x03 \x01(\x05\x12\r\n\x05\x65_o_s\x18\x04 \x01(\x05\x12\x12\n\ngranulepos\x18\x05 \x01(\x05\x12\x10\n\x08packetno\x18\x06 \x01(\x05\x62\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'theora_packet_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _THEORAPACKET._serialized_start=23 + _THEORAPACKET._serialized_end=140 +# @@protoc_insertion_point(module_scope) diff --git a/server/src/xbot2_gui_server/server.py b/server/src/xbot2_gui_server/server.py index 209b8ae..745af7f 100644 --- a/server/src/xbot2_gui_server/server.py +++ b/server/src/xbot2_gui_server/server.py @@ -19,6 +19,8 @@ from . import utils from . import mkcert +from xbot2_gui_server.proto import generic_pb2, text_pb2 + class ServerBase: @@ -78,6 +80,7 @@ def __init__(self) -> None: self.udp : asyncudp.Socket = None self.udp_clients = set() # set of pairs (addr, port) self.udp_clients_timeout = dict() + self.udp_msg_seq = 0 # add routes routes = [ @@ -91,6 +94,10 @@ def __init__(self) -> None: for route in routes: self.app.router.add_route(method=route[0], path=route[1], handler=route[2], name=route[3]) + webui_path = os.path.abspath(os.path.dirname(__file__)) + '/webui' + + self.app.add_routes([web.static('/webui', webui_path)]) + def add_route(self, method, path, handler, name): try: @@ -111,19 +118,44 @@ async def ws_send_to_all(self, msg, clients=None): if clients is None: clients = self.ws_clients + else: + clients = set(clients) & self.ws_clients + + if len(clients) == 0: + return + + # wrap with protobuf if needed + pbmsg = generic_pb2.Message() + + if isinstance(msg, generic_pb2.Message): + pbmsg = msg - if len(clients) > 0 and isinstance(msg, dict): + elif isinstance(msg, dict): msg = json.dumps(msg) + pbmsg.text.text = msg + + elif isinstance(msg, str): + pbmsg = generic_pb2.Message() + pbmsg.text.text = msg + # serialize msg to bytes + msg = pbmsg.SerializeToString() + + # print(f'sending ws message size {len(msg)} to {len(clients)} clients') + + expired_clients = set(ws for ws in clients if ws not in self.ws_clients) + # iterate over sockets (one per client) for ws in clients: try: - await ws.send_str(msg) + await ws.send_bytes(msg) except ConnectionResetError as e: pass except BaseException as e: print(f'error: {e}') + + return expired_clients async def log(self, txt, sev=0): @@ -141,8 +173,24 @@ async def log(self, txt, sev=0): async def udp_send_to_all(self, msg: str, clients=None): + # wrap with protobuf if needed + pbmsg = generic_pb2.Message() + + if isinstance(msg, generic_pb2.Message): + pbmsg = msg + + elif isinstance(msg, dict): + msg = json.dumps(msg) + pbmsg.text.text = msg + + elif isinstance(msg, str): + pbmsg = generic_pb2.Message() + pbmsg.text.text = msg + + # here we have a protobuf message + # tunnel udp via ws for wasm clients - await self.ws_send_to_all(msg, self.ws_udp_tunnel) + # await self.ws_send_to_all(pbmsg, self.ws_udp_tunnel) # send udp to normal clients if self.udp is None: @@ -150,14 +198,25 @@ async def udp_send_to_all(self, msg: str, clients=None): if clients is None: clients = self.udp_clients + else: + clients = set(clients) & self.udp_clients - if len(clients) > 0 and isinstance(msg, dict): - msg = json.dumps(msg) + if len(clients) == 0: + return + + # set sequence number and serialize msg to bytes + pbmsg.seq = self.udp_msg_seq + msg = pbmsg.SerializeToString() + self.udp_msg_seq += 1 + + # print(f'sending udp message size {len(msg)} to {len(clients)} clients') + + expired_clients = set(addr for addr in clients if addr not in self.udp_clients) for addr in clients: - self.udp.sendto(msg.encode(), addr) + self.udp.sendto(msg, addr) - return True + return expired_clients def run_server(self, static='.', host='0.0.0.0', port=8080): @@ -211,7 +270,7 @@ async def heartbeat(self): """ broadcast periodic heartbeat with server-relate lightweight data - note: this also cleans up close websockets + note: this also cleans up close websockets and udp clients """ # serialize msg to json @@ -222,7 +281,7 @@ async def heartbeat(self): ) while True: - + # save disconnected sockets for later removal ws_to_remove = set() udp_to_remove = set() @@ -245,20 +304,28 @@ async def heartbeat(self): print(f'error: {e}') for ws in ws_to_remove: - self.ws_clients.remove(ws) - self.ws_udp_tunnel.remove(ws) + try: + self.ws_clients.remove(ws) + except KeyError: + print('ws already removed') + + try: + self.ws_udp_tunnel.remove(ws) + except KeyError: + pass for addr in udp_to_remove: self.udp_clients.remove(addr) del self.udp_clients_timeout[addr] - + + # periodic loop at 10 Hz await asyncio.sleep(0.666) # root handler serves html for web app async def root_handler(self, request): - return aiohttp.web.HTTPFound('/next_ui.html') + return aiohttp.web.HTTPFound('/webui/xbot2_gui.html') # websocket handler diff --git a/server/src/xbot2_gui_server/theora_video.py b/server/src/xbot2_gui_server/theora_video.py index 04d9f91..82bae3c 100644 --- a/server/src/xbot2_gui_server/theora_video.py +++ b/server/src/xbot2_gui_server/theora_video.py @@ -9,6 +9,7 @@ from .server import ServerBase from . import utils +from .proto import generic_pb2 class TheoraVideoHandler: @@ -16,6 +17,7 @@ def __init__(self, srv: ServerBase, config=dict()) -> None: # save server object, register our handlers self.srv = srv + self.srv.register_ws_coroutine(self.handle_ws_msg) self.srv.add_route('GET', '/video/get_names', self.get_names_handler, 'video_get_names') self.srv.add_route('PUT', '/video/set_stream', self.set_stream_handler, 'video_set_stream') @@ -27,6 +29,9 @@ def __init__(self, srv: ServerBase, config=dict()) -> None: self.img_data = dict() self.img_sub = None self.img_msg_to_send = {} + + # clients + self.clients = dict() # event loop self.loop = asyncio.get_event_loop() @@ -94,7 +99,7 @@ async def set_stream_handler(self, request): })) print('got headers') - + self.srv.schedule_task(self.run(self.img_data[stream_name])) return web.Response(text=json.dumps({ @@ -109,6 +114,10 @@ async def run(self, stream_data): # unpack stream_name, img_sub, img_hdr_pkt, img_msg_queue = stream_data + + # check if we have a client for this stream + if stream_name not in self.clients.keys(): + self.clients[stream_name] = {'ws': set(), 'udp': set()} print(f'{stream_name} started') @@ -117,11 +126,11 @@ async def run(self, stream_data): # await for a new packet to be received from ros th_pkt = await img_msg_queue.get() - # serialize msg to json - msg_str = json.dumps(th_pkt) - # iterate over sockets (one per client) - await self.srv.ws_send_to_all(msg_str) + ws_clients = self.clients[stream_name]['ws'] + udp_clients = self.clients[stream_name]['udp'] + expired_udp = await self.srv.udp_send_to_all(msg=th_pkt, clients=udp_clients) + expired_ws = await self.srv.ws_send_to_all(msg=th_pkt, clients=ws_clients) print(f'{stream_name} exiting') @@ -129,25 +138,51 @@ async def run(self, stream_data): def on_th_pkt_recv(self, msg: TheoraPacket, stream_data): stream_name, img_sub, img_hdr_pkt, img_msg_queue = stream_data - - th_pkt = dict() - th_pkt['type'] = 'theora' - th_pkt['stream_name'] = stream_name - th_pkt['data'] = base64.b64encode(msg.data).decode('ascii') - th_pkt['b_o_s'] = msg.b_o_s - th_pkt['e_o_s'] = msg.e_o_s - th_pkt['granulepos'] = msg.granulepos - th_pkt['packetno'] = msg.packetno + + pbmsg = generic_pb2.Message() + pbmsg.theora_packet.stream_name = stream_name + pbmsg.theora_packet.data = msg.data + pbmsg.theora_packet.b_o_s = msg.b_o_s + pbmsg.theora_packet.e_o_s = msg.e_o_s + pbmsg.theora_packet.granulepos = msg.granulepos + pbmsg.theora_packet.packetno = msg.packetno + + def json_msg(): + th_pkt = dict() + th_pkt['type'] = 'theora' + th_pkt['streamName'] = stream_name + th_pkt['data'] = base64.b64encode(msg.data).decode('ascii') + th_pkt['bOS'] = msg.b_o_s + th_pkt['eOS'] = msg.e_o_s + th_pkt['granulepos'] = msg.granulepos + th_pkt['packetno'] = msg.packetno + return th_pkt if msg.b_o_s == 1: - img_hdr_pkt.append(th_pkt) + img_hdr_pkt.append(json_msg()) print(f'got header {len(img_hdr_pkt)}/3') return if msg.granulepos == 0: - img_hdr_pkt.append(th_pkt) + img_hdr_pkt.append(json_msg()) print(f'got header {len(img_hdr_pkt)}/3') return - _ = asyncio.run_coroutine_threadsafe(img_msg_queue.put(th_pkt), self.loop) + _ = asyncio.run_coroutine_threadsafe(img_msg_queue.put(pbmsg), self.loop) + + async def handle_ws_msg(self, msg, proto, sock): + if msg['type'] == 'video_request': + stream_name = msg['stream_name'] + op = msg.get('operation', 'connect') + if stream_name not in self.clients.keys(): + self.clients[stream_name] = {'ws': set(), 'udp': set()} + if op == 'disconnect': + self.clients[stream_name]['ws'].discard(sock) + self.clients[stream_name]['udp'].discard(sock) + await self.srv.log(f'disconnected client from stream {stream_name}') + else: + self.clients[stream_name][proto].add(sock) + await self.srv.log(f'new client {proto} {sock} for stream {stream_name}') + + print(self.clients) diff --git a/server/src/xbot2_gui_server/utils.py b/server/src/xbot2_gui_server/utils.py index f110d4f..add7da9 100644 --- a/server/src/xbot2_gui_server/utils.py +++ b/server/src/xbot2_gui_server/utils.py @@ -55,3 +55,14 @@ async def async_wrapper(self, *args, **kwargs): return async_wrapper + +def print_exceptions(func): + + @functools.wraps(func) + async def async_wrapper(self, *args, **kwargs): + try: + return await func(self, *args, **kwargs) + except BaseException as e: + traceback.print_exc() + return async_wrapper + diff --git a/server/src/xbot2_gui_server/webui/qtloader.js b/server/src/xbot2_gui_server/webui/qtloader.js new file mode 100644 index 0000000..532fd02 --- /dev/null +++ b/server/src/xbot2_gui_server/webui/qtloader.js @@ -0,0 +1,309 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +/** + * Loads the instance of a WASM module. + * + * @param config May contain any key normally accepted by emscripten and the 'qt' extra key, with + * the following sub-keys: + * - environment: { [name:string] : string } + * environment variables set on the instance + * - onExit: (exitStatus: { text: string, code?: number, crashed: bool }) => void + * called when the application has exited for any reason. There are two cases: + * aborted: crashed is true, text contains an error message. + * exited: crashed is false, code contians the exit code. + * + * Note that by default Emscripten does not exit when main() returns. This behavior + * is controlled by the EXIT_RUNTIME linker flag; set "-s EXIT_RUNTIME=1" to make + * Emscripten tear down the runtime and exit when main() returns. + * + * - containerElements: HTMLDivElement[] + * Array of host elements for Qt screens. Each of these elements is mapped to a QScreen on + * launch. + * - fontDpi: number + * Specifies font DPI for the instance + * - onLoaded: () => void + * Called when the module has loaded, at the point in time where any loading placeholder + * should be hidden and the application window should be shown. + * - entryFunction: (emscriptenConfig: object) => Promise + * Qt always uses emscripten's MODULARIZE option. This is the MODULARIZE entry function. + * - module: Promise + * The module to create the instance from (optional). Specifying the module allows optimizing + * use cases where several instances are created from a single WebAssembly source. + * - qtdir: string + * Path to Qt installation. This path will be used for loading Qt shared libraries and plugins. + * The path is set to 'qt' by default, and is relative to the path of the web page's html file. + * This property is not in use when static linking is used, since this build mode includes all + * libraries and plugins in the wasm file. + * - preload: [string]: Array of file paths to json-encoded files which specifying which files to preload. + * The preloaded files will be downloaded at application startup and copied to the in-memory file + * system provided by Emscripten. + * + * Each json file must contain an array of source, destination objects: + * [ + * { + * "source": "path/to/source", + * "destination": "/path/to/destination" + * }, + * ... + * ] + * The source path is relative to the html file path. The destination path must be + * an absolute path. + * + * $QTDIR may be used as a placeholder for the "qtdir" configuration property (see @qtdir), for instance: + * "source": "$QTDIR/plugins/imageformats/libqjpeg.so" + * - localFonts.requestPermission: bool + * Whether Qt should request for local fonts access permission on startup (default false). + * - localFonts.familiesCollection string + * Specifies a collection of local fonts to load. Possible values are: + * "NoFontFamilies" : Don't load any font families + * "DefaultFontFamilies" : A subset of available font families; currently the "web-safe" fonts (default). + * "AllFontFamilies" : All local font families (not reccomended) + * - localFonts.extraFamilies: [string] + * Adds additional font families to be loaded at startup. + * + * @return Promise + * The promise is resolved when the module has been instantiated and its main function has been + * called. + * + * @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten for + * EmscriptenModule + */ +async function qtLoad(config) +{ + const throwIfEnvUsedButNotExported = (instance, config) => + { + const environment = config.qt.environment; + if (!environment || Object.keys(environment).length === 0) + return; + const descriptor = Object.getOwnPropertyDescriptor(instance, 'ENV'); + const isEnvExported = typeof descriptor.value === 'object'; + if (!isEnvExported) { + throw new Error('ENV must be exported if environment variables are passed, ' + + 'add it to the QT_WASM_EXTRA_EXPORTED_METHODS CMake target property'); + } + }; + + if (typeof config !== 'object') + throw new Error('config is required, expected an object'); + if (typeof config.qt !== 'object') + throw new Error('config.qt is required, expected an object'); + if (typeof config.qt.entryFunction !== 'function') + throw new Error('config.qt.entryFunction is required, expected a function'); + + config.qt.qtdir ??= 'qt'; + config.qt.preload ??= []; + + config.qtContainerElements = config.qt.containerElements; + delete config.qt.containerElements; + config.qtFontDpi = config.qt.fontDpi; + delete config.qt.fontDpi; + + // Make Emscripten not call main(); this gives us more control over + // the startup sequence. + const originalNoInitialRun = config.noInitialRun; + const originalArguments = config.arguments; + config.noInitialRun = true; + + // Used for rejecting a failed load's promise where emscripten itself does not allow it, + // like in instantiateWasm below. This allows us to throw in case of a load error instead of + // hanging on a promise to entry function, which emscripten unfortunately does. + let circuitBreakerReject; + const circuitBreaker = new Promise((_, reject) => { circuitBreakerReject = reject; }); + + // If module async getter is present, use it so that module reuse is possible. + if (config.qt.module) { + config.instantiateWasm = async (imports, successCallback) => + { + try { + const module = await config.qt.module; + successCallback( + await WebAssembly.instantiate(module, imports), module); + } catch (e) { + circuitBreakerReject(e); + } + } + } + const preloadFetchHelper = async (path) => { + const response = await fetch(path); + if (!response.ok) + throw new Error("Could not fetch preload file: " + path); + return response.json(); + } + const filesToPreload = (await Promise.all(config.qt.preload.map(preloadFetchHelper))).flat(); + const qtPreRun = (instance) => { + // Copy qt.environment to instance.ENV + throwIfEnvUsedButNotExported(instance, config); + for (const [name, value] of Object.entries(config.qt.environment ?? {})) + instance.ENV[name] = value; + + // Preload files from qt.preload + const makeDirs = (FS, filePath) => { + const parts = filePath.split("/"); + let path = "/"; + for (let i = 0; i < parts.length - 1; ++i) { + const part = parts[i]; + if (part == "") + continue; + path += part + "/"; + try { + FS.mkdir(path); + } catch (error) { + const EEXIST = 20; + if (error.errno != EEXIST) + throw error; + } + } + } + + const extractFilenameAndDir = (path) => { + const parts = path.split('/'); + const filename = parts.pop(); + const dir = parts.join('/'); + return { + filename: filename, + dir: dir + }; + } + const preloadFile = (file) => { + makeDirs(instance.FS, file.destination); + const source = file.source.replace('$QTDIR', config.qt.qtdir); + const filenameAndDir = extractFilenameAndDir(file.destination); + instance.FS.createPreloadedFile(filenameAndDir.dir, filenameAndDir.filename, source, true, true); + } + const isFsExported = typeof instance.FS === 'object'; + if (!isFsExported) + throw new Error('FS must be exported if preload is used'); + filesToPreload.forEach(preloadFile); + } + + if (!config.preRun) + config.preRun = []; + config.preRun.push(qtPreRun); + + const originalOnRuntimeInitialized = config.onRuntimeInitialized; + config.onRuntimeInitialized = () => { + originalOnRuntimeInitialized?.(); + config.qt.onLoaded?.(); + } + + const originalLocateFile = config.locateFile; + config.locateFile = filename => { + const originalLocatedFilename = originalLocateFile ? originalLocateFile(filename) : filename; + if (originalLocatedFilename.startsWith('libQt6')) + return `${config.qt.qtdir}/lib/${originalLocatedFilename}`; + return originalLocatedFilename; + } + + let onExitCalled = false; + const originalOnExit = config.onExit; + config.onExit = code => { + originalOnExit?.(); + + if (!onExitCalled) { + onExitCalled = true; + config.qt.onExit?.({ + code, + crashed: false + }); + } + } + + const originalOnAbort = config.onAbort; + config.onAbort = text => + { + originalOnAbort?.(); + + if (!onExitCalled) { + onExitCalled = true; + config.qt.onExit?.({ + text, + crashed: true + }); + } + }; + + // Call app/emscripten module entry function. It may either come from the emscripten + // runtime script or be customized as needed. + let instance; + try { + instance = await Promise.race( + [circuitBreaker, config.qt.entryFunction(config)]); + + // Call main after creating the instance. We've opted into manually + // calling main() by setting noInitialRun in the config. Thie Works around + // issue where Emscripten suppresses all exceptions thrown during main. + if (!originalNoInitialRun) + instance.callMain(originalArguments); + } catch (e) { + // If this is the exception thrown by app.exec() then that is a normal + // case and we suppress it. + if (e == "unwind") // not much to go on + return; + + if (!onExitCalled) { + onExitCalled = true; + config.qt.onExit?.({ + text: e.message, + crashed: true + }); + } + throw e; + } + + return instance; +} + +// Compatibility API. This API is deprecated, +// and will be removed in a future version of Qt. +function QtLoader(qtConfig) { + + const warning = 'Warning: The QtLoader API is deprecated and will be removed in ' + + 'a future version of Qt. Please port to the new qtLoad() API.'; + console.warn(warning); + + let emscriptenConfig = qtConfig.moduleConfig || {} + qtConfig.moduleConfig = undefined; + const showLoader = qtConfig.showLoader; + qtConfig.showLoader = undefined; + const showError = qtConfig.showError; + qtConfig.showError = undefined; + const showExit = qtConfig.showExit; + qtConfig.showExit = undefined; + const showCanvas = qtConfig.showCanvas; + qtConfig.showCanvas = undefined; + if (qtConfig.canvasElements) { + qtConfig.containerElements = qtConfig.canvasElements + qtConfig.canvasElements = undefined; + } else { + qtConfig.containerElements = qtConfig.containerElements; + qtConfig.containerElements = undefined; + } + emscriptenConfig.qt = qtConfig; + + let qtloader = { + exitCode: undefined, + exitText: "", + loadEmscriptenModule: _name => { + try { + qtLoad(emscriptenConfig); + } catch (e) { + showError?.(e.message); + } + } + } + + qtConfig.onLoaded = () => { + showCanvas?.(); + } + + qtConfig.onExit = exit => { + qtloader.exitCode = exit.code + qtloader.exitText = exit.text; + showExit?.(); + } + + showLoader?.("Loading"); + + return qtloader; +}; diff --git a/server/src/xbot2_gui_server/webui/qtlogo.svg b/server/src/xbot2_gui_server/webui/qtlogo.svg new file mode 100644 index 0000000..bfe2493 --- /dev/null +++ b/server/src/xbot2_gui_server/webui/qtlogo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/server/src/xbot2_gui_server/webui/xbot2_gui.html b/server/src/xbot2_gui_server/webui/xbot2_gui.html new file mode 100644 index 0000000..ac77083 --- /dev/null +++ b/server/src/xbot2_gui_server/webui/xbot2_gui.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + xbot2_gui + + + +
+
+ + Qt for WebAssembly: xbot2_gui +
+ +
+
+
+ + + + + + diff --git a/server/src/xbot2_gui_server/webui/xbot2_gui.js b/server/src/xbot2_gui_server/webui/xbot2_gui.js new file mode 100644 index 0000000..d44d790 --- /dev/null +++ b/server/src/xbot2_gui_server/webui/xbot2_gui.js @@ -0,0 +1,19 @@ + +var xbot2_gui_entry = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + if (typeof __filename != 'undefined') _scriptName = _scriptName || __filename; + return ( +function(moduleArg = {}) { + var moduleRtn; + +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&process.type!="renderer";if(ENVIRONMENT_IS_NODE){}var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);var ret=fs.readFileSync(filename);return ret};readAsync=(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return new Promise((resolve,reject)=>{fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)reject(err);else resolve(binary?data.buffer:data)})})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>{if(isFileURI(url)){return new Promise((resolve,reject)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response);return}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}return fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))})}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAP64,HEAPU64,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);Module["HEAP64"]=HEAP64=new BigInt64Array(b);Module["HEAPU64"]=HEAPU64=new BigUint64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){var preRuns=Module["preRun"];if(preRuns){if(typeof preRuns=="function")preRuns=[preRuns];preRuns.forEach(addOnPreRun)}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;SOCKFS.root=FS.mount(SOCKFS,{},null);if(!Module["noFSInit"]&&!FS.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){var postRuns=Module["postRun"];if(postRuns){if(typeof postRuns=="function")postRuns=[postRuns];postRuns.forEach(addOnPostRun)}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");function findWasmBinary(){var f="xbot2_gui.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=applySignatureConversions(wasmExports);wasmMemory=wasmExports["Vi"];updateMemoryViews();wasmTable=wasmExports["Xi"];addOnInit(wasmExports["Wi"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}wasmBinaryFile??=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}function jsHaveAsyncify(){return typeof Asyncify!=="undefined"}function jsHaveJspi(){return typeof Asyncify!=="undefined"&&!!Asyncify.makeAsyncFunction&&(!!WebAssembly.Function||!!WebAssembly.Suspending)}function __asyncjs__qt_asyncify_suspend_js(){return Asyncify.handleAsync(async()=>{if(Module.qtSuspendId===undefined)Module.qtSuspendId=0;++Module.qtSuspendId;await new Promise(resolve=>{Module.qtAsyncifyWakeUp=resolve})})}function qt_asyncify_resume_js(){let wakeUp=Module.qtAsyncifyWakeUp;if(wakeUp==undefined)return;Module.qtAsyncifyWakeUp=undefined;const suspendId=Module.qtSuspendId;setTimeout(()=>{if(Module.qtSuspendId!==suspendId)return;wakeUp()})}function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var callRuntimeCallbacks=callbacks=>{callbacks.forEach(f=>f(Module))};var noExitRuntime=Module["noExitRuntime"]||true;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var INT53_MAX=9007199254740992;var INT53_MIN=-9007199254740992;var bigintToI53Checked=num=>numINT53_MAX?NaN:Number(num);var wasmTableMirror=[];var wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};function ___call_sighandler(fp,sig){fp>>>=0;return getWasmTableEntry(fp)(sig)}var exceptionCaught=[];var uncaughtExceptionCount=0;function ___cxa_begin_catch(ptr){ptr>>>=0;var info=new ExceptionInfo(ptr);if(!info.get_caught()){info.set_caught(true);uncaughtExceptionCount--}info.set_rethrown(false);exceptionCaught.push(info);___cxa_increment_exception_refcount(ptr);return ___cxa_get_exception_ptr(ptr)}var exceptionLast=0;var ___cxa_end_catch=()=>{_setThrew(0,0);var info=exceptionCaught.pop();___cxa_decrement_exception_refcount(info.excPtr);exceptionLast=0};class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>>2>>>0]=type}get_type(){return HEAPU32[this.ptr+4>>>2>>>0]}set_destructor(destructor){HEAPU32[this.ptr+8>>>2>>>0]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>>2>>>0]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12>>>0]=caught}get_caught(){return HEAP8[this.ptr+12>>>0]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>>0]=rethrown}get_rethrown(){return HEAP8[this.ptr+13>>>0]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>>2>>>0]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>>2>>>0]}}function ___resumeException(ptr){ptr>>>=0;if(!exceptionLast){exceptionLast=ptr}throw exceptionLast}var setTempRet0=val=>__emscripten_tempret_set(val);var findMatchingCatch=args=>{var thrown=exceptionLast;if(!thrown){setTempRet0(0);return 0}var info=new ExceptionInfo(thrown);info.set_adjusted_ptr(thrown);var thrownType=info.get_type();if(!thrownType){setTempRet0(0);return thrown}for(var caughtType of args){if(caughtType===0||caughtType===thrownType){break}var adjusted_ptr_addr=info.ptr+16;if(___cxa_can_catch(caughtType,thrownType,adjusted_ptr_addr)){setTempRet0(caughtType);return thrown}}setTempRet0(thrownType);return thrown};function ___cxa_find_matching_catch_2(){return findMatchingCatch([])}function ___cxa_find_matching_catch_3(arg0){arg0>>>=0;return findMatchingCatch([arg0])}var ___cxa_rethrow=()=>{var info=exceptionCaught.pop();if(!info){abort("no exception to throw")}var ptr=info.excPtr;if(!info.get_rethrown()){exceptionCaught.push(info);info.set_rethrown(true);info.set_caught(false);uncaughtExceptionCount++}exceptionLast=ptr;throw exceptionLast};function ___cxa_throw(ptr,type,destructor){ptr>>>=0;type>>>=0;destructor>>>=0;var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size)};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(ptr)zeroMemory(ptr,size);return ptr};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}}return{ptr,allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var asyncLoad=(url,onload,onerror,noRunDep)=>{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url).then(arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},err=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{constructor(errno){this.name="ErrnoError";this.errno=errno}},genericErrors:{},filesystems:null,syncFSRequests:0,readFiles:{},FSStream:class{constructor(){this.shared={}}get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;this.readMode=292|73;this.writeMode=146}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var SOCKFS={mount(mount){Module["websocket"]=Module["websocket"]&&"object"===typeof Module["websocket"]?Module["websocket"]:{};Module["websocket"]._callbacks={};Module["websocket"]["on"]=function(event,callback){if("function"===typeof callback){this._callbacks[event]=callback}return this};Module["websocket"].emit=function(event,param){if("function"===typeof this._callbacks[event]){this._callbacks[event].call(this,param)}};return FS.createNode(null,"/",16384|511,0)},createSocket(family,type,protocol){type&=~526336;var streaming=type==1;if(streaming&&protocol&&protocol!=6){throw new FS.ErrnoError(66)}var sock={family,type,protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node,flags:2,seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return"socket["+SOCKFS.nextname.current+++"]"},websocket_sock_ops:{createPeer(sock,addr,port){var ws;if(typeof addr=="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var runtimeConfig=Module["websocket"]&&"object"===typeof Module["websocket"];var url="ws:#".replace("#","//");if(runtimeConfig){if("string"===typeof Module["websocket"]["url"]){url=Module["websocket"]["url"]}}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}var subProtocols="binary";if(runtimeConfig){if("string"===typeof Module["websocket"]["subprotocol"]){subProtocols=Module["websocket"]["subprotocol"]}}var opts=undefined;if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=subProtocols}if(runtimeConfig&&null===Module["websocket"]["subprotocol"]){subProtocols="null";opts=undefined}var WebSocketConstructor;if(ENVIRONMENT_IS_NODE){WebSocketConstructor=require("ws")}else{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(23)}}var peer={addr,port,socket:ws,msg_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!="undefined"){peer.msg_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer(sock,addr,port){return sock.peers[addr+":"+port]},addPeer(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents(sock,peer){var first=true;var handleOpen=function(){Module["websocket"].emit("open",sock.stream.fd);try{var queued=peer.msg_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.msg_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data=="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}data=new Uint8Array(data)}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data});Module["websocket"].emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,isBinary){if(!isBinary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){Module["websocket"].emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){Module["websocket"].emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=16}return mask},ioctl(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>>2>>>0]=bytes;return 0;default:return 28}},close(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i{var socket=SOCKFS.getSocket(fd);if(!socket)throw new FS.ErrnoError(8);return socket};var inetPton4=str=>{var b=str.split(".");for(var i=0;i<4;i++){var tmp=Number(b[i]);if(isNaN(tmp))return null;b[i]=tmp}return(b[0]|b[1]<<8|b[2]<<16|b[3]<<24)>>>0};var jstoi_q=str=>parseInt(str);var inetPton6=str=>{var words;var w,offset,z;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.startsWith("::")){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=jstoi_q(words[words.length-4])+jstoi_q(words[words.length-3])*256;words[words.length-3]=jstoi_q(words[words.length-2])+jstoi_q(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w{switch(family){case 2:addr=inetPton4(addr);zeroMemory(sa,16);if(addrlen){HEAP32[addrlen>>>2>>>0]=16}HEAP16[sa>>>1>>>0]=family;HEAP32[sa+4>>>2>>>0]=addr;HEAP16[sa+2>>>1>>>0]=_htons(port);break;case 10:addr=inetPton6(addr);zeroMemory(sa,28);if(addrlen){HEAP32[addrlen>>>2>>>0]=28}HEAP32[sa>>>2>>>0]=family;HEAP32[sa+8>>>2>>>0]=addr[0];HEAP32[sa+12>>>2>>>0]=addr[1];HEAP32[sa+16>>>2>>>0]=addr[2];HEAP32[sa+20>>>2>>>0]=addr[3];HEAP16[sa+2>>>1>>>0]=_htons(port);break;default:return 5}return 0};var DNS={address_map:{id:1,addrs:{},names:{}},lookup_name(name){var res=inetPton4(name);if(res!==null){return name}res=inetPton6(name);if(res!==null){return name}var addr;if(DNS.address_map.addrs[name]){addr=DNS.address_map.addrs[name]}else{var id=DNS.address_map.id++;assert(id<65535,"exceeded max address mappings of 65535");addr="172.29."+(id&255)+"."+(id&65280);DNS.address_map.names[addr]=name;DNS.address_map.addrs[name]=addr}return addr},lookup_addr(addr){if(DNS.address_map.names[addr]){return DNS.address_map.names[addr]}return null}};function ___syscall_accept4(fd,addr,addrlen,flags,d1,d2){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var newsock=sock.sock_ops.accept(sock);if(addr){var errno=writeSockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport,addrlen)}return newsock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var inetNtop4=addr=>(addr&255)+"."+(addr>>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255);var inetNtop6=ints=>{var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=inetNtop4(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word{var family=HEAP16[sa>>>1>>>0];var port=_ntohs(HEAPU16[sa+2>>>1>>>0]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>>2>>>0];addr=inetNtop4(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>>2>>>0],HEAP32[sa+12>>>2>>>0],HEAP32[sa+16>>>2>>>0],HEAP32[sa+20>>>2>>>0]];addr=inetNtop6(addr);break;default:return{errno:5}}return{family,addr,port}};var getSocketAddress=(addrp,addrlen)=>{var info=readSockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};function ___syscall_bind(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.bind(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;HEAP64[buf+24>>>3]=BigInt(stat.size);HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>>3]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3*1e3;HEAP64[buf+56>>>3]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3*1e3;HEAP64[buf+72>>>3]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3*1e3;HEAP64[buf+88>>>3]=BigInt(stat.ino);return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_chmod(path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_connect(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.connect(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function syscallGetVarargI(){var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret}var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>>1>>>0]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ftruncate64(fd,length){length=bigintToI53Checked(length);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){buf>>>=0;size>>>=0;try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size>>=0;count>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);stream.getdents||=FS.readdir(stream.path);var struct_size=280;var pos=0;var off=FS.llseek(stream,0,1);var idx=Math.floor(off/struct_size);while(idx>>3]=BigInt(id);HEAP64[dirp+pos+8>>>3]=BigInt((idx+1)*struct_size);HEAP16[dirp+pos+16>>>1>>>0]=280;HEAP8[dirp+pos+18>>>0]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size;idx+=1}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_getpeername(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);if(!sock.daddr){return-53}var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_getsockname(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_getsockopt(fd,level,optname,optval,optlen,d1){optval>>>=0;optlen>>>=0;try{var sock=getSocketFromFD(fd);if(level===1){if(optname===4){HEAP32[optval>>>2>>>0]=sock.error;HEAP32[optlen>>>2>>>0]=4;sock.error=null;return 0}}return-50}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_listen(fd,backlog){try{var sock=getSocketFromFD(fd);sock.sock_ops.listen(sock,backlog);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_mkdirat(dirfd,path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_readlinkat(dirfd,path,buf,bufsize){path>>>=0;buf>>>=0;bufsize>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len>>>0];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len>>>0]=endChar;return len}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_recvfrom(fd,buf,len,flags,addr,addrlen){buf>>>=0;len>>>=0;addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port,addrlen)}HEAPU8.set(msg.buffer,buf>>>0);return msg.buffer.byteLength}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_recvmsg(fd,message,flags,d1,d2,d3){message>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var total=0;for(var i=0;i>>2>>>0]}var msg=sock.sock_ops.recvmsg(sock,total);if(!msg)return 0;var name=HEAPU32[message>>>2>>>0];if(name){var errno=writeSockaddr(name,sock.family,DNS.lookup_name(msg.addr),msg.port)}var bytesRead=0;var bytesRemaining=msg.buffer.byteLength;for(var i=0;bytesRemaining>0&&i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];if(!iovlen){continue}var length=Math.min(iovlen,bytesRemaining);var buf=msg.buffer.subarray(bytesRead,bytesRead+length);HEAPU8.set(buf,iovbase+bytesRead>>>0);bytesRead+=length;bytesRemaining-=length}return bytesRead}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_renameat(olddirfd,oldpath,newdirfd,newpath){oldpath>>>=0;newpath>>>=0;try{oldpath=SYSCALLS.getStr(oldpath);newpath=SYSCALLS.getStr(newpath);oldpath=SYSCALLS.calculateAt(olddirfd,oldpath);newpath=SYSCALLS.calculateAt(newdirfd,newpath);FS.rename(oldpath,newpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_rmdir(path){path>>>=0;try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_sendmsg(fd,message,flags,d1,d2,d3){message>>>=0;d1>>>=0;d2>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var addr,port;var name=HEAPU32[message>>>2>>>0];var namelen=HEAP32[message+4>>>2>>>0];if(name){var info=getSocketAddress(name,namelen);port=info.port;addr=info.addr}var total=0;for(var i=0;i>>2>>>0]}var view=new Uint8Array(total);var offset=0;for(var i=0;i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];for(var j=0;j>>0]}}return sock.sock_ops.sendmsg(sock,view,0,total,addr,port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_socket(domain,type,protocol){try{var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_symlink(target,linkpath){target>>>=0;linkpath>>>=0;try{target=SYSCALLS.getStr(target);linkpath=SYSCALLS.getStr(linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_truncate64(path,length){path>>>=0;length=bigintToI53Checked(length);try{if(isNaN(length))return 61;path=SYSCALLS.getStr(path);FS.truncate(path,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_unlinkat(dirfd,path,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(flags===0){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{abort("Invalid flags passed to unlinkat")}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var readI53FromI64=ptr=>HEAPU32[ptr>>>2>>>0]+HEAP32[ptr+4>>>2>>>0]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){path>>>=0;times>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);var now=Date.now(),atime,mtime;if(!times){atime=now;mtime=now}else{var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>>2>>>0];if(nanoseconds==1073741823){atime=now}else if(nanoseconds==1073741822){atime=-1}else{atime=seconds*1e3+nanoseconds/(1e3*1e3)}times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>>2>>>0];if(nanoseconds==1073741823){mtime=now}else if(nanoseconds==1073741822){mtime=-1}else{mtime=seconds*1e3+nanoseconds/(1e3*1e3)}}if(mtime!=-1||atime!=-1){FS.utime(path,atime,mtime)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>{abort("")};var embindRepr=v=>{if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c>>>0]){ret+=embind_charCodes[HEAPU8[c++>>>0]]}return ret};var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var BindingError;var throwBindingError=message=>{throw new BindingError(message)};var InternalError;var throwInternalError=message=>{throw new InternalError(message)};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(type=>typeDependencies[type]=dependentTypes);function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){return sharedRegisterType(rawType,registeredInstance,options)}var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer>>>0]:pointer=>HEAPU8[pointer>>>0];case 2:return signed?pointer=>HEAP16[pointer>>>1>>>0]:pointer=>HEAPU16[pointer>>>1>>>0];case 4:return signed?pointer=>HEAP32[pointer>>>2>>>0]:pointer=>HEAPU32[pointer>>>2>>>0];case 8:return signed?pointer=>HEAP64[pointer>>>3]:pointer=>HEAPU64[pointer>>>3];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};function __embind_register_bigint(primitiveType,name,size,minRange,maxRange){primitiveType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);var isUnsignedType=name.indexOf("u")!=-1;if(isUnsignedType){maxRange=(1n<<64n)-1n}registerType(primitiveType,{name,fromWireType:value=>value,toWireType:function(destructors,value){if(typeof value!="bigint"&&typeof value!="number"){throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${this.name}`)}if(typeof value=="number"){value=BigInt(value)}return value},argPackAdvance:GenericWireTypeSize,readValueFromPointer:integerReadValueFromPointer(name,size,!isUnsignedType),destructorFunction:null})}var GenericWireTypeSize=8;function __embind_register_bool(rawType,name,trueValue,falseValue){rawType>>>=0;name>>>=0;name=readLatin1String(name);registerType(rawType,{name,fromWireType:function(wt){return!!wt},toWireType:function(destructors,o){return o?trueValue:falseValue},argPackAdvance:GenericWireTypeSize,readValueFromPointer:function(pointer){return this["fromWireType"](HEAPU8[pointer>>>0])},destructorFunction:null})}var shallowCopyInternalPointer=o=>({count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType});var throwInstanceAlreadyDeleted=obj=>{function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")};var finalizationRegistry=false;var detachFinalizer=handle=>{};var runDestructor=$$=>{if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}};var releaseClassHandle=$$=>{$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}};var downcastPointer=(ptr,ptrClass,desiredClass)=>{if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)};var registeredPointers={};var registeredInstances={};var getBasestPointer=(class_,ptr)=>{if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr};var getInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]};var makeClassHandle=(prototype,record)=>{if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record,writable:true}}))};function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}var attachFinalizer=handle=>{if("undefined"===typeof FinalizationRegistry){attachFinalizer=handle=>handle;return handle}finalizationRegistry=new FinalizationRegistry(info=>{releaseClassHandle(info.$$)});attachFinalizer=handle=>{var $$=handle.$$;var hasSmartPtr=!!$$.smartPtr;if(hasSmartPtr){var info={$$};finalizationRegistry.register(handle,info,handle)}return handle};detachFinalizer=handle=>finalizationRegistry.unregister(handle);return attachFinalizer(handle)};var deletionQueue=[];var flushPendingDeletes=()=>{while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}};var delayFunction;var init_ClassHandle=()=>{Object.assign(ClassHandle.prototype,{isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;other.$$=other.$$;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right},clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}},delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}},isDeleted(){return!this.$$.ptr},deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}})};function ClassHandle(){}var createNamedFunction=(name,body)=>Object.defineProperty(body,"name",{value:name});var ensureOverloadTable=(proto,methodName,humanName)=>{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(...args){if(!proto[methodName].overloadTable.hasOwnProperty(args.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[args.length].apply(this,args)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module[name].overloadTable.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}var upcastPointer=(ptr,ptrClass,desiredClass)=>{while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr};function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle||!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,Emval.toHandle(()=>clonedHandle["delete"]()));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>>2>>>0])}var init_RegisteredPointer=()=>{Object.assign(RegisteredPointer.prototype,{getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr},destructor(ptr){this.rawDestructor?.(ptr)},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,fromWireType:RegisteredPointer_fromWireType})};function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistent public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCall=(sig,ptr,args=[])=>{var rtn=getWasmTableEntry(ptr)(...args);return sig[0]=="p"?rtn>>>0:rtn};var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("p")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var UnboundTypeError;var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};function __embind_register_class(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor){rawType>>>=0;rawPointerType>>>=0;rawConstPointerType>>>=0;baseClassRawType>>>=0;getActualTypeSignature>>>=0;getActualType>>>=0;upcastSignature>>>=0;upcast>>>=0;downcastSignature>>>=0;downcast>>>=0;name>>>=0;destructorSignature>>>=0;rawDestructor>>>=0;name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);upcast&&=embind__requireFunction(upcastSignature,upcast);downcast&&=embind__requireFunction(downcastSignature,downcast);rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError(`Cannot construct ${name} due to unbound types`,[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],base=>{base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(name,function(...args){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[args.length];if(undefined===body){throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`)}return body.apply(this,args)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);if(registeredClass.baseClass){registeredClass.baseClass.__derivedClasses??=[];registeredClass.baseClass.__derivedClasses.push(registeredClass)}var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})}var heap32VectorToArray=(count,firstElement)=>{var array=[];for(var i=0;i>>2>>>0])}return array};var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function usesDestructorStack(argTypes){for(var i=1;i>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;invoker>>>=0;rawConstructor>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`constructor ${classType.name}`;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`)}classType.registeredClass.constructor_body[argCount-1]=()=>{throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`,rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{argTypes.splice(1,0,null);classType.registeredClass.constructor_body[argCount-1]=craftInvokerFunction(humanName,argTypes,null,invoker,rawConstructor);return[]});return[]})};var getFunctionName=signature=>{signature=signature.trim();const argsIndex=signature.indexOf("(");if(argsIndex!==-1){return signature.substr(0,argsIndex)}else{return signature}};var __embind_register_class_function=function(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual,isAsync,isNonnullReturn){rawClassType>>>=0;methodName>>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;rawInvoker>>>=0;context>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context,isAsync);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})};var emval_freelist=[];var emval_handles=[];function __emval_decref(handle){handle>>>=0;if(handle>9&&0===--emval_handles[handle+1]){emval_handles[handle]=undefined;emval_freelist.push(handle)}}var count_emval_handles=()=>emval_handles.length/2-5-emval_freelist.length;var init_emval=()=>{emval_handles.push(0,1,undefined,1,null,1,true,1,false,1);Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles[handle]},toHandle:value=>{switch(value){case undefined:return 2;case null:return 4;case true:return 6;case false:return 8;default:{const handle=emval_freelist.pop()||emval_handles.length;emval_handles[handle]=value;emval_handles[handle+1]=1;return handle}}}};var EmValType={name:"emscripten::val",fromWireType:handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},toWireType:(destructors,value)=>Emval.toHandle(value),argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:null};function __embind_register_emval(rawType){rawType>>>=0;return registerType(rawType,EmValType)}var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>>2>>>0])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>>3>>>0])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=function(rawType,name,size){rawType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);registerType(rawType,{name,fromWireType:value=>value,toWireType:(destructors,value)=>value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:floatReadValueFromPointer(name,size),destructorFunction:null})};function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync,isNonnullReturn){name>>>=0;rawArgTypesAddr>>>=0;signature>>>=0;rawInvoker>>>=0;fn>>>=0;var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);name=getFunctionName(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){primitiveType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name,fromWireType,toWireType,argPackAdvance:GenericWireTypeSize,readValueFromPointer:integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){rawType>>>=0;name>>>=0;var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>>2>>>0];var data=HEAPU32[handle+4>>>2>>>0];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name,fromWireType:decodeMemoryView,argPackAdvance:GenericWireTypeSize,readValueFromPointer:decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){rawType>>>=0;name>>>=0;name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name,fromWireType(value){var length=HEAPU32[value>>>2>>>0];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr>>>0]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>>0])}str=a.join("")}_free(value);return str},toWireType(destructors,value){if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var length;var valueIsOfTypeString=typeof value=="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){length=lengthBytesUTF8(value)}else{length=value.length}var base=_malloc(4+length+1);var ptr=base+4;HEAPU32[base>>>2>>>0]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i>>>0]=charCode}}else{for(var i=0;i>>0]=value[i]}}}if(destructors!==null){destructors.push(_free,base)}return base},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})}var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx>>>0])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr>>>0,endPtr>>>0));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>>1>>>0];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>>1>>>0]=codeUnit;outPtr+=2}HEAP16[outPtr>>>1>>>0]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>>2>>>0];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{outPtr>>>=0;maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>>2>>>0]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>>2>>>0]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=function(rawType,charSize,name){rawType>>>=0;charSize>>>=0;name>>>=0;name=readLatin1String(name);var decodeString,encodeString,readCharAt,lengthBytesUTF;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;readCharAt=pointer=>HEAPU16[pointer>>>1>>>0]}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;readCharAt=pointer=>HEAPU32[pointer>>>2>>>0]}registerType(rawType,{name,fromWireType:value=>{var length=HEAPU32[value>>>2>>>0];var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||readCharAt(currentBytePtr)==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},toWireType:(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>>2>>>0]=length/charSize;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_void=function(rawType,name){rawType>>>=0;name>>>=0;name=readLatin1String(name);registerType(rawType,{isVoid:true,name,argPackAdvance:0,fromWireType:()=>undefined,toWireType:(destructors,o)=>undefined})};function __emscripten_fetch_free(id){if(Fetch.xhrs.has(id)){var xhr=Fetch.xhrs.get(id);Fetch.xhrs.free(id);if(xhr.readyState>0&&xhr.readyState<4){xhr.abort()}}}function __emscripten_fetch_get_response_headers(id,dst,dstSizeBytes){dst>>>=0;dstSizeBytes>>>=0;var responseHeaders=Fetch.xhrs.get(id).getAllResponseHeaders();var lengthBytes=lengthBytesUTF8(responseHeaders)+1;stringToUTF8(responseHeaders,dst,dstSizeBytes);return Math.min(lengthBytes,dstSizeBytes)}function __emscripten_fetch_get_response_headers_length(id){return lengthBytesUTF8(Fetch.xhrs.get(id).getAllResponseHeaders())+1}var nowIsMonotonic=1;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};var __emscripten_throw_longjmp=()=>{throw Infinity};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`)}return impl};var emval_returnValue=(returnType,destructorsRef,handle)=>{var destructors=[];var result=returnType["toWireType"](destructors,handle);if(destructors.length){HEAPU32[destructorsRef>>>2>>>0]=Emval.toHandle(destructors)}return result};function __emval_as(handle,returnType,destructorsRef){handle>>>=0;returnType>>>=0;destructorsRef>>>=0;handle=Emval.toValue(handle);returnType=requireRegisteredType(returnType,"emval::as");return emval_returnValue(returnType,destructorsRef,handle)}var emval_methodCallers=[];function __emval_call(caller,handle,destructorsRef,args){caller>>>=0;handle>>>=0;destructorsRef>>>=0;args>>>=0;caller=emval_methodCallers[caller];handle=Emval.toValue(handle);return caller(null,handle,destructorsRef,args)}var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol};function __emval_call_method(caller,objHandle,methodName,destructorsRef,args){caller>>>=0;objHandle>>>=0;methodName>>>=0;destructorsRef>>>=0;args>>>=0;caller=emval_methodCallers[caller];objHandle=Emval.toValue(objHandle);methodName=getStringOrSymbol(methodName);return caller(objHandle,objHandle[methodName],destructorsRef,args)}function __emval_delete(object,property){object>>>=0;property>>>=0;object=Emval.toValue(object);property=Emval.toValue(property);return delete object[property]}function __emval_equals(first,second){first>>>=0;second>>>=0;first=Emval.toValue(first);second=Emval.toValue(second);return first==second}var emval_get_global=()=>{if(typeof globalThis=="object"){return globalThis}return function(){return Function}()("return this")()};function __emval_get_global(name){name>>>=0;if(name===0){return Emval.toHandle(emval_get_global())}else{name=getStringOrSymbol(name);return Emval.toHandle(emval_get_global()[name])}}var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>>2>>>0],"parameter "+i)}return a};var reflectConstruct=Reflect.construct;function __emval_get_method_caller(argCount,argTypes,kind){argTypes>>>=0;var types=emval_lookupTypes(argCount,argTypes);var retType=types.shift();argCount--;var functionBody=`return function (obj, func, destructorsRef, args) {\n`;var offset=0;var argsList=[];if(kind===0){argsList.push("obj")}var params=["retType"];var args=[retType];for(var i=0;it.name).join(", ")}) => ${retType.name}>`;return emval_addMethodCaller(createNamedFunction(functionName,invokerFunction))}function __emval_get_module_property(name){name>>>=0;name=getStringOrSymbol(name);return Emval.toHandle(Module[name])}function __emval_get_property(handle,key){handle>>>=0;key>>>=0;handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])}function __emval_incref(handle){handle>>>=0;if(handle>9){emval_handles[handle+1]+=1}}function __emval_instanceof(object,constructor){object>>>=0;constructor>>>=0;object=Emval.toValue(object);constructor=Emval.toValue(constructor);return object instanceof constructor}function __emval_new_array(){return Emval.toHandle([])}function __emval_new_cstring(v){v>>>=0;return Emval.toHandle(getStringOrSymbol(v))}function __emval_new_object(){return Emval.toHandle({})}function __emval_not(object){object>>>=0;object=Emval.toValue(object);return!object}function __emval_run_destructors(handle){handle>>>=0;var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle>>>=0;key>>>=0;value>>>=0;handle=Emval.toValue(handle);key=Emval.toValue(key);value=Emval.toValue(value);handle[key]=value}function __emval_take_value(type,arg){type>>>=0;arg>>>=0;type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](arg);return Emval.toHandle(v)}function __gmtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getUTCSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getUTCMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getUTCHours();HEAP32[tmPtr+12>>>2>>>0]=date.getUTCDate();HEAP32[tmPtr+16>>>2>>>0]=date.getUTCMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>>2>>>0]=yday}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr+36>>>2>>>0]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>>2>>>0]=dst}var __mktime_js=function(tmPtr){tmPtr>>>=0;var ret=(()=>{var date=new Date(HEAP32[tmPtr+20>>>2>>>0]+1900,HEAP32[tmPtr+16>>>2>>>0],HEAP32[tmPtr+12>>>2>>>0],HEAP32[tmPtr+8>>>2>>>0],HEAP32[tmPtr+4>>>2>>>0],HEAP32[tmPtr>>>2>>>0],0);var dst=HEAP32[tmPtr+32>>>2>>>0];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>>2>>>0]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getYear();var timeMs=date.getTime();if(isNaN(timeMs)){return-1}return timeMs/1e3})();return BigInt(ret)};function __mmap_js(len,prot,flags,fd,offset,allocated,addr){len>>>=0;offset=bigintToI53Checked(offset);allocated>>>=0;addr>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>>2>>>0]=res.allocated;HEAPU32[addr>>>2>>>0]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset){addr>>>=0;len>>>=0;offset=bigintToI53Checked(offset);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __tzset_js=function(timezone,daylight,std_name,dst_name){timezone>>>=0;daylight>>>=0;std_name>>>=0;dst_name>>>=0;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>>2>>>0]=stdTimezoneOffset*60;HEAP32[daylight>>>2>>>0]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffset{MainLoop.timingMode=mode;MainLoop.timingValue=value;if(!MainLoop.func){return 1}if(!MainLoop.running){MainLoop.running=true}if(mode==0){MainLoop.scheduler=function MainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,MainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(MainLoop.runner,timeUntilNextTick)};MainLoop.method="timeout"}else if(mode==1){MainLoop.scheduler=function MainLoop_scheduler_rAF(){MainLoop.requestAnimationFrame(MainLoop.runner)};MainLoop.method="rAF"}else if(mode==2){if(typeof MainLoop.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var MainLoop_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",MainLoop_setImmediate_messageHandler,true);MainLoop.setImmediate=func=>{setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){Module["setImmediates"]??=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{MainLoop.setImmediate=setImmediate}}MainLoop.scheduler=function MainLoop_scheduler_setImmediate(){MainLoop.setImmediate(MainLoop.runner)};MainLoop.method="immediate"}return 0};var _emscripten_get_now=()=>performance.now();var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var setMainLoop=(iterFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{MainLoop.func=iterFunc;MainLoop.arg=arg;var thisMainLoopId=MainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=MainLoop.queue.shift();blocker.func(blocker.arg);if(MainLoop.remainingBlockers){var remaining=MainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){MainLoop.remainingBlockers=next}else{next=next+.5;MainLoop.remainingBlockers=(8*remaining+next)/9}}MainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(MainLoop.runner,0);return}if(!checkIsRunning())return;MainLoop.currentFrameNumber=MainLoop.currentFrameNumber+1|0;if(MainLoop.timingMode==1&&MainLoop.timingValue>1&&MainLoop.currentFrameNumber%MainLoop.timingValue!=0){MainLoop.scheduler();return}else if(MainLoop.timingMode==0){MainLoop.tickStartTime=_emscripten_get_now()}MainLoop.runIter(iterFunc);if(!checkIsRunning())return;MainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}MainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var MainLoop={running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],preMainLoop:[],postMainLoop:[],pause(){MainLoop.scheduler=null;MainLoop.currentlyRunningMainloop++},resume(){MainLoop.currentlyRunningMainloop++;var timingMode=MainLoop.timingMode;var timingValue=MainLoop.timingValue;var func=MainLoop.func;MainLoop.func=null;setMainLoop(func,0,false,MainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);MainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=MainLoop.remainingBlockers??0;var expected=MainLoop.expectedBlockers??0;if(remaining){if(remaining=MainLoop.nextRAF){MainLoop.nextRAF+=1e3/60}}var delay=Math.max(MainLoop.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=MainLoop.fakeRequestAnimationFrame;RAF(func)}};var AL={QUEUE_INTERVAL:25,QUEUE_LOOKAHEAD:.1,DEVICE_NAME:"Emscripten OpenAL",CAPTURE_DEVICE_NAME:"Emscripten OpenAL capture",ALC_EXTENSIONS:{ALC_SOFT_pause_device:true,ALC_SOFT_HRTF:true},AL_EXTENSIONS:{AL_EXT_float32:true,AL_SOFT_loop_points:true,AL_SOFT_source_length:true,AL_EXT_source_distance_model:true,AL_SOFT_source_spatialize:true},_alcErr:0,alcErr:0,deviceRefCounts:{},alcStringCache:{},paused:false,stringCache:{},contexts:{},currentCtx:null,buffers:{0:{id:0,refCount:0,audioBuf:null,frequency:0,bytesPerSample:2,channels:1,length:0}},paramArray:[],_nextId:1,newId:()=>AL.freeIds.length>0?AL.freeIds.pop():AL._nextId++,freeIds:[],scheduleContextAudio:ctx=>{if(MainLoop.timingMode===1&&document["visibilityState"]!="visible"){return}for(var i in ctx.sources){AL.scheduleSourceAudio(ctx.sources[i])}},scheduleSourceAudio:(src,lookahead)=>{if(MainLoop.timingMode===1&&document["visibilityState"]!="visible"){return}if(src.state!==4114){return}var currentTime=AL.updateSourceTime(src);var startTime=src.bufStartTime;var startOffset=src.bufOffset;var bufCursor=src.bufsProcessed;for(var i=0;i=src.bufQueue.length){if(src.looping){bufCursor%=src.bufQueue.length}else{break}}var buf=src.bufQueue[bufCursor%src.bufQueue.length];if(buf.length===0){skipCount++;if(skipCount===src.bufQueue.length){break}}else{var audioSrc=src.context.audioCtx.createBufferSource();audioSrc.buffer=buf.audioBuf;audioSrc.playbackRate.value=src.playbackRate;if(buf.audioBuf._loopStart||buf.audioBuf._loopEnd){audioSrc.loopStart=buf.audioBuf._loopStart;audioSrc.loopEnd=buf.audioBuf._loopEnd}var duration=0;if(src.type===4136&&src.looping){duration=Number.POSITIVE_INFINITY;audioSrc.loop=true;if(buf.audioBuf._loopStart){audioSrc.loopStart=buf.audioBuf._loopStart}if(buf.audioBuf._loopEnd){audioSrc.loopEnd=buf.audioBuf._loopEnd}}else{duration=(buf.audioBuf.duration-startOffset)/src.playbackRate}audioSrc._startOffset=startOffset;audioSrc._duration=duration;audioSrc._skipCount=skipCount;skipCount=0;audioSrc.connect(src.gain);if(typeof audioSrc.start!="undefined"){startTime=Math.max(startTime,src.context.audioCtx.currentTime);audioSrc.start(startTime,startOffset)}else if(typeof audioSrc.noteOn!="undefined"){startTime=Math.max(startTime,src.context.audioCtx.currentTime);audioSrc.noteOn(startTime)}audioSrc._startTime=startTime;src.audioQueue.push(audioSrc);startTime+=duration}startOffset=0;bufCursor++}},updateSourceTime:src=>{var currentTime=src.context.audioCtx.currentTime;if(src.state!==4114){return currentTime}if(!isFinite(src.bufStartTime)){src.bufStartTime=currentTime-src.bufOffset/src.playbackRate;src.bufOffset=0}var nextStartTime=0;while(src.audioQueue.length){var audioSrc=src.audioQueue[0];src.bufsProcessed+=audioSrc._skipCount;nextStartTime=audioSrc._startTime+audioSrc._duration;if(currentTime=src.bufQueue.length&&!src.looping){AL.setSourceState(src,4116)}else if(src.type===4136&&src.looping){var buf=src.bufQueue[0];if(buf.length===0){src.bufOffset=0}else{var delta=(currentTime-src.bufStartTime)*src.playbackRate;var loopStart=buf.audioBuf._loopStart||0;var loopEnd=buf.audioBuf._loopEnd||buf.audioBuf.duration;if(loopEnd<=loopStart){loopEnd=buf.audioBuf.duration}if(delta0){src.bufStartTime+=Math.floor((currentTime-src.bufStartTime)/srcDuration)*srcDuration}}for(var i=0;i=src.bufQueue.length){if(src.looping){src.bufsProcessed%=src.bufQueue.length}else{AL.setSourceState(src,4116);break}}var buf=src.bufQueue[src.bufsProcessed];if(buf.length>0){nextStartTime=src.bufStartTime+buf.audioBuf.duration/src.playbackRate;if(currentTime{AL.updateSourceTime(src);for(var i=1;i1){src.audioQueue.length=1}},stopSourceAudio:src=>{for(var i=0;i{if(state===4114){if(src.state===4114||src.state==4116){src.bufsProcessed=0;src.bufOffset=0}else{}AL.stopSourceAudio(src);src.state=4114;src.bufStartTime=Number.NEGATIVE_INFINITY;AL.scheduleSourceAudio(src)}else if(state===4115){if(src.state===4114){AL.updateSourceTime(src);AL.stopSourceAudio(src);src.state=4115}}else if(state===4116){if(src.state!==4113){src.state=4116;src.bufsProcessed=src.bufQueue.length;src.bufStartTime=Number.NEGATIVE_INFINITY;src.bufOffset=0;AL.stopSourceAudio(src)}}else if(state===4113){if(src.state!==4113){src.state=4113;src.bufsProcessed=0;src.bufStartTime=Number.NEGATIVE_INFINITY;src.bufOffset=0;AL.stopSourceAudio(src)}}},initSourcePanner:src=>{if(src.type===4144){return}var templateBuf=AL.buffers[0];for(var i=0;i{for(var i in ctx.sources){AL.updateSourceGlobal(ctx.sources[i])}},updateSourceGlobal:src=>{var panner=src.panner;if(!panner){return}panner.refDistance=src.refDistance;panner.maxDistance=src.maxDistance;panner.rolloffFactor=src.rolloffFactor;panner.panningModel=src.context.hrtf?"HRTF":"equalpower";var distanceModel=src.context.sourceDistanceModel?src.distanceModel:src.context.distanceModel;switch(distanceModel){case 0:panner.distanceModel="inverse";panner.refDistance=340282e33;break;case 53249:case 53250:panner.distanceModel="inverse";break;case 53251:case 53252:panner.distanceModel="linear";break;case 53253:case 53254:panner.distanceModel="exponential";break}},updateListenerSpace:ctx=>{var listener=ctx.audioCtx.listener;if(listener.positionX){listener.positionX.value=ctx.listener.position[0];listener.positionY.value=ctx.listener.position[1];listener.positionZ.value=ctx.listener.position[2]}else{listener.setPosition(ctx.listener.position[0],ctx.listener.position[1],ctx.listener.position[2])}if(listener.forwardX){listener.forwardX.value=ctx.listener.direction[0];listener.forwardY.value=ctx.listener.direction[1];listener.forwardZ.value=ctx.listener.direction[2];listener.upX.value=ctx.listener.up[0];listener.upY.value=ctx.listener.up[1];listener.upZ.value=ctx.listener.up[2]}else{listener.setOrientation(ctx.listener.direction[0],ctx.listener.direction[1],ctx.listener.direction[2],ctx.listener.up[0],ctx.listener.up[1],ctx.listener.up[2])}for(var i in ctx.sources){AL.updateSourceSpace(ctx.sources[i])}},updateSourceSpace:src=>{if(!src.panner){return}var panner=src.panner;var posX=src.position[0];var posY=src.position[1];var posZ=src.position[2];var dirX=src.direction[0];var dirY=src.direction[1];var dirZ=src.direction[2];var listener=src.context.listener;var lPosX=listener.position[0];var lPosY=listener.position[1];var lPosZ=listener.position[2];if(src.relative){var lBackX=-listener.direction[0];var lBackY=-listener.direction[1];var lBackZ=-listener.direction[2];var lUpX=listener.up[0];var lUpY=listener.up[1];var lUpZ=listener.up[2];var inverseMagnitude=(x,y,z)=>{var length=Math.sqrt(x*x+y*y+z*z);if(length{if(src.state===4114){AL.cancelPendingSourceAudio(src);var audioSrc=src.audioQueue[0];if(!audioSrc){return}var duration;if(src.type===4136&&src.looping){duration=Number.POSITIVE_INFINITY}else{duration=(audioSrc.buffer.duration-audioSrc._startOffset)/src.playbackRate}audioSrc._duration=duration;audioSrc.playbackRate.value=src.playbackRate;AL.scheduleSourceAudio(src)}},sourceDuration:src=>{var length=0;for(var i=0;i{AL.updateSourceTime(src);var offset=0;for(var i=0;i{var playing=src.state==4114;if(playing){AL.setSourceState(src,4113)}if(src.bufQueue[src.bufsProcessed].audioBuf!==null){src.bufsProcessed=0;while(offset>src.bufQueue[src.bufsProcessed].audioBuf.duration){offset-=src.bufQueue[src.bufsProcessed].audioBuf.duration;src.bufsProcessed++}src.bufOffset=offset}if(playing){AL.setSourceState(src,4114)}},getGlobalParam:(funcname,param)=>{if(!AL.currentCtx){return null}switch(param){case 49152:return AL.currentCtx.dopplerFactor;case 49155:return AL.currentCtx.speedOfSound;case 53248:return AL.currentCtx.distanceModel;default:AL.currentCtx.err=40962;return null}},setGlobalParam:(funcname,param,value)=>{if(!AL.currentCtx){return}switch(param){case 49152:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}AL.currentCtx.dopplerFactor=value;AL.updateListenerSpace(AL.currentCtx);break;case 49155:if(!Number.isFinite(value)||value<=0){AL.currentCtx.err=40963;return}AL.currentCtx.speedOfSound=value;AL.updateListenerSpace(AL.currentCtx);break;case 53248:switch(value){case 0:case 53249:case 53250:case 53251:case 53252:case 53253:case 53254:AL.currentCtx.distanceModel=value;AL.updateContextGlobal(AL.currentCtx);break;default:AL.currentCtx.err=40963;return}break;default:AL.currentCtx.err=40962;return}},getListenerParam:(funcname,param)=>{if(!AL.currentCtx){return null}switch(param){case 4100:return AL.currentCtx.listener.position;case 4102:return AL.currentCtx.listener.velocity;case 4111:return AL.currentCtx.listener.direction.concat(AL.currentCtx.listener.up);case 4106:return AL.currentCtx.gain.gain.value;default:AL.currentCtx.err=40962;return null}},setListenerParam:(funcname,param,value)=>{if(!AL.currentCtx){return}if(value===null){AL.currentCtx.err=40962;return}var listener=AL.currentCtx.listener;switch(param){case 4100:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])){AL.currentCtx.err=40963;return}listener.position[0]=value[0];listener.position[1]=value[1];listener.position[2]=value[2];AL.updateListenerSpace(AL.currentCtx);break;case 4102:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])){AL.currentCtx.err=40963;return}listener.velocity[0]=value[0];listener.velocity[1]=value[1];listener.velocity[2]=value[2];AL.updateListenerSpace(AL.currentCtx);break;case 4106:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}AL.currentCtx.gain.gain.value=value;break;case 4111:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])||!Number.isFinite(value[3])||!Number.isFinite(value[4])||!Number.isFinite(value[5])){AL.currentCtx.err=40963;return}listener.direction[0]=value[0];listener.direction[1]=value[1];listener.direction[2]=value[2];listener.up[0]=value[3];listener.up[1]=value[4];listener.up[2]=value[5];AL.updateListenerSpace(AL.currentCtx);break;default:AL.currentCtx.err=40962;return}},getBufferParam:(funcname,bufferId,param)=>{if(!AL.currentCtx){return}var buf=AL.buffers[bufferId];if(!buf||bufferId===0){AL.currentCtx.err=40961;return}switch(param){case 8193:return buf.frequency;case 8194:return buf.bytesPerSample*8;case 8195:return buf.channels;case 8196:return buf.length*buf.bytesPerSample*buf.channels;case 8213:if(buf.length===0){return[0,0]}return[(buf.audioBuf._loopStart||0)*buf.frequency,(buf.audioBuf._loopEnd||buf.length)*buf.frequency];default:AL.currentCtx.err=40962;return null}},setBufferParam:(funcname,bufferId,param,value)=>{if(!AL.currentCtx){return}var buf=AL.buffers[bufferId];if(!buf||bufferId===0){AL.currentCtx.err=40961;return}if(value===null){AL.currentCtx.err=40962;return}switch(param){case 8196:if(value!==0){AL.currentCtx.err=40963;return}break;case 8213:if(value[0]<0||value[0]>buf.length||value[1]<0||value[1]>buf.Length||value[0]>=value[1]){AL.currentCtx.err=40963;return}if(buf.refCount>0){AL.currentCtx.err=40964;return}if(buf.audioBuf){buf.audioBuf._loopStart=value[0]/buf.frequency;buf.audioBuf._loopEnd=value[1]/buf.frequency}break;default:AL.currentCtx.err=40962;return}},getSourceParam:(funcname,sourceId,param)=>{if(!AL.currentCtx){return null}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return null}switch(param){case 514:return src.relative;case 4097:return src.coneInnerAngle;case 4098:return src.coneOuterAngle;case 4099:return src.pitch;case 4100:return src.position;case 4101:return src.direction;case 4102:return src.velocity;case 4103:return src.looping;case 4105:if(src.type===4136){return src.bufQueue[0].id}return 0;case 4106:return src.gain.gain.value;case 4109:return src.minGain;case 4110:return src.maxGain;case 4112:return src.state;case 4117:if(src.bufQueue.length===1&&src.bufQueue[0].id===0){return 0}return src.bufQueue.length;case 4118:if(src.bufQueue.length===1&&src.bufQueue[0].id===0||src.looping){return 0}return src.bufsProcessed;case 4128:return src.refDistance;case 4129:return src.rolloffFactor;case 4130:return src.coneOuterGain;case 4131:return src.maxDistance;case 4132:return AL.sourceTell(src);case 4133:var offset=AL.sourceTell(src);if(offset>0){offset*=src.bufQueue[0].frequency}return offset;case 4134:var offset=AL.sourceTell(src);if(offset>0){offset*=src.bufQueue[0].frequency*src.bufQueue[0].bytesPerSample}return offset;case 4135:return src.type;case 4628:return src.spatialize;case 8201:var length=0;var bytesPerFrame=0;for(var i=0;i{if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}if(value===null){AL.currentCtx.err=40962;return}switch(param){case 514:if(value===1){src.relative=true;AL.updateSourceSpace(src)}else if(value===0){src.relative=false;AL.updateSourceSpace(src)}else{AL.currentCtx.err=40963;return}break;case 4097:if(!Number.isFinite(value)){AL.currentCtx.err=40963;return}src.coneInnerAngle=value;if(src.panner){src.panner.coneInnerAngle=value%360}break;case 4098:if(!Number.isFinite(value)){AL.currentCtx.err=40963;return}src.coneOuterAngle=value;if(src.panner){src.panner.coneOuterAngle=value%360}break;case 4099:if(!Number.isFinite(value)||value<=0){AL.currentCtx.err=40963;return}if(src.pitch===value){break}src.pitch=value;AL.updateSourceRate(src);break;case 4100:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])){AL.currentCtx.err=40963;return}src.position[0]=value[0];src.position[1]=value[1];src.position[2]=value[2];AL.updateSourceSpace(src);break;case 4101:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])){AL.currentCtx.err=40963;return}src.direction[0]=value[0];src.direction[1]=value[1];src.direction[2]=value[2];AL.updateSourceSpace(src);break;case 4102:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])){AL.currentCtx.err=40963;return}src.velocity[0]=value[0];src.velocity[1]=value[1];src.velocity[2]=value[2];AL.updateSourceSpace(src);break;case 4103:if(value===1){src.looping=true;AL.updateSourceTime(src);if(src.type===4136&&src.audioQueue.length>0){var audioSrc=src.audioQueue[0];audioSrc.loop=true;audioSrc._duration=Number.POSITIVE_INFINITY}}else if(value===0){src.looping=false;var currentTime=AL.updateSourceTime(src);if(src.type===4136&&src.audioQueue.length>0){var audioSrc=src.audioQueue[0];audioSrc.loop=false;audioSrc._duration=src.bufQueue[0].audioBuf.duration/src.playbackRate;audioSrc._startTime=currentTime-src.bufOffset/src.playbackRate}}else{AL.currentCtx.err=40963;return}break;case 4105:if(src.state===4114||src.state===4115){AL.currentCtx.err=40964;return}if(value===0){for(var i in src.bufQueue){src.bufQueue[i].refCount--}src.bufQueue.length=1;src.bufQueue[0]=AL.buffers[0];src.bufsProcessed=0;src.type=4144}else{var buf=AL.buffers[value];if(!buf){AL.currentCtx.err=40963;return}for(var i in src.bufQueue){src.bufQueue[i].refCount--}src.bufQueue.length=0;buf.refCount++;src.bufQueue=[buf];src.bufsProcessed=0;src.type=4136}AL.initSourcePanner(src);AL.scheduleSourceAudio(src);break;case 4106:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.gain.gain.value=value;break;case 4109:if(!Number.isFinite(value)||value<0||value>Math.min(src.maxGain,1)){AL.currentCtx.err=40963;return}src.minGain=value;break;case 4110:if(!Number.isFinite(value)||value1){AL.currentCtx.err=40963;return}src.maxGain=value;break;case 4128:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.refDistance=value;if(src.panner){src.panner.refDistance=value}break;case 4129:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.rolloffFactor=value;if(src.panner){src.panner.rolloffFactor=value}break;case 4130:if(!Number.isFinite(value)||value<0||value>1){AL.currentCtx.err=40963;return}src.coneOuterGain=value;if(src.panner){src.panner.coneOuterGain=value}break;case 4131:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.maxDistance=value;if(src.panner){src.panner.maxDistance=value}break;case 4132:if(value<0||value>AL.sourceDuration(src)){AL.currentCtx.err=40963;return}AL.sourceSeek(src,value);break;case 4133:var srcLen=AL.sourceDuration(src);if(srcLen>0){var frequency;for(var bufId in src.bufQueue){if(bufId){frequency=src.bufQueue[bufId].frequency;break}}value/=frequency}if(value<0||value>srcLen){AL.currentCtx.err=40963;return}AL.sourceSeek(src,value);break;case 4134:var srcLen=AL.sourceDuration(src);if(srcLen>0){var bytesPerSec;for(var bufId in src.bufQueue){if(bufId){var buf=src.bufQueue[bufId];bytesPerSec=buf.frequency*buf.bytesPerSample*buf.channels;break}}value/=bytesPerSec}if(value<0||value>srcLen){AL.currentCtx.err=40963;return}AL.sourceSeek(src,value);break;case 4628:if(value!==0&&value!==1&&value!==2){AL.currentCtx.err=40963;return}src.spatialize=value;AL.initSourcePanner(src);break;case 8201:case 8202:case 8203:AL.currentCtx.err=40964;break;case 53248:switch(value){case 0:case 53249:case 53250:case 53251:case 53252:case 53253:case 53254:src.distanceModel=value;if(AL.currentCtx.sourceDistanceModel){AL.updateContextGlobal(AL.currentCtx)}break;default:AL.currentCtx.err=40963;return}break;default:AL.currentCtx.err=40962;return}},captures:{},sharedCaptureAudioCtx:null,requireValidCaptureDevice:(deviceId,funcname)=>{if(deviceId===0){AL.alcErr=40961;return null}var c=AL.captures[deviceId];if(!c){AL.alcErr=40961;return null}var err=c.mediaStreamError;if(err){AL.alcErr=40961;return null}return c}};function _alBufferData(bufferId,format,pData,size,freq){pData>>>=0;if(!AL.currentCtx){return}var buf=AL.buffers[bufferId];if(!buf){AL.currentCtx.err=40963;return}if(freq<=0){AL.currentCtx.err=40963;return}var audioBuf=null;try{switch(format){case 4352:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(1,size,freq);var channel0=audioBuf.getChannelData(0);for(var i=0;i>>0]*.0078125-1}}buf.bytesPerSample=1;buf.channels=1;buf.length=size;break;case 4353:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(1,size>>1,freq);var channel0=audioBuf.getChannelData(0);pData>>=1;for(var i=0;i>1;++i){channel0[i]=HEAP16[pData++>>>0]*30517578125e-15}}buf.bytesPerSample=2;buf.channels=1;buf.length=size>>1;break;case 4354:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(2,size>>1,freq);var channel0=audioBuf.getChannelData(0);var channel1=audioBuf.getChannelData(1);for(var i=0;i>1;++i){channel0[i]=HEAPU8[pData++>>>0]*.0078125-1;channel1[i]=HEAPU8[pData++>>>0]*.0078125-1}}buf.bytesPerSample=1;buf.channels=2;buf.length=size>>1;break;case 4355:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(2,size>>2,freq);var channel0=audioBuf.getChannelData(0);var channel1=audioBuf.getChannelData(1);pData>>=1;for(var i=0;i>2;++i){channel0[i]=HEAP16[pData++>>>0]*30517578125e-15;channel1[i]=HEAP16[pData++>>>0]*30517578125e-15}}buf.bytesPerSample=2;buf.channels=2;buf.length=size>>2;break;case 65552:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(1,size>>2,freq);var channel0=audioBuf.getChannelData(0);pData>>=2;for(var i=0;i>2;++i){channel0[i]=HEAPF32[pData++>>>0]}}buf.bytesPerSample=4;buf.channels=1;buf.length=size>>2;break;case 65553:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(2,size>>3,freq);var channel0=audioBuf.getChannelData(0);var channel1=audioBuf.getChannelData(1);pData>>=2;for(var i=0;i>3;++i){channel0[i]=HEAPF32[pData++>>>0];channel1[i]=HEAPF32[pData++>>>0]}}buf.bytesPerSample=4;buf.channels=2;buf.length=size>>3;break;default:AL.currentCtx.err=40963;return}buf.frequency=freq;buf.audioBuf=audioBuf}catch(e){AL.currentCtx.err=40963;return}}function _alDeleteBuffers(count,pBufferIds){pBufferIds>>>=0;if(!AL.currentCtx){return}for(var i=0;i>>2>>>0];if(bufId===0){continue}if(!AL.buffers[bufId]){AL.currentCtx.err=40961;return}if(AL.buffers[bufId].refCount){AL.currentCtx.err=40964;return}}for(var i=0;i>>2>>>0];if(bufId===0){continue}AL.deviceRefCounts[AL.buffers[bufId].deviceId]--;delete AL.buffers[bufId];AL.freeIds.push(bufId)}}var _alSourcei=(sourceId,param,value)=>{switch(param){case 514:case 4097:case 4098:case 4103:case 4105:case 4128:case 4129:case 4131:case 4132:case 4133:case 4134:case 4628:case 8201:case 8202:case 53248:AL.setSourceParam("alSourcei",sourceId,param,value);break;default:AL.setSourceParam("alSourcei",sourceId,param,null);break}};function _alDeleteSources(count,pSourceIds){pSourceIds>>>=0;if(!AL.currentCtx){return}for(var i=0;i>>2>>>0];if(!AL.currentCtx.sources[srcId]){AL.currentCtx.err=40961;return}}for(var i=0;i>>2>>>0];AL.setSourceState(AL.currentCtx.sources[srcId],4116);_alSourcei(srcId,4105,0);delete AL.currentCtx.sources[srcId];AL.freeIds.push(srcId)}}function _alGenBuffers(count,pBufferIds){pBufferIds>>>=0;if(!AL.currentCtx){return}for(var i=0;i>>2>>>0]=buf.id}}function _alGenSources(count,pSourceIds){pSourceIds>>>=0;if(!AL.currentCtx){return}for(var i=0;i>>2>>>0]=src.id}}var _alGetError=()=>{if(!AL.currentCtx){return 40964}var err=AL.currentCtx.err;AL.currentCtx.err=0;return err};function _alGetSourcei(sourceId,param,pValue){pValue>>>=0;var val=AL.getSourceParam("alGetSourcei",sourceId,param);if(val===null){return}if(!pValue){AL.currentCtx.err=40963;return}switch(param){case 514:case 4097:case 4098:case 4103:case 4105:case 4112:case 4117:case 4118:case 4128:case 4129:case 4131:case 4132:case 4133:case 4134:case 4135:case 4628:case 8201:case 8202:case 53248:HEAP32[pValue>>>2>>>0]=val;break;default:AL.currentCtx.err=40962;return}}var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};function _alGetString(param){if(AL.stringCache[param]){return AL.stringCache[param]}var ret;switch(param){case 0:ret="No Error";break;case 40961:ret="Invalid Name";break;case 40962:ret="Invalid Enum";break;case 40963:ret="Invalid Value";break;case 40964:ret="Invalid Operation";break;case 40965:ret="Out of Memory";break;case 45057:ret="Emscripten";break;case 45058:ret="1.1";break;case 45059:ret="WebAudio";break;case 45060:ret=Object.keys(AL.AL_EXTENSIONS).join(" ");break;default:if(AL.currentCtx){AL.currentCtx.err=40962}else{}return 0}ret=stringToNewUTF8(ret);AL.stringCache[param]=ret;return ret}function _alIsExtensionPresent(pExtName){pExtName>>>=0;var name=UTF8ToString(pExtName);return AL.AL_EXTENSIONS[name]?1:0}var _alSourcePause=sourceId=>{if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}AL.setSourceState(src,4115)};var _alSourcePlay=sourceId=>{if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}AL.setSourceState(src,4114)};function _alSourceQueueBuffers(sourceId,count,pBufferIds){pBufferIds>>>=0;if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}if(src.type===4136){AL.currentCtx.err=40964;return}if(count===0){return}var templateBuf=AL.buffers[0];for(var i=0;i>>2>>>0];var buf=AL.buffers[bufId];if(!buf){AL.currentCtx.err=40961;return}if(templateBuf.id!==0&&(buf.frequency!==templateBuf.frequency||buf.bytesPerSample!==templateBuf.bytesPerSample||buf.channels!==templateBuf.channels)){AL.currentCtx.err=40964}}if(src.bufQueue.length===1&&src.bufQueue[0].id===0){src.bufQueue.length=0}src.type=4137;for(var i=0;i>>2>>>0];var buf=AL.buffers[bufId];buf.refCount++;src.bufQueue.push(buf)}if(src.looping){AL.cancelPendingSourceAudio(src)}AL.initSourcePanner(src);AL.scheduleSourceAudio(src)}var _alSourceRewind=sourceId=>{if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}AL.setSourceState(src,4116);AL.setSourceState(src,4113)};var _alSourceStop=sourceId=>{if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}AL.setSourceState(src,4116)};function _alSourceUnqueueBuffers(sourceId,count,pBufferIds){pBufferIds>>>=0;if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}if(count>(src.bufQueue.length===1&&src.bufQueue[0].id===0?0:src.bufsProcessed)){AL.currentCtx.err=40963;return}if(count===0){return}for(var i=0;i>>2>>>0]=buf.id;src.bufsProcessed--}if(src.bufQueue.length===0){src.bufQueue.push(AL.buffers[0])}AL.initSourcePanner(src);AL.scheduleSourceAudio(src)}var _alSourcef=(sourceId,param,value)=>{switch(param){case 4097:case 4098:case 4099:case 4106:case 4109:case 4110:case 4128:case 4129:case 4130:case 4131:case 4132:case 4133:case 4134:case 8203:AL.setSourceParam("alSourcef",sourceId,param,value);break;default:AL.setSourceParam("alSourcef",sourceId,param,null);break}};var _alcCaptureCloseDevice=function(deviceId){deviceId>>>=0;var c=AL.requireValidCaptureDevice(deviceId,"alcCaptureCloseDevice");if(!c)return false;delete AL.captures[deviceId];AL.freeIds.push(deviceId);c.mediaStreamSourceNode?.disconnect();c.mergerNode?.disconnect();c.splitterNode?.disconnect();c.scriptProcessorNode?.disconnect();if(c.mediaStream){c.mediaStream.getTracks().forEach(track=>track.stop())}delete c.buffers;c.capturedFrameCount=0;c.isCapturing=false;return true};var listenOnce=(object,event,func)=>{object.addEventListener(event,func,{once:true})};var autoResumeAudioContext=(ctx,elements)=>{if(!elements){elements=[document,document.getElementById("canvas")]}["keydown","mousedown","touchstart"].forEach(event=>{elements.forEach(element=>{if(element){listenOnce(element,event,()=>{if(ctx.state==="suspended")ctx.resume()})}})})};function _alcCaptureOpenDevice(pDeviceName,requestedSampleRate,format,bufferFrameCapacity){pDeviceName>>>=0;var resolvedDeviceName=AL.CAPTURE_DEVICE_NAME;if(pDeviceName!==0){resolvedDeviceName=UTF8ToString(pDeviceName);if(resolvedDeviceName!==AL.CAPTURE_DEVICE_NAME){AL.alcErr=40965;return 0}}if(bufferFrameCapacity<0){AL.alcErr=40964;return 0}navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia;var has_getUserMedia=navigator.getUserMedia||navigator.mediaDevices&&navigator.mediaDevices.getUserMedia;if(!has_getUserMedia){AL.alcErr=40965;return 0}var AudioContext=window.AudioContext||window.webkitAudioContext;if(!AL.sharedCaptureAudioCtx){try{AL.sharedCaptureAudioCtx=new AudioContext}catch(e){AL.alcErr=40965;return 0}}autoResumeAudioContext(AL.sharedCaptureAudioCtx);var outputChannelCount;switch(format){case 65552:case 4353:case 4352:outputChannelCount=1;break;case 65553:case 4355:case 4354:outputChannelCount=2;break;default:AL.alcErr=40964;return 0}function newF32Array(cap){return new Float32Array(cap)}function newI16Array(cap){return new Int16Array(cap)}function newU8Array(cap){return new Uint8Array(cap)}var requestedSampleType;var newSampleArray;switch(format){case 65552:case 65553:requestedSampleType="f32";newSampleArray=newF32Array;break;case 4353:case 4355:requestedSampleType="i16";newSampleArray=newI16Array;break;case 4352:case 4354:requestedSampleType="u8";newSampleArray=newU8Array;break}var buffers=[];try{for(var chan=0;chan{newCapture.mediaStreamError=mediaStreamError};var onSuccess=mediaStream=>{newCapture.mediaStreamSourceNode=newCapture.audioCtx.createMediaStreamSource(mediaStream);newCapture.mediaStream=mediaStream;var inputChannelCount=1;switch(newCapture.mediaStreamSourceNode.channelCountMode){case"max":inputChannelCount=outputChannelCount;break;case"clamped-max":inputChannelCount=Math.min(outputChannelCount,newCapture.mediaStreamSourceNode.channelCount);break;case"explicit":inputChannelCount=newCapture.mediaStreamSourceNode.channelCount;break}newCapture.inputChannelCount=inputChannelCount;var processorFrameCount=512;newCapture.scriptProcessorNode=newCapture.audioCtx.createScriptProcessor(processorFrameCount,inputChannelCount,outputChannelCount);if(inputChannelCount>outputChannelCount){newCapture.mergerNode=newCapture.audioCtx.createChannelMerger(inputChannelCount);newCapture.mediaStreamSourceNode.connect(newCapture.mergerNode);newCapture.mergerNode.connect(newCapture.scriptProcessorNode)}else if(inputChannelCount{if(!newCapture.isCapturing){return}var c=newCapture;var srcBuf=audioProcessingEvent.inputBuffer;switch(format){case 65552:var channel0=srcBuf.getChannelData(0);for(var i=0;i>>=0;pFrames>>>=0;var c=AL.requireValidCaptureDevice(deviceId,"alcCaptureSamples");if(!c)return;var dstfreq=c.requestedSampleRate;var srcfreq=c.audioCtx.sampleRate;var fratio=srcfreq/dstfreq;if(requestedFrameCount<0||requestedFrameCount>c.capturedFrameCount/fratio){AL.alcErr=40964;return}function setF32Sample(i,sample){HEAPF32[pFrames+4*i>>>2>>>0]=sample}function setI16Sample(i,sample){HEAP16[pFrames+2*i>>>1>>>0]=sample}function setU8Sample(i,sample){HEAP8[pFrames+i>>>0]=sample}var setSample;switch(c.requestedSampleType){case"f32":setSample=setF32Sample;break;case"i16":setSample=setI16Sample;break;case"u8":setSample=setU8Sample;break;default:return}if(Math.floor(fratio)==fratio){for(var i=0,frame_i=0;frame_i>>=0;var c=AL.requireValidCaptureDevice(deviceId,"alcCaptureStart");if(!c)return;if(c.isCapturing){return}c.isCapturing=true;c.capturedFrameCount=0;c.capturePlayhead=0}function _alcCaptureStop(deviceId){deviceId>>>=0;var c=AL.requireValidCaptureDevice(deviceId,"alcCaptureStop");if(!c)return;c.isCapturing=false}function _alcCloseDevice(deviceId){deviceId>>>=0;if(!(deviceId in AL.deviceRefCounts)||AL.deviceRefCounts[deviceId]>0){return 0}delete AL.deviceRefCounts[deviceId];AL.freeIds.push(deviceId);return 1}function _alcCreateContext(deviceId,pAttrList){deviceId>>>=0;pAttrList>>>=0;if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return 0}var options=null;var attrs=[];var hrtf=null;pAttrList>>=2;if(pAttrList){var attr=0;var val=0;while(true){attr=HEAP32[pAttrList++>>>0];attrs.push(attr);if(attr===0){break}val=HEAP32[pAttrList++>>>0];attrs.push(val);switch(attr){case 4103:if(!options){options={}}options.sampleRate=val;break;case 4112:case 4113:break;case 6546:switch(val){case 0:hrtf=false;break;case 1:hrtf=true;break;case 2:break;default:AL.alcErr=40964;return 0}break;case 6550:if(val!==0){AL.alcErr=40964;return 0}break;default:AL.alcErr=40964;return 0}}}var AudioContext=window.AudioContext||window.webkitAudioContext;var ac=null;try{if(options){ac=new AudioContext(options)}else{ac=new AudioContext}}catch(e){if(e.name==="NotSupportedError"){AL.alcErr=40964}else{AL.alcErr=40961}return 0}autoResumeAudioContext(ac);if(typeof ac.createGain=="undefined"){ac.createGain=ac.createGainNode}var gain=ac.createGain();gain.connect(ac.destination);var ctx={deviceId,id:AL.newId(),attrs,audioCtx:ac,listener:{position:[0,0,0],velocity:[0,0,0],direction:[0,0,0],up:[0,0,0]},sources:[],interval:setInterval(()=>AL.scheduleContextAudio(ctx),AL.QUEUE_INTERVAL),gain,distanceModel:53250,speedOfSound:343.3,dopplerFactor:1,sourceDistanceModel:false,hrtf:hrtf||false,_err:0,get err(){return this._err},set err(val){if(this._err===0||val===0){this._err=val}}};AL.deviceRefCounts[deviceId]++;AL.contexts[ctx.id]=ctx;if(hrtf!==null){for(var ctxId in AL.contexts){var c=AL.contexts[ctxId];if(c.deviceId===deviceId){c.hrtf=hrtf;AL.updateContextGlobal(c)}}}return ctx.id}function _alcDestroyContext(contextId){contextId>>>=0;var ctx=AL.contexts[contextId];if(AL.currentCtx===ctx){AL.alcErr=40962;return}if(AL.contexts[contextId].interval){clearInterval(AL.contexts[contextId].interval)}AL.deviceRefCounts[ctx.deviceId]--;delete AL.contexts[contextId];AL.freeIds.push(contextId)}function _alcGetError(deviceId){deviceId>>>=0;var err=AL.alcErr;AL.alcErr=0;return err}function _alcGetIntegerv(deviceId,param,size,pValues){deviceId>>>=0;pValues>>>=0;if(size===0||!pValues){return}switch(param){case 4096:HEAP32[pValues>>>2>>>0]=1;break;case 4097:HEAP32[pValues>>>2>>>0]=1;break;case 4098:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>>2>>>0]=AL.currentCtx.attrs.length;break;case 4099:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}for(var i=0;i>>2>>>0]=AL.currentCtx.attrs[i]}break;case 4103:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>>2>>>0]=AL.currentCtx.audioCtx.sampleRate;break;case 4112:case 4113:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>>2>>>0]=2147483647;break;case 6546:case 6547:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}var hrtfStatus=0;for(var ctxId in AL.contexts){var ctx=AL.contexts[ctxId];if(ctx.deviceId===deviceId){hrtfStatus=ctx.hrtf?1:0}}HEAP32[pValues>>>2>>>0]=hrtfStatus;break;case 6548:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}HEAP32[pValues>>>2>>>0]=1;break;case 131075:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>>2>>>0]=1;case 786:var c=AL.requireValidCaptureDevice(deviceId,"alcGetIntegerv");if(!c){return}var n=c.capturedFrameCount;var dstfreq=c.requestedSampleRate;var srcfreq=c.audioCtx.sampleRate;var nsamples=Math.floor(n*(dstfreq/srcfreq));HEAP32[pValues>>>2>>>0]=nsamples;break;default:AL.alcErr=40963;return}}function _alcGetString(deviceId,param){deviceId>>>=0;if(AL.alcStringCache[param]){return AL.alcStringCache[param]}var ret;switch(param){case 0:ret="No Error";break;case 40961:ret="Invalid Device";break;case 40962:ret="Invalid Context";break;case 40963:ret="Invalid Enum";break;case 40964:ret="Invalid Value";break;case 40965:ret="Out of Memory";break;case 4100:if(typeof AudioContext!="undefined"||typeof webkitAudioContext!="undefined"){ret=AL.DEVICE_NAME}else{return 0}break;case 4101:if(typeof AudioContext!="undefined"||typeof webkitAudioContext!="undefined"){ret=AL.DEVICE_NAME+"\0"}else{ret="\0"}break;case 785:ret=AL.CAPTURE_DEVICE_NAME;break;case 784:if(deviceId===0){ret=AL.CAPTURE_DEVICE_NAME+"\0"}else{var c=AL.requireValidCaptureDevice(deviceId,"alcGetString");if(!c){return 0}ret=c.deviceName}break;case 4102:if(!deviceId){AL.alcErr=40961;return 0}ret=Object.keys(AL.ALC_EXTENSIONS).join(" ");break;default:AL.alcErr=40963;return 0}ret=stringToNewUTF8(ret);AL.alcStringCache[param]=ret;return ret}function _alcMakeContextCurrent(contextId){contextId>>>=0;if(contextId===0){AL.currentCtx=null}else{AL.currentCtx=AL.contexts[contextId]}return 1}function _alcOpenDevice(pDeviceName){pDeviceName>>>=0;if(pDeviceName){var name=UTF8ToString(pDeviceName);if(name!==AL.DEVICE_NAME){return 0}}if(typeof AudioContext!="undefined"||typeof webkitAudioContext!="undefined"){var deviceId=AL.newId();AL.deviceRefCounts[deviceId]=0;return deviceId}return 0}var safeSetTimeout=(func,timeout)=>setTimeout(()=>{callUserCallback(func)},timeout);var warnOnce=text=>{warnOnce.shown||={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};var Browser={useWebGL:false,isFullscreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init(){if(Browser.initted)return;Browser.initted=true;var imagePlugin={};imagePlugin["canHandle"]=function imagePlugin_canHandle(name){return!Module["noImageDecoding"]&&/\.(jpg|jpeg|png|bmp|webp)$/i.test(name)};imagePlugin["handle"]=function imagePlugin_handle(byteArray,name,onload,onerror){var b=new Blob([byteArray],{type:Browser.getMimetype(name)});if(b.size!==byteArray.length){b=new Blob([new Uint8Array(byteArray).buffer],{type:Browser.getMimetype(name)})}var url=URL.createObjectURL(b);var img=new Image;img.onload=()=>{var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;URL.revokeObjectURL(url);onload?.(byteArray)};img.onerror=event=>{err(`Image ${url} could not be decoded`);onerror?.()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module["noAudioDecoding"]&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;onload?.(byteArray)}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`);function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:typeof WebGL2RenderingContext!="undefined"?2:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Browser.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}Module["onFullScreen"]?.(Browser.isFullscreen);Module["onFullscreen"]?.(Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},safeSetTimeout(func,timeout){return safeSetTimeout(func,timeout)},getMimetype(name){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia(func){window.getUserMedia||=navigator["getUserMedia"]||navigator["mozGetUserMedia"];window.getUserMedia(func)},getMovementX(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseCoords(pageX,pageY){var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;var adjustedX=pageX-(scrollX+rect.left);var adjustedY=pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);return{x:adjustedX,y:adjustedY}},setMouseCoords(pageX,pageY){const{x,y}=Browser.calculateMouseCoords(pageX,pageY);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y},calculateMouseEvent(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}else{if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var coords=Browser.calculateMouseCoords(touch.pageX,touch.pageY);if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];last||=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}Browser.setMouseCoords(event.pageX,event.pageY)}},resizeListeners:[],updateResizeListeners(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags|8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags&~8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/hMainLoop.requestAnimationFrame(()=>{callUserCallback(func)});function _emscripten_async_call(func,arg,millis){func>>>=0;arg>>>=0;function wrapper(){getWasmTableEntry(func)(arg)}if(millis>=0||ENVIRONMENT_IS_NODE){safeSetTimeout(wrapper,millis)}else{safeRequestAnimationFrame(wrapper)}}var _emscripten_cancel_animation_frame=id=>cancelAnimationFrame(id);var _emscripten_clear_timeout=clearTimeout;var _emscripten_date_now=()=>Date.now();var JSEvents={removeAllEventListeners(){while(JSEvents.eventHandlers.length){JSEvents._removeHandler(JSEvents.eventHandlers.length-1)}JSEvents.deferredCalls=[]},inEventHandler:0,deferredCalls:[],deferCall(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var call of JSEvents.deferredCalls){if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction,precedence,argsList});JSEvents.deferredCalls.sort((x,y)=>x.precedencecall.targetFunction!=targetFunction)},canPerformEventHandlerRequests(){if(navigator.userActivation){return navigator.userActivation.isActive}return JSEvents.inEventHandler&&JSEvents.currentEventHandler.allowsDeferredCalls},runDeferredCalls(){if(!JSEvents.canPerformEventHandlerRequests()){return}var deferredCalls=JSEvents.deferredCalls;JSEvents.deferredCalls=[];for(var call of deferredCalls){call.targetFunction(...call.argsList)}},eventHandlers:[],removeAllHandlersOnTarget:(target,eventTypeString)=>{for(var i=0;icString>2?UTF8ToString(cString):cString;var specialHTMLTargets=[0,typeof document!="undefined"?document:0,typeof window!="undefined"?window:0];var findEventTarget=target=>{target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!="undefined"?document.querySelector(target):undefined);return domElement};var getBoundingClientRect=e=>specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{left:0,top:0};function _emscripten_get_element_css_size(target,width,height){target>>>=0;width>>>=0;height>>>=0;target=findEventTarget(target);if(!target)return-4;var rect=getBoundingClientRect(target);HEAPF64[width>>>3>>>0]=rect.width;HEAPF64[height>>>3>>>0]=rect.height;return 0}var getHeapMax=()=>4294901760;function _emscripten_get_heap_max(){return getHeapMax()}var GLctx;var webgl_enable_ANGLE_instanced_arrays=ctx=>{var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=(index,divisor)=>ext["vertexAttribDivisorANGLE"](index,divisor);ctx["drawArraysInstanced"]=(mode,first,count,primcount)=>ext["drawArraysInstancedANGLE"](mode,first,count,primcount);ctx["drawElementsInstanced"]=(mode,count,type,indices,primcount)=>ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount);return 1}};var webgl_enable_OES_vertex_array_object=ctx=>{var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=()=>ext["createVertexArrayOES"]();ctx["deleteVertexArray"]=vao=>ext["deleteVertexArrayOES"](vao);ctx["bindVertexArray"]=vao=>ext["bindVertexArrayOES"](vao);ctx["isVertexArray"]=vao=>ext["isVertexArrayOES"](vao);return 1}};var webgl_enable_WEBGL_draw_buffers=ctx=>{var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=(n,bufs)=>ext["drawBuffersWEBGL"](n,bufs);return 1}};var webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"));var webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"));var webgl_enable_EXT_polygon_offset_clamp=ctx=>!!(ctx.extPolygonOffsetClamp=ctx.getExtension("EXT_polygon_offset_clamp"));var webgl_enable_EXT_clip_control=ctx=>!!(ctx.extClipControl=ctx.getExtension("EXT_clip_control"));var webgl_enable_WEBGL_polygon_mode=ctx=>!!(ctx.webglPolygonMode=ctx.getExtension("WEBGL_polygon_mode"));var webgl_enable_WEBGL_multi_draw=ctx=>!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"));var getEmscriptenSupportedExtensions=ctx=>{var supportedExtensions=["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_disjoint_timer_query","EXT_frag_depth","EXT_shader_texture_lod","EXT_sRGB","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_color_buffer_float","WEBGL_depth_texture","WEBGL_draw_buffers","EXT_color_buffer_float","EXT_conservative_depth","EXT_disjoint_timer_query_webgl2","EXT_texture_norm16","NV_shader_noperspective_interpolation","WEBGL_clip_cull_distance","EXT_clip_control","EXT_color_buffer_half_float","EXT_depth_clamp","EXT_float_blend","EXT_polygon_offset_clamp","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","KHR_parallel_shader_compile","OES_texture_float_linear","WEBGL_blend_func_extended","WEBGL_compressed_texture_astc","WEBGL_compressed_texture_etc","WEBGL_compressed_texture_etc1","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_lose_context","WEBGL_multi_draw","WEBGL_polygon_mode"];return(ctx.getSupportedExtensions()||[]).filter(ext=>supportedExtensions.includes(ext))};var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],stringCache:{},stringiCache:{},unpackAlignment:4,unpackRowLength:0,recordError:errorCode=>{if(!GL.lastError){GL.lastError=errorCode}},getNewId:table=>{var ret=GL.counter++;for(var i=table.length;i{for(var i=0;i>>2>>>0]=id}},getSource:(shader,count,string,length)=>{var source="";for(var i=0;i>>2>>>0]:undefined;source+=UTF8ToString(HEAPU32[string+i*4>>>2>>>0],len)}return source},createContext:(canvas,webGLContextAttributes)=>{if(!canvas.getContextSafariWebGL2Fixed){canvas.getContextSafariWebGL2Fixed=canvas.getContext;function fixedGetContext(ver,attrs){var gl=canvas.getContextSafariWebGL2Fixed(ver,attrs);return ver=="webgl"==gl instanceof WebGLRenderingContext?gl:null}canvas.getContext=fixedGetContext}var ctx=webGLContextAttributes.majorVersion>1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:(ctx,webGLContextAttributes)=>{var handle=GL.getNewId(GL.contexts);var context={handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:contextHandle=>{GL.currentContext=GL.contexts[contextHandle];Module.ctx=GLctx=GL.currentContext?.GLctx;return!(contextHandle&&!GLctx)},getContext:contextHandle=>GL.contexts[contextHandle],deleteContext:contextHandle=>{if(GL.currentContext===GL.contexts[contextHandle]){GL.currentContext=null}if(typeof JSEvents=="object"){JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas)}if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas){GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined}GL.contexts[contextHandle]=null},initExtensions:context=>{context||=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;webgl_enable_WEBGL_multi_draw(GLctx);webgl_enable_EXT_polygon_offset_clamp(GLctx);webgl_enable_EXT_clip_control(GLctx);webgl_enable_WEBGL_polygon_mode(GLctx);webgl_enable_ANGLE_instanced_arrays(GLctx);webgl_enable_OES_vertex_array_object(GLctx);webgl_enable_WEBGL_draw_buffers(GLctx);webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(context.version>=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}getEmscriptenSupportedExtensions(GLctx).forEach(ext=>{if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};var _glActiveTexture=x0=>GLctx.activeTexture(x0);var _emscripten_glActiveTexture=_glActiveTexture;var _glAttachShader=(program,shader)=>{GLctx.attachShader(GL.programs[program],GL.shaders[shader])};var _emscripten_glAttachShader=_glAttachShader;var _glBeginQuery=(target,id)=>{GLctx.beginQuery(target,GL.queries[id])};var _emscripten_glBeginQuery=_glBeginQuery;var _glBeginQueryEXT=(target,id)=>{GLctx.disjointTimerQueryExt["beginQueryEXT"](target,GL.queries[id])};var _emscripten_glBeginQueryEXT=_glBeginQueryEXT;var _glBeginTransformFeedback=x0=>GLctx.beginTransformFeedback(x0);var _emscripten_glBeginTransformFeedback=_glBeginTransformFeedback;function _glBindAttribLocation(program,index,name){name>>>=0;GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}var _emscripten_glBindAttribLocation=_glBindAttribLocation;var _glBindBuffer=(target,buffer)=>{if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])};var _emscripten_glBindBuffer=_glBindBuffer;var _glBindBufferBase=(target,index,buffer)=>{GLctx.bindBufferBase(target,index,GL.buffers[buffer])};var _emscripten_glBindBufferBase=_glBindBufferBase;function _glBindBufferRange(target,index,buffer,offset,ptrsize){offset>>>=0;ptrsize>>>=0;GLctx.bindBufferRange(target,index,GL.buffers[buffer],offset,ptrsize)}var _emscripten_glBindBufferRange=_glBindBufferRange;var _glBindFramebuffer=(target,framebuffer)=>{GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])};var _emscripten_glBindFramebuffer=_glBindFramebuffer;var _glBindRenderbuffer=(target,renderbuffer)=>{GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])};var _emscripten_glBindRenderbuffer=_glBindRenderbuffer;var _glBindSampler=(unit,sampler)=>{GLctx.bindSampler(unit,GL.samplers[sampler])};var _emscripten_glBindSampler=_glBindSampler;var _glBindTexture=(target,texture)=>{GLctx.bindTexture(target,GL.textures[texture])};var _emscripten_glBindTexture=_glBindTexture;var _glBindTransformFeedback=(target,id)=>{GLctx.bindTransformFeedback(target,GL.transformFeedbacks[id])};var _emscripten_glBindTransformFeedback=_glBindTransformFeedback;var _glBindVertexArray=vao=>{GLctx.bindVertexArray(GL.vaos[vao])};var _emscripten_glBindVertexArray=_glBindVertexArray;var _glBindVertexArrayOES=_glBindVertexArray;var _emscripten_glBindVertexArrayOES=_glBindVertexArrayOES;var _glBlendColor=(x0,x1,x2,x3)=>GLctx.blendColor(x0,x1,x2,x3);var _emscripten_glBlendColor=_glBlendColor;var _glBlendEquation=x0=>GLctx.blendEquation(x0);var _emscripten_glBlendEquation=_glBlendEquation;var _glBlendEquationSeparate=(x0,x1)=>GLctx.blendEquationSeparate(x0,x1);var _emscripten_glBlendEquationSeparate=_glBlendEquationSeparate;var _glBlendFunc=(x0,x1)=>GLctx.blendFunc(x0,x1);var _emscripten_glBlendFunc=_glBlendFunc;var _glBlendFuncSeparate=(x0,x1,x2,x3)=>GLctx.blendFuncSeparate(x0,x1,x2,x3);var _emscripten_glBlendFuncSeparate=_glBlendFuncSeparate;var _glBlitFramebuffer=(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)=>GLctx.blitFramebuffer(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);var _emscripten_glBlitFramebuffer=_glBlitFramebuffer;function _glBufferData(target,size,data,usage){size>>>=0;data>>>=0;GLctx.bufferData(target,data?HEAPU8.subarray(data>>>0,data+size>>>0):size,usage)}var _emscripten_glBufferData=_glBufferData;function _glBufferSubData(target,offset,size,data){offset>>>=0;size>>>=0;data>>>=0;GLctx.bufferSubData(target,offset,HEAPU8.subarray(data>>>0,data+size>>>0))}var _emscripten_glBufferSubData=_glBufferSubData;var _glCheckFramebufferStatus=x0=>GLctx.checkFramebufferStatus(x0);var _emscripten_glCheckFramebufferStatus=_glCheckFramebufferStatus;var _glClear=x0=>GLctx.clear(x0);var _emscripten_glClear=_glClear;var _glClearBufferfi=(x0,x1,x2,x3)=>GLctx.clearBufferfi(x0,x1,x2,x3);var _emscripten_glClearBufferfi=_glClearBufferfi;function _glClearBufferfv(buffer,drawbuffer,value){value>>>=0;GLctx.clearBufferfv(buffer,drawbuffer,HEAPF32,value>>>2)}var _emscripten_glClearBufferfv=_glClearBufferfv;function _glClearBufferiv(buffer,drawbuffer,value){value>>>=0;GLctx.clearBufferiv(buffer,drawbuffer,HEAP32,value>>>2)}var _emscripten_glClearBufferiv=_glClearBufferiv;function _glClearBufferuiv(buffer,drawbuffer,value){value>>>=0;GLctx.clearBufferuiv(buffer,drawbuffer,HEAPU32,value>>>2)}var _emscripten_glClearBufferuiv=_glClearBufferuiv;var _glClearColor=(x0,x1,x2,x3)=>GLctx.clearColor(x0,x1,x2,x3);var _emscripten_glClearColor=_glClearColor;var _glClearDepthf=x0=>GLctx.clearDepth(x0);var _emscripten_glClearDepthf=_glClearDepthf;var _glClearStencil=x0=>GLctx.clearStencil(x0);var _emscripten_glClearStencil=_glClearStencil;function _glClientWaitSync(sync,flags,timeout){sync>>>=0;timeout=Number(timeout);return GLctx.clientWaitSync(GL.syncs[sync],flags,timeout)}var _emscripten_glClientWaitSync=_glClientWaitSync;var _glClipControlEXT=(origin,depth)=>{GLctx.extClipControl["clipControlEXT"](origin,depth)};var _emscripten_glClipControlEXT=_glClipControlEXT;var _glColorMask=(red,green,blue,alpha)=>{GLctx.colorMask(!!red,!!green,!!blue,!!alpha)};var _emscripten_glColorMask=_glColorMask;var _glCompileShader=shader=>{GLctx.compileShader(GL.shaders[shader])};var _emscripten_glCompileShader=_glCompileShader;function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){data>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data);return}}GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,HEAPU8.subarray(data>>>0,data+imageSize>>>0))}var _emscripten_glCompressedTexImage2D=_glCompressedTexImage2D;function _glCompressedTexImage3D(target,level,internalFormat,width,height,depth,border,imageSize,data){data>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.compressedTexImage3D(target,level,internalFormat,width,height,depth,border,imageSize,data)}else{GLctx.compressedTexImage3D(target,level,internalFormat,width,height,depth,border,HEAPU8,data,imageSize)}}var _emscripten_glCompressedTexImage3D=_glCompressedTexImage3D;function _glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){data>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx.compressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data);return}}GLctx.compressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,HEAPU8.subarray(data>>>0,data+imageSize>>>0))}var _emscripten_glCompressedTexSubImage2D=_glCompressedTexSubImage2D;function _glCompressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data){data>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.compressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data)}else{GLctx.compressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,HEAPU8,data,imageSize)}}var _emscripten_glCompressedTexSubImage3D=_glCompressedTexSubImage3D;function _glCopyBufferSubData(x0,x1,x2,x3,x4){x2>>>=0;x3>>>=0;x4>>>=0;return GLctx.copyBufferSubData(x0,x1,x2,x3,x4)}var _emscripten_glCopyBufferSubData=_glCopyBufferSubData;var _glCopyTexImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7);var _emscripten_glCopyTexImage2D=_glCopyTexImage2D;var _glCopyTexSubImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7);var _emscripten_glCopyTexSubImage2D=_glCopyTexSubImage2D;var _glCopyTexSubImage3D=(x0,x1,x2,x3,x4,x5,x6,x7,x8)=>GLctx.copyTexSubImage3D(x0,x1,x2,x3,x4,x5,x6,x7,x8);var _emscripten_glCopyTexSubImage3D=_glCopyTexSubImage3D;var _glCreateProgram=()=>{var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id};var _emscripten_glCreateProgram=_glCreateProgram;var _glCreateShader=shaderType=>{var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id};var _emscripten_glCreateShader=_glCreateShader;var _glCullFace=x0=>GLctx.cullFace(x0);var _emscripten_glCullFace=_glCullFace;function _glDeleteBuffers(n,buffers){buffers>>>=0;for(var i=0;i>>2>>>0];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}var _emscripten_glDeleteBuffers=_glDeleteBuffers;function _glDeleteFramebuffers(n,framebuffers){framebuffers>>>=0;for(var i=0;i>>2>>>0];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}var _emscripten_glDeleteFramebuffers=_glDeleteFramebuffers;var _glDeleteProgram=id=>{if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null};var _emscripten_glDeleteProgram=_glDeleteProgram;function _glDeleteQueries(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var query=GL.queries[id];if(!query)continue;GLctx.deleteQuery(query);GL.queries[id]=null}}var _emscripten_glDeleteQueries=_glDeleteQueries;function _glDeleteQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var query=GL.queries[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.queries[id]=null}}var _emscripten_glDeleteQueriesEXT=_glDeleteQueriesEXT;function _glDeleteRenderbuffers(n,renderbuffers){renderbuffers>>>=0;for(var i=0;i>>2>>>0];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}var _emscripten_glDeleteRenderbuffers=_glDeleteRenderbuffers;function _glDeleteSamplers(n,samplers){samplers>>>=0;for(var i=0;i>>2>>>0];var sampler=GL.samplers[id];if(!sampler)continue;GLctx.deleteSampler(sampler);sampler.name=0;GL.samplers[id]=null}}var _emscripten_glDeleteSamplers=_glDeleteSamplers;var _glDeleteShader=id=>{if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null};var _emscripten_glDeleteShader=_glDeleteShader;function _glDeleteSync(id){id>>>=0;if(!id)return;var sync=GL.syncs[id];if(!sync){GL.recordError(1281);return}GLctx.deleteSync(sync);sync.name=0;GL.syncs[id]=null}var _emscripten_glDeleteSync=_glDeleteSync;function _glDeleteTextures(n,textures){textures>>>=0;for(var i=0;i>>2>>>0];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}var _emscripten_glDeleteTextures=_glDeleteTextures;function _glDeleteTransformFeedbacks(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var transformFeedback=GL.transformFeedbacks[id];if(!transformFeedback)continue;GLctx.deleteTransformFeedback(transformFeedback);transformFeedback.name=0;GL.transformFeedbacks[id]=null}}var _emscripten_glDeleteTransformFeedbacks=_glDeleteTransformFeedbacks;function _glDeleteVertexArrays(n,vaos){vaos>>>=0;for(var i=0;i>>2>>>0];GLctx.deleteVertexArray(GL.vaos[id]);GL.vaos[id]=null}}var _emscripten_glDeleteVertexArrays=_glDeleteVertexArrays;var _glDeleteVertexArraysOES=_glDeleteVertexArrays;var _emscripten_glDeleteVertexArraysOES=_glDeleteVertexArraysOES;var _glDepthFunc=x0=>GLctx.depthFunc(x0);var _emscripten_glDepthFunc=_glDepthFunc;var _glDepthMask=flag=>{GLctx.depthMask(!!flag)};var _emscripten_glDepthMask=_glDepthMask;var _glDepthRangef=(x0,x1)=>GLctx.depthRange(x0,x1);var _emscripten_glDepthRangef=_glDepthRangef;var _glDetachShader=(program,shader)=>{GLctx.detachShader(GL.programs[program],GL.shaders[shader])};var _emscripten_glDetachShader=_glDetachShader;var _glDisable=x0=>GLctx.disable(x0);var _emscripten_glDisable=_glDisable;var _glDisableVertexAttribArray=index=>{GLctx.disableVertexAttribArray(index)};var _emscripten_glDisableVertexAttribArray=_glDisableVertexAttribArray;var _glDrawArrays=(mode,first,count)=>{GLctx.drawArrays(mode,first,count)};var _emscripten_glDrawArrays=_glDrawArrays;var _glDrawArraysInstanced=(mode,first,count,primcount)=>{GLctx.drawArraysInstanced(mode,first,count,primcount)};var _emscripten_glDrawArraysInstanced=_glDrawArraysInstanced;var _glDrawArraysInstancedANGLE=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedANGLE=_glDrawArraysInstancedANGLE;var _glDrawArraysInstancedARB=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedARB=_glDrawArraysInstancedARB;var _glDrawArraysInstancedEXT=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedEXT=_glDrawArraysInstancedEXT;var _glDrawArraysInstancedNV=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedNV=_glDrawArraysInstancedNV;var tempFixedLengthArray=[];function _glDrawBuffers(n,bufs){bufs>>>=0;var bufArray=tempFixedLengthArray[n];for(var i=0;i>>2>>>0]}GLctx.drawBuffers(bufArray)}var _emscripten_glDrawBuffers=_glDrawBuffers;var _glDrawBuffersEXT=_glDrawBuffers;var _emscripten_glDrawBuffersEXT=_glDrawBuffersEXT;var _glDrawBuffersWEBGL=_glDrawBuffers;var _emscripten_glDrawBuffersWEBGL=_glDrawBuffersWEBGL;function _glDrawElements(mode,count,type,indices){indices>>>=0;GLctx.drawElements(mode,count,type,indices)}var _emscripten_glDrawElements=_glDrawElements;function _glDrawElementsInstanced(mode,count,type,indices,primcount){indices>>>=0;GLctx.drawElementsInstanced(mode,count,type,indices,primcount)}var _emscripten_glDrawElementsInstanced=_glDrawElementsInstanced;var _glDrawElementsInstancedANGLE=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedANGLE=_glDrawElementsInstancedANGLE;var _glDrawElementsInstancedARB=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedARB=_glDrawElementsInstancedARB;var _glDrawElementsInstancedEXT=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedEXT=_glDrawElementsInstancedEXT;var _glDrawElementsInstancedNV=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedNV=_glDrawElementsInstancedNV;function _glDrawRangeElements(mode,start,end,count,type,indices){indices>>>=0;_glDrawElements(mode,count,type,indices)}var _emscripten_glDrawRangeElements=_glDrawRangeElements;var _glEnable=x0=>GLctx.enable(x0);var _emscripten_glEnable=_glEnable;var _glEnableVertexAttribArray=index=>{GLctx.enableVertexAttribArray(index)};var _emscripten_glEnableVertexAttribArray=_glEnableVertexAttribArray;var _glEndQuery=x0=>GLctx.endQuery(x0);var _emscripten_glEndQuery=_glEndQuery;var _glEndQueryEXT=target=>{GLctx.disjointTimerQueryExt["endQueryEXT"](target)};var _emscripten_glEndQueryEXT=_glEndQueryEXT;var _glEndTransformFeedback=()=>GLctx.endTransformFeedback();var _emscripten_glEndTransformFeedback=_glEndTransformFeedback;function _glFenceSync(condition,flags){var sync=GLctx.fenceSync(condition,flags);if(sync){var id=GL.getNewId(GL.syncs);sync.name=id;GL.syncs[id]=sync;return id}return 0}var _emscripten_glFenceSync=_glFenceSync;var _glFinish=()=>GLctx.finish();var _emscripten_glFinish=_glFinish;var _glFlush=()=>GLctx.flush();var _emscripten_glFlush=_glFlush;var _glFramebufferRenderbuffer=(target,attachment,renderbuffertarget,renderbuffer)=>{GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])};var _emscripten_glFramebufferRenderbuffer=_glFramebufferRenderbuffer;var _glFramebufferTexture2D=(target,attachment,textarget,texture,level)=>{GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)};var _emscripten_glFramebufferTexture2D=_glFramebufferTexture2D;var _glFramebufferTextureLayer=(target,attachment,texture,level,layer)=>{GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)};var _emscripten_glFramebufferTextureLayer=_glFramebufferTextureLayer;var _glFrontFace=x0=>GLctx.frontFace(x0);var _emscripten_glFrontFace=_glFrontFace;function _glGenBuffers(n,buffers){buffers>>>=0;GL.genObject(n,buffers,"createBuffer",GL.buffers)}var _emscripten_glGenBuffers=_glGenBuffers;function _glGenFramebuffers(n,ids){ids>>>=0;GL.genObject(n,ids,"createFramebuffer",GL.framebuffers)}var _emscripten_glGenFramebuffers=_glGenFramebuffers;function _glGenQueries(n,ids){ids>>>=0;GL.genObject(n,ids,"createQuery",GL.queries)}var _emscripten_glGenQueries=_glGenQueries;function _glGenQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0]=0;return}var id=GL.getNewId(GL.queries);query.name=id;GL.queries[id]=query;HEAP32[ids+i*4>>>2>>>0]=id}}var _emscripten_glGenQueriesEXT=_glGenQueriesEXT;function _glGenRenderbuffers(n,renderbuffers){renderbuffers>>>=0;GL.genObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}var _emscripten_glGenRenderbuffers=_glGenRenderbuffers;function _glGenSamplers(n,samplers){samplers>>>=0;GL.genObject(n,samplers,"createSampler",GL.samplers)}var _emscripten_glGenSamplers=_glGenSamplers;function _glGenTextures(n,textures){textures>>>=0;GL.genObject(n,textures,"createTexture",GL.textures)}var _emscripten_glGenTextures=_glGenTextures;function _glGenTransformFeedbacks(n,ids){ids>>>=0;GL.genObject(n,ids,"createTransformFeedback",GL.transformFeedbacks)}var _emscripten_glGenTransformFeedbacks=_glGenTransformFeedbacks;function _glGenVertexArrays(n,arrays){arrays>>>=0;GL.genObject(n,arrays,"createVertexArray",GL.vaos)}var _emscripten_glGenVertexArrays=_glGenVertexArrays;var _glGenVertexArraysOES=_glGenVertexArrays;var _emscripten_glGenVertexArraysOES=_glGenVertexArraysOES;var _glGenerateMipmap=x0=>GLctx.generateMipmap(x0);var _emscripten_glGenerateMipmap=_glGenerateMipmap;var __glGetActiveAttribOrUniform=(funcName,program,index,bufSize,length,size,type,name)=>{program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull;if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}};function _glGetActiveAttrib(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;__glGetActiveAttribOrUniform("getActiveAttrib",program,index,bufSize,length,size,type,name)}var _emscripten_glGetActiveAttrib=_glGetActiveAttrib;function _glGetActiveUniform(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;__glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}var _emscripten_glGetActiveUniform=_glGetActiveUniform;function _glGetActiveUniformBlockName(program,uniformBlockIndex,bufSize,length,uniformBlockName){length>>>=0;uniformBlockName>>>=0;program=GL.programs[program];var result=GLctx.getActiveUniformBlockName(program,uniformBlockIndex);if(!result)return;if(uniformBlockName&&bufSize>0){var numBytesWrittenExclNull=stringToUTF8(result,uniformBlockName,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>>2>>>0]=0}}var _emscripten_glGetActiveUniformBlockName=_glGetActiveUniformBlockName;function _glGetActiveUniformBlockiv(program,uniformBlockIndex,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}program=GL.programs[program];if(pname==35393){var name=GLctx.getActiveUniformBlockName(program,uniformBlockIndex);HEAP32[params>>>2>>>0]=name.length+1;return}var result=GLctx.getActiveUniformBlockParameter(program,uniformBlockIndex,pname);if(result===null)return;if(pname==35395){for(var i=0;i>>2>>>0]=result[i]}}else{HEAP32[params>>>2>>>0]=result}}var _emscripten_glGetActiveUniformBlockiv=_glGetActiveUniformBlockiv;function _glGetActiveUniformsiv(program,uniformCount,uniformIndices,pname,params){uniformIndices>>>=0;params>>>=0;if(!params){GL.recordError(1281);return}if(uniformCount>0&&uniformIndices==0){GL.recordError(1281);return}program=GL.programs[program];var ids=[];for(var i=0;i>>2>>>0])}var result=GLctx.getActiveUniforms(program,ids,pname);if(!result)return;var len=result.length;for(var i=0;i>>2>>>0]=result[i]}}var _emscripten_glGetActiveUniformsiv=_glGetActiveUniformsiv;function _glGetAttachedShaders(program,maxCount,count,shaders){count>>>=0;shaders>>>=0;var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>>2>>>0]=len;for(var i=0;i>>2>>>0]=id}}var _emscripten_glGetAttachedShaders=_glGetAttachedShaders;function _glGetAttribLocation(program,name){name>>>=0;return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}var _emscripten_glGetAttribLocation=_glGetAttribLocation;var writeI53ToI64=(ptr,num)=>{HEAPU32[ptr>>>2>>>0]=num;var lower=HEAPU32[ptr>>>2>>>0];HEAPU32[ptr+4>>>2>>>0]=(num-lower)/4294967296};var webglGetExtensions=function $webglGetExtensions(){var exts=getEmscriptenSupportedExtensions(GLctx);exts=exts.concat(exts.map(e=>"GL_"+e));return exts};var emscriptenWebGLGet=(name_,p,type)=>{if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 34814:case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break;case 33309:if(GL.currentContext.version<2){GL.recordError(1282);return}ret=webglGetExtensions().length;break;case 33307:case 33308:if(GL.currentContext.version<2){GL.recordError(1280);return}ret=name_==33307?3:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>>2>>>0]=result[i];break;case 2:HEAPF32[p+i*4>>>2>>>0]=result[i];break;case 4:HEAP8[p+i>>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`);return}}break;default:GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof result}!`);return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>>2>>>0]=ret;break;case 2:HEAPF32[p>>>2>>>0]=ret;break;case 4:HEAP8[p>>>0]=ret?1:0;break}};function _glGetBooleanv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,4)}var _emscripten_glGetBooleanv=_glGetBooleanv;function _glGetBufferParameteri64v(target,value,data){data>>>=0;if(!data){GL.recordError(1281);return}writeI53ToI64(data,GLctx.getBufferParameter(target,value))}var _emscripten_glGetBufferParameteri64v=_glGetBufferParameteri64v;function _glGetBufferParameteriv(target,value,data){data>>>=0;if(!data){GL.recordError(1281);return}HEAP32[data>>>2>>>0]=GLctx.getBufferParameter(target,value)}var _emscripten_glGetBufferParameteriv=_glGetBufferParameteriv;var _glGetError=()=>{var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error};var _emscripten_glGetError=_glGetError;function _glGetFloatv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,2)}var _emscripten_glGetFloatv=_glGetFloatv;function _glGetFragDataLocation(program,name){name>>>=0;return GLctx.getFragDataLocation(GL.programs[program],UTF8ToString(name))}var _emscripten_glGetFragDataLocation=_glGetFragDataLocation;function _glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){params>>>=0;var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>>2>>>0]=result}var _emscripten_glGetFramebufferAttachmentParameteriv=_glGetFramebufferAttachmentParameteriv;var emscriptenWebGLGetIndexed=(target,index,data,type)=>{if(!data){GL.recordError(1281);return}var result=GLctx.getIndexedParameter(target,index);var ret;switch(typeof result){case"boolean":ret=result?1:0;break;case"number":ret=result;break;case"object":if(result===null){switch(target){case 35983:case 35368:ret=0;break;default:{GL.recordError(1280);return}}}else if(result instanceof WebGLBuffer){ret=result.name|0}else{GL.recordError(1280);return}break;default:GL.recordError(1280);return}switch(type){case 1:writeI53ToI64(data,ret);break;case 0:HEAP32[data>>>2>>>0]=ret;break;case 2:HEAPF32[data>>>2>>>0]=ret;break;case 4:HEAP8[data>>>0]=ret?1:0;break;default:throw"internal emscriptenWebGLGetIndexed() error, bad type: "+type}};function _glGetInteger64i_v(target,index,data){data>>>=0;return emscriptenWebGLGetIndexed(target,index,data,1)}var _emscripten_glGetInteger64i_v=_glGetInteger64i_v;function _glGetInteger64v(name_,p){p>>>=0;emscriptenWebGLGet(name_,p,1)}var _emscripten_glGetInteger64v=_glGetInteger64v;function _glGetIntegeri_v(target,index,data){data>>>=0;return emscriptenWebGLGetIndexed(target,index,data,0)}var _emscripten_glGetIntegeri_v=_glGetIntegeri_v;function _glGetIntegerv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,0)}var _emscripten_glGetIntegerv=_glGetIntegerv;function _glGetInternalformativ(target,internalformat,pname,bufSize,params){params>>>=0;if(bufSize<0){GL.recordError(1281);return}if(!params){GL.recordError(1281);return}var ret=GLctx.getInternalformatParameter(target,internalformat,pname);if(ret===null)return;for(var i=0;i>>2>>>0]=ret[i]}}var _emscripten_glGetInternalformativ=_glGetInternalformativ;function _glGetProgramBinary(program,bufSize,length,binaryFormat,binary){length>>>=0;binaryFormat>>>=0;binary>>>=0;GL.recordError(1282)}var _emscripten_glGetProgramBinary=_glGetProgramBinary;function _glGetProgramInfoLog(program,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}var _emscripten_glGetProgramInfoLog=_glGetProgramInfoLog;function _glGetProgramiv(program,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>>2>>>0]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(var i=0;i>>2>>>0]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){var numActiveAttributes=GLctx.getProgramParameter(program,35721);for(var i=0;i>>2>>>0]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){var numActiveUniformBlocks=GLctx.getProgramParameter(program,35382);for(var i=0;i>>2>>>0]=program.maxUniformBlockNameLength}else{HEAP32[p>>>2>>>0]=GLctx.getProgramParameter(program,pname)}}var _emscripten_glGetProgramiv=_glGetProgramiv;function _glGetQueryObjecti64vEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;if(GL.currentContext.version<2){param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}else{param=GLctx.getQueryParameter(query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}var _emscripten_glGetQueryObjecti64vEXT=_glGetQueryObjecti64vEXT;function _glGetQueryObjectivEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>>2>>>0]=ret}var _emscripten_glGetQueryObjectivEXT=_glGetQueryObjectivEXT;var _glGetQueryObjectui64vEXT=_glGetQueryObjecti64vEXT;var _emscripten_glGetQueryObjectui64vEXT=_glGetQueryObjectui64vEXT;function _glGetQueryObjectuiv(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.getQueryParameter(query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>>2>>>0]=ret}var _emscripten_glGetQueryObjectuiv=_glGetQueryObjectuiv;var _glGetQueryObjectuivEXT=_glGetQueryObjectivEXT;var _emscripten_glGetQueryObjectuivEXT=_glGetQueryObjectuivEXT;function _glGetQueryiv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getQuery(target,pname)}var _emscripten_glGetQueryiv=_glGetQueryiv;function _glGetQueryivEXT(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}var _emscripten_glGetQueryivEXT=_glGetQueryivEXT;function _glGetRenderbufferParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getRenderbufferParameter(target,pname)}var _emscripten_glGetRenderbufferParameteriv=_glGetRenderbufferParameteriv;function _glGetSamplerParameterfv(sampler,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAPF32[params>>>2>>>0]=GLctx.getSamplerParameter(GL.samplers[sampler],pname)}var _emscripten_glGetSamplerParameterfv=_glGetSamplerParameterfv;function _glGetSamplerParameteriv(sampler,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getSamplerParameter(GL.samplers[sampler],pname)}var _emscripten_glGetSamplerParameteriv=_glGetSamplerParameteriv;function _glGetShaderInfoLog(shader,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}var _emscripten_glGetShaderInfoLog=_glGetShaderInfoLog;function _glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){range>>>=0;precision>>>=0;var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>>2>>>0]=result.rangeMin;HEAP32[range+4>>>2>>>0]=result.rangeMax;HEAP32[precision>>>2>>>0]=result.precision}var _emscripten_glGetShaderPrecisionFormat=_glGetShaderPrecisionFormat;function _glGetShaderSource(shader,bufSize,length,source){length>>>=0;source>>>=0;var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}var _emscripten_glGetShaderSource=_glGetShaderSource;function _glGetShaderiv(shader,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>>2>>>0]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>>2>>>0]=sourceLength}else{HEAP32[p>>>2>>>0]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}var _emscripten_glGetShaderiv=_glGetShaderiv;function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:ret=stringToNewUTF8(webglGetExtensions().join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s?stringToNewUTF8(s):0;break;case 7938:var webGLVersion=GLctx.getParameter(7938);var glVersion=`OpenGL ES 2.0 (${webGLVersion})`;if(GL.currentContext.version>=2)glVersion=`OpenGL ES 3.0 (${webGLVersion})`;ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion=`OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}var _emscripten_glGetString=_glGetString;function _glGetStringi(name,index){if(GL.currentContext.version<2){GL.recordError(1282);return 0}var stringiCache=GL.stringiCache[name];if(stringiCache){if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index]}switch(name){case 7939:var exts=webglGetExtensions().map(stringToNewUTF8);stringiCache=GL.stringiCache[name]=exts;if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index];default:GL.recordError(1280);return 0}}var _emscripten_glGetStringi=_glGetStringi;function _glGetSynciv(sync,pname,bufSize,length,values){sync>>>=0;length>>>=0;values>>>=0;if(bufSize<0){GL.recordError(1281);return}if(!values){GL.recordError(1281);return}var ret=GLctx.getSyncParameter(GL.syncs[sync],pname);if(ret!==null){HEAP32[values>>>2>>>0]=ret;if(length)HEAP32[length>>>2>>>0]=1}}var _emscripten_glGetSynciv=_glGetSynciv;function _glGetTexParameterfv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAPF32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}var _emscripten_glGetTexParameterfv=_glGetTexParameterfv;function _glGetTexParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}var _emscripten_glGetTexParameteriv=_glGetTexParameteriv;function _glGetTransformFeedbackVarying(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;program=GL.programs[program];var info=GLctx.getTransformFeedbackVarying(program,index);if(!info)return;if(name&&bufSize>0){var numBytesWrittenExclNull=stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>>2>>>0]=0}if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}var _emscripten_glGetTransformFeedbackVarying=_glGetTransformFeedbackVarying;function _glGetUniformBlockIndex(program,uniformBlockName){uniformBlockName>>>=0;return GLctx.getUniformBlockIndex(GL.programs[program],UTF8ToString(uniformBlockName))}var _emscripten_glGetUniformBlockIndex=_glGetUniformBlockIndex;function _glGetUniformIndices(program,uniformCount,uniformNames,uniformIndices){uniformNames>>>=0;uniformIndices>>>=0;if(!uniformIndices){GL.recordError(1281);return}if(uniformCount>0&&(uniformNames==0||uniformIndices==0)){GL.recordError(1281);return}program=GL.programs[program];var names=[];for(var i=0;i>>2>>>0]));var result=GLctx.getUniformIndices(program,names);if(!result)return;var len=result.length;for(var i=0;i>>2>>>0]=result[i]}}var _emscripten_glGetUniformIndices=_glGetUniformIndices;var webglGetLeftBracePos=name=>name.slice(-1)=="]"&&name.lastIndexOf("[");var webglPrepareUniformLocationsBeforeFirstUse=program=>{var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j>>=0;name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex{var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?`[${webglLoc}]`:""))}return webglLoc}else{GL.recordError(1282)}};var emscriptenWebGLGetUniform=(program,location,params,type)=>{if(!params){GL.recordError(1281);return}program=GL.programs[program];webglPrepareUniformLocationsBeforeFirstUse(program);var data=GLctx.getUniform(program,webglGetUniformLocation(location));if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break}}}};function _glGetUniformfv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,2)}var _emscripten_glGetUniformfv=_glGetUniformfv;function _glGetUniformiv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,0)}var _emscripten_glGetUniformiv=_glGetUniformiv;function _glGetUniformuiv(program,location,params){params>>>=0;return emscriptenWebGLGetUniform(program,location,params,0)}var _emscripten_glGetUniformuiv=_glGetUniformuiv;var emscriptenWebGLGetVertexAttrib=(index,pname,params,type)=>{if(!params){GL.recordError(1281);return}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>>2>>>0]=data&&data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break;case 5:HEAP32[params>>>2>>>0]=Math.fround(data);break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break;case 5:HEAP32[params+i*4>>>2>>>0]=Math.fround(data[i]);break}}}};function _glGetVertexAttribIiv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,0)}var _emscripten_glGetVertexAttribIiv=_glGetVertexAttribIiv;var _glGetVertexAttribIuiv=_glGetVertexAttribIiv;var _emscripten_glGetVertexAttribIuiv=_glGetVertexAttribIuiv;function _glGetVertexAttribPointerv(index,pname,pointer){pointer>>>=0;if(!pointer){GL.recordError(1281);return}HEAP32[pointer>>>2>>>0]=GLctx.getVertexAttribOffset(index,pname)}var _emscripten_glGetVertexAttribPointerv=_glGetVertexAttribPointerv;function _glGetVertexAttribfv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,2)}var _emscripten_glGetVertexAttribfv=_glGetVertexAttribfv;function _glGetVertexAttribiv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,5)}var _emscripten_glGetVertexAttribiv=_glGetVertexAttribiv;var _glHint=(x0,x1)=>GLctx.hint(x0,x1);var _emscripten_glHint=_glHint;function _glInvalidateFramebuffer(target,numAttachments,attachments){attachments>>>=0;var list=tempFixedLengthArray[numAttachments];for(var i=0;i>>2>>>0]}GLctx.invalidateFramebuffer(target,list)}var _emscripten_glInvalidateFramebuffer=_glInvalidateFramebuffer;function _glInvalidateSubFramebuffer(target,numAttachments,attachments,x,y,width,height){attachments>>>=0;var list=tempFixedLengthArray[numAttachments];for(var i=0;i>>2>>>0]}GLctx.invalidateSubFramebuffer(target,list,x,y,width,height)}var _emscripten_glInvalidateSubFramebuffer=_glInvalidateSubFramebuffer;var _glIsBuffer=buffer=>{var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)};var _emscripten_glIsBuffer=_glIsBuffer;var _glIsEnabled=x0=>GLctx.isEnabled(x0);var _emscripten_glIsEnabled=_glIsEnabled;var _glIsFramebuffer=framebuffer=>{var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)};var _emscripten_glIsFramebuffer=_glIsFramebuffer;var _glIsProgram=program=>{program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)};var _emscripten_glIsProgram=_glIsProgram;var _glIsQuery=id=>{var query=GL.queries[id];if(!query)return 0;return GLctx.isQuery(query)};var _emscripten_glIsQuery=_glIsQuery;var _glIsQueryEXT=id=>{var query=GL.queries[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)};var _emscripten_glIsQueryEXT=_glIsQueryEXT;var _glIsRenderbuffer=renderbuffer=>{var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)};var _emscripten_glIsRenderbuffer=_glIsRenderbuffer;var _glIsSampler=id=>{var sampler=GL.samplers[id];if(!sampler)return 0;return GLctx.isSampler(sampler)};var _emscripten_glIsSampler=_glIsSampler;var _glIsShader=shader=>{var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)};var _emscripten_glIsShader=_glIsShader;function _glIsSync(sync){sync>>>=0;return GLctx.isSync(GL.syncs[sync])}var _emscripten_glIsSync=_glIsSync;var _glIsTexture=id=>{var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)};var _emscripten_glIsTexture=_glIsTexture;var _glIsTransformFeedback=id=>GLctx.isTransformFeedback(GL.transformFeedbacks[id]);var _emscripten_glIsTransformFeedback=_glIsTransformFeedback;var _glIsVertexArray=array=>{var vao=GL.vaos[array];if(!vao)return 0;return GLctx.isVertexArray(vao)};var _emscripten_glIsVertexArray=_glIsVertexArray;var _glIsVertexArrayOES=_glIsVertexArray;var _emscripten_glIsVertexArrayOES=_glIsVertexArrayOES;var _glLineWidth=x0=>GLctx.lineWidth(x0);var _emscripten_glLineWidth=_glLineWidth;var _glLinkProgram=program=>{program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}};var _emscripten_glLinkProgram=_glLinkProgram;var _glPauseTransformFeedback=()=>GLctx.pauseTransformFeedback();var _emscripten_glPauseTransformFeedback=_glPauseTransformFeedback;var _glPixelStorei=(pname,param)=>{if(pname==3317){GL.unpackAlignment=param}else if(pname==3314){GL.unpackRowLength=param}GLctx.pixelStorei(pname,param)};var _emscripten_glPixelStorei=_glPixelStorei;var _glPolygonModeWEBGL=(face,mode)=>{GLctx.webglPolygonMode["polygonModeWEBGL"](face,mode)};var _emscripten_glPolygonModeWEBGL=_glPolygonModeWEBGL;var _glPolygonOffset=(x0,x1)=>GLctx.polygonOffset(x0,x1);var _emscripten_glPolygonOffset=_glPolygonOffset;var _glPolygonOffsetClampEXT=(factor,units,clamp)=>{GLctx.extPolygonOffsetClamp["polygonOffsetClampEXT"](factor,units,clamp)};var _emscripten_glPolygonOffsetClampEXT=_glPolygonOffsetClampEXT;function _glProgramBinary(program,binaryFormat,binary,length){binary>>>=0;GL.recordError(1280)}var _emscripten_glProgramBinary=_glProgramBinary;var _glProgramParameteri=(program,pname,value)=>{GL.recordError(1280)};var _emscripten_glProgramParameteri=_glProgramParameteri;var _glQueryCounterEXT=(id,target)=>{GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.queries[id],target)};var _emscripten_glQueryCounterEXT=_glQueryCounterEXT;var _glReadBuffer=x0=>GLctx.readBuffer(x0);var _emscripten_glReadBuffer=_glReadBuffer;var computeUnpackAlignedImageSize=(width,height,sizePerPixel)=>{function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=(GL.unpackRowLength||width)*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,GL.unpackAlignment);return height*alignedRowSize};var colorChannelsInGlTextureFormat=format=>{var colorChannels={5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4};return colorChannels[format-6402]||1};var heapObjectForWebGLType=type=>{type-=5120;if(type==0)return HEAP8;if(type==1)return HEAPU8;if(type==2)return HEAP16;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922||type==28520||type==30779||type==30782)return HEAPU32;return HEAPU16};var toTypedArrayIndex=(pointer,heap)=>pointer>>>31-Math.clz32(heap.BYTES_PER_ELEMENT);var emscriptenWebGLGetTexPixelData=(type,format,width,height,pixels,internalFormat)=>{var heap=heapObjectForWebGLType(type);var sizePerPixel=colorChannelsInGlTextureFormat(format)*heap.BYTES_PER_ELEMENT;var bytes=computeUnpackAlignedImageSize(width,height,sizePerPixel);return heap.subarray(toTypedArrayIndex(pixels,heap)>>>0,toTypedArrayIndex(pixels+bytes,heap)>>>0)};function _glReadPixels(x,y,width,height,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels);return}}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}var _emscripten_glReadPixels=_glReadPixels;var _glReleaseShaderCompiler=()=>{};var _emscripten_glReleaseShaderCompiler=_glReleaseShaderCompiler;var _glRenderbufferStorage=(x0,x1,x2,x3)=>GLctx.renderbufferStorage(x0,x1,x2,x3);var _emscripten_glRenderbufferStorage=_glRenderbufferStorage;var _glRenderbufferStorageMultisample=(x0,x1,x2,x3,x4)=>GLctx.renderbufferStorageMultisample(x0,x1,x2,x3,x4);var _emscripten_glRenderbufferStorageMultisample=_glRenderbufferStorageMultisample;var _glResumeTransformFeedback=()=>GLctx.resumeTransformFeedback();var _emscripten_glResumeTransformFeedback=_glResumeTransformFeedback;var _glSampleCoverage=(value,invert)=>{GLctx.sampleCoverage(value,!!invert)};var _emscripten_glSampleCoverage=_glSampleCoverage;var _glSamplerParameterf=(sampler,pname,param)=>{GLctx.samplerParameterf(GL.samplers[sampler],pname,param)};var _emscripten_glSamplerParameterf=_glSamplerParameterf;function _glSamplerParameterfv(sampler,pname,params){params>>>=0;var param=HEAPF32[params>>>2>>>0];GLctx.samplerParameterf(GL.samplers[sampler],pname,param)}var _emscripten_glSamplerParameterfv=_glSamplerParameterfv;var _glSamplerParameteri=(sampler,pname,param)=>{GLctx.samplerParameteri(GL.samplers[sampler],pname,param)};var _emscripten_glSamplerParameteri=_glSamplerParameteri;function _glSamplerParameteriv(sampler,pname,params){params>>>=0;var param=HEAP32[params>>>2>>>0];GLctx.samplerParameteri(GL.samplers[sampler],pname,param)}var _emscripten_glSamplerParameteriv=_glSamplerParameteriv;var _glScissor=(x0,x1,x2,x3)=>GLctx.scissor(x0,x1,x2,x3);var _emscripten_glScissor=_glScissor;function _glShaderBinary(count,shaders,binaryformat,binary,length){shaders>>>=0;binary>>>=0;GL.recordError(1280)}var _emscripten_glShaderBinary=_glShaderBinary;function _glShaderSource(shader,count,string,length){string>>>=0;length>>>=0;var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}var _emscripten_glShaderSource=_glShaderSource;var _glStencilFunc=(x0,x1,x2)=>GLctx.stencilFunc(x0,x1,x2);var _emscripten_glStencilFunc=_glStencilFunc;var _glStencilFuncSeparate=(x0,x1,x2,x3)=>GLctx.stencilFuncSeparate(x0,x1,x2,x3);var _emscripten_glStencilFuncSeparate=_glStencilFuncSeparate;var _glStencilMask=x0=>GLctx.stencilMask(x0);var _emscripten_glStencilMask=_glStencilMask;var _glStencilMaskSeparate=(x0,x1)=>GLctx.stencilMaskSeparate(x0,x1);var _emscripten_glStencilMaskSeparate=_glStencilMaskSeparate;var _glStencilOp=(x0,x1,x2)=>GLctx.stencilOp(x0,x1,x2);var _emscripten_glStencilOp=_glStencilOp;var _glStencilOpSeparate=(x0,x1,x2,x3)=>GLctx.stencilOpSeparate(x0,x1,x2,x3);var _emscripten_glStencilOpSeparate=_glStencilOpSeparate;function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels);return}}var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null;GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixelData)}var _emscripten_glTexImage2D=_glTexImage2D;function _glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels){pixels>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height*depth,pixels,internalFormat);GLctx.texImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixelData)}else{GLctx.texImage3D(target,level,internalFormat,width,height,depth,border,format,type,null)}}var _emscripten_glTexImage3D=_glTexImage3D;var _glTexParameterf=(x0,x1,x2)=>GLctx.texParameterf(x0,x1,x2);var _emscripten_glTexParameterf=_glTexParameterf;function _glTexParameterfv(target,pname,params){params>>>=0;var param=HEAPF32[params>>>2>>>0];GLctx.texParameterf(target,pname,param)}var _emscripten_glTexParameterfv=_glTexParameterfv;var _glTexParameteri=(x0,x1,x2)=>GLctx.texParameteri(x0,x1,x2);var _emscripten_glTexParameteri=_glTexParameteri;function _glTexParameteriv(target,pname,params){params>>>=0;var param=HEAP32[params>>>2>>>0];GLctx.texParameteri(target,pname,param)}var _emscripten_glTexParameteriv=_glTexParameteriv;var _glTexStorage2D=(x0,x1,x2,x3,x4)=>GLctx.texStorage2D(x0,x1,x2,x3,x4);var _emscripten_glTexStorage2D=_glTexStorage2D;var _glTexStorage3D=(x0,x1,x2,x3,x4,x5)=>GLctx.texStorage3D(x0,x1,x2,x3,x4,x5);var _emscripten_glTexStorage3D=_glTexStorage3D;function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels);return}}var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0):null;GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}var _emscripten_glTexSubImage2D=_glTexSubImage2D;function _glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){pixels>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,heap,toTypedArrayIndex(pixels,heap))}else{GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}var _emscripten_glTexSubImage3D=_glTexSubImage3D;function _glTransformFeedbackVaryings(program,count,varyings,bufferMode){varyings>>>=0;program=GL.programs[program];var vars=[];for(var i=0;i>>2>>>0]));GLctx.transformFeedbackVaryings(program,vars,bufferMode)}var _emscripten_glTransformFeedbackVaryings=_glTransformFeedbackVaryings;var _glUniform1f=(location,v0)=>{GLctx.uniform1f(webglGetUniformLocation(location),v0)};var _emscripten_glUniform1f=_glUniform1f;var miniTempWebGLFloatBuffers=[];function _glUniform1fv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1fv(webglGetUniformLocation(location),view)}var _emscripten_glUniform1fv=_glUniform1fv;var _glUniform1i=(location,v0)=>{GLctx.uniform1i(webglGetUniformLocation(location),v0)};var _emscripten_glUniform1i=_glUniform1i;var miniTempWebGLIntBuffers=[];function _glUniform1iv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}var _emscripten_glUniform1iv=_glUniform1iv;var _glUniform1ui=(location,v0)=>{GLctx.uniform1ui(webglGetUniformLocation(location),v0)};var _emscripten_glUniform1ui=_glUniform1ui;function _glUniform1uiv(location,count,value){value>>>=0;count&&GLctx.uniform1uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count)}var _emscripten_glUniform1uiv=_glUniform1uiv;var _glUniform2f=(location,v0,v1)=>{GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)};var _emscripten_glUniform2f=_glUniform2f;function _glUniform2fv(location,count,value){value>>>=0;if(count<=144){count*=2;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}var _emscripten_glUniform2fv=_glUniform2fv;var _glUniform2i=(location,v0,v1)=>{GLctx.uniform2i(webglGetUniformLocation(location),v0,v1)};var _emscripten_glUniform2i=_glUniform2i;function _glUniform2iv(location,count,value){value>>>=0;if(count<=144){count*=2;var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}var _emscripten_glUniform2iv=_glUniform2iv;var _glUniform2ui=(location,v0,v1)=>{GLctx.uniform2ui(webglGetUniformLocation(location),v0,v1)};var _emscripten_glUniform2ui=_glUniform2ui;function _glUniform2uiv(location,count,value){value>>>=0;count&&GLctx.uniform2uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count*2)}var _emscripten_glUniform2uiv=_glUniform2uiv;var _glUniform3f=(location,v0,v1,v2)=>{GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)};var _emscripten_glUniform3f=_glUniform3f;function _glUniform3fv(location,count,value){value>>>=0;if(count<=96){count*=3;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}var _emscripten_glUniform3fv=_glUniform3fv;var _glUniform3i=(location,v0,v1,v2)=>{GLctx.uniform3i(webglGetUniformLocation(location),v0,v1,v2)};var _emscripten_glUniform3i=_glUniform3i;function _glUniform3iv(location,count,value){value>>>=0;if(count<=96){count*=3;var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3iv(webglGetUniformLocation(location),view)}var _emscripten_glUniform3iv=_glUniform3iv;var _glUniform3ui=(location,v0,v1,v2)=>{GLctx.uniform3ui(webglGetUniformLocation(location),v0,v1,v2)};var _emscripten_glUniform3ui=_glUniform3ui;function _glUniform3uiv(location,count,value){value>>>=0;count&&GLctx.uniform3uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count*3)}var _emscripten_glUniform3uiv=_glUniform3uiv;var _glUniform4f=(location,v0,v1,v2,v3)=>{GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)};var _emscripten_glUniform4f=_glUniform4f;function _glUniform4fv(location,count,value){value>>>=0;if(count<=72){var view=miniTempWebGLFloatBuffers[4*count];var heap=HEAPF32;value=value>>>2;count*=4;for(var i=0;i>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}var _emscripten_glUniform4fv=_glUniform4fv;var _glUniform4i=(location,v0,v1,v2,v3)=>{GLctx.uniform4i(webglGetUniformLocation(location),v0,v1,v2,v3)};var _emscripten_glUniform4i=_glUniform4i;function _glUniform4iv(location,count,value){value>>>=0;if(count<=72){count*=4;var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAP32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}var _emscripten_glUniform4iv=_glUniform4iv;var _glUniform4ui=(location,v0,v1,v2,v3)=>{GLctx.uniform4ui(webglGetUniformLocation(location),v0,v1,v2,v3)};var _emscripten_glUniform4ui=_glUniform4ui;function _glUniform4uiv(location,count,value){value>>>=0;count&&GLctx.uniform4uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count*4)}var _emscripten_glUniform4uiv=_glUniform4uiv;var _glUniformBlockBinding=(program,uniformBlockIndex,uniformBlockBinding)=>{program=GL.programs[program];GLctx.uniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding)};var _emscripten_glUniformBlockBinding=_glUniformBlockBinding;function _glUniformMatrix2fv(location,count,transpose,value){value>>>=0;if(count<=72){count*=4;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,view)}var _emscripten_glUniformMatrix2fv=_glUniformMatrix2fv;function _glUniformMatrix2x3fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*6)}var _emscripten_glUniformMatrix2x3fv=_glUniformMatrix2x3fv;function _glUniformMatrix2x4fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*8)}var _emscripten_glUniformMatrix2x4fv=_glUniformMatrix2x4fv;function _glUniformMatrix3fv(location,count,transpose,value){value>>>=0;if(count<=32){count*=9;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0];view[i+4]=HEAPF32[value+(4*i+16)>>>2>>>0];view[i+5]=HEAPF32[value+(4*i+20)>>>2>>>0];view[i+6]=HEAPF32[value+(4*i+24)>>>2>>>0];view[i+7]=HEAPF32[value+(4*i+28)>>>2>>>0];view[i+8]=HEAPF32[value+(4*i+32)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*36>>>2>>>0)}GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,view)}var _emscripten_glUniformMatrix3fv=_glUniformMatrix3fv;function _glUniformMatrix3x2fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*6)}var _emscripten_glUniformMatrix3x2fv=_glUniformMatrix3x2fv;function _glUniformMatrix3x4fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*12)}var _emscripten_glUniformMatrix3x4fv=_glUniformMatrix3x4fv;function _glUniformMatrix4fv(location,count,transpose,value){value>>>=0;if(count<=18){var view=miniTempWebGLFloatBuffers[16*count];var heap=HEAPF32;value=value>>>2;count*=16;for(var i=0;i>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0];view[i+4]=heap[dst+4>>>0];view[i+5]=heap[dst+5>>>0];view[i+6]=heap[dst+6>>>0];view[i+7]=heap[dst+7>>>0];view[i+8]=heap[dst+8>>>0];view[i+9]=heap[dst+9>>>0];view[i+10]=heap[dst+10>>>0];view[i+11]=heap[dst+11>>>0];view[i+12]=heap[dst+12>>>0];view[i+13]=heap[dst+13>>>0];view[i+14]=heap[dst+14>>>0];view[i+15]=heap[dst+15>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*64>>>2>>>0)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}var _emscripten_glUniformMatrix4fv=_glUniformMatrix4fv;function _glUniformMatrix4x2fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*8)}var _emscripten_glUniformMatrix4x2fv=_glUniformMatrix4x2fv;function _glUniformMatrix4x3fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*12)}var _emscripten_glUniformMatrix4x3fv=_glUniformMatrix4x3fv;var _glUseProgram=program=>{program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program};var _emscripten_glUseProgram=_glUseProgram;var _glValidateProgram=program=>{GLctx.validateProgram(GL.programs[program])};var _emscripten_glValidateProgram=_glValidateProgram;var _glVertexAttrib1f=(x0,x1)=>GLctx.vertexAttrib1f(x0,x1);var _emscripten_glVertexAttrib1f=_glVertexAttrib1f;function _glVertexAttrib1fv(index,v){v>>>=0;GLctx.vertexAttrib1f(index,HEAPF32[v>>>2])}var _emscripten_glVertexAttrib1fv=_glVertexAttrib1fv;var _glVertexAttrib2f=(x0,x1,x2)=>GLctx.vertexAttrib2f(x0,x1,x2);var _emscripten_glVertexAttrib2f=_glVertexAttrib2f;function _glVertexAttrib2fv(index,v){v>>>=0;GLctx.vertexAttrib2f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2])}var _emscripten_glVertexAttrib2fv=_glVertexAttrib2fv;var _glVertexAttrib3f=(x0,x1,x2,x3)=>GLctx.vertexAttrib3f(x0,x1,x2,x3);var _emscripten_glVertexAttrib3f=_glVertexAttrib3f;function _glVertexAttrib3fv(index,v){v>>>=0;GLctx.vertexAttrib3f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2])}var _emscripten_glVertexAttrib3fv=_glVertexAttrib3fv;var _glVertexAttrib4f=(x0,x1,x2,x3,x4)=>GLctx.vertexAttrib4f(x0,x1,x2,x3,x4);var _emscripten_glVertexAttrib4f=_glVertexAttrib4f;function _glVertexAttrib4fv(index,v){v>>>=0;GLctx.vertexAttrib4f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2],HEAPF32[v+12>>>2])}var _emscripten_glVertexAttrib4fv=_glVertexAttrib4fv;var _glVertexAttribDivisor=(index,divisor)=>{GLctx.vertexAttribDivisor(index,divisor)};var _emscripten_glVertexAttribDivisor=_glVertexAttribDivisor;var _glVertexAttribDivisorANGLE=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorANGLE=_glVertexAttribDivisorANGLE;var _glVertexAttribDivisorARB=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorARB=_glVertexAttribDivisorARB;var _glVertexAttribDivisorEXT=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorEXT=_glVertexAttribDivisorEXT;var _glVertexAttribDivisorNV=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorNV=_glVertexAttribDivisorNV;var _glVertexAttribI4i=(x0,x1,x2,x3,x4)=>GLctx.vertexAttribI4i(x0,x1,x2,x3,x4);var _emscripten_glVertexAttribI4i=_glVertexAttribI4i;function _glVertexAttribI4iv(index,v){v>>>=0;GLctx.vertexAttribI4i(index,HEAP32[v>>>2],HEAP32[v+4>>>2],HEAP32[v+8>>>2],HEAP32[v+12>>>2])}var _emscripten_glVertexAttribI4iv=_glVertexAttribI4iv;var _glVertexAttribI4ui=(x0,x1,x2,x3,x4)=>GLctx.vertexAttribI4ui(x0,x1,x2,x3,x4);var _emscripten_glVertexAttribI4ui=_glVertexAttribI4ui;function _glVertexAttribI4uiv(index,v){v>>>=0;GLctx.vertexAttribI4ui(index,HEAPU32[v>>>2],HEAPU32[v+4>>>2],HEAPU32[v+8>>>2],HEAPU32[v+12>>>2])}var _emscripten_glVertexAttribI4uiv=_glVertexAttribI4uiv;function _glVertexAttribIPointer(index,size,type,stride,ptr){ptr>>>=0;GLctx.vertexAttribIPointer(index,size,type,stride,ptr)}var _emscripten_glVertexAttribIPointer=_glVertexAttribIPointer;function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){ptr>>>=0;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}var _emscripten_glVertexAttribPointer=_glVertexAttribPointer;var _glViewport=(x0,x1,x2,x3)=>GLctx.viewport(x0,x1,x2,x3);var _emscripten_glViewport=_glViewport;function _glWaitSync(sync,flags,timeout){sync>>>=0;timeout=Number(timeout);GLctx.waitSync(GL.syncs[sync],flags,timeout)}var _emscripten_glWaitSync=_glWaitSync;var IDBStore={indexedDB(){if(typeof indexedDB!="undefined")return indexedDB;var ret=null;if(typeof window=="object")ret=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;assert(ret,"IDBStore used, but indexedDB not supported");return ret},DB_VERSION:22,DB_STORE_NAME:"FILE_DATA",dbs:{},blobs:[0],getDB(name,callback){var db=IDBStore.dbs[name];if(db){return callback(null,db)}var req;try{req=IDBStore.indexedDB().open(name,IDBStore.DB_VERSION)}catch(e){return callback(e)}req.onupgradeneeded=e=>{var db=e.target.result;var transaction=e.target.transaction;var fileStore;if(db.objectStoreNames.contains(IDBStore.DB_STORE_NAME)){fileStore=transaction.objectStore(IDBStore.DB_STORE_NAME)}else{fileStore=db.createObjectStore(IDBStore.DB_STORE_NAME)}};req.onsuccess=()=>{db=req.result;IDBStore.dbs[name]=db;callback(null,db)};req.onerror=function(event){callback(event.target.error||"unknown error");event.preventDefault()}},getStore(dbName,type,callback){IDBStore.getDB(dbName,(error,db)=>{if(error)return callback(error);var transaction=db.transaction([IDBStore.DB_STORE_NAME],type);transaction.onerror=event=>{callback(event.target.error||"unknown error");event.preventDefault()};var store=transaction.objectStore(IDBStore.DB_STORE_NAME);callback(null,store)})},getFile(dbName,id,callback){IDBStore.getStore(dbName,"readonly",(err,store)=>{if(err)return callback(err);var req=store.get(id);req.onsuccess=event=>{var result=event.target.result;if(!result){return callback(`file ${id} not found`)}return callback(null,result)};req.onerror=callback})},setFile(dbName,id,data,callback){IDBStore.getStore(dbName,"readwrite",(err,store)=>{if(err)return callback(err);var req=store.put(data,id);req.onsuccess=event=>callback();req.onerror=callback})},deleteFile(dbName,id,callback){IDBStore.getStore(dbName,"readwrite",(err,store)=>{if(err)return callback(err);var req=store.delete(id);req.onsuccess=event=>callback();req.onerror=callback})},existsFile(dbName,id,callback){IDBStore.getStore(dbName,"readonly",(err,store)=>{if(err)return callback(err);var req=store.count(id);req.onsuccess=event=>callback(null,event.target.result>0);req.onerror=callback})},clearStore(dbName,callback){IDBStore.getStore(dbName,"readwrite",(err,store)=>{if(err)return callback(err);var req=store.clear();req.onsuccess=event=>callback();req.onerror=callback})}};function _emscripten_idb_delete(db,id,perror){db>>>=0;id>>>=0;perror>>>=0;throw"Please compile your program with async support in order to use synchronous operations like emscripten_idb_delete, etc."}function _emscripten_idb_exists(db,id,pexists,perror){db>>>=0;id>>>=0;pexists>>>=0;perror>>>=0;throw"Please compile your program with async support in order to use synchronous operations like emscripten_idb_exists, etc."}function _emscripten_idb_load(db,id,pbuffer,pnum,perror){db>>>=0;id>>>=0;pbuffer>>>=0;pnum>>>=0;perror>>>=0;throw"Please compile your program with async support in order to use synchronous operations like emscripten_idb_load, etc."}function _emscripten_idb_store(db,id,ptr,num,perror){db>>>=0;id>>>=0;ptr>>>=0;perror>>>=0;throw"Please compile your program with async support in order to use synchronous operations like emscripten_idb_store, etc."}var _emscripten_is_main_browser_thread=()=>!ENVIRONMENT_IS_WORKER;function _emscripten_is_webgl_context_lost(contextHandle){contextHandle>>>=0;return!GL.contexts[contextHandle]||GL.contexts[contextHandle].GLctx.isContextLost()}var reallyNegative=x=>x<0||x===0&&1/x===-Infinity;var convertI32PairToI53=(lo,hi)=>(lo>>>0)+hi*4294967296;var convertU32PairToI53=(lo,hi)=>(lo>>>0)+(hi>>>0)*4294967296;var reSign=(value,bits)=>{if(value<=0){return value}var half=bits<=32?Math.abs(1<=half&&(bits<=32||value>half)){value=-2*half+value}return value};var unSign=(value,bits)=>{if(value>=0){return value}return bits<=32?2*Math.abs(1<{var end=ptr;while(HEAPU8[end>>>0])++end;return end-ptr};var formatString=(format,varargs)=>{var textIndex=format;var argIndex=varargs;function prepVararg(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){ptr+=4}}else{}return ptr}function getNextArg(type){var ret;argIndex=prepVararg(argIndex,type);if(type==="double"){ret=HEAPF64[argIndex>>>3>>>0];argIndex+=8}else if(type=="i64"){ret=[HEAP32[argIndex>>>2>>>0],HEAP32[argIndex+4>>>2>>>0]];argIndex+=8}else{type="i32";ret=HEAP32[argIndex>>>2>>>0];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>>0];if(curr===0)break;next=HEAP8[textIndex+1>>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break}case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;currArg=getNextArg("i"+argSize*8);var argText;if(argSize==8){currArg=next==117?convertU32PairToI53(currArg[0],currArg[1]):convertI32PairToI53(currArg[0],currArg[1])}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){argText=reSign(currArg,8*argSize).toString(10)}else if(next==117){argText=unSign(currArg,8*argSize).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.substr(1)}while(prefix.length+argText.lengthret.push(chr.charCodeAt(0)));break}case"f":case"F":case"e":case"E":case"g":case"G":{currArg=getNextArg("double");var argText;if(isNaN(currArg)){argText="nan";flagZeroPad=false}else if(!isFinite(currArg)){argText=(currArg<0?"-":"")+"inf";flagZeroPad=false}else{var isGeneral=false;var effectivePrecision=Math.min(precision,20);if(next==103||next==71){isGeneral=true;precision=precision||1;var exponent=parseInt(currArg.toExponential(effectivePrecision).split("e")[1],10);if(precision>exponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].includes(".")&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.lengthret.push(chr.charCodeAt(0)));break}case"s":{var arg=getNextArg("i8*");var argLength=arg?strLen(arg):"(null)".length;if(precisionSet)argLength=Math.min(argLength,precision);if(!flagLeftAlign){while(argLength>>0])}}else{ret=ret.concat(intArrayFromString("(null)".substr(0,argLength),true))}if(flagLeftAlign){while(argLength0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break}case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>>2>>>0]=ret.length;break}case"%":{ret.push(curr);break}default:{for(var i=startTextIndex;i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret};function jsStackTrace(){return(new Error).stack.toString()}function getCallstack(flags){var callstack=jsStackTrace();var iThisFunc=callstack.lastIndexOf("_emscripten_log");var iThisFunc2=callstack.lastIndexOf("_emscripten_get_callstack");var iNextLine=callstack.indexOf("\n",Math.max(iThisFunc,iThisFunc2))+1;callstack=callstack.slice(iNextLine);if(flags&8&&typeof emscripten_source_map=="undefined"){warnOnce('Source map information is not available, emscripten_log with EM_LOG_C_STACK will be ignored. Build with "--pre-js $EMSCRIPTEN/src/emscripten-source-map.min.js" linker flag to add source map loading to code.');flags^=8;flags|=16}var lines=callstack.split("\n");callstack="";var newFirefoxRe=new RegExp("\\s*(.*?)@(.*?):([0-9]+):([0-9]+)");var firefoxRe=new RegExp("\\s*(.*?)@(.*):(.*)(:(.*))?");var chromeRe=new RegExp("\\s*at (.*?) \\((.*):(.*):(.*)\\)");for(var l in lines){var line=lines[l];var symbolName="";var file="";var lineno=0;var column=0;var parts=chromeRe.exec(line);if(parts&&parts.length==5){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]}else{parts=newFirefoxRe.exec(line)||firefoxRe.exec(line);if(parts&&parts.length>=4){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]|0}else{callstack+=line+"\n";continue}}var haveSourceMap=false;if(flags&8){var orig=emscripten_source_map.originalPositionFor({line:lineno,column});haveSourceMap=orig?.source;if(haveSourceMap){if(flags&64){orig.source=orig.source.substring(orig.source.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=` at ${symbolName} (${orig.source}:${orig.line}:${orig.column})\n`}}if(flags&16||!haveSourceMap){if(flags&64){file=file.substring(file.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=(haveSourceMap?` = ${symbolName}`:` at ${symbolName}`)+` (${file}:${lineno}:${column})\n`}}callstack=callstack.replace(/\s+$/,"");return callstack}var emscriptenLog=(flags,str)=>{if(flags&24){str=str.replace(/\s+$/,"");str+=(str.length>0?"\n":"")+getCallstack(flags)}if(flags&1){if(flags&4){console.error(str)}else if(flags&2){console.warn(str)}else if(flags&512){console.info(str)}else if(flags&256){console.debug(str)}else{console.log(str)}}else if(flags&6){err(str)}else{out(str)}};function _emscripten_log(flags,format,varargs){format>>>=0;varargs>>>=0;var result=formatString(format,varargs);var str=UTF8ArrayToString(result);emscriptenLog(flags,str)}var _emscripten_pause_main_loop=()=>{MainLoop.pause()};var _emscripten_performance_now=()=>performance.now();var _emscripten_request_animation_frame=function(cb,userData){cb>>>=0;userData>>>=0;return requestAnimationFrame(timeStamp=>getWasmTableEntry(cb)(timeStamp,userData))};function _emscripten_request_animation_frame_loop(cb,userData){cb>>>=0;userData>>>=0;function tick(timeStamp){if(getWasmTableEntry(cb)(timeStamp,userData)){requestAnimationFrame(tick)}}return requestAnimationFrame(tick)}var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){func>>>=0;var iterFunc=getWasmTableEntry(func);setMainLoop(iterFunc,fps,simulateInfiniteLoop)}var registerUiEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.uiEvent||=_malloc(36);target=findEventTarget(target);var uiEventHandlerFunc=(e=event)=>{if(e.target!=target){return}var b=document.body;if(!b){return}var uiEvent=JSEvents.uiEvent;HEAP32[uiEvent>>>2>>>0]=0;HEAP32[uiEvent+4>>>2>>>0]=b.clientWidth;HEAP32[uiEvent+8>>>2>>>0]=b.clientHeight;HEAP32[uiEvent+12>>>2>>>0]=innerWidth;HEAP32[uiEvent+16>>>2>>>0]=innerHeight;HEAP32[uiEvent+20>>>2>>>0]=outerWidth;HEAP32[uiEvent+24>>>2>>>0]=outerHeight;HEAP32[uiEvent+28>>>2>>>0]=pageXOffset|0;HEAP32[uiEvent+32>>>2>>>0]=pageYOffset|0;if(getWasmTableEntry(callbackfunc)(eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target,eventTypeString,callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",targetThread)}var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var _setNetworkCallback=(event,userData,callback)=>{function _callback(data){try{if(event==="error"){var sp=stackSave();var msg=stringToUTF8OnStack(data[2]);getWasmTableEntry(callback)(data[0],data[1],msg,userData);stackRestore(sp)}else{getWasmTableEntry(callback)(data,userData)}}catch(e){if(!(e instanceof ExitStatus)){if(e&&typeof e=="object"&&e.stack)err("exception thrown: "+[e,e.stack]);throw e}}}Module["websocket"]["on"](event,callback?_callback:null)};function _emscripten_set_socket_close_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("close",userData,callback)}function _emscripten_set_socket_connection_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("connection",userData,callback)}function _emscripten_set_socket_error_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("error",userData,callback)}function _emscripten_set_socket_listen_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("listen",userData,callback)}function _emscripten_set_socket_message_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("message",userData,callback)}function _emscripten_set_socket_open_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("open",userData,callback)}var _emscripten_set_timeout=function(cb,msecs,userData){cb>>>=0;userData>>>=0;return safeSetTimeout(()=>getWasmTableEntry(cb)(userData),msecs)};var fillMouseEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.timeStamp;var idx=eventStruct>>>2;HEAP32[idx+2>>>0]=e.screenX;HEAP32[idx+3>>>0]=e.screenY;HEAP32[idx+4>>>0]=e.clientX;HEAP32[idx+5>>>0]=e.clientY;HEAP8[eventStruct+24>>>0]=e.ctrlKey;HEAP8[eventStruct+25>>>0]=e.shiftKey;HEAP8[eventStruct+26>>>0]=e.altKey;HEAP8[eventStruct+27>>>0]=e.metaKey;HEAP16[idx*2+14>>>0]=e.button;HEAP16[idx*2+15>>>0]=e.buttons;HEAP32[idx+8>>>0]=e["movementX"];HEAP32[idx+9>>>0]=e["movementY"];var rect=getBoundingClientRect(target);HEAP32[idx+10>>>0]=e.clientX-(rect.left|0);HEAP32[idx+11>>>0]=e.clientY-(rect.top|0)};var registerWheelEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.wheelEvent||=_malloc(96);var wheelHandlerFunc=(e=event)=>{var wheelEvent=JSEvents.wheelEvent;fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+64>>>3>>>0]=e["deltaX"];HEAPF64[wheelEvent+72>>>3>>>0]=e["deltaY"];HEAPF64[wheelEvent+80>>>3>>>0]=e["deltaZ"];HEAP32[wheelEvent+88>>>2>>>0]=e["deltaMode"];if(getWasmTableEntry(callbackfunc)(eventTypeId,wheelEvent,userData))e.preventDefault()};var eventHandler={target,allowsDeferredCalls:true,eventTypeString,callbackfunc,handlerFunc:wheelHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;target=findEventTarget(target);if(!target)return-4;if(typeof target.onwheel!="undefined"){return registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread)}else{return-1}}var _emscripten_sleep=()=>{throw"Please compile your program with async support in order to use asynchronous operations like emscripten_sleep"};class HandleAllocator{constructor(){this.allocated=[undefined];this.freelist=[]}get(id){return this.allocated[id]}has(id){return this.allocated[id]!==undefined}allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id}free(id){this.allocated[id]=undefined;this.freelist.push(id)}}var Fetch={openDatabase(dbname,dbversion,onsuccess,onerror){try{var openRequest=indexedDB.open(dbname,dbversion)}catch(e){return onerror(e)}openRequest.onupgradeneeded=event=>{var db=event.target.result;if(db.objectStoreNames.contains("FILES")){db.deleteObjectStore("FILES")}db.createObjectStore("FILES")};openRequest.onsuccess=event=>onsuccess(event.target.result);openRequest.onerror=onerror},init(){Fetch.xhrs=new HandleAllocator;var onsuccess=db=>{Fetch.dbInstance=db;removeRunDependency("library_fetch_init")};var onerror=()=>{Fetch.dbInstance=false;removeRunDependency("library_fetch_init")};addRunDependency("library_fetch_init");Fetch.openDatabase("emscripten_filesystem",1,onsuccess,onerror)}};function fetchXHR(fetch,onsuccess,onerror,onprogress,onreadystatechange){var url=HEAPU32[fetch+8>>>2>>>0];if(!url){onerror(fetch,0,"no url specified!");return}var url_=UTF8ToString(url);var fetch_attr=fetch+108;var requestMethod=UTF8ToString(fetch_attr+0);requestMethod||="GET";var timeoutMsecs=HEAPU32[fetch_attr+56>>>2>>>0];var userName=HEAPU32[fetch_attr+68>>>2>>>0];var password=HEAPU32[fetch_attr+72>>>2>>>0];var requestHeaders=HEAPU32[fetch_attr+76>>>2>>>0];var overriddenMimeType=HEAPU32[fetch_attr+80>>>2>>>0];var dataPtr=HEAPU32[fetch_attr+84>>>2>>>0];var dataLength=HEAPU32[fetch_attr+88>>>2>>>0];var fetchAttributes=HEAPU32[fetch_attr+52>>>2>>>0];var fetchAttrLoadToMemory=!!(fetchAttributes&1);var fetchAttrStreamData=!!(fetchAttributes&2);var fetchAttrSynchronous=!!(fetchAttributes&64);var userNameStr=userName?UTF8ToString(userName):undefined;var passwordStr=password?UTF8ToString(password):undefined;var xhr=new XMLHttpRequest;xhr.withCredentials=!!HEAPU8[fetch_attr+60>>>0];xhr.open(requestMethod,url_,!fetchAttrSynchronous,userNameStr,passwordStr);if(!fetchAttrSynchronous)xhr.timeout=timeoutMsecs;xhr.url_=url_;xhr.responseType="arraybuffer";if(overriddenMimeType){var overriddenMimeTypeStr=UTF8ToString(overriddenMimeType);xhr.overrideMimeType(overriddenMimeTypeStr)}if(requestHeaders){for(;;){var key=HEAPU32[requestHeaders>>>2>>>0];if(!key)break;var value=HEAPU32[requestHeaders+4>>>2>>>0];if(!value)break;requestHeaders+=8;var keyStr=UTF8ToString(key);var valueStr=UTF8ToString(value);xhr.setRequestHeader(keyStr,valueStr)}}var id=Fetch.xhrs.allocate(xhr);HEAPU32[fetch>>>2>>>0]=id;var data=dataPtr&&dataLength?HEAPU8.slice(dataPtr,dataPtr+dataLength):null;function saveResponseAndStatus(){var ptr=0;var ptrLen=0;if(xhr.response&&fetchAttrLoadToMemory&&HEAPU32[fetch+12>>>2>>>0]===0){ptrLen=xhr.response.byteLength}if(ptrLen>0){ptr=_malloc(ptrLen);HEAPU8.set(new Uint8Array(xhr.response),ptr>>>0)}HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,ptrLen);writeI53ToI64(fetch+24,0);var len=xhr.response?xhr.response.byteLength:0;if(len){writeI53ToI64(fetch+32,len)}HEAP16[fetch+40>>>1>>>0]=xhr.readyState;HEAP16[fetch+42>>>1>>>0]=xhr.status;if(xhr.statusText)stringToUTF8(xhr.statusText,fetch+44,64)}xhr.onload=e=>{if(!Fetch.xhrs.has(id)){return}saveResponseAndStatus();if(xhr.status>=200&&xhr.status<300){onsuccess?.(fetch,xhr,e)}else{onerror?.(fetch,xhr,e)}};xhr.onerror=e=>{if(!Fetch.xhrs.has(id)){return}saveResponseAndStatus();onerror?.(fetch,xhr,e)};xhr.ontimeout=e=>{if(!Fetch.xhrs.has(id)){return}onerror?.(fetch,xhr,e)};xhr.onprogress=e=>{if(!Fetch.xhrs.has(id)){return}var ptrLen=fetchAttrLoadToMemory&&fetchAttrStreamData&&xhr.response?xhr.response.byteLength:0;var ptr=0;if(ptrLen>0&&fetchAttrLoadToMemory&&fetchAttrStreamData){ptr=_malloc(ptrLen);HEAPU8.set(new Uint8Array(xhr.response),ptr>>>0)}HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,ptrLen);writeI53ToI64(fetch+24,e.loaded-ptrLen);writeI53ToI64(fetch+32,e.total);HEAP16[fetch+40>>>1>>>0]=xhr.readyState;if(xhr.readyState>=3&&xhr.status===0&&e.loaded>0)xhr.status=200;HEAP16[fetch+42>>>1>>>0]=xhr.status;if(xhr.statusText)stringToUTF8(xhr.statusText,fetch+44,64);onprogress?.(fetch,xhr,e);if(ptr){_free(ptr)}};xhr.onreadystatechange=e=>{if(!Fetch.xhrs.has(id)){return}HEAP16[fetch+40>>>1>>>0]=xhr.readyState;if(xhr.readyState>=2){HEAP16[fetch+42>>>1>>>0]=xhr.status}onreadystatechange?.(fetch,xhr,e)};try{xhr.send(data)}catch(e){onerror?.(fetch,xhr,e)}}function fetchCacheData(db,fetch,data,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var destinationPath=HEAPU32[fetch_attr+64>>>2>>>0];destinationPath||=HEAPU32[fetch+8>>>2>>>0];var destinationPathStr=UTF8ToString(destinationPath);try{var transaction=db.transaction(["FILES"],"readwrite");var packages=transaction.objectStore("FILES");var putRequest=packages.put(data,destinationPathStr);putRequest.onsuccess=event=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,destinationPathStr)};putRequest.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=413;stringToUTF8("Payload Too Large",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function fetchLoadCachedData(db,fetch,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var path=HEAPU32[fetch_attr+64>>>2>>>0];path||=HEAPU32[fetch+8>>>2>>>0];var pathStr=UTF8ToString(path);try{var transaction=db.transaction(["FILES"],"readonly");var packages=transaction.objectStore("FILES");var getRequest=packages.get(pathStr);getRequest.onsuccess=event=>{if(event.target.result){var value=event.target.result;var len=value.byteLength||value.length;var ptr=_malloc(len);HEAPU8.set(new Uint8Array(value),ptr>>>0);HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,len);writeI53ToI64(fetch+24,0);writeI53ToI64(fetch+32,len);HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,value)}else{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,"no data")}};getRequest.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function fetchDeleteCachedData(db,fetch,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var path=HEAPU32[fetch_attr+64>>>2>>>0];path||=HEAPU32[fetch+8>>>2>>>0];var pathStr=UTF8ToString(path);try{var transaction=db.transaction(["FILES"],"readwrite");var packages=transaction.objectStore("FILES");var request=packages.delete(pathStr);request.onsuccess=event=>{var value=event.target.result;HEAPU32[fetch+12>>>2>>>0]=0;writeI53ToI64(fetch+16,0);writeI53ToI64(fetch+24,0);writeI53ToI64(fetch+32,0);HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,value)};request.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function _emscripten_start_fetch(fetch,successcb,errorcb,progresscb,readystatechangecb){fetch>>>=0;var fetch_attr=fetch+108;var onsuccess=HEAPU32[fetch_attr+36>>>2>>>0];var onerror=HEAPU32[fetch_attr+40>>>2>>>0];var onprogress=HEAPU32[fetch_attr+44>>>2>>>0];var onreadystatechange=HEAPU32[fetch_attr+48>>>2>>>0];var fetchAttributes=HEAPU32[fetch_attr+52>>>2>>>0];var fetchAttrSynchronous=!!(fetchAttributes&64);function doCallback(f){if(fetchAttrSynchronous){f()}else{callUserCallback(f)}}var reportSuccess=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};var reportProgress=(fetch,xhr,e)=>{doCallback(()=>{if(onprogress)getWasmTableEntry(onprogress)(fetch);else progresscb?.(fetch)})};var reportError=(fetch,xhr,e)=>{doCallback(()=>{if(onerror)getWasmTableEntry(onerror)(fetch);else errorcb?.(fetch)})};var reportReadyStateChange=(fetch,xhr,e)=>{doCallback(()=>{if(onreadystatechange)getWasmTableEntry(onreadystatechange)(fetch);else readystatechangecb?.(fetch)})};var performUncachedXhr=(fetch,xhr,e)=>{fetchXHR(fetch,reportSuccess,reportError,reportProgress,reportReadyStateChange)};var cacheResultAndReportSuccess=(fetch,xhr,e)=>{var storeSuccess=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};var storeError=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};fetchCacheData(Fetch.dbInstance,fetch,xhr.response,storeSuccess,storeError)};var performCachedXhr=(fetch,xhr,e)=>{fetchXHR(fetch,cacheResultAndReportSuccess,reportError,reportProgress,reportReadyStateChange)};var requestMethod=UTF8ToString(fetch_attr+0);var fetchAttrReplace=!!(fetchAttributes&16);var fetchAttrPersistFile=!!(fetchAttributes&4);var fetchAttrNoDownload=!!(fetchAttributes&32);if(requestMethod==="EM_IDB_STORE"){var ptr=HEAPU32[fetch_attr+84>>>2>>>0];var size=HEAPU32[fetch_attr+88>>>2>>>0];fetchCacheData(Fetch.dbInstance,fetch,HEAPU8.slice(ptr,ptr+size),reportSuccess,reportError)}else if(requestMethod==="EM_IDB_DELETE"){fetchDeleteCachedData(Fetch.dbInstance,fetch,reportSuccess,reportError)}else if(!fetchAttrReplace){fetchLoadCachedData(Fetch.dbInstance,fetch,reportSuccess,fetchAttrNoDownload?reportError:fetchAttrPersistFile?performCachedXhr:performUncachedXhr)}else if(!fetchAttrNoDownload){fetchXHR(fetch,fetchAttrPersistFile?cacheResultAndReportSuccess:reportSuccess,reportError,reportProgress,reportReadyStateChange)}else{return 0}return fetch}var webglPowerPreferences=["default","low-power","high-performance"];var findCanvasEventTarget=findEventTarget;function _emscripten_webgl_do_create_context(target,attributes){target>>>=0;attributes>>>=0;var attr32=attributes>>>2;var powerPreference=HEAP32[attr32+(8>>2)>>>0];var contextAttributes={alpha:!!HEAP8[attributes+0>>>0],depth:!!HEAP8[attributes+1>>>0],stencil:!!HEAP8[attributes+2>>>0],antialias:!!HEAP8[attributes+3>>>0],premultipliedAlpha:!!HEAP8[attributes+4>>>0],preserveDrawingBuffer:!!HEAP8[attributes+5>>>0],powerPreference:webglPowerPreferences[powerPreference],failIfMajorPerformanceCaveat:!!HEAP8[attributes+12>>>0],majorVersion:HEAP32[attr32+(16>>2)>>>0],minorVersion:HEAP32[attr32+(20>>2)>>>0],enableExtensionsByDefault:HEAP8[attributes+24>>>0],explicitSwapControl:HEAP8[attributes+25>>>0],proxyContextToMainThread:HEAP32[attr32+(28>>2)>>>0],renderViaOffscreenBackBuffer:HEAP8[attributes+32>>>0]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;function _emscripten_webgl_destroy_context(contextHandle){contextHandle>>>=0;if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}function _emscripten_webgl_get_context_attributes(c,a){c>>>=0;a>>>=0;if(!a)return-5;c=GL.contexts[c];if(!c)return-3;var t=c.GLctx;if(!t)return-3;t=t.getContextAttributes();HEAP8[a>>>0]=t.alpha;HEAP8[a+1>>>0]=t.depth;HEAP8[a+2>>>0]=t.stencil;HEAP8[a+3>>>0]=t.antialias;HEAP8[a+4>>>0]=t.premultipliedAlpha;HEAP8[a+5>>>0]=t.preserveDrawingBuffer;var power=t["powerPreference"]&&webglPowerPreferences.indexOf(t["powerPreference"]);HEAP32[a+8>>>2>>>0]=power;HEAP8[a+12>>>0]=t.failIfMajorPerformanceCaveat;HEAP32[a+16>>>2>>>0]=c.version;HEAP32[a+20>>>2>>>0]=0;HEAP8[a+24>>>0]=c.attributes.enableExtensionsByDefault;return 0}function _emscripten_webgl_make_context_current(contextHandle){contextHandle>>>=0;var success=GL.makeContextCurrent(contextHandle);return success?0:-5}var webSockets=new HandleAllocator;var WS={socketEvent:null,getSocket(socketId){if(!webSockets.has(socketId)){return 0}return webSockets.get(socketId)},getSocketEvent(socketId){this.socketEvent||=_malloc(520);HEAPU32[this.socketEvent>>>2>>>0]=socketId;return this.socketEvent}};function _emscripten_websocket_close(socketId,code,reason){reason>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var reasonStr=reason?UTF8ToString(reason):undefined;if(reason)socket.close(code||undefined,UTF8ToString(reason));else if(code)socket.close(code);else socket.close();return 0}var _emscripten_websocket_delete=socketId=>{var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=socket.onerror=socket.onclose=socket.onmessage=null;webSockets.free(socketId);return 0};function _emscripten_websocket_get_ready_state(socketId,readyState){readyState>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}HEAP16[readyState>>>1>>>0]=socket.readyState;return 0}function _emscripten_websocket_new(createAttributes){createAttributes>>>=0;if(typeof WebSocket=="undefined"){return-1}if(!createAttributes){return-5}var url=UTF8ToString(HEAPU32[createAttributes>>>2>>>0]);var protocols=HEAPU32[createAttributes+4>>>2>>>0];var socket=protocols?new WebSocket(url,UTF8ToString(protocols).split(",")):new WebSocket(url);socket.binaryType="arraybuffer";var socketId=webSockets.allocate(socket);return socketId}function _emscripten_websocket_send_binary(socketId,binaryData,dataLength){binaryData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.send(HEAPU8.subarray(binaryData>>>0,binaryData+dataLength>>>0));return 0}function _emscripten_websocket_send_utf8_text(socketId,textData){textData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var str=UTF8ToString(textData);socket.send(str);return 0}function _emscripten_websocket_set_onclose_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onclose=function(e){var eventPtr=WS.getSocketEvent(socketId);HEAP8[eventPtr+4>>>0]=e.wasClean,HEAP16[eventPtr+6>>>1>>>0]=e.code,stringToUTF8(e.reason,eventPtr+8,512);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}function _emscripten_websocket_set_onerror_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onerror=function(e){var eventPtr=WS.getSocketEvent(socketId);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}function _emscripten_websocket_set_onmessage_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onmessage=function(e){var isText=typeof e.data=="string";if(isText){var buf=stringToNewUTF8(e.data);var len=lengthBytesUTF8(e.data)+1}else{var len=e.data.byteLength;var buf=_malloc(len);HEAP8.set(new Uint8Array(e.data),buf>>>0)}var eventPtr=WS.getSocketEvent(socketId);HEAPU32[eventPtr+4>>>2>>>0]=buf,HEAP32[eventPtr+8>>>2>>>0]=len,HEAP8[eventPtr+12>>>0]=isText,getWasmTableEntry(callbackFunc)(0,eventPtr,userData);_free(buf)};return 0}function _emscripten_websocket_set_onopen_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=function(e){var eventPtr=WS.getSocketEvent(socketId);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0]=0};var _environ_get=function(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>>2>>>0]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=function(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){pbuf>>>=0;try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4}HEAP8[pbuf>>>0]=type;HEAP16[pbuf+2>>>1>>>0]=flags;HEAP64[pbuf+8>>>3]=BigInt(rightsBase);HEAP64[pbuf+16>>>3]=BigInt(rightsInheriting);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>>3]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops?.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _getaddrinfo(node,service,hint,out){node>>>=0;service>>>=0;hint>>>=0;out>>>=0;var addr=0;var port=0;var flags=0;var family=0;var type=0;var proto=0;var ai;function allocaddrinfo(family,type,proto,canon,addr,port){var sa,salen,ai;var errno;salen=family===10?28:16;addr=family===10?inetNtop6(addr):inetNtop4(addr);sa=_malloc(salen);errno=writeSockaddr(sa,family,addr,port);assert(!errno);ai=_malloc(32);HEAP32[ai+4>>>2>>>0]=family;HEAP32[ai+8>>>2>>>0]=type;HEAP32[ai+12>>>2>>>0]=proto;HEAPU32[ai+24>>>2>>>0]=canon;HEAPU32[ai+20>>>2>>>0]=sa;if(family===10){HEAP32[ai+16>>>2>>>0]=28}else{HEAP32[ai+16>>>2>>>0]=16}HEAP32[ai+28>>>2>>>0]=0;return ai}if(hint){flags=HEAP32[hint>>>2>>>0];family=HEAP32[hint+4>>>2>>>0];type=HEAP32[hint+8>>>2>>>0];proto=HEAP32[hint+12>>>2>>>0]}if(type&&!proto){proto=type===2?17:6}if(!type&&proto){type=proto===17?2:1}if(proto===0){proto=6}if(type===0){type=1}if(!node&&!service){return-2}if(flags&~(1|2|4|1024|8|16|32)){return-1}if(hint!==0&&HEAP32[hint>>>2>>>0]&2&&!node){return-1}if(flags&32){return-2}if(type!==0&&type!==1&&type!==2){return-7}if(family!==0&&family!==2&&family!==10){return-6}if(service){service=UTF8ToString(service);port=parseInt(service,10);if(isNaN(port)){if(flags&1024){return-2}return-8}}if(!node){if(family===0){family=2}if((flags&1)===0){if(family===2){addr=_htonl(2130706433)}else{addr=[0,0,0,_htonl(1)]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}node=UTF8ToString(node);addr=inetPton4(node);if(addr!==null){if(family===0||family===2){family=2}else if(family===10&&flags&8){addr=[0,0,_htonl(65535),addr];family=10}else{return-2}}else{addr=inetPton6(node);if(addr!==null){if(family===0||family===10){family=10}else{return-2}}}if(addr!=null){ai=allocaddrinfo(family,type,proto,node,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=inetPton4(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}function _getentropy(buffer,size){buffer>>>=0;size>>>=0;randomFill(HEAPU8.subarray(buffer>>>0,buffer+size>>>0));return 0}function _llvm_eh_typeid_for(type){type>>>=0;return type}FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};init_ClassHandle();init_RegisteredPointer();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();Module["requestAnimationFrame"]=MainLoop.requestAnimationFrame;Module["pauseMainLoop"]=MainLoop.pause;Module["resumeMainLoop"]=MainLoop.resume;MainLoop.init();Module["requestFullscreen"]=Browser.requestFullscreen;Module["setCanvasSize"]=Browser.setCanvasSize;Module["getUserMedia"]=Browser.getUserMedia;Module["createContext"]=Browser.createContext;var preloadedImages={};var preloadedAudios={};for(var i=0;i<32;++i)tempFixedLengthArray.push(new Array(i));var miniTempWebGLFloatBuffersStorage=new Float32Array(288);for(var i=0;i<=288;++i){miniTempWebGLFloatBuffers[i]=miniTempWebGLFloatBuffersStorage.subarray(0,i)}var miniTempWebGLIntBuffersStorage=new Int32Array(288);for(var i=0;i<=288;++i){miniTempWebGLIntBuffers[i]=miniTempWebGLIntBuffersStorage.subarray(0,i)}Fetch.init();var wasmImports={Va:__asyncjs__qt_asyncify_suspend_js,mc:___call_sighandler,I:___cxa_begin_catch,V:___cxa_end_catch,a:___cxa_find_matching_catch_2,m:___cxa_find_matching_catch_3,df:___cxa_rethrow,w:___cxa_throw,c:___resumeException,bb:___syscall_accept4,$b:___syscall_bind,fb:___syscall_chmod,_b:___syscall_connect,Ic:___syscall_faccessat,Gc:___syscall_fchmod,ca:___syscall_fcntl64,Ec:___syscall_fstat64,zc:___syscall_ftruncate64,yc:___syscall_getcwd,lc:___syscall_getdents64,Zb:___syscall_getpeername,Yb:___syscall_getsockname,Ka:___syscall_getsockopt,db:___syscall_ioctl,Xb:___syscall_listen,Bc:___syscall_lstat64,uc:___syscall_mkdirat,Cc:___syscall_newfstatat,Fc:___syscall_openat,kc:___syscall_readlinkat,Wb:___syscall_recvfrom,Vb:___syscall_recvmsg,hc:___syscall_renameat,ic:___syscall_rmdir,Ub:___syscall_sendmsg,ab:___syscall_socket,Dc:___syscall_stat64,gc:___syscall_symlink,ec:___syscall_truncate64,jc:___syscall_unlinkat,dc:___syscall_utimensat,Jc:__abort_js,zb:__embind_register_bigint,Gi:__embind_register_bool,Ya:__embind_register_class,Xa:__embind_register_class_constructor,Wa:__embind_register_class_function,Fi:__embind_register_emval,yb:__embind_register_float,O:__embind_register_function,ja:__embind_register_integer,X:__embind_register_memory_view,xb:__embind_register_std_string,Ra:__embind_register_std_wstring,Hi:__embind_register_void,bi:__emscripten_fetch_free,$h:__emscripten_fetch_get_response_headers,ai:__emscripten_fetch_get_response_headers_length,Hc:__emscripten_get_now_is_monotonic,oc:__emscripten_runtime_keepalive_clear,ac:__emscripten_throw_longjmp,y:__emval_as,ba:__emval_call,v:__emval_call_method,i:__emval_decref,ub:__emval_delete,ga:__emval_equals,E:__emval_get_global,t:__emval_get_method_caller,J:__emval_get_module_property,o:__emval_get_property,r:__emval_incref,Ei:__emval_instanceof,qa:__emval_new_array,l:__emval_new_cstring,W:__emval_new_object,Ci:__emval_not,n:__emval_run_destructors,B:__emval_set_property,A:__emval_take_value,rc:__gmtime_js,sc:__localtime_js,tc:__mktime_js,pc:__mmap_js,qc:__munmap_js,Kc:__tzset_js,ib:_alBufferData,ji:_alDeleteBuffers,ki:_alDeleteSources,ni:_alGenBuffers,oi:_alGenSources,da:_alGetError,va:_alGetSourcei,lb:_alGetString,fi:_alIsExtensionPresent,gi:_alSourcePause,Ga:_alSourcePlay,hb:_alSourceQueueBuffers,wa:_alSourceRewind,li:_alSourceStop,gb:_alSourceUnqueueBuffers,jb:_alSourcef,si:_alcCaptureCloseDevice,ti:_alcCaptureOpenDevice,ob:_alcCaptureSamples,nb:_alcCaptureStart,mb:_alcCaptureStop,hi:_alcCloseDevice,pi:_alcCreateContext,ii:_alcDestroyContext,oa:_alcGetError,Ma:_alcGetIntegerv,xa:_alcGetString,kb:_alcMakeContextCurrent,ri:_alcOpenDevice,Ta:_emscripten_async_call,Qa:_emscripten_cancel_animation_frame,Ia:_emscripten_clear_timeout,eb:_emscripten_date_now,wi:_emscripten_get_element_css_size,fc:_emscripten_get_heap_max,ha:_emscripten_get_now,Bh:_emscripten_glActiveTexture,Ah:_emscripten_glAttachShader,Ae:_emscripten_glBeginQuery,Rh:_emscripten_glBeginQueryEXT,he:_emscripten_glBeginTransformFeedback,zh:_emscripten_glBindAttribLocation,yh:_emscripten_glBindBuffer,ee:_emscripten_glBindBufferBase,fe:_emscripten_glBindBufferRange,xh:_emscripten_glBindFramebuffer,wh:_emscripten_glBindRenderbuffer,kd:_emscripten_glBindSampler,vh:_emscripten_glBindTexture,cd:_emscripten_glBindTransformFeedback,me:_emscripten_glBindVertexArray,Jh:_emscripten_glBindVertexArrayOES,uh:_emscripten_glBlendColor,th:_emscripten_glBlendEquation,sh:_emscripten_glBlendEquationSeparate,rh:_emscripten_glBlendFunc,qh:_emscripten_glBlendFuncSeparate,pe:_emscripten_glBlitFramebuffer,ph:_emscripten_glBufferData,oh:_emscripten_glBufferSubData,nh:_emscripten_glCheckFramebufferStatus,mh:_emscripten_glClear,Hd:_emscripten_glClearBufferfi,Id:_emscripten_glClearBufferfv,Kd:_emscripten_glClearBufferiv,Jd:_emscripten_glClearBufferuiv,lh:_emscripten_glClearColor,kh:_emscripten_glClearDepthf,jh:_emscripten_glClearStencil,td:_emscripten_glClientWaitSync,Qe:_emscripten_glClipControlEXT,hh:_emscripten_glColorMask,gh:_emscripten_glCompileShader,fh:_emscripten_glCompressedTexImage2D,Fe:_emscripten_glCompressedTexImage3D,eh:_emscripten_glCompressedTexSubImage2D,Ee:_emscripten_glCompressedTexSubImage3D,Fd:_emscripten_glCopyBufferSubData,dh:_emscripten_glCopyTexImage2D,ch:_emscripten_glCopyTexSubImage2D,Ge:_emscripten_glCopyTexSubImage3D,bh:_emscripten_glCreateProgram,ah:_emscripten_glCreateShader,$g:_emscripten_glCullFace,_g:_emscripten_glDeleteBuffers,Zg:_emscripten_glDeleteFramebuffers,Yg:_emscripten_glDeleteProgram,Ce:_emscripten_glDeleteQueries,Th:_emscripten_glDeleteQueriesEXT,Xg:_emscripten_glDeleteRenderbuffers,md:_emscripten_glDeleteSamplers,Wg:_emscripten_glDeleteShader,ud:_emscripten_glDeleteSync,Vg:_emscripten_glDeleteTextures,bd:_emscripten_glDeleteTransformFeedbacks,le:_emscripten_glDeleteVertexArrays,Ih:_emscripten_glDeleteVertexArraysOES,Ug:_emscripten_glDepthFunc,Tg:_emscripten_glDepthMask,Sg:_emscripten_glDepthRangef,Rg:_emscripten_glDetachShader,Qg:_emscripten_glDisable,Pg:_emscripten_glDisableVertexAttribArray,Og:_emscripten_glDrawArrays,yd:_emscripten_glDrawArraysInstanced,Eh:_emscripten_glDrawArraysInstancedANGLE,Nc:_emscripten_glDrawArraysInstancedARB,Ne:_emscripten_glDrawArraysInstancedEXT,Oc:_emscripten_glDrawArraysInstancedNV,we:_emscripten_glDrawBuffers,Le:_emscripten_glDrawBuffersEXT,Fh:_emscripten_glDrawBuffersWEBGL,Ng:_emscripten_glDrawElements,xd:_emscripten_glDrawElementsInstanced,Dh:_emscripten_glDrawElementsInstancedANGLE,Lc:_emscripten_glDrawElementsInstancedARB,Mc:_emscripten_glDrawElementsInstancedEXT,Me:_emscripten_glDrawElementsInstancedNV,Je:_emscripten_glDrawRangeElements,Mg:_emscripten_glEnable,Lg:_emscripten_glEnableVertexAttribArray,ze:_emscripten_glEndQuery,Qh:_emscripten_glEndQueryEXT,ge:_emscripten_glEndTransformFeedback,wd:_emscripten_glFenceSync,Kg:_emscripten_glFinish,Jg:_emscripten_glFlush,Ig:_emscripten_glFramebufferRenderbuffer,Hg:_emscripten_glFramebufferTexture2D,ne:_emscripten_glFramebufferTextureLayer,Gg:_emscripten_glFrontFace,Eg:_emscripten_glGenBuffers,Cg:_emscripten_glGenFramebuffers,De:_emscripten_glGenQueries,Uh:_emscripten_glGenQueriesEXT,Bg:_emscripten_glGenRenderbuffers,nd:_emscripten_glGenSamplers,Ag:_emscripten_glGenTextures,ad:_emscripten_glGenTransformFeedbacks,ke:_emscripten_glGenVertexArrays,Hh:_emscripten_glGenVertexArraysOES,Dg:_emscripten_glGenerateMipmap,zg:_emscripten_glGetActiveAttrib,yg:_emscripten_glGetActiveUniform,Ad:_emscripten_glGetActiveUniformBlockName,Bd:_emscripten_glGetActiveUniformBlockiv,Dd:_emscripten_glGetActiveUniformsiv,xg:_emscripten_glGetAttachedShaders,wg:_emscripten_glGetAttribLocation,vg:_emscripten_glGetBooleanv,od:_emscripten_glGetBufferParameteri64v,ug:_emscripten_glGetBufferParameteriv,tg:_emscripten_glGetError,sg:_emscripten_glGetFloatv,Ud:_emscripten_glGetFragDataLocation,rg:_emscripten_glGetFramebufferAttachmentParameteriv,pd:_emscripten_glGetInteger64i_v,rd:_emscripten_glGetInteger64v,ie:_emscripten_glGetIntegeri_v,qg:_emscripten_glGetIntegerv,Rc:_emscripten_glGetInternalformativ,Yc:_emscripten_glGetProgramBinary,og:_emscripten_glGetProgramInfoLog,pg:_emscripten_glGetProgramiv,Lh:_emscripten_glGetQueryObjecti64vEXT,Nh:_emscripten_glGetQueryObjectivEXT,Kh:_emscripten_glGetQueryObjectui64vEXT,xe:_emscripten_glGetQueryObjectuiv,Mh:_emscripten_glGetQueryObjectuivEXT,ye:_emscripten_glGetQueryiv,Oh:_emscripten_glGetQueryivEXT,ng:_emscripten_glGetRenderbufferParameteriv,ed:_emscripten_glGetSamplerParameterfv,fd:_emscripten_glGetSamplerParameteriv,lg:_emscripten_glGetShaderInfoLog,kg:_emscripten_glGetShaderPrecisionFormat,jg:_emscripten_glGetShaderSource,mg:_emscripten_glGetShaderiv,ig:_emscripten_glGetString,Gd:_emscripten_glGetStringi,qd:_emscripten_glGetSynciv,hg:_emscripten_glGetTexParameterfv,gg:_emscripten_glGetTexParameteriv,ce:_emscripten_glGetTransformFeedbackVarying,Cd:_emscripten_glGetUniformBlockIndex,Ed:_emscripten_glGetUniformIndices,dg:_emscripten_glGetUniformLocation,fg:_emscripten_glGetUniformfv,eg:_emscripten_glGetUniformiv,Vd:_emscripten_glGetUniformuiv,ae:_emscripten_glGetVertexAttribIiv,$d:_emscripten_glGetVertexAttribIuiv,ag:_emscripten_glGetVertexAttribPointerv,cg:_emscripten_glGetVertexAttribfv,bg:_emscripten_glGetVertexAttribiv,$f:_emscripten_glHint,Vc:_emscripten_glInvalidateFramebuffer,Uc:_emscripten_glInvalidateSubFramebuffer,_f:_emscripten_glIsBuffer,Zf:_emscripten_glIsEnabled,Yf:_emscripten_glIsFramebuffer,Xf:_emscripten_glIsProgram,Be:_emscripten_glIsQuery,Sh:_emscripten_glIsQueryEXT,Wf:_emscripten_glIsRenderbuffer,ld:_emscripten_glIsSampler,Vf:_emscripten_glIsShader,vd:_emscripten_glIsSync,Uf:_emscripten_glIsTexture,$c:_emscripten_glIsTransformFeedback,je:_emscripten_glIsVertexArray,Gh:_emscripten_glIsVertexArrayOES,Tf:_emscripten_glLineWidth,Sf:_emscripten_glLinkProgram,_c:_emscripten_glPauseTransformFeedback,Rf:_emscripten_glPixelStorei,Pe:_emscripten_glPolygonModeWEBGL,Qf:_emscripten_glPolygonOffset,Re:_emscripten_glPolygonOffsetClampEXT,Xc:_emscripten_glProgramBinary,Wc:_emscripten_glProgramParameteri,Ph:_emscripten_glQueryCounterEXT,Ke:_emscripten_glReadBuffer,Pf:_emscripten_glReadPixels,Of:_emscripten_glReleaseShaderCompiler,Nf:_emscripten_glRenderbufferStorage,oe:_emscripten_glRenderbufferStorageMultisample,Zc:_emscripten_glResumeTransformFeedback,Mf:_emscripten_glSampleCoverage,hd:_emscripten_glSamplerParameterf,gd:_emscripten_glSamplerParameterfv,jd:_emscripten_glSamplerParameteri,id:_emscripten_glSamplerParameteriv,Lf:_emscripten_glScissor,Kf:_emscripten_glShaderBinary,Jf:_emscripten_glShaderSource,If:_emscripten_glStencilFunc,Hf:_emscripten_glStencilFuncSeparate,Gf:_emscripten_glStencilMask,Ff:_emscripten_glStencilMaskSeparate,Ef:_emscripten_glStencilOp,Df:_emscripten_glStencilOpSeparate,Cf:_emscripten_glTexImage2D,Ie:_emscripten_glTexImage3D,Bf:_emscripten_glTexParameterf,Af:_emscripten_glTexParameterfv,zf:_emscripten_glTexParameteri,yf:_emscripten_glTexParameteriv,Tc:_emscripten_glTexStorage2D,Sc:_emscripten_glTexStorage3D,xf:_emscripten_glTexSubImage2D,He:_emscripten_glTexSubImage3D,de:_emscripten_glTransformFeedbackVaryings,wf:_emscripten_glUniform1f,vf:_emscripten_glUniform1fv,uf:_emscripten_glUniform1i,tf:_emscripten_glUniform1iv,Td:_emscripten_glUniform1ui,Pd:_emscripten_glUniform1uiv,sf:_emscripten_glUniform2f,rf:_emscripten_glUniform2fv,qf:_emscripten_glUniform2i,pf:_emscripten_glUniform2iv,Sd:_emscripten_glUniform2ui,Od:_emscripten_glUniform2uiv,of:_emscripten_glUniform3f,nf:_emscripten_glUniform3fv,mf:_emscripten_glUniform3i,lf:_emscripten_glUniform3iv,Rd:_emscripten_glUniform3ui,Md:_emscripten_glUniform3uiv,kf:_emscripten_glUniform4f,jf:_emscripten_glUniform4fv,hf:_emscripten_glUniform4i,gf:_emscripten_glUniform4iv,Qd:_emscripten_glUniform4ui,Ld:_emscripten_glUniform4uiv,zd:_emscripten_glUniformBlockBinding,ff:_emscripten_glUniformMatrix2fv,ve:_emscripten_glUniformMatrix2x3fv,te:_emscripten_glUniformMatrix2x4fv,ef:_emscripten_glUniformMatrix3fv,ue:_emscripten_glUniformMatrix3x2fv,re:_emscripten_glUniformMatrix3x4fv,cf:_emscripten_glUniformMatrix4fv,se:_emscripten_glUniformMatrix4x2fv,qe:_emscripten_glUniformMatrix4x3fv,bf:_emscripten_glUseProgram,af:_emscripten_glValidateProgram,$e:_emscripten_glVertexAttrib1f,_e:_emscripten_glVertexAttrib1fv,Ze:_emscripten_glVertexAttrib2f,Ye:_emscripten_glVertexAttrib2fv,Xe:_emscripten_glVertexAttrib3f,We:_emscripten_glVertexAttrib3fv,Ve:_emscripten_glVertexAttrib4f,Ue:_emscripten_glVertexAttrib4fv,dd:_emscripten_glVertexAttribDivisor,Ch:_emscripten_glVertexAttribDivisorANGLE,Pc:_emscripten_glVertexAttribDivisorARB,Oe:_emscripten_glVertexAttribDivisorEXT,Qc:_emscripten_glVertexAttribDivisorNV,_d:_emscripten_glVertexAttribI4i,Xd:_emscripten_glVertexAttribI4iv,Zd:_emscripten_glVertexAttribI4ui,Wd:_emscripten_glVertexAttribI4uiv,be:_emscripten_glVertexAttribIPointer,Te:_emscripten_glVertexAttribPointer,Se:_emscripten_glViewport,sd:_emscripten_glWaitSync,Mb:_emscripten_idb_delete,Ob:_emscripten_idb_exists,Nb:_emscripten_idb_load,Lb:_emscripten_idb_store,di:_emscripten_is_main_browser_thread,xi:_emscripten_is_webgl_context_lost,ih:_emscripten_log,Ri:_emscripten_pause_main_loop,Di:_emscripten_performance_now,wb:_emscripten_request_animation_frame,vi:_emscripten_request_animation_frame_loop,bc:_emscripten_resize_heap,Ui:_emscripten_set_main_loop,vb:_emscripten_set_resize_callback_on_thread,Cb:_emscripten_set_socket_close_callback,Eb:_emscripten_set_socket_connection_callback,Sa:_emscripten_set_socket_error_callback,Fb:_emscripten_set_socket_listen_callback,Db:_emscripten_set_socket_message_callback,Gb:_emscripten_set_socket_open_callback,Qi:_emscripten_set_timeout,Hb:_emscripten_set_wheel_callback_on_thread,Ti:_emscripten_sleep,ci:_emscripten_start_fetch,tb:_emscripten_webgl_create_context,Bi:_emscripten_webgl_destroy_context,Ai:_emscripten_webgl_get_context_attributes,yi:_emscripten_webgl_make_context_current,Bb:_emscripten_websocket_close,Ab:_emscripten_websocket_delete,pa:_emscripten_websocket_get_ready_state,Mi:_emscripten_websocket_new,Ni:_emscripten_websocket_send_binary,Oi:_emscripten_websocket_send_utf8_text,Ii:_emscripten_websocket_set_onclose_callback_on_thread,Ji:_emscripten_websocket_set_onerror_callback_on_thread,Ki:_emscripten_websocket_set_onmessage_callback_on_thread,Li:_emscripten_websocket_set_onopen_callback_on_thread,wc:_environ_get,xc:_environ_sizes_get,Ea:_exit,Fa:_fd_close,cc:_fd_fdstat_get,cb:_fd_read,vc:_fd_seek,Ac:_fd_sync,La:_fd_write,ei:_getaddrinfo,Fg:_getentropy,Sb:invoke_dii,Y:invoke_diii,Aa:invoke_diiii,ea:invoke_diiiii,Wh:invoke_fi,H:invoke_i,f:invoke_ii,_:invoke_iid,b:invoke_iii,h:invoke_iiii,Yh:invoke_iiiif,p:invoke_iiiii,D:invoke_iiiiii,x:invoke_iiiiiii,Zh:invoke_iiiiiiif,$:invoke_iiiiiiii,ta:invoke_iiiiiiiii,Ca:invoke_iiiiiiiiii,_h:invoke_iiiiiiiiiii,Nd:invoke_iiiiiij,ua:invoke_iiij,R:invoke_iij,ma:invoke_iiji,$a:invoke_iijii,sa:invoke_iijiii,Kb:invoke_iijji,Qb:invoke_ij,Pb:invoke_iji,N:invoke_ji,aa:invoke_jii,S:invoke_jiii,zi:invoke_jiiiii,_a:invoke_jiiiiiiii,Z:invoke_jiij,na:invoke_jiiji,Yd:invoke_jij,qi:invoke_jj,u:invoke_v,Ja:invoke_vdiiiiiii,j:invoke_vi,Xh:invoke_vidd,ui:invoke_vidi,Tb:invoke_vidii,sb:invoke_vifi,e:invoke_vii,rb:invoke_viid,ra:invoke_viidiiii,Da:invoke_viif,d:invoke_viii,Vh:invoke_viiif,g:invoke_viiii,k:invoke_viiiii,s:invoke_viiiiii,q:invoke_viiiiiii,C:invoke_viiiiiiii,F:invoke_viiiiiiiii,M:invoke_viiiiiiiiii,K:invoke_viiiiiiiiiii,G:invoke_viiiiiiiiiiii,za:invoke_viiiiiiiiiiiii,ya:invoke_viiiiiiiiiiiiii,Ha:invoke_viiiiiiiiiiiiiii,pb:invoke_viiiiiiiiiiiiiiii,ia:invoke_viiiiiiiiiiiiiiiii,Oa:invoke_viiiiiiiiiiiiiiiiii,Na:invoke_viiiiiiiiiiiiiiiiiiiiii,qb:invoke_viiiiiiiiiiiiiiiiiiiiiii,Pa:invoke_viiiiiiiiiiiiiiiiiiiiiiii,la:invoke_viiiijii,Q:invoke_viij,Rb:invoke_viiji,z:invoke_viijii,Ba:invoke_viijiii,ka:invoke_viijiiii,Ib:invoke_viijj,P:invoke_vij,T:invoke_viji,fa:invoke_vijii,L:invoke_vijiii,Si:invoke_vijj,Pi:invoke_vj,mi:invoke_vjiii,Jb:jsHaveAsyncify,Za:jsHaveJspi,U:_llvm_eh_typeid_for,nc:_proc_exit,Ua:qt_asyncify_resume_js};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["Wi"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["Yi"])(a0,a1);var _free=a0=>(_free=wasmExports["Zi"])(a0);var _malloc=a0=>(_malloc=wasmExports["_i"])(a0);var ___getTypeName=a0=>(___getTypeName=wasmExports["$i"])(a0);var _htonl=a0=>(_htonl=wasmExports["aj"])(a0);var _htons=a0=>(_htons=wasmExports["bj"])(a0);var _ntohs=a0=>(_ntohs=wasmExports["cj"])(a0);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["dj"])(a0,a1);var _setThrew=(a0,a1)=>(_setThrew=wasmExports["ej"])(a0,a1);var __emscripten_tempret_set=a0=>(__emscripten_tempret_set=wasmExports["fj"])(a0);var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["gj"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["hj"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["ij"])();var ___cxa_decrement_exception_refcount=a0=>(___cxa_decrement_exception_refcount=wasmExports["jj"])(a0);var ___cxa_increment_exception_refcount=a0=>(___cxa_increment_exception_refcount=wasmExports["kj"])(a0);var ___cxa_can_catch=(a0,a1,a2)=>(___cxa_can_catch=wasmExports["lj"])(a0,a1,a2);var ___cxa_get_exception_ptr=a0=>(___cxa_get_exception_ptr=wasmExports["mj"])(a0);function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jj(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_vjiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viji(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_iij(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viij(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiij(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_ji(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_jiiji(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_iiij(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jij(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_iiiiiij(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vijii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iijiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vij(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiji(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iid(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vidii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_dii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_diii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiijii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vdiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viidiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vijiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiji(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_ij(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iijii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_iji(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_diiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iijji(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_diiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijj(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vijj(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vj(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viif(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vifi(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viid(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vidi(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiif(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiif(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vidd(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_fi(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiif(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_ppp=f=>(a0,a1)=>f(a0,a1)>>>0;var makeWrapper_p=f=>()=>f()>>>0;wasmExports["_i"]=makeWrapper_pp(wasmExports["_i"]);wasmExports["$i"]=makeWrapper_pp(wasmExports["$i"]);wasmExports["dj"]=makeWrapper_ppp(wasmExports["dj"]);wasmExports["hj"]=makeWrapper_pp(wasmExports["hj"]);wasmExports["ij"]=makeWrapper_p(wasmExports["ij"]);wasmExports["mj"]=makeWrapper_pp(wasmExports["mj"]);return wasmExports}Module["callMain"]=callMain;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;Module["JSEvents"]=JSEvents;Module["specialHTMLTargets"]=specialHTMLTargets;Module["FS"]=FS;var calledRun;var calledPrerun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=_main;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>>2>>>0]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>>2>>>0]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}if(!calledPrerun){calledPrerun=1;preRun();if(runDependencies>0){return}}function doRun(){if(calledRun)return;calledRun=1;Module["calledRun"]=1;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();moduleRtn=readyPromise; + + + return moduleRtn; +} +); +})(); +if (typeof exports === 'object' && typeof module === 'object') + module.exports = xbot2_gui_entry; +else if (typeof define === 'function' && define['amd']) + define([], () => xbot2_gui_entry); diff --git a/server/src/xbot2_gui_server/xbot2_gui.py b/server/src/xbot2_gui_server/xbot2_gui.py new file mode 100644 index 0000000..c924642 --- /dev/null +++ b/server/src/xbot2_gui_server/xbot2_gui.py @@ -0,0 +1,49 @@ +import asyncio +import os +import subprocess + +cmd_gui_server = 'xbot2_gui_server' +cmd_gui_client = '~/.xbot2_gui_client/xbot2_gui_client_x86_64/bin/xbot2_gui' + +# check if xbot2_gui_client exists, if not download it +if not os.path.exists( os.path.expanduser(cmd_gui_client) ): + + print('Downloading xbot2_gui_client...') + subprocess.run(f'wget -P /tmp https://github.com/ADVRHumanoids/robot_monitoring/releases/latest/download/xbot2_gui_client_x86_64.zip', + shell=True, + timeout=120.0, + check=True) + + print('Extracting xbot2_gui_client... to ~/.xbot2_gui_client') + subprocess.run(f'rm -rf ~/.xbot2_gui_client && mkdir ~/.xbot2_gui_client && unzip -o /tmp/xbot2_gui_client_x86_64.zip -d ~/.xbot2_gui_client', + shell=True, + timeout=120.0, + check=True) + + +# run command and print output in real time +async def run_command(cmd, name): + proc = await asyncio.create_subprocess_shell( + cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.STDOUT + ) + + while True: + line = await proc.stdout.readline() + if not line: + break + print(f'[{name}] {line.decode()}', end='', flush=True) + + retcode = await proc.wait() + + print(f'[{name}] process exited with {retcode}') + + +def main(): + # spawn tasks + asyncio.get_event_loop().create_task(run_command(cmd_gui_server, 'gui_srv')) + asyncio.get_event_loop().create_task(run_command(cmd_gui_client, 'gui_cli')) + + # then, loop forever + asyncio.get_event_loop().run_forever() diff --git a/xbot2_gui/CMakeLists.txt b/xbot2_gui/CMakeLists.txt index 4c3c871..5b55d08 100644 --- a/xbot2_gui/CMakeLists.txt +++ b/xbot2_gui/CMakeLists.txt @@ -30,13 +30,25 @@ if(NOT EMSCRIPTEN) endif() -qt_standard_project_setup(REQUIRES 6.6) +if(NOT EMSCRIPTEN AND NOT ANDROID) + + find_package(Qt6 COMPONENTS + WebEngineQuick + REQUIRED + ) +endif() + +qt_standard_project_setup(REQUIRES 6.9) ## ui main qt_add_executable(xbot2_gui main.cpp) set_property(TARGET xbot2_gui APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android) +set_source_files_properties(SharedData1.qml PROPERTIES + QT_QML_SINGLETON_TYPE TRUE +) + qt_add_qml_module(xbot2_gui VERSION 1.0 URI Main @@ -47,6 +59,7 @@ qt_add_qml_module(xbot2_gui ClientEndpoint.js DeserializationWorker.js sharedData.js + SharedData1.qml ) target_compile_definitions(xbot2_gui @@ -111,11 +124,11 @@ add_subdirectory(Monitoring) add_subdirectory(Network) -# if(NOT EMSCRIPTEN) +if(NOT EMSCRIPTEN) -# add_subdirectory(Protobuf) + add_subdirectory(Protobuf) -# endif() +endif() add_subdirectory(TestThings) diff --git a/xbot2_gui/ClientEndpoint.js b/xbot2_gui/ClientEndpoint.js index 4bc8ae5..a451946 100644 --- a/xbot2_gui/ClientEndpoint.js +++ b/xbot2_gui/ClientEndpoint.js @@ -152,50 +152,14 @@ let lastJsSeqId = -1 function handleMessage(obj) { - if(obj.type === "joint_states") - { - robotConnected = true - - robotConnectedTimer.restart() - - obj.name = SharedData.jointNames - - SharedData.latestJointState = obj - - jointStateReceived(obj) - - root.jsMsgRecv += 1 - - if(lastJsSeqId < 0) { - lastJsSeqId = obj.seq - } - else { - root.jsDropped += (obj.seq - lastJsSeqId - 1) - lastJsSeqId = obj.seq - } - - if(isConnected && !isFinalized) - { - client.active = true - - doRequestAsync("GET", "/joint_states/info", "") - .then((response) => { - root.onInfoReceived(response) - }) - } - } - else if(obj.type === "proc") - { - procMessageReceived(obj) - } - else if(obj.type === "jpeg") + if(obj.type === "jpeg") { jpegReceived(obj) } - else if(obj.type === "theora") - { - theoraPacketReceived(obj) - } + // else if(obj.type === "theora") + // { + // theoraPacketReceived(obj) + // } else if(obj.type === "plugin_stats") { pluginStatMessageReceived(obj) diff --git a/xbot2_gui/ClientEndpoint.qml b/xbot2_gui/ClientEndpoint.qml index d7458de..f14065f 100644 --- a/xbot2_gui/ClientEndpoint.qml +++ b/xbot2_gui/ClientEndpoint.qml @@ -5,11 +5,16 @@ import QtQml.WorkerScript import Common import Network +import Protobuf + import "ClientEndpoint.js" as Client import "sharedData.js" as SharedData +import xbot2_gui.msgs + Item { + // note: the appData object is exposed by main.cpp // if running from web it contains the server address @@ -34,7 +39,7 @@ Item signal finalized() // triggered upon reception of a new joint state msg - signal jointStateReceived(var js) + signal jointStateReceived(jointState js) // receiving joint states property bool robotConnected: false @@ -46,20 +51,22 @@ Item signal connected(var msg) // triggerd upon reception of a proc msg - signal procMessageReceived(var msg) + signal processOutputReceived(processOutput msg) // triggerd upon reception of a plugin stat msg signal pluginStatMessageReceived(var msg) // image received signal jpegReceived(var msg) - signal theoraPacketReceived(var msg) + signal theoraPacketReceived(theoraPacket msg) // generic message signal objectReceived(var msg) // bytes received counter - property int bytesRecv: 0 + property alias bytesRecvCounters: pb.recvBytes + property alias numMsgCounters: pb.numMsg + property int bytesRecv: pb.recvBytes.all property int bytesSent: 0 property real srvRtt: 0 property int jsMsgRecv: 0 @@ -116,89 +123,125 @@ Item // websocket for streaming data - WebSocket { + + WebSocketAsync { id: socket url: "ws://" + hostname + ":" + port + "/ws" active: true - onTextMessageReceived: function (message) { + onBinaryMessageReceived: function (data) { + // root.bytesRecv += data.byteLength + pb.processBinaryMessage(data) + } + + onConnected: { + + CommonProperties.notifications.info('Server connected', 'webclient') + + root.connected('Server connected') + + root.isConnected = true - root.bytesRecv += message.length + // root.bytesRecv = 0 + root.bytesSent = 0 if(appData.wasm) { - // deserialize directly since workers have issues in wasm - Client.handleMessage(JSON.parse(message)) + root.sendTextMessage( + JSON.stringify( + { + 'type': 'request_ws_udp_tunnel' + } + ) + ) } else { - // send to worker thread for deserialization - worker.sendMessage(message) + root.doRequestAsync("GET", "/udp", "") + .then((response) => { + udp.hostname = root.hostname + udp.port = response.port + }) } + } + onDisconnected: { + root.isConnected = false + root.isFinalized = false + udp.rebind() + } - + onErrorOccurred: function(err) { + CommonProperties.notifications.error('Error: ' + err, 'webclient') + root.error(err) } + } - onStatusChanged: { + ProtobufDeserialization { - print(`status changed [url ${url}]: ${socket.status}`) + id: pb - if (socket.status === WebSocket.Error) { + onTextMessageReceived: function (message) { + + if(appData.wasm) { + // deserialize directly since workers have issues in wasm + Client.handleMessage(JSON.parse(message)) + } + else { + // send to worker thread for deserialization + worker.sendMessage(message) + } - CommonProperties.notifications.error('Error: ' + socket.errorString, 'webclient') + } - error(socket.errorString) + onJointStateReceived: function(js) { - active = false + root.robotConnected = true - isConnected = false + robotConnectedTimer.restart() - root.isFinalized = false + SharedData.latestJointState = js - } else if (socket.status === WebSocket.Open) { + SharedData1.latestJointState = js - CommonProperties.notifications.info('Server connected', 'webclient') + root.jointStateReceived(js) - connected('Server connected') + root.jsMsgRecv += 1 - isConnected = true + // if(lastJsSeqId < 0) { + // lastJsSeqId = obj.seq + // } + // else { + // root.jsDropped += (obj.seq - lastJsSeqId - 1) + // lastJsSeqId = obj.seq + // } - root.bytesRecv = 0 - root.bytesSent = 0 + if(isConnected && !isFinalized) + { + client.active = true - if(appData.wasm) { - root.sendTextMessage( - JSON.stringify( - { - 'type': 'request_ws_udp_tunnel' - } - ) - ) - } - else { - doRequestAsync("GET", "/udp", "") + doRequestAsync("GET", "/joint_states/info", "") .then((response) => { - udp.hostname = root.hostname - udp.port = response.port - }) - } - - } else if (socket.status === WebSocket.Closed) { - CommonProperties.notifications.error('Socket closed', 'webclient') - isConnected = false - active = false - root.isFinalized = false - udp.rebind() + root.onInfoReceived(response) + }) } } + + onProcessOutputReceived: function(po) { + root.processOutputReceived(po) + } + + onTheoraPacketReceived: function(pkt) { + root.theoraPacketReceived(pkt) + } + } // udp socket to receive unreliable data UdpSocket { id: udp - onTextMessageReceived: function (message) { - root.bytesRecv += message.length - worker.sendMessage(message) + onBinaryMessageReceived: function (data) { + // root.bytesRecv += data.byteLength + pb.processBinaryMessage(data) } } diff --git a/xbot2_gui/Common/Card1.qml b/xbot2_gui/Common/Card1.qml index 1755c8d..252336d 100644 --- a/xbot2_gui/Common/Card1.qml +++ b/xbot2_gui/Common/Card1.qml @@ -8,7 +8,6 @@ import Common Item { - // public property string name: 'CardName' @@ -19,6 +18,10 @@ Item { property color backgroundColor: defaultBackground + property color borderColor + + property int borderWidth: 0 + readonly property color defaultBackground: CommonProperties.colors.cardBackground property alias nameFont: titleLabel.font @@ -49,6 +52,8 @@ Item { property list toolButtons + property alias statusIcon: statusIcon + signal applyConfiguration() @@ -56,8 +61,8 @@ Item { id: root Component.onCompleted: { - frontItem.parent = flip.frontSide.contentItemWrapper - backItem.parent = flip.backSide.contentItemWrapper + frontItem.parent = flip.front.contentItemWrapper + backItem.parent = flip.back.contentItemWrapper } implicitWidth: flip.implicitWidth @@ -79,15 +84,16 @@ Item { id: flip - implicitWidth: root.flipped ? backSide.implicitWidth : frontSide.implicitWidth - implicitHeight: root.flipped ? backSide.implicitHeight : frontSide.implicitHeight + implicitWidth: root.flipped ? back.implicitWidth : front.implicitWidth + implicitHeight: root.flipped ? back.implicitHeight : front.implicitHeight width: parent.width height: parent.height // front side is rendered as a rectangle whose content is layed out in a column // with header (card title and tool buttons) and content (item) - property Item frontSide: Control { + + front: Control { property alias contentItemWrapper: frontContentWrapper @@ -102,6 +108,8 @@ Item { background: Rectangle { color: root.backgroundColor radius: CommonProperties.geom.cardRadius + border.color: root.borderColor + border.width: root.borderWidth } // implicitHeight: frontColumn.implicitHeight @@ -138,12 +146,26 @@ Item { text: root.name font.pixelSize: CommonProperties.font.h2 verticalAlignment: Text.AlignVCenter - Layout.fillWidth: true wrapMode: Text.Wrap + MouseArea { + id: mouse + enabled: root.collapsable + anchors.fill: parent + onDoubleClicked: root.collapsed = !root.collapsed + } + } + + Label { + id: statusIcon + visible: text !== '' + verticalAlignment: Text.AlignVCenter + leftPadding: 4 } Item { + Layout.preferredWidth: 1 Layout.minimumWidth: 6 + Layout.fillWidth: true } Control { @@ -174,6 +196,7 @@ Item { // expand/collpse button SmallToolButton { id: showHideBtn + visible: root.collapsable Layout.alignment: Qt.AlignVCenter text: root.collapsed ? '\uf078' : '\uf077' @@ -216,7 +239,7 @@ Item { } } - property Item backSide: Control { + back: Control { property alias contentItemWrapper: backItemWrapper @@ -230,7 +253,7 @@ Item { padding: root.margins - contentItem: Column { + contentItem: ColumnLayout { id: backColumn @@ -239,7 +262,7 @@ Item { RowLayout { id: backHeaderRow - width: backColumn.width + Layout.fillWidth: true Label { id: titleLabelBack @@ -247,31 +270,6 @@ Item { font: titleLabel.font Layout.fillWidth: true } - - // SmallToolButton { - // Layout.alignment: Qt.AlignVCenter - // text: '\uf013' - // font.family: CommonProperties.fontAwesome.solid.family - // font.pixelSize: CommonProperties.font.h3 - // onClicked: { - - // } - - // DebugRectangle { - // target: parent - // } - // } - // SmallToolButton { - - // Layout.alignment: Qt.AlignVCenter - // text: '\uf013' - // font.family: CommonProperties.fontAwesome.solid.family - // font.pixelSize: CommonProperties.font.h3 - - // onClicked: { - - // } - // } } Item { @@ -280,21 +278,23 @@ Item { } Item { + Layout.fillHeight: true id: backItemWrapper implicitWidth: children[0].implicitWidth implicitHeight: children[0].implicitHeight - width: parent.width - height: children.length > 0 ? children[0].height : 0 + // width: parent.width + // height: children.length > 0 ? children[0].height : 0 clip: true } - Row { + RowLayout { spacing: root.margins Button { id: cfgOkBtn text: 'Ok' + Layout.fillWidth: true onReleased: { root.flipped = false root.collapsed = root._collapsed_before_flip @@ -305,6 +305,7 @@ Item { Button { id: cfgCancelBtn text: 'Cancel' + Layout.fillWidth: true onReleased: { root.flipped = false root.collapsed = root._collapsed_before_flip @@ -317,10 +318,6 @@ Item { } - front: frontSide - - back: backSide - transform: Rotation { id: rotation origin.x: root.width/2 diff --git a/xbot2_gui/Common/MultiColumnLayout1.qml b/xbot2_gui/Common/MultiColumnLayout1.qml index 020e6a5..649d901 100644 --- a/xbot2_gui/Common/MultiColumnLayout1.qml +++ b/xbot2_gui/Common/MultiColumnLayout1.qml @@ -65,10 +65,18 @@ Control { } } + function clearColumns() { + for(let i = 0; i < row.visibleChildren.length; i++) { + row.visibleChildren[i].children = [] + } + } + function computeLayout() { try { + clearColumns() + // console.log('computeLayout START') _layout_in_progress = true diff --git a/xbot2_gui/Common/MultiPaneResponsiveLayout.qml b/xbot2_gui/Common/MultiPaneResponsiveLayout.qml index 48ee96d..3a2dfd0 100644 --- a/xbot2_gui/Common/MultiPaneResponsiveLayout.qml +++ b/xbot2_gui/Common/MultiPaneResponsiveLayout.qml @@ -10,20 +10,20 @@ Item { signal beforeLayoutChange() signal afterLayoutChange() - property alias layoutHelper: layout + // property alias layoutHelper: layout // id: root - LayoutClassHelper { - id: layout - targetWidth: root.width + // LayoutClassHelper { + // id: layout + // targetWidth: root.width - onBeforeLayoutChange: root.beforeLayoutChange() - onAfterLayoutChange: root.afterLayoutChange() + // onBeforeLayoutChange: root.beforeLayoutChange() + // onAfterLayoutChange: root.afterLayoutChange() - onExpandedChanged: console.log(`mprl layout expanded = ${expanded}`) - } + // onExpandedChanged: console.log(`mprl layout expanded = ${expanded}`) + // } default property alias items: container.data diff --git a/xbot2_gui/Ecat/Ecat.qml b/xbot2_gui/Ecat/Ecat.qml index a6eef05..bdcbcba 100644 --- a/xbot2_gui/Ecat/Ecat.qml +++ b/xbot2_gui/Ecat/Ecat.qml @@ -192,8 +192,8 @@ Control { Layout.fillHeight: true Layout.fillWidth: true id: sdoGrid - columns: Math.max(1, selectedSdo.length) + 2 - rowSpacing: -4 + columns: Math.max(1, selectedSdo.length) + 1 + // rowSpacing: -4 columnSpacing: 8 } @@ -210,7 +210,7 @@ Control { sdoHdr.createObject(sdoGrid, {'text': '--', 'enabled': false}) } - empty.createObject(sdoGrid) + // empty.createObject(sdoGrid) // some space for(let i = 0; i < sdoGrid.columns; i++) { @@ -229,7 +229,7 @@ Control { sdoDelegate.createObject(sdoGrid, {'enabled': false}) } - readBtn.createObject(sdoGrid, {'id': id}) + // readBtn.createObject(sdoGrid, {'id': id}) } } @@ -268,6 +268,7 @@ Control { } property Component sdoDelegate: TextField { + id: sdoTextField property string id property string sdo Layout.fillWidth: true @@ -276,6 +277,15 @@ Control { readOnly: !writeCheck.checked onTextEdited: writeBtn.visible = true + onFocusChanged: { + if(focus) { + readBtn.visible = !writeCheck.checked + } + else if(!readBtn.focus) { + readBtn.visible = false + } + } + ToolButton { id: writeBtn anchors.right: parent.right @@ -289,12 +299,33 @@ Control { visible: false } + ToolButton { + id: readBtn + anchors.right: parent.right + height: parent.height + text: 'Read' + z: 1 + onClicked: { + Logic.readSdo([parent.id], parent.sdo) + visible = false + } + visible: false + } + Connections { target: root function onSdoValuesChanged() { text = root.sdoValues?.[id]?.[sdo] ?? '--' } } + + Shortcut { + sequence: "Ctrl+C" + onActivated: { + console.log('AAA' + sdoTextField.text + 'AAA') + appData.copyToClipboard(sdoTextField.text) + } + } } property Component readBtn: Button { diff --git a/xbot2_gui/Font/CMakeLists.txt b/xbot2_gui/Font/CMakeLists.txt index 394ecee..c04bf3c 100644 --- a/xbot2_gui/Font/CMakeLists.txt +++ b/xbot2_gui/Font/CMakeLists.txt @@ -20,6 +20,7 @@ qt_add_resources(xbot2_gui_font "app_fonts" "materialsymbols/MaterialSymbolsOutlined[opsz,wght,FILL,GRAD@20,200,1,200].otf" "materialsymbols/MaterialSymbolsOutlined[opsz,wght,FILL,GRAD@20,200,0,200].otf" "materialsymbols/MaterialSymbolsOutlined[opsz,wght,FILL,GRAD@20,400,0,200].otf" + "materialsymbols/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf" ) qt_add_resources(xbot2_gui_font "app_icons" diff --git a/xbot2_gui/Font/MaterialSymbolNames.qml b/xbot2_gui/Font/MaterialSymbolNames.qml index 215e770..c7f8fb2 100644 --- a/xbot2_gui/Font/MaterialSymbolNames.qml +++ b/xbot2_gui/Font/MaterialSymbolNames.qml @@ -38,6 +38,9 @@ Item { property string netSettings: '\ueb2f' property string tune: '\ue429' property string emergency: '\ue82a' + property string volumeOff: '\ue04f' + property string copy: '\ue14d' + property string clean: '\uf0ff' property FontLoader filledFont: FontLoader { source: `/Font/materialsymbols/MaterialSymbolsOutlined[opsz,wght,FILL,GRAD@20,200,1,200].otf` diff --git a/xbot2_gui/Font/MaterialSymbols.qml b/xbot2_gui/Font/MaterialSymbols.qml index 9818291..69a0491 100644 --- a/xbot2_gui/Font/MaterialSymbols.qml +++ b/xbot2_gui/Font/MaterialSymbols.qml @@ -20,6 +20,10 @@ QtObject { source: `/Font/materialsymbols/MaterialSymbolsOutlined[opsz,wght,FILL,GRAD@20,200,0,200].otf` } + property FontLoader variableFont: FontLoader { + source: `/Font/materialsymbols/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf` + } + // to get more variants: // (1) https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20,200,0,200 // (2) change the last four values diff --git a/xbot2_gui/Font/materialsymbols/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf b/xbot2_gui/Font/materialsymbols/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf new file mode 100644 index 0000000..be867f5 Binary files /dev/null and b/xbot2_gui/Font/materialsymbols/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf differ diff --git a/xbot2_gui/Home/CMakeLists.txt b/xbot2_gui/Home/CMakeLists.txt index e67a96e..fa31f27 100644 --- a/xbot2_gui/Home/CMakeLists.txt +++ b/xbot2_gui/Home/CMakeLists.txt @@ -9,6 +9,7 @@ qt_add_qml_module(xbot2_gui_home QML_FILES Configuration.qml QML_FILES ConfigurationGeneral.qml QML_FILES ConfigurationAudio.qml + QML_FILES StatisticsCard.qml ) target_link_libraries(xbot2_gui PRIVATE xbot2_gui_homeplugin) diff --git a/xbot2_gui/Home/HelloScreen.qml b/xbot2_gui/Home/HelloScreen.qml index b9d6d6e..3dbbc01 100644 --- a/xbot2_gui/Home/HelloScreen.qml +++ b/xbot2_gui/Home/HelloScreen.qml @@ -128,6 +128,12 @@ MultiPaneResponsiveLayout { width: scroll.availableWidth } + StatisticsCard { + client: root.client + width: scroll.availableWidth + + } + } } @@ -171,63 +177,4 @@ MultiPaneResponsiveLayout { } - // MaterialResponsiveGrid { - - // id: mainGrid - - // anchors.fill: parent - - // SectionHeader { - // property int columnSpan: mainGrid.columns - // text: 'XBot2 GUI' - // } - - // ServerStatusCard { - // id: srvStatus - // client: root.client - // onStatsUpdated: { - // let t = appData.getTimeNs()*1e-9 - statsPlot.t0 - // statsPlot.addPoint(statsPlot.currSeries['rx data'], - // t, rxKbps) - // statsPlot.addPoint(statsPlot.currSeries['tx data'], - // t, txKbps) - // statsPlot.addPoint(statsPlot.currSeries['server rtt'], - // t, client.srvRtt) - // } - // } - - // Card { - - // name: 'Statistics' - - // height: srvStatus.height - - // property int columnSpan: 8 - - // toolButtons: [ - // SmallToolButton { - // text: '\uf021' - // font.family: CommonProperties.fontAwesome.solid.family - // onClicked: statsPlot.resetView() - // } - // ] - - // frontItem: Plotter { - // id: statsPlot - // anchors.fill: parent - // property real t0: appData.getTimeNs()*1e-9 - // axisLeftTitle: 'RTT [ms]' - // axisRightTitle: 'Data rate [kbps]' - - // } - - // Component.onCompleted: { - // statsPlot.addSeries('server rtt', {}) - // statsPlot.addSeries('rx data', {}, true) - // statsPlot.addSeries('tx data', {}, true) - // } - // } - // } - - } diff --git a/xbot2_gui/Home/StatisticsCard.qml b/xbot2_gui/Home/StatisticsCard.qml new file mode 100644 index 0000000..14fb168 --- /dev/null +++ b/xbot2_gui/Home/StatisticsCard.qml @@ -0,0 +1,126 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Common +import Main + +Card1 { + + property ClientEndpoint client + + // + id: root + + property real bytesAll: 0 + property real bytesDelta: 0 + + configurable: false + collapsable: true + collapsed: true + + name: 'Network Statistics' + + frontItem: Control { + topPadding: 6 + anchors.fill: parent + contentItem: GridLayout { + + id: grid + + columns: 3 + + columnSpacing: CommonProperties.geom.spacing + rowSpacing: CommonProperties.geom.spacing + + } + } + + toolButtons: [ + Switch { + id: showTotalSwitch + text: 'Show total' + checked: false + } + + ] + + Timer { + id: timer + running: true + repeat: true + onTriggered: { + + let brc = client.bytesRecvCounters + let numKeys = Object.keys(brc).length + + root.bytesDelta = brc.all/1024. - bytesAll + root.bytesAll = brc.all/1024. + + if(grid.children.length !== numKeys * 3) + { + grid.children = [] + + for(const key of Object.keys(brc)) { + rowHdr.createObject(grid, {'text': key}) + numField.createObject(grid, {'text': '--', 'fieldName': key}) + kBField.createObject(grid, {'text': '--', 'fieldName': key}) + } + } + } + } + + property Component rowHdr: Label { + + } + + property Component numField: TextField { + id: numField + property string fieldName + property int oldValue: 0 + readOnly: true + placeholderText: 'num msg' + Layout.preferredHeight: 40 + Layout.minimumWidth: 100 + Layout.fillWidth: true + Connections { + target: timer + function onTriggered() { + let value = client.numMsgCounters[fieldName] + if(showTotalSwitch.checked) { + numField.text = value + } + else { + numField.text = value - numField.oldValue + } + numField.oldValue = value + } + } + } + + property Component kBField: TextField { + id: kBField + property string fieldName + property real oldValue: 0 + readOnly: true + placeholderText: 'bandwidth' + Layout.preferredHeight: 40 + Layout.minimumWidth: 100 + Layout.fillWidth: true + Connections { + target: timer + function onTriggered() { + let value = client.bytesRecvCounters[fieldName] / 1024. + if(showTotalSwitch.checked) { + kBField.text = `${(value*8).toFixed(1)} kb (${(value/root.bytesAll*100).toFixed(0)} %)` + } + else { + let delta = value - kBField.oldValue + kBField.text = `${(delta*8).toFixed(1)} kbps (${(delta/root.bytesDelta*100).toFixed(0)} %)` + } + kBField.oldValue = value + } + } + } + +} diff --git a/xbot2_gui/Horizon/Horizon.qml b/xbot2_gui/Horizon/Horizon.qml index 5ed20a9..b08a47b 100644 --- a/xbot2_gui/Horizon/Horizon.qml +++ b/xbot2_gui/Horizon/Horizon.qml @@ -9,10 +9,10 @@ import "Horizon.js" as Logic Item { - LayoutClassHelper { - id: layout - targetWidth: parent.width - } + // LayoutClassHelper { + // id: layout + // targetWidth: parent.width + // } property ClientEndpoint client diff --git a/xbot2_gui/Horizon/HorizonControl.qml b/xbot2_gui/Horizon/HorizonControl.qml index 1229c1c..ad2d47c 100644 --- a/xbot2_gui/Horizon/HorizonControl.qml +++ b/xbot2_gui/Horizon/HorizonControl.qml @@ -18,9 +18,10 @@ Pane { contentItem: ColumnLayout { Switch { - visible: true + visible: false id: enableSwitch text: 'Enable gait' + checked: true } Item { @@ -39,7 +40,7 @@ Pane { id: gaitCombo enabled: enableSwitch.checked Layout.fillWidth: true - model: ['Trot', 'Walk', 'Crawl'] + model: ['Trot', 'Crawl'] } Item { diff --git a/xbot2_gui/Joy/Joy.qml b/xbot2_gui/Joy/Joy.qml index 5fcaabb..03a3251 100644 --- a/xbot2_gui/Joy/Joy.qml +++ b/xbot2_gui/Joy/Joy.qml @@ -14,10 +14,6 @@ Item { id: root - LayoutClassHelper { - id: layout - targetWidth: parent.width - } property ClientEndpoint client JoyCartesianCard { @@ -119,7 +115,7 @@ Item { Connections { target: client function onTheoraPacketReceived(msg) { - if(msg.stream_name === setupCard.videoStream) { + if(msg.streamName === setupCard.videoStream) { video.setTheoraPacket(msg) } } diff --git a/xbot2_gui/Joy/JoyCartesianCard.qml b/xbot2_gui/Joy/JoyCartesianCard.qml index be98e79..b2b3d18 100644 --- a/xbot2_gui/Joy/JoyCartesianCard.qml +++ b/xbot2_gui/Joy/JoyCartesianCard.qml @@ -105,6 +105,7 @@ Card1 { VideoStream.refreshNames(undefined, (topics) => { videoStreamCombo.model = topics + videoStreamCombo.currentTextChanged() }) } } diff --git a/xbot2_gui/Launcher/ConsoleCard.qml b/xbot2_gui/Launcher/ConsoleCard.qml index f422cce..53aa82e 100644 --- a/xbot2_gui/Launcher/ConsoleCard.qml +++ b/xbot2_gui/Launcher/ConsoleCard.qml @@ -8,51 +8,34 @@ import "ConsoleCard.js" as Logic Item { - property string name + property alias listModel: view.model - property bool scrollOnOutput: true - - function appendText(text) { - - model.append({'txt': text}) - - if(scrollOnOutput) Qt.callLater(view.positionViewAtEnd) + function scrollToEnd() { + Qt.callLater(view.positionViewAtEnd) } - function clearText() { - model.clear() - } - - function getText() { - let txt = '' - for(let i = 0; i < model.count; i++) { - txt = txt + model.get(i).txt + '\n' - } - return txt - - } + property int pixelSize: 14 id: root implicitHeight: view.implicitHeight implicitWidth: view.implicitWidth + + property Component delegate: TextEdit { - font.pixelSize: 14 + required property string txt + // required property color txtColor + font.pixelSize: root.pixelSize width: view.width wrapMode: Text.WrapAnywhere readOnly: true textFormat: TextEdit.RichText text: txt - color: palette.text - } - - ListModel { - id: model + // color: txtColor } ListView { id: view - model: model delegate: root.delegate // implicitHeight: contentHeight // note: breaks performance!!!! anchors.fill: parent @@ -62,5 +45,4 @@ Item { active: true } } - } diff --git a/xbot2_gui/Launcher/Launcher.js b/xbot2_gui/Launcher/Launcher.js index 2c5b2ec..0014141 100644 --- a/xbot2_gui/Launcher/Launcher.js +++ b/xbot2_gui/Launcher/Launcher.js @@ -74,25 +74,26 @@ function processCmd(name, cmd, opt) { } -function onProcMessageReceived(procRepeater, consoleItem, msg) { +function onProcessOutputReceived(procRepeater, consoleItem, msg) { - // handle output - if(msg.content === 'output') - { - let prefix = '[' + msg.name + '] ' + let muted = root.processMutedState[msg.name] - if(msg.stdout.length > 0) { - consoleItem.appendText(msg.name, prefix + msg.stdout) - } + // handle output + let prefix = '[' + msg.name + '] ' - if(msg.stderr.length > 0) { - consoleItem.appendText(msg.name, '' + prefix + msg.stderr + '') - root.numErrors += 1 - } + if(msg.out.length > 0) { + consoleItem.appendText(msg.name, prefix + msg.out, muted) + } - return; + if(msg.err.length > 0) { + consoleItem.appendText(msg.name, '' + prefix + msg.err + '', muted) + root.numErrors += 1 } +} + +function onProcessStatusReceived(procRepeater, consoleItem, msg) { + // handle status for(let i = 0; i < procRepeater.count; i++) { @@ -101,11 +102,7 @@ function onProcMessageReceived(procRepeater, consoleItem, msg) { // found! if(item_i.processName === msg.name) { - if(msg.content === 'status') - { - item_i.processState = msg.status - } - + item_i.processState = msg.status break } } diff --git a/xbot2_gui/Launcher/Launcher.qml b/xbot2_gui/Launcher/Launcher.qml index 5d8b01d..fd15e4c 100644 --- a/xbot2_gui/Launcher/Launcher.qml +++ b/xbot2_gui/Launcher/Launcher.qml @@ -16,6 +16,14 @@ MultiPaneResponsiveLayout { property int numErrors: 0 + property var processMutedState: Object() + + + LayoutClassHelper { + id: layout + targetWidth: root.width + } + ScrollView { property string iconText: 'Launcher' @@ -106,7 +114,7 @@ MultiPaneResponsiveLayout { id: processLayout width: parent.width - columns: root.layoutHelper.compact ? 1 : 2 + columns: Math.ceil(width / 400.0) Repeater { @@ -115,6 +123,7 @@ MultiPaneResponsiveLayout { ProcessCard { visible: (showAllChk.checked || modelData.visible) && processRepeater.visible + muted: !modelData.visible processName: modelData.name processState: modelData.status @@ -125,6 +134,8 @@ MultiPaneResponsiveLayout { onStart: Logic.processCmd(processName, 'start', processOptions) onStop: Logic.processCmd(processName, 'stop', {}) onKill: Logic.processCmd(processName, 'kill', {}) + + onMutedChanged: root.processMutedState[processName] = muted } } @@ -173,7 +184,7 @@ MultiPaneResponsiveLayout { id: pluginLayout width: parent.width - columns: root.layoutHelper.compact ? 1 : 2 + columns: Math.ceil(width / 400.0) Repeater { @@ -218,14 +229,19 @@ MultiPaneResponsiveLayout { target: root.client - function onProcMessageReceived(msg) { - Logic.onProcMessageReceived(processRepeater, consoleItem, msg) + function onProcessOutputReceived(msg) { + Logic.onProcessOutputReceived(processRepeater, consoleItem, msg) } function onPluginStatMessageReceived(msg) { Logic.onPluginMessageReceived(pluginRepeater, msg) } + function onObjectReceived(msg) { + if(msg.type === 'proc_status') { + Logic.onProcessStatusReceived(processRepeater, consoleItem, msg) + } + } } } diff --git a/xbot2_gui/Launcher/LauncherConsoleItem.qml b/xbot2_gui/Launcher/LauncherConsoleItem.qml index dd37b50..f8f6065 100644 --- a/xbot2_gui/Launcher/LauncherConsoleItem.qml +++ b/xbot2_gui/Launcher/LauncherConsoleItem.qml @@ -1,15 +1,16 @@ import QtQuick import QtQuick.Layouts import QtQuick.Controls +import QtCore import Font import "../Common" Item { - function appendText(procName, text) { + function appendText(procName: string, text: string, muted: bool) { - var i = 0 + let i = 0 if(procName === 'launcher') { i = -1 @@ -24,7 +25,7 @@ Item { consoleRepeater.itemAt(i+2).appendText(text) - if(i >= 0 && !procCheckRepeater.itemAt(i).checked) { + if(i >= 0 && muted) { return } @@ -64,8 +65,12 @@ Item { name: 'Console Output' toolButtons: [ - Button { - text: 'Copy' + SmallToolButton { + text: MaterialSymbolNames.copy + font.family: 'Material Symbols Outlined' + font.variableAxes: {'opsz': 48} + font.pixelSize: 16 + onClicked: { let txt = consoleRepeater.itemAt(consoleCombo.currentIndex).getText() appData.copyToClipboard(txt) @@ -81,8 +86,12 @@ Item { } }, - Button { - text: 'Clear' + SmallToolButton { + text: MaterialSymbolNames.clean + font.family: 'Material Symbols Outlined' + font.variableAxes: {'opsz': 48} + font.pixelSize: 16 + onClicked: { consoleRepeater.itemAt(consoleCombo.currentIndex).clearText() } @@ -95,17 +104,75 @@ Item { ] frontItem: StackLayout { - width: parent.width - height: root.height - 80 + + anchors.fill: parent currentIndex: consoleCombo.currentIndex + Repeater { + id: consoleRepeater + model: ['all', 'launcher'].concat(root.processNames) - ConsoleCard { - name: modelData + + Item { + required property int index + required property string modelData + // property color txtColor: root.colors[index % root.colors.length] + + function appendText(txt) { + // console.log(root.colors[index % root.colors.length]) + // console.log(txtColor) + listModel.append({'txt': txt}) // , 'txtColor': txtColor}) + if(scrollOnOutputCheck.checked) { + consoleLoader.item?.scrollToEnd() + } + } + + function clearText() { + listModel.clear() + } + + function getText() { + let txt = '' + for(let i = 0; i < listModel.count; i++) { + txt = txt + listModel.get(i).txt + '\n' + } + return txt + } + Layout.fillWidth: true Layout.fillHeight: true - scrollOnOutput: scrollOnOutputCheck.checked + implicitHeight: consoleLoader.implicitHeight + implicitWidth: consoleLoader.implicitWidth + + Loader { + + id: consoleLoader + + active: index === consoleCombo.currentIndex + + anchors.fill: parent + + sourceComponent: ConsoleCard { + id: cardInner + pixelSize: fontSizeSpin.value + } + + onLoaded: { + item.listModel = listModel + if(scrollOnOutputCheck.checked) { + item.scrollToEnd() + + } + console.log(`${modelData} loaded ${listModel.count} lines`) + } + + } + + ListModel { + id: listModel + } + } } } @@ -136,21 +203,23 @@ Item { } Label { - text: 'Select the processes to show in the global console' - font.pixelSize: CommonProperties.font.h3 - Layout.columnSpan: Math.max(1, grid.columns) + text: 'Font size' } - Repeater { - id: procCheckRepeater - model: root.processNames - CheckBox { - text: modelData - checked: root.hiddenProcessNames.indexOf(modelData) === -1 - } + SpinBox { + id: fontSizeSpin + from: 1 + to: 18 + value: 12 } + } } + Settings { + category: 'console' + property alias fontSize: fontSizeSpin.value + } + } diff --git a/xbot2_gui/Launcher/PluginCard.qml b/xbot2_gui/Launcher/PluginCard.qml index becaee4..338ab48 100644 --- a/xbot2_gui/Launcher/PluginCard.qml +++ b/xbot2_gui/Launcher/PluginCard.qml @@ -32,7 +32,7 @@ Item { property var colorMap: { 'Aborted': CommonProperties.colors.err, 'Starting': Qt.lighter(CommonProperties.colors.ok, 3), - 'Stopping': CommonProperties.colors.warn, + 'Stopping': CommonProperties.colors.err, 'Running': Qt.lighter(CommonProperties.colors.ok), 'Initialized': card.defaultBackground, 'Stopped': card.defaultBackground, @@ -57,7 +57,41 @@ Item { collapsed: true configurable: false + // color management backgroundColor: colorMap[pluginState] + borderWidth: 2 + borderColor: pluginState === 'Aborted' ? Qt.darker(backgroundColor) : Qt.lighter(backgroundColor) + + SequentialAnimation on backgroundColor { + + loops: Animation.Infinite + + running: root.pluginState === 'Starting' || + root.pluginState === 'Stopping' + + alwaysRunToEnd: false + + ColorAnimation { + from: colorMap[pluginState] + to: card.defaultBackground + duration: 555 + easing { + type: Easing.OutSine + } + } + + ColorAnimation { + from: card.defaultBackground + to: colorMap[pluginState] + duration: 555 + easing { + type: Easing.InSine + } + } + + onFinished: card.backgroundColor = Qt.binding(() => colorMap[pluginState]) + + } toolButtons: [ SmallToolButton { diff --git a/xbot2_gui/Launcher/ProcessCard.qml b/xbot2_gui/Launcher/ProcessCard.qml index 42c32e6..381bd17 100644 --- a/xbot2_gui/Launcher/ProcessCard.qml +++ b/xbot2_gui/Launcher/ProcessCard.qml @@ -3,7 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import Common -import "../Common" +import Font Item { @@ -15,6 +15,7 @@ Item { property string processName: 'ProcessName' property alias processConfig: configPanel.description property alias processOptions: configPanel.options + property alias muted: muteSwitch.checked signal start() signal stop() @@ -28,7 +29,7 @@ Item { 'Stopped': card.defaultBackground, 'Killed': CommonProperties.colors.err, 'Waiting': Qt.lighter(CommonProperties.colors.ok, 3), - 'Killing': CommonProperties.colors.warn + 'Killing': CommonProperties.colors.err } id: root @@ -47,28 +48,82 @@ Item { collapsed: true + // status icon (mute) + statusIcon.text: MaterialSymbolNames.volumeOff + statusIcon.font.family: 'Material Symbols Outlined' + statusIcon.font.pixelSize: 18 + statusIcon.visible: muteSwitch.checked + + // color management backgroundColor: colorMap[processState] + borderWidth: 2 + borderColor: processKilled ? Qt.darker(backgroundColor) : Qt.lighter(backgroundColor) + + + + SequentialAnimation on backgroundColor { + + loops: Animation.Infinite + + running: root.processState === 'Waiting' || + root.processState === 'Killing' + + alwaysRunToEnd: true + + ColorAnimation { + from: colorMap[processState] + to: card.defaultBackground + duration: 555 + easing { + type: Easing.OutSine + } + } + + ColorAnimation { + from: card.defaultBackground + to: colorMap[processState] + duration: 555 + easing { + type: Easing.InSine + } + } + + onFinished: card.backgroundColor = Qt.binding(() => colorMap[processState]) + + } toolButtons: [ + SmallToolButton { id: startQuickBtn text: root.processRunning ? '\uf04d' : '\uf04b' font.family: CommonProperties.fontAwesome.solid.family onClicked: root.processRunning ? root.stop() : root.start() } + ] frontItem: GridLayout { // anchors.fill: parent columns: 2 height: implicitHeight + anchors.fill: parent Button { text: root.processRunning ? 'Stop' : 'Start' onClicked: root.processRunning ? root.stop() : root.start() + Layout.fillWidth: true } Button { text: 'Kill' onClicked: root.kill() + Layout.fillWidth: true + } + Switch { + Layout.columnSpan: 2 + + id: muteSwitch + text: 'Mute' + checked: false } } diff --git a/xbot2_gui/LivePlot/Plot.qml b/xbot2_gui/LivePlot/Plot.qml index 34771b9..a0d88f7 100644 --- a/xbot2_gui/LivePlot/Plot.qml +++ b/xbot2_gui/LivePlot/Plot.qml @@ -10,25 +10,25 @@ MultiPaneResponsiveLayout { onPageSelected: livePlot.rebuild() - onAfterLayoutChange: livePlot.rebuild() + // onAfterLayoutChange: livePlot.rebuild() - LayoutClassHelper { - id: lay - targetWidth: parent.width - } + // LayoutClassHelper { + // id: lay + // targetWidth: parent.width + // } GridLayout { anchors.fill: parent - rows: lay.expanded ? 1 : -1 - columns: lay.expanded ? -1 : 1 + rows: layout.expanded ? 1 : -1 + columns: layout.expanded ? -1 : 1 PlotterLegend { id: plotterLegend chart: livePlot.chartView - Layout.fillWidth: !lay.expanded - Layout.fillHeight: lay.expanded + Layout.fillWidth: !layout.expanded + Layout.fillHeight: layout.expanded } Plotter { diff --git a/xbot2_gui/Monitoring/BarPlot/BarPlot.js b/xbot2_gui/Monitoring/BarPlot/BarPlot.js index 6d04e4a..e8b1184 100644 --- a/xbot2_gui/Monitoring/BarPlot/BarPlot.js +++ b/xbot2_gui/Monitoring/BarPlot/BarPlot.js @@ -83,12 +83,24 @@ function setJointStateMessage(msg) } var barPlotDefaultModel = [ + { + 'fieldName': 'linkPos', + 'refName': 'posRef', + 'min': SharedData.qmin, + 'max': SharedData.qmax, + }, { 'fieldName': 'motPos', 'refName': 'posRef', 'min': SharedData.qmin, 'max': SharedData.qmax, }, + { + 'fieldName': 'linkVel', + 'refName': 'velRef', + 'min': SharedData.vmax.map(x => -x), + 'max': SharedData.vmax, + }, { 'fieldName': 'motVel', 'refName': 'velRef', @@ -98,8 +110,8 @@ var barPlotDefaultModel = [ { 'fieldName': 'tor', 'refName': 'torRef', - 'min': SharedData.taumax.map(x => -x), - 'max': SharedData.taumax, + 'min': SharedData.taumax.map(x => -x/3.), + 'max': SharedData.taumax.map(x => x/3.), }, { 'fieldName': 'motorTemp', diff --git a/xbot2_gui/Monitoring/BarPlot/BarPlot.qml b/xbot2_gui/Monitoring/BarPlot/BarPlot.qml index 0386207..6c89623 100644 --- a/xbot2_gui/Monitoring/BarPlot/BarPlot.qml +++ b/xbot2_gui/Monitoring/BarPlot/BarPlot.qml @@ -13,6 +13,7 @@ Item { property list jointNames: [] property list min: [] property list max: [] + property list selectedJoints: [] property string fieldName: "tor" property string fieldNameRef: "torRef" property alias container: container @@ -59,7 +60,7 @@ Item { bar.value: 0 jointName: root.jointNames[index] bar.type: type - + isSelected: root.selectedJoints.indexOf(jointName) >= 0 onJointClicked: function(jn) { root.jointClicked(jn) } diff --git a/xbot2_gui/Monitoring/BarPlot/BarPlotItem.qml b/xbot2_gui/Monitoring/BarPlot/BarPlotItem.qml index 6550173..49074d4 100644 --- a/xbot2_gui/Monitoring/BarPlot/BarPlotItem.qml +++ b/xbot2_gui/Monitoring/BarPlot/BarPlotItem.qml @@ -6,8 +6,9 @@ Item { property string jointName: "joint_name" property alias bar: bar - property real labelColorAlpha: 0.3 + property real labelColorAlpha: (isSelected || labelMouseArea.containsMouse) ? 0.6 : 0.3 property alias labelMouseArea: labelMouseArea + property bool isSelected: false signal jointClicked(string jName) @@ -49,19 +50,6 @@ Item { id: labelMouseArea anchors.fill: parent hoverEnabled: true - preventStealing: true - - onHoveredChanged: { - console.log(jointName) - if(labelMouseArea.containsMouse) - { - labelColorAlpha = 0.6 - } - else - { - labelColorAlpha = 0.3 - } - } onClicked: { jointClicked(jointName) diff --git a/xbot2_gui/Monitoring/BarPlot/BarPlotStack.qml b/xbot2_gui/Monitoring/BarPlot/BarPlotStack.qml index cacc3c4..ba2c7b4 100644 --- a/xbot2_gui/Monitoring/BarPlot/BarPlotStack.qml +++ b/xbot2_gui/Monitoring/BarPlot/BarPlotStack.qml @@ -9,6 +9,10 @@ Item { property list fieldNames + property list selectedJoints + + property bool enableMultipleSelection + property alias currentIndex: stack.currentIndex function setJointStateMessage(js_msg) { @@ -17,6 +21,7 @@ Item { signal jointClicked(string jointName) + function setStatus(jName, ok) { let idx = SharedData.jointNames.indexOf(jName) statusOk[idx] = ok @@ -99,8 +104,23 @@ Item { onJointClicked: function(jn) { root.jointClicked(jn) + + if(root.selectedJoints.indexOf(jn) < 0) { + if(root.enableMultipleSelection) { + root.selectedJoints.push(jn) + } + else { + root.selectedJoints = [jn] + } + } + else { + root.selectedJoints = root.selectedJoints.filter(item => item !== jn) + } + } + selectedJoints: root.selectedJoints + } diff --git a/xbot2_gui/Monitoring/CMakeLists.txt b/xbot2_gui/Monitoring/CMakeLists.txt index 1ab4fe0..f6ff361 100644 --- a/xbot2_gui/Monitoring/CMakeLists.txt +++ b/xbot2_gui/Monitoring/CMakeLists.txt @@ -1,5 +1,9 @@ add_library(xbot2_gui_monitoring STATIC) +# set_target_properties(xbot2_gui_monitoring PROPERTIES +# QT_QMLCACHEGEN_ARGUMENTS "--verbose" +# ) + qt_add_qml_module(xbot2_gui_monitoring URI Monitoring VERSION 1.0 @@ -19,12 +23,13 @@ qt_add_qml_module(xbot2_gui_monitoring Parameter/ParameterView.qml MonWidget.qml MonWidget.js + SoftSafetyButton.qml SOURCES Parameter/parameter_tree_item.h Parameter/parameter_tree_item.cpp Parameter/parameter_tree_model.h Parameter/parameter_tree_model.cpp - QML_FILES SoftSafetyButton.qml + QML_FILES Gripper.qml ) target_include_directories(xbot2_gui_monitoring PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Parameter) diff --git a/xbot2_gui/Monitoring/Gripper.qml b/xbot2_gui/Monitoring/Gripper.qml new file mode 100644 index 0000000..849016f --- /dev/null +++ b/xbot2_gui/Monitoring/Gripper.qml @@ -0,0 +1,143 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Main +import Common +import Monitoring.BarPlot + +import "JointCommand.js" as Logic + +Card1 { + + // property ClientEndpoint client + + property alias gripperNames: gripperCombo.model + + name: 'Gripper Command' + + frontItem: GridLayout { + + anchors.fill: parent + + columns: 2 + + RowLayout { + Layout.fillWidth: true + Layout.columnSpan: 2 + ComboBox { + id: gripperCombo + model: ['Gripper1', 'Gripper2'] + Layout.fillWidth: true + } + + Button { + text: 'Refresh' + onClicked: Logic.updateGripperNames() + } + } + + + Item { + Layout.fillWidth: true + Layout.columnSpan: 2 + Layout.preferredHeight: 8 + } + + + // Label { + // text: 'Position' + // } + + // TwoSideBar { + // id: posBar + // Layout.fillWidth: true + // } + + + // Label { + // text: 'Effort' + // } + + // TwoSideBar { + // id: torBar + // Layout.fillWidth: true + // } + + + // Item { + // Layout.fillWidth: true + // Layout.columnSpan: 2 + // Layout.preferredHeight: 8 + // } + + RowLayout { + + Layout.fillWidth: true + Layout.columnSpan: 2 + + Label { + text: 'Effort reference' + } + + Slider { + Layout.fillWidth: true + id: slider + + onMoved: { + + } + + from: -10 + to: 10 + + } + + TextField { + id: sliderLabel + text: slider.value.toFixed(2) + onTextEdited: { + slider.value = parseFloat(text) + } + } + + } + + RowLayout { + + Layout.fillWidth: true + Layout.columnSpan: 2 + + Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + text: 'Open' + onClicked: Logic.sendGripperCommand(gripperCombo.currentText, 'open') + } + + Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + text: 'Apply force' + onClicked: Logic.sendGripperCommand(gripperCombo.currentText, 'close', slider.value) + } + + } + + + } + + Component.onCompleted: Logic.updateGripperNames() + + // Connections { + // target: client + // function onObjectReceived(msg) { + // if(msg.type === 'gripper_state') { + // if(msg.name === gripperCombo.currentText) { + + // } + // } + // } + // } + +} diff --git a/xbot2_gui/Monitoring/JointCommand.js b/xbot2_gui/Monitoring/JointCommand.js index aacc50a..9b90361 100644 --- a/xbot2_gui/Monitoring/JointCommand.js +++ b/xbot2_gui/Monitoring/JointCommand.js @@ -9,7 +9,10 @@ function sendCommand(ctrlJoints, cmdField, ref, trjtime) { client.doRequestAsync('PUT', `/joint_command/goto/${jointNames}?qref=${cmd}&time=${trjtime}&ctrl=${cmdField}`) - .then((response) => trjCmdBtn.running = false) + .then((response) => { + trjCmdBtn.running = false + robotViewer.showRobotCmd = false + }) .catch((err) => console.error(err)) } @@ -113,3 +116,22 @@ function currentValue(ctrlJoints, cmdField) { return SharedData.latestJointState.d[idx] } } + +function updateGripperNames() { + client.doRequestAsync('GET', + `/joint_states/grippers`) + .then((response) => gripperCombo.model = response.gripper_names) + .catch((err) => console.error(err)) +} + +function sendGripperCommand(name, action, effort=0) { + let msg = Object() + msg.type = 'gripper_cmd' + msg.name = name + msg.action = action + msg.effort = effort + + client.sendTextMessage(JSON.stringify(msg)) + + console.log(JSON.stringify(msg)) +} diff --git a/xbot2_gui/Monitoring/JointCommandCard.qml b/xbot2_gui/Monitoring/JointCommandCard.qml index ce54e00..10ff63f 100644 --- a/xbot2_gui/Monitoring/JointCommandCard.qml +++ b/xbot2_gui/Monitoring/JointCommandCard.qml @@ -15,8 +15,10 @@ Card1 { property RobotModelNode robotCmd signal resetCmd() signal cmdChanged() + signal jointRemoved() property list ctrlJoints property alias activeCtrl: ctrlCombo.currentText + property alias enableMultipleSelection: multiJointChk.checked function selectJoint(jName) { if(multiJointChk.checked) { @@ -30,6 +32,7 @@ Card1 { function removeJoint(jName) { ctrlJoints = ctrlJoints.filter(n => n !== jName) + jointRemoved() } @@ -91,7 +94,7 @@ Card1 { id: clearBtn text: 'X' visible: jointRepeater.count > 1 - onClicked: root.ctrlJoints = [] + onClicked: {root.ctrlJoints = []; root.jointRemoved()} } } @@ -121,7 +124,7 @@ Card1 { enabled: root.ctrlJoints.length > 0 id: sliderLabel text: slider.value.toFixed(2) - onAccepted: { + onEditingFinished: { slider.value = parseFloat(text) } } diff --git a/xbot2_gui/Monitoring/MonWidget.qml b/xbot2_gui/Monitoring/MonWidget.qml index 02ccbb8..91b3088 100644 --- a/xbot2_gui/Monitoring/MonWidget.qml +++ b/xbot2_gui/Monitoring/MonWidget.qml @@ -83,6 +83,7 @@ Control { Column { + Layout.alignment: Qt.AlignTop Layout.fillWidth: true Layout.columnSpan: 2 @@ -93,7 +94,7 @@ Control { } Label { - text: `${vBatt} V` + text: `${vBatt.toFixed(1)} V` anchors.horizontalCenter: parent.horizontalCenter } @@ -101,6 +102,7 @@ Control { Column { + Layout.alignment: Qt.AlignTop Layout.preferredWidth: 40 Layout.fillWidth: true @@ -118,13 +120,17 @@ Control { Label { text: root.jnameMaxTempDri anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Text.WrapAnywhere font.pointSize: 6 + width: parent.width + horizontalAlignment: Text.AlignHCenter } } Column { + Layout.alignment: Qt.AlignTop Layout.preferredWidth: 40 Layout.fillWidth: true @@ -142,7 +148,10 @@ Control { Label { text: root.jnameMaxTempMot anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Text.WrapAnywhere font.pointSize: 6 + width: parent.width + horizontalAlignment: Text.AlignHCenter } } @@ -155,7 +164,9 @@ Control { running: true repeat: true onTriggered: { + let js = SharedData.latestJointState + if(js === undefined) { return } diff --git a/xbot2_gui/Monitoring/Monitoring.js b/xbot2_gui/Monitoring/Monitoring.js index 3284267..fb4138f 100644 --- a/xbot2_gui/Monitoring/Monitoring.js +++ b/xbot2_gui/Monitoring/Monitoring.js @@ -23,7 +23,7 @@ function jsCallback(js) { addJointStatePoint(livePlot, js) - for(let aux of js.aux_types) { + for(let aux of Object.keys(js.aux)) { barPlot.addAuxType(aux) } @@ -37,7 +37,7 @@ function jsCallback(js) { } vbatt = js.vbatt - iload = js.iload + iload = js.ibatt } @@ -102,12 +102,12 @@ function addJointStatePoint(livePlot, msg) { } // recompute jIndex if needed - if(msg.name[props.jIndex] !== props.jName) { - props.jIndex = msg.name.indexOf(props.jName) + if(SharedData.jointNames[props.jIndex] !== props.jName) { + props.jIndex = SharedData.jointNames.indexOf(props.jName) } // compute relative time - let t = msg.stamp + let t = msg.stamp ?? appData.getTimeNs() * 1e-9 if(livePlot.initialTime < 0) { livePlot.initialTime = t diff --git a/xbot2_gui/Monitoring/Monitoring.qml b/xbot2_gui/Monitoring/Monitoring.qml index a267728..f8a14bf 100644 --- a/xbot2_gui/Monitoring/Monitoring.qml +++ b/xbot2_gui/Monitoring/Monitoring.qml @@ -26,7 +26,7 @@ MultiPaneResponsiveLayout { property real iload LayoutClassHelper { - id: lay + id: layout targetWidth: root.width } @@ -50,8 +50,8 @@ MultiPaneResponsiveLayout { width: parent.width - rows: lay.compact ? -1 : 1 - columns: lay.compact ? 1 : -1 + rows: layout.compact ? -1 : 1 + columns: layout.compact ? 1 : -1 rowSpacing: 8 columnSpacing: 8 @@ -141,6 +141,13 @@ MultiPaneResponsiveLayout { jointState.selectJoint(jointName) jointCommand.selectJoint(jointName) } + + onSelectedJointsChanged: { + jointCommand.ctrlJoints = selectedJoints + loader.item.selectedJoints = selectedJoints + } + + enableMultipleSelection: jointCommand.enableMultipleSelection } } @@ -199,21 +206,42 @@ MultiPaneResponsiveLayout { onJointClicked: function(jointName) { jointState.selectJoint(jointName) - jointCommand.selectJoint(jointName) + } + onSelectedJointsChanged: { + barPlot.selectedJoints = selectedJoints + jointCommand.ctrlJoints = selectedJoints + } + + enableMultipleSelection: jointCommand.enableMultipleSelection + } } JointCommandCard { id: jointCommand + collapsed: true Layout.fillWidth: true client: root.client robotCmd: loader.item.robotCmd onResetCmd: robotViewer.resetCmd() onCmdChanged: robotViewer.showRobotCmd = true enabled: jointDevice.jointActive + // ctrlJoints: loader.item.selectedJoints + onJointRemoved: { + barPlot.selectedJoints = ctrlJoints + loader.item.selectedJoints = ctrlJoints + } + } + + Gripper { + + collapsed: true + Layout.fillWidth: true + visible: gripperNames.length > 0 + } } diff --git a/xbot2_gui/Monitoring/RobotModelViewer.js b/xbot2_gui/Monitoring/RobotModelViewer.js deleted file mode 100644 index 290d579..0000000 --- a/xbot2_gui/Monitoring/RobotModelViewer.js +++ /dev/null @@ -1,50 +0,0 @@ -function updateViewerState(js, robot, fieldName) { - - if(robot.ndof === 0) { - return - } - - robot.q = updateViewerQ(js, - robot.jointNames, - fieldName, - [...robot.q]) - -} - - -function updateViewerQ(js, jointNames, fieldName, q) { - - for(let i = 0; i < js.name.length; i++) { - - let name = js.name[i] - let idx = jointNames.indexOf(name) - if(idx < 0) - { - continue - } - - q[idx] = js[fieldName][i] - - } - - return q -} - - -function sendCommand(jointName, cmd) { - - client.doRequestAsync('PUT', - `/joint_command/goto/${jointName}?qref=${cmd}&time=${3}`) - .then((response) => trjCmdBtn.running = false) - .catch((err) => console.error(err)) - -} - -function stopCommand(jointName, cmd) { - - client.doRequestAsync('POST', - `/joint_command/goto/stop`) - .then((response) => trjCmdBtn.running = false) - .catch((err) => console.error(err)) - -} diff --git a/xbot2_gui/Monitoring/RobotModelViewer.qml b/xbot2_gui/Monitoring/RobotModelViewer.qml deleted file mode 100644 index 7dac289..0000000 --- a/xbot2_gui/Monitoring/RobotModelViewer.qml +++ /dev/null @@ -1,129 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import QtQuick.Controls - -import Qt3D.Core -import Qt3D.Render -import Qt3D.Input -import Qt3D.Logic -import Qt3D.Extras -import Qt3D.Animation -import QtQuick.Scene2D -import QtQuick.Scene3D - - -import Viewer3D -import Main -import "/qt/qml/Main/sharedData.js" as SharedData -import "RobotModelViewer.js" as Logic - -Viewer3D { - - property ClientEndpoint client - property alias robotState: robotState - property alias robotCmd: robotCmd - - function updateRobotState(js, robot, fieldName) { - Logic.updateViewerState(js, robot, fieldName) - } - - function resetCmd() { - Logic.updateViewerState(SharedData.latestJointState, - robotCmd, - 'posRef') - } - - - // private - id: root - - nodes: [ - RobotModelNode { - id: robotState - client: root.client - visible: stateCheck.checked - color: 'white' - - onModelChanged: { - Logic.updateViewerState(SharedData.latestJointState, - robotState, - 'linkPos') - } - }, - - RobotModelNode { - id: robotCmd - client: root.client - visible: cmdCheck.checked - color: 'red' - - onModelChanged: { - Logic.updateViewerState(SharedData.latestJointState, - robotCmd, - 'posRef') - } - } - ] - - GridLayout { - - id: ctrlGrid - - anchors { - top: parent.top - bottom: parent.bottom - left: parent.left - margins: 0 - } - - columns: 2 - - columnSpacing: 8 - rowSpacing: 4 - - CheckBox { - id: stateCheck - text: 'Show state robot' - Layout.columnSpan: 2 - checked: true - checkable: true - } - - CheckBox { - id: cmdCheck - text: 'Show command robot' - Layout.columnSpan: 2 - checked: true - checkable: true - } - - Button { - Layout.columnSpan: 2 - Layout.fillWidth: true - text: 'Reload' - onClicked: { - robotState.createViewer() - robotCmd.createViewer() - } - } - - Button { - Layout.columnSpan: 2 - Layout.fillWidth: true - text: 'Clear Cache' - onClicked: { - robotState.clearCache() - robotCmd.clearCache() - } - } - - Item { - Layout.fillHeight: true - } - } - - Component.onCompleted: { - robotCmd.createViewer() - robotState.createViewer() - } -} diff --git a/xbot2_gui/Monitoring/SingleJointState/SingleJointState1.qml b/xbot2_gui/Monitoring/SingleJointState/SingleJointState1.qml index 9eaa1da..40e1103 100644 --- a/xbot2_gui/Monitoring/SingleJointState/SingleJointState1.qml +++ b/xbot2_gui/Monitoring/SingleJointState/SingleJointState1.qml @@ -13,7 +13,7 @@ Item { property list jointNames: SharedData.jointNames function setJointStateMessage(js) { - for(let aux of js.aux_types) { + for(let aux of Object.keys(js.aux)) { if(auxTypes.indexOf(aux) < 0) { fieldsModel.append( { @@ -291,8 +291,6 @@ Item { target: updTimer function onTriggered() { - - if(shortName === '') { return } diff --git a/xbot2_gui/Network/CMakeLists.txt b/xbot2_gui/Network/CMakeLists.txt index ea91d94..d93fa5f 100644 --- a/xbot2_gui/Network/CMakeLists.txt +++ b/xbot2_gui/Network/CMakeLists.txt @@ -7,7 +7,11 @@ qt_add_qml_module(xbot2_gui_network SOURCES udpsocket.h udpsocket.cpp + websocket.h + websocket.cpp ) +target_link_libraries(xbot2_gui_network PRIVATE Qt6::WebSockets) + target_link_libraries(xbot2_gui PRIVATE xbot2_gui_networkplugin) diff --git a/xbot2_gui/Network/udpsocket.cpp b/xbot2_gui/Network/udpsocket.cpp index 25842fd..ca97673 100644 --- a/xbot2_gui/Network/udpsocket.cpp +++ b/xbot2_gui/Network/udpsocket.cpp @@ -85,9 +85,11 @@ void UdpSocket::readyRead() { _dg = _sock.receiveDatagram(); - QString decoded_data(_dg.data()); + emit binaryMessageReceived(_dg.data()); - emit textMessageReceived(decoded_data); + // QString decoded_data(_dg.data()); + + // emit textMessageReceived(decoded_data); } } diff --git a/xbot2_gui/Network/udpsocket.h b/xbot2_gui/Network/udpsocket.h index 77f44c9..2b15177 100644 --- a/xbot2_gui/Network/udpsocket.h +++ b/xbot2_gui/Network/udpsocket.h @@ -49,6 +49,8 @@ class UdpSocket : public QObject void addressChanged(); + void binaryMessageReceived(QByteArray data); + void textMessageReceived(QString msg); void boundChanged(bool); diff --git a/xbot2_gui/Network/websocket.cpp b/xbot2_gui/Network/websocket.cpp new file mode 100644 index 0000000..2b1843f --- /dev/null +++ b/xbot2_gui/Network/websocket.cpp @@ -0,0 +1,168 @@ +#include "websocket.h" + +WebSocketWorker::WebSocketWorker(QObject *parent) + : QObject(parent) +{ + +} + +void WebSocketWorker::initialize() +{ + qInfo("initializing websocket..."); + + _ws = new QWebSocket("", QWebSocketProtocol::VersionLatest, this); + + connect(_ws, &QWebSocket::connected, this, &WebSocketWorker::connected); + + connect(_ws, &QWebSocket::disconnected, this, [this]() { + emit disconnected(); + _active = false; + emit activeChanged(_active); + }); + + connect(_ws, &QWebSocket::binaryMessageReceived, this, &WebSocketWorker::binaryMessageReceived); + + connect(_ws, &QWebSocket::stateChanged, this, [](QAbstractSocket::SocketState ss) { + qInfo() << "ws state changed: " << ss; + }); + + connect(_ws, &QWebSocket::errorOccurred, this, [this](QAbstractSocket::SocketError se) { + qInfo() << "socket error: " << _ws->errorString(); + emit errorOccurred(_ws->errorString()); + }); + + qInfo("...done"); +} + +void WebSocketWorker::setUrl(QUrl url) +{ + if (!_ws) + { + qFatal("ws not initialized"); + return; + } + + if (_url == url) + { + return; + } + + _url = url; + + qInfo() << "set url" << _url; + + if (_active) { + _ws->close(); + _ws->open(_url); + } + + emit urlChanged(_url); +} + +void WebSocketWorker::setActive(bool active) +{ + if (_active == active) { + return; + } + + qInfo() << "set active" << active; + + _active = active; + + if (_active) + { + _ws->open(_url); + } + else + { + _ws->close(); + } + + emit activeChanged(_active); + +} + +void WebSocketWorker::sendTextMessage(QString msg) +{ + if (!_ws) { + qWarning("try to send text message from null websocket"); + return; + } + + _ws->sendTextMessage(msg); +} + +WebSocketAsync::WebSocketAsync(QObject *parent) + : QObject(parent) +{ + // create worker + auto worker = new WebSocketWorker; + + // move worker to thread + worker->moveToThread(&_thread); + + // initialize + connect(&_thread, &QThread::started, + worker, &WebSocketWorker::initialize); + + // connect signals and slots + connect(this, &WebSocketAsync::setUrlRequested, worker, &WebSocketWorker::setUrl); + + connect(worker, &WebSocketWorker::urlChanged, this, [this](QUrl url) { + _url_cached = url; + emit urlChanged(); + }); + + connect(this, &WebSocketAsync::setActiveRequested, worker, &WebSocketWorker::setActive); + + connect(worker, &WebSocketWorker::activeChanged, this, [this](bool active) { + _active_cached = active; + emit activeChanged(); + }); + + connect(worker, &WebSocketWorker::connected, this, &WebSocketAsync::connected); + + connect(worker, &WebSocketWorker::disconnected, this, &WebSocketAsync::disconnected); + + connect(worker, &WebSocketWorker::errorOccurred, this, &WebSocketAsync::errorOccurred); + + connect(worker, + &WebSocketWorker::binaryMessageReceived, + this, + &WebSocketAsync::binaryMessageReceived); + + connect(this, &WebSocketAsync::sendTextMessage, worker, &WebSocketWorker::sendTextMessage); + + + // start thread +#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0) + _thread.setServiceLevel(QThread::QualityOfService::Eco); +#endif + _thread.start(QThread::Priority::LowPriority); +} + +void WebSocketAsync::setUrl(QUrl _url) +{ + emit setUrlRequested(_url); +} + +void WebSocketAsync::setActive(bool value) +{ + emit setActiveRequested(value); +} + +QUrl WebSocketAsync::url() const +{ + return _url_cached; +} + +bool WebSocketAsync::active() const +{ + return _active_cached; +} + +WebSocketAsync::~WebSocketAsync() +{ + _thread.quit(); + _thread.wait(); +} diff --git a/xbot2_gui/Network/websocket.h b/xbot2_gui/Network/websocket.h new file mode 100644 index 0000000..88e409b --- /dev/null +++ b/xbot2_gui/Network/websocket.h @@ -0,0 +1,102 @@ +#ifndef WEBSOCKET_H +#define WEBSOCKET_H + +#include +#include +#include + +class WebSocketWorker : public QObject +{ + Q_OBJECT + +public: + + WebSocketWorker(QObject *parent = nullptr); + +signals: + + void activeChanged(bool active); + + void errorOccurred(QString error); + + void connected(); + + void disconnected(); + + void urlChanged(QUrl url); + + void binaryMessageReceived(QByteArray msg); + +public slots: + + void initialize(); + + void setUrl(QUrl url); + + void setActive(bool active); + + void sendTextMessage(QString msg); + + +private: + + QWebSocket * _ws; + + bool _active = true; + + QUrl _url; +}; + +class WebSocketAsync : public QObject +{ + + Q_OBJECT + QML_ELEMENT + +public: + + WebSocketAsync(QObject *parent = nullptr); + + Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged FINAL) + + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged FINAL) + + void setUrl(QUrl _url); + + void setActive(bool value); + + QUrl url() const; + + bool active() const; + + ~WebSocketAsync(); + +signals: + + void activeChanged(); + + void errorOccurred(QString error); + + void connected(); + + void disconnected(); + + void urlChanged(); + + void binaryMessageReceived(QByteArray msg); + + void sendTextMessage(QString msg); + + void setUrlRequested(QUrl url); + + void setActiveRequested(bool active); + +private: + + QThread _thread; + QUrl _url_cached; + bool _active_cached = true; +}; + + +#endif // WEBSOCKET_H diff --git a/xbot2_gui/Protobuf/CMakeLists.txt b/xbot2_gui/Protobuf/CMakeLists.txt index 28da762..da95032 100644 --- a/xbot2_gui/Protobuf/CMakeLists.txt +++ b/xbot2_gui/Protobuf/CMakeLists.txt @@ -1,16 +1,35 @@ find_package(Qt6 COMPONENTS Protobuf + ProtobufQuick ) -set(PROTO_FILES - joint_states.proto - tlv.proto +add_library(xbot2_gui_proto STATIC) + +qt_add_qml_module(xbot2_gui_proto + URI Protobuf + VERSION 1.0 + QML_FILES + SOURCES + protobuf_deserialization.h + protobuf_deserialization.cpp + ) -qt_add_protobuf(protobuf_messages +qt_add_protobuf(xbot2_gui_msgs PROTO_FILES - ${PROTO_FILES} + ${CMAKE_SOURCE_DIR}/proto/generic.proto + ${CMAKE_SOURCE_DIR}/proto/jointstate.proto + ${CMAKE_SOURCE_DIR}/proto/text.proto + ${CMAKE_SOURCE_DIR}/proto/process_output.proto + ${CMAKE_SOURCE_DIR}/proto/theora_packet.proto QML - QML_URI xbot2_gui.msgs + QML_URI "xbot2_gui.msgs" ) + + +target_link_libraries(xbot2_gui_proto PRIVATE Qt6::Protobuf Qt6::ProtobufQuick xbot2_gui_msgs) + +target_link_libraries(xbot2_gui PRIVATE xbot2_gui_protoplugin xbot2_gui_msgs) + + diff --git a/xbot2_gui/Protobuf/joint_states.proto b/xbot2_gui/Protobuf/joint_states.proto deleted file mode 100644 index 6933946..0000000 --- a/xbot2_gui/Protobuf/joint_states.proto +++ /dev/null @@ -1,11 +0,0 @@ - -syntax = "proto3"; - -package xbot2_gui.msgs.joint_states; - -message JointStates { - repeated string name = 1; - repeated float motor_position = 2; - repeated float motor_velocity = 3; - repeated float effort = 4; -} diff --git a/xbot2_gui/Protobuf/protobuf_deserialization.cpp b/xbot2_gui/Protobuf/protobuf_deserialization.cpp new file mode 100644 index 0000000..fc94e2e --- /dev/null +++ b/xbot2_gui/Protobuf/protobuf_deserialization.cpp @@ -0,0 +1,119 @@ +#include "protobuf_deserialization.h" + +void ProtobufDeserializationWorker::processBinaryMessage(const QByteArray &msg) +{ + if (!_msg.deserialize(&_serializer, msg)) + { + qWarning().nospace() << "unable to deserialize datagram (" + << qToUnderlying(_serializer.lastError()) << ")" + << _serializer.lastErrorString(); + return; + } + + _counters.all++; + _bytes_recv.all += msg.size(); + + if (_msg.hasJointstate()) + { + _counters.js++; + _bytes_recv.js += msg.size(); + emit jointStateReceived(_msg.jointstate()); + } + else if (_msg.hasText()) + { + _counters.text++; + _bytes_recv.text += msg.size(); + emit textMessageReceived(_msg.text().text()); + } + else if(_msg.hasProcessOutput()) + { + _counters.proc++; + _bytes_recv.proc += msg.size(); + emit processOutputReceived(_msg.processOutput()); + } + else if(_msg.hasTheoraPacket()) + { + _counters.video++; + _bytes_recv.video += msg.size(); + emit theoraPacketReceived(_msg.theoraPacket()); + } + else + { + qWarning("empty protobuf msg received"); + } + + emit countersUpdated(_counters); + emit bytesRecvUpdated(_bytes_recv); +} + +ProtobufDeserialization::ProtobufDeserialization(QObject *parent) +{ + auto worker = new ProtobufDeserializationWorker; + + connect(this, + &ProtobufDeserialization::processBinaryMessage, + worker, + &ProtobufDeserializationWorker::processBinaryMessage); + + connect(worker, + &ProtobufDeserializationWorker::textMessageReceived, + this, + &ProtobufDeserialization::textMessageReceived); + + connect(worker, + &ProtobufDeserializationWorker::jointStateReceived, + this, + &ProtobufDeserialization::jointStateReceived); + + connect(worker, + &ProtobufDeserializationWorker::processOutputReceived, + this, + &ProtobufDeserialization::processOutputReceived); + + connect(worker, + &ProtobufDeserializationWorker::theoraPacketReceived, + this, + &ProtobufDeserialization::theoraPacketReceived); + + connect(worker, + &ProtobufDeserializationWorker::bytesRecvUpdated, + this, + [this](Counters br) + { + _bytes_recv = br; + emit recvBytesChanged(); + }); + + connect(worker, + &ProtobufDeserializationWorker::countersUpdated, + this, + [this](Counters br) + { + _num_msg = br; + emit numMsgChanged(); + }); + + worker->moveToThread(&_thread); +#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0) + _thread.setServiceLevel(QThread::QualityOfService::Eco); +#endif + + _thread.start(QThread::Priority::LowPriority); + +} + +ProtobufDeserialization::~ProtobufDeserialization() +{ + _thread.quit(); + _thread.wait(); +} + +Counters ProtobufDeserialization::recvBytes() const +{ + return _bytes_recv; +} + +Counters ProtobufDeserialization::numMsg() const +{ + return _num_msg; +} diff --git a/xbot2_gui/Protobuf/protobuf_deserialization.h b/xbot2_gui/Protobuf/protobuf_deserialization.h new file mode 100644 index 0000000..0a87759 --- /dev/null +++ b/xbot2_gui/Protobuf/protobuf_deserialization.h @@ -0,0 +1,116 @@ +#ifndef PROTOBUF_DESERIALIZATION_H +#define PROTOBUF_DESERIALIZATION_H + +#include +#include +#include + +#include + +#include "generic.qpb.h" + +class Counters { + + Q_GADGET + +public: + + Q_PROPERTY(int all MEMBER all); + Q_PROPERTY(int js MEMBER js); + Q_PROPERTY(int text MEMBER text); + Q_PROPERTY(int proc MEMBER proc); + Q_PROPERTY(int video MEMBER video); + QML_ELEMENT + + int all = 0; + int js = 0; + int text = 0; + int proc = 0; + int video = 0; +}; + +class ProtobufDeserializationWorker : public QObject +{ + Q_OBJECT + +public: + + void processBinaryMessage(const QByteArray& msg); + +signals: + + void textMessageReceived(const QString&); + + void jointStateReceived(const JointState&); + + void processOutputReceived(const ProcessOutput&); + + void theoraPacketReceived(const TheoraPacket&); + + void countersUpdated(Counters c); + + void bytesRecvUpdated(Counters c); + + +private: + + + QProtobufSerializer _serializer; + + Message _msg; + + Counters _counters; + + Counters _bytes_recv; + +}; + +class ProtobufDeserialization : public QObject +{ + Q_OBJECT + QML_ELEMENT + +public: + + ProtobufDeserialization(QObject * parent = nullptr); + + Q_PROPERTY(Counters recvBytes READ recvBytes NOTIFY recvBytesChanged FINAL) + + Q_PROPERTY(Counters numMsg READ numMsg NOTIFY numMsgChanged FINAL) + + ~ProtobufDeserialization(); + + Counters recvBytes() const; + + Counters numMsg() const; + + +signals: + + void processBinaryMessage(const QByteArray& msg); + + void textMessageReceived(const QString&); + + void jointStateReceived(const JointState&); + + void processOutputReceived(const ProcessOutput&); + + void theoraPacketReceived(const TheoraPacket&); + + void recvBytesChanged(); + + void numMsgChanged(); + +private: + + QThread _thread; + + Counters _bytes_recv, _num_msg; + + + + + +}; + +#endif // PROTOBUF_DESERIALIZATION_H diff --git a/xbot2_gui/Protobuf/tlv.proto b/xbot2_gui/Protobuf/tlv.proto deleted file mode 100644 index 146e3f4..0000000 --- a/xbot2_gui/Protobuf/tlv.proto +++ /dev/null @@ -1,16 +0,0 @@ - -syntax = "proto3"; - -package xbot2_gui.msgs.tlv; - -enum MessageType { - Coordinates = 0; - Temperature = 1; - WarningNotification = 2; -} - -// Protobuf messages imply inline data size. -message TlvMessage { - MessageType type = 1; - bytes value = 2; -} diff --git a/xbot2_gui/SharedData1.qml b/xbot2_gui/SharedData1.qml new file mode 100644 index 0000000..15a2089 --- /dev/null +++ b/xbot2_gui/SharedData1.qml @@ -0,0 +1,14 @@ +pragma Singleton + +import QtQuick + +import xbot2_gui.msgs + +Item { + + id: root + + property jointState latestJointState + property list jointNames + +} diff --git a/xbot2_gui/TestThings/CMakeLists.txt b/xbot2_gui/TestThings/CMakeLists.txt index c8dc4cc..6466124 100644 --- a/xbot2_gui/TestThings/CMakeLists.txt +++ b/xbot2_gui/TestThings/CMakeLists.txt @@ -12,7 +12,7 @@ qt_add_qml_module(xbot2_gui_testthings MotionTabPlot.qml MotionTab.js ConfigureMotorPopup.qml - QML_FILES AnimatedRectangle.qml + AnimatedRectangle.qml ) target_link_libraries(xbot2_gui PRIVATE xbot2_gui_testthingsplugin) diff --git a/xbot2_gui/TestThings/Playground2.qml b/xbot2_gui/TestThings/Playground2.qml index bf1487f..7389395 100644 --- a/xbot2_gui/TestThings/Playground2.qml +++ b/xbot2_gui/TestThings/Playground2.qml @@ -1,15 +1,8 @@ import QtQuick import QtQuick.Controls -import QtCharts +import QtQuick.Layouts import Main -import RobotModel -import ViewerQuick3D - - -import QtQuick.Layouts -import QtQuick3D -import QtQuick3D.Helpers @@ -18,78 +11,162 @@ Item { id: root property ClientEndpoint client + // function appendText(i, txt) { + // txt = `` + txt + '' + // rep.itemAt(i).model.append({'txt': txt}) + // rep.itemAt(i).scrollToEnd() + // } - View3D { - id: v3d - anchors.fill: parent - camera: camera + // ColumnLayout { - environment: SceneEnvironment { - clearColor: "blue" - antialiasingMode: SceneEnvironment.MSAA -// backgroundMode: SceneEnvironment.Color + // anchors.fill: parent - } + // TabBar { + // id: bar + // Layout.fillWidth: true - Node { + // TabButton { + // text: 'A' + // } - id: originNode - position: Qt.vector3d(2.0, 0, 0.0) - eulerRotation: Qt.vector3d(90, 0, 0) + // TabButton { + // text: 'B' + // } + // } - PerspectiveCamera { - id: camera + // StackLayout { - clipNear: 0.05 - clipFar: 2 - fieldOfView: 90 - } + // currentIndex: bar.currentIndex - } + // Layout.fillHeight: true + // Layout.fillWidth: true - OrbitCameraController { - anchors.fill: parent - origin: originNode - camera: camera - } + // StackLayout { - DirectionalLight { - position: Qt.vector3d(-5, 5, -1) - color: Qt.rgba(0.4, 0.2, 0.6, 1.0) - ambientColor: Qt.rgba(0.1, 0.1, 0.1, 1.0) - } + // Layout.fillHeight: true + // Layout.fillWidth: true - PointLight { - position: Qt.vector3d(0, 2, 2) - color: Qt.rgba(1, 1, 1, 1.0) - ambientColor: Qt.rgba(0.2, 0.2, 0.2, 1.0) - } - PointLight { - position: Qt.vector3d(0, -2, 2) - color: Qt.rgba(1, 1, 1, 1.0) - ambientColor: Qt.rgba(0.2, 0.2, 0.2, 1.0) - } + // Flipable { + // id: flip + // property bool flipped: false + // Layout.fillHeight: true + // Layout.fillWidth: true - RobotModelNode { - client: root.client - } + // front: StackLayout { - Model { - scale: Qt.vector3d(10, 10, 10) - geometry: GridGeometry { - horizontalLines: 100 - verticalLines: 100 - } - materials: [ DefaultMaterial { } ] - } + // height: flip.height + // width: flip.width + // currentIndex: pageSpin.value + // Repeater { + // id: rep + // model: 5 - } + // Item { + // property alias listview: view + // property alias model: listModel + // required property int index + // Layout.fillHeight: true + // Layout.fillWidth: true + // implicitHeight: view.implicitHeight + // implicitWidth: view.implicitWidth + + // function scrollToEnd() { + // Qt.callLater(view.positionViewAtEnd) + // } + + // ListModel { + // id: listModel + // } + + // ListView { + + // anchors.fill: parent + + // id: view + // model: listModel + // delegate: TextEdit { + // text: txt + // width: view.width + // wrapMode: Text.WrapAnywhere + // readOnly: true + // textFormat: TextEdit.RichText + // // color: palette.active.text + // } + // implicitHeight: contentHeight + // spacing: 1 + // clip: true + // ScrollBar.vertical: ScrollBar { + // active: true + // } - Component.onCompleted: { - camera.lookAt(Qt.vector3d(0, 0, 0)) + // } + + // } + // } + // } + + // transform: Rotation { + // id: rotation + // origin.x: flip.width/2 + // origin.y: flip.height/2 + // axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis + // angle: 0 // the default angle + // } + + // states: State { + // name: "back" + // PropertyChanges { target: rotation; angle: 180 } + // when: flip.flipped + // } + + // transitions: Transition { + // NumberAnimation { target: rotation; property: "angle"; duration: 400 } + // } + + // } + + // } + + // Rectangle { + // color: 'red' + // } + + // } + + // RowLayout { + + // Layout.fillWidth: true + + // Button { + // text: 'Generate a lot of text' + // Layout.fillWidth: true + // onClicked: { + // for(let i = 0; i < 10000; i++) { + // appendText(pageSpin.value, 'Example text Example text Example text Example text Example text Example text Example text Example text Example text Example text Example text Example text Example text ') + // } + // } + // } + + // Button { + // text: 'Flip' + // onClicked: flip.flipped = !flip.flipped + // } + + // SpinBox { + // from: 0 + // to: 5 + // id: pageSpin + // } + + // } + // } + + + LauncherConsoleItem2 { + anchors.fill: parent } } diff --git a/xbot2_gui/Video/VideoStream.js b/xbot2_gui/Video/VideoStream.js index 68d3740..3d6a526 100644 --- a/xbot2_gui/Video/VideoStream.js +++ b/xbot2_gui/Video/VideoStream.js @@ -1,5 +1,18 @@ +function _base64ToArrayBuffer(base64) { + return appData.base64ToBytes(base64) +} + function setStream (stream_name, video) { + + // request disconnection from previous video stream + console.log('requesting video stream disconnection via ws..') + client.sendTextMessage(JSON.stringify({'type': 'video_request', + 'operation': 'disconnect', + 'stream_name': video.streamName})) + console.log('..done') + let body = JSON.stringify({'stream_name': stream_name}) + client.doRequest('PUT', '/video/set_stream', body, function(msg) { @@ -10,9 +23,24 @@ function setStream (stream_name, video) { console.log(`enabled stream ${stream_name}, setting headers..`) + // convert hdr.data from base64 + for(let i = 0; i < 3; i++) { + msg.hdr[i].data = _base64ToArrayBuffer(msg.hdr[i].data) + } + video.setTheoraHeader(msg.hdr) + + video.streamName = stream_name + + // request video messages via ws + console.log(`requesting video stream ${stream_name} via ws..`) + client.sendTextMessage(JSON.stringify({'type': 'video_request', + 'stream_name': stream_name})) + console.log('..done') } ) + + } function refreshNames(video = undefined, cb = undefined) { diff --git a/xbot2_gui/Video/VideoStream.qml b/xbot2_gui/Video/VideoStream.qml index 5eacab8..cb32068 100644 --- a/xbot2_gui/Video/VideoStream.qml +++ b/xbot2_gui/Video/VideoStream.qml @@ -10,14 +10,14 @@ Item { // public function setTheoraHeader(hdr) { for(let i = 0; i < 3; i++) { + console.log(`got bos=${hdr[i].bOS} eos=${hdr[i].eOS} pktno=${hdr[i].packetno}`) video.setTheoraPacket(hdr[i].data, - hdr[i].b_o_s, - hdr[i].e_o_s, + hdr[i].bOS, + hdr[i].eOS, hdr[i].granulepos, hdr[i].packetno) } _hdr_recv = true - console.log(streamName + ': set headers done') } function setTheoraPacket(msg) { @@ -27,8 +27,8 @@ Item { } video.setTheoraPacket(msg.data, - msg.b_o_s, - msg.e_o_s, + msg.bOS, + msg.eOS, msg.granulepos, msg.packetno) } @@ -37,6 +37,7 @@ Item { id: root property bool _hdr_recv: false + property string streamName // force video painter to respect the source aspect ratio AspectRatio { diff --git a/xbot2_gui/Video/videostreampainter.cpp b/xbot2_gui/Video/videostreampainter.cpp index 5bd2a6a..9a735fa 100644 --- a/xbot2_gui/Video/videostreampainter.cpp +++ b/xbot2_gui/Video/videostreampainter.cpp @@ -157,14 +157,14 @@ void theora2qimage(const th_ycbcr_buffer& ycbcr_buffer, using hrc = std::chrono::high_resolution_clock; -void VideoStreamPainter::setTheoraPacket(const QByteArray &datab64, +void VideoStreamPainter::setTheoraPacket(const QByteArray &data, int b_o_s, int e_o_s, long granulepos, long packetno) { - _decoder->addPacket(datab64, b_o_s, e_o_s, granulepos, packetno); + _decoder->addPacket(data, b_o_s, e_o_s, granulepos, packetno); packetReady(); @@ -423,7 +423,7 @@ void Decoder::onPacketReady() pkt = _q.dequeue(); - if(pkt.datab64.size() == 0) + if(pkt.data.size() == 0) { return; } @@ -434,14 +434,13 @@ void Decoder::onPacketReady() auto tic = hrc::now(); // create ogg packet - auto data = QByteArray::fromBase64(pkt.datab64); ogg_packet oggpacket; - oggpacket.bytes = data.size(); + oggpacket.bytes = pkt.data.size(); oggpacket.b_o_s = pkt.b_o_s; oggpacket.e_o_s = pkt.e_o_s; oggpacket.granulepos = pkt.granulepos; oggpacket.packetno = pkt.packetno; - oggpacket.packet = reinterpret_cast(data.data()); + oggpacket.packet = reinterpret_cast(pkt.data.data()); tic = hrc::now(); diff --git a/xbot2_gui/Video/videostreampainter.h b/xbot2_gui/Video/videostreampainter.h index 21c7c1e..0860230 100644 --- a/xbot2_gui/Video/videostreampainter.h +++ b/xbot2_gui/Video/videostreampainter.h @@ -56,7 +56,7 @@ public slots: VideoStreamPainter * _parent; struct Packet { - QByteArray datab64; + QByteArray data; int b_o_s; int e_o_s; long granulepos; diff --git a/xbot2_gui/ViewerQuick3D/CustomMesh.qml b/xbot2_gui/ViewerQuick3D/CustomMesh.qml index c364174..f2a21ea 100644 --- a/xbot2_gui/ViewerQuick3D/CustomMesh.qml +++ b/xbot2_gui/ViewerQuick3D/CustomMesh.qml @@ -23,6 +23,7 @@ Node { property real cylinderLength property string parentJointName + property bool isSelected: false // private @@ -40,13 +41,13 @@ Node { id: model visible: true pickable: true - property bool isPicked: false property alias parentJointName: root.parentJointName + property alias isSelected: root.isSelected materials: [ PrincipledMaterial { id: material - baseColor: model.isPicked ? - Qt.lighter(root.color) : + baseColor: root.isSelected ? + Qt.lighter(root.color, 1.7) : root.color metalness: 0 roughness: 0 @@ -91,8 +92,6 @@ Node { cachedVisual.addMesh(encodeURIComponent(meshUri), `http://${client.hostname}:${client.port}/visual/get_mesh/${encodeURIComponent(meshUri)}`) - - } diff --git a/xbot2_gui/ViewerQuick3D/RobotModelNode.qml b/xbot2_gui/ViewerQuick3D/RobotModelNode.qml index 74da583..58cc662 100644 --- a/xbot2_gui/ViewerQuick3D/RobotModelNode.qml +++ b/xbot2_gui/ViewerQuick3D/RobotModelNode.qml @@ -23,6 +23,8 @@ Node { property var q: Array(ndof).fill(0.0) + property list selectedJoints + signal modelChanged() onQChanged: updateQ(q) @@ -65,6 +67,7 @@ Node { visible: root.visible client: root.client axesVisible: root.axesVisible + isSelected: root.selectedJoints.indexOf(parentJointName) >= 0 } } diff --git a/xbot2_gui/ViewerQuick3D/RobotModelViewer.js b/xbot2_gui/ViewerQuick3D/RobotModelViewer.js index 290d579..925965d 100644 --- a/xbot2_gui/ViewerQuick3D/RobotModelViewer.js +++ b/xbot2_gui/ViewerQuick3D/RobotModelViewer.js @@ -1,3 +1,5 @@ +.import "/qt/qml/Main/sharedData.js" as SharedData + function updateViewerState(js, robot, fieldName) { if(robot.ndof === 0) { @@ -14,9 +16,11 @@ function updateViewerState(js, robot, fieldName) { function updateViewerQ(js, jointNames, fieldName, q) { - for(let i = 0; i < js.name.length; i++) { + let jsname = SharedData.jointNames + + for(let i = 0; i < jsname.length; i++) { - let name = js.name[i] + let name = jsname[i] let idx = jointNames.indexOf(name) if(idx < 0) { diff --git a/xbot2_gui/ViewerQuick3D/RobotModelViewer.qml b/xbot2_gui/ViewerQuick3D/RobotModelViewer.qml index f6427bf..c97fcb1 100644 --- a/xbot2_gui/ViewerQuick3D/RobotModelViewer.qml +++ b/xbot2_gui/ViewerQuick3D/RobotModelViewer.qml @@ -20,6 +20,9 @@ Rectangle { signal jointClicked(string jointName) + property alias selectedJoints: robotState.selectedJoints + property bool enableMultipleSelection: false + function updateRobotState(js, robot, fieldName) { Logic.updateViewerState(js, robot, fieldName) } @@ -30,6 +33,10 @@ Rectangle { 'posRef') } + function resetView() { + originNode.resetView() + } + // id: root @@ -37,20 +44,29 @@ Rectangle { z: 10 + padding: 8 + contentItem: GridLayout { - columns: 2 + columns: 1 CheckBox { id: showAxesChk Layout.fillWidth: true - Layout.columnSpan: 2 + Layout.preferredHeight: 40 + // Layout.columnSpan: 2 text: 'Show axes' } CheckBox { id: showCmdChk Layout.fillWidth: true - Layout.columnSpan: 2 + Layout.preferredHeight: 40 + // Layout.columnSpan: 2 text: 'Show command robot' } + Button { + text: 'Reset view' + onClicked: root.resetView() + Layout.fillWidth: true + } } } @@ -76,6 +92,15 @@ Rectangle { eulerRotation.y: 40 eulerRotation.x: -40 + function resetView() { + x = 50 + y = 100 + z = 50 + eulerRotation.y = 40 + eulerRotation.x = -40 + cameraPerspectiveTwo.z = 200 + } + } Axes3D { @@ -93,7 +118,7 @@ Rectangle { } DirectionalLight { - ambientColor: Qt.rgba(0.5, 0.5, 0.5, 1.0) + ambientColor: Qt.rgba(-0.5, -0.5, 0.5, 1.0) brightness: 1 eulerRotation.x: 25 } @@ -144,20 +169,29 @@ Rectangle { MouseArea { anchors.fill: parent - property var lastPicked: undefined - onClicked: (mouse) => { - try { - lastPicked.isPicked = false - } - catch(err) {} + // property var lastPicked: undefined + onClicked: function(mouse) { + // try { + // lastPicked.isPicked = false + // } + // catch(err) {} var result = view3d.pick(mouse.x, mouse.y); var pickedObject = result.objectHit; - pickedObject.isPicked = !pickedObject.isPicked; + // pickedObject.isPicked = !pickedObject.isPicked; console.log(pickedObject.parentJointName) root.jointClicked(pickedObject.parentJointName) - lastPicked = pickedObject + if(pickedObject.isSelected) { + root.selectedJoints = root.selectedJoints.filter(item => item !== pickedObject.parentJointName) + } + else if(enableMultipleSelection) { + root.selectedJoints.push(pickedObject.parentJointName) + } + else { + root.selectedJoints = [pickedObject.parentJointName] + } + } } } diff --git a/xbot2_gui/android/build.gradle b/xbot2_gui/android/build.gradle index fbd0a48..59ab084 100644 --- a/xbot2_gui/android/build.gradle +++ b/xbot2_gui/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.4.1' + classpath 'com.android.tools.build:gradle:8.4.1' } } @@ -42,6 +42,9 @@ android { // Extract native libraries from the APK packagingOptions.jniLibs.useLegacyPackaging true + namespace="it.iit.hhcm.xbot2_gui_client" + + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' diff --git a/xbot2_gui/android/gradle/wrapper/gradle-wrapper.properties b/xbot2_gui/android/gradle/wrapper/gradle-wrapper.properties index ac72c34..a80b22c 100644 --- a/xbot2_gui/android/gradle/wrapper/gradle-wrapper.properties +++ b/xbot2_gui/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/xbot2_gui/main.cpp b/xbot2_gui/main.cpp index 91e5392..b031972 100644 --- a/xbot2_gui/main.cpp +++ b/xbot2_gui/main.cpp @@ -76,6 +76,11 @@ class AppData : public QObject return true; } + Q_INVOKABLE QByteArray base64ToBytes(QString b64) + { + return QByteArray::fromBase64(b64.toUtf8()); + } + Q_INVOKABLE static QUrl fromUserInput(const QString& userInput) { if (userInput.isEmpty()) @@ -161,6 +166,7 @@ int main(int argc, char *argv[]) // set app properties QApplication app(argc, argv); auto font = app.font(); + qInfo() << "FONT" << font; font.setPixelSize(12); app.setFont(font); diff --git a/xbot2_gui/main.qml b/xbot2_gui/main.qml index f67527e..a6dadc7 100644 --- a/xbot2_gui/main.qml +++ b/xbot2_gui/main.qml @@ -86,6 +86,7 @@ ApplicationWindow { z: 200 opacity: 0.8 visible: CommonProperties.config.showMonWidget + width: expanded ? 94 : implicitWidth } @@ -177,7 +178,7 @@ ApplicationWindow { } PageItem { - name: "Tuning" + name: "Parameters" page: "/qt/qml/Monitoring/Parameters.qml" iconText: MaterialSymbolNames.tune iconFont: syms.font.family