diff --git a/docs/0gitee/bigscreen/index.html b/docs/0gitee/bigscreen/index.html new file mode 100644 index 0000000..f1ce071 --- /dev/null +++ b/docs/0gitee/bigscreen/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/0gitee/iotsystem/index.html b/docs/0gitee/iotsystem/index.html new file mode 100644 index 0000000..78178c8 --- /dev/null +++ b/docs/0gitee/iotsystem/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/0gitee/video_system/index.html b/docs/0gitee/video_system/index.html new file mode 100644 index 0000000..6f82a3b --- /dev/null +++ b/docs/0gitee/video_system/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/0github/bigscreen/index.html b/docs/0github/bigscreen/index.html new file mode 100644 index 0000000..83f6cc3 --- /dev/null +++ b/docs/0github/bigscreen/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/0github/iotsystem/index.html b/docs/0github/iotsystem/index.html new file mode 100644 index 0000000..f2a2519 --- /dev/null +++ b/docs/0github/iotsystem/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/0github/video_system/index.html b/docs/0github/video_system/index.html new file mode 100644 index 0000000..1431684 --- /dev/null +++ b/docs/0github/video_system/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/bigscreen.html b/docs/bigscreen.html new file mode 100644 index 0000000..7d2a56a --- /dev/null +++ b/docs/bigscreen.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/bigscreen/index.html b/docs/bigscreen/index.html new file mode 100644 index 0000000..bb085e0 --- /dev/null +++ b/docs/bigscreen/index.html @@ -0,0 +1,752 @@ + + + + + +可视化大屏系统开发及使用手册 + +
+
  • 0 前言说明

    0.1 编译说明

    1. 编译后可执行文件在和源码文件夹同级目录的bin文件夹下,配置文件bigscreen.ini文件在可执行文件所在目录下的config文件夹下,数据库文件在可执行文件所在目录下的db文件夹下。
    2. 编译后记得将源码下的file目录下(切记是file目录下而不是file目录)的所有文件复制到可执行文件同一目录。
    3. 大屏中用到了视频监控模块,所以还需要拷贝ffmpeg的动态库文件到可执行文件同一目录,编译成功后记得将dll_ffmpeg4(64位的构建套件对应的是dll_ffmpeg4_64)对应目录下的库复制到可执行文件同一目录。如果是linux系统则那些exe和dll都不需要拷贝,那个是ffmpeg对应win的运行库,linux上采用的静态库。
    4. dll+lib 链接: https://pan.baidu.com/s/13LDRu6mXC6gaADtrGprNVA 提取码: ujm7。
    5. 如果程序异常结束并提示 miniblink.dll 文件不存在请先拷贝,你还需要在dll+lib下载地址的地方找到 dll_miniblink.zip 下载并解压出来拷贝文件到可执行文件目录。一般这个是因为你用的mingw编译器,win+qt5.6以上+mingw编译器,没有浏览器控件,采用的miniblink第三方浏览器控件。
    6. 如果是linux系统,记得将ffmpeg目录下的linuxlib 找到你系统的版本位数,将文件夹版本位数去掉,比如你操作系统是ubuntu16.04 64位的,则将linuxlib16.04.64改成linuxlib即可,这些是ffmpeg对应linux系统的静态库。
    7. 当然你也可以选择不启用视频监控模块,只需要将pro中的videoffmpeg改成videoffmpeg1即可。
    8. 目录下的bigscreen.sql为数据库脚本,可以在系统设置中单击初始化数据来执行。bigscreen_mysql.sql脚本为Navicat工具对应的导入脚本。
    9. 如果发现地图打不开,请先确认file目录下的所有文件有没有拷贝过去,还有就是将MapBaiDu::Instance()->setSaveFile(false); 改成true;
    10. 如果是用vs+qt可能报错 error LNK2026: 模块对于 SAFESEH 映像是不安全的。

    0.2 版本说明

    V20220718

    1. 中间地图模块增加隐藏地图功能,只保留最顶部的标题栏。
    2. 增加表格看板模块,通用的表格窗体模块,指定表名、列名、列宽即可,自动刷新对应表数据。可以作为ERP库存电子看板使用。

    V20220417

    1. 设备状态监测增加进度条控件,每个设备都有一个进度条对应完成进度。
    2. 设备状态数据库增加字段progress存储进度,flicker控制是否闪烁,1表示闪烁。
    3. 增加大量的代码注释。

    V20211015

    1. 修正停靠窗体鼠标右键弹出菜单复选框样式、右键菜单子菜单三角形图标样式。
    2. 修正全局复选框样式,比如用户管理中勾选用户权限。
    3. 顶部banner改成透明度20%,这样自适应多种背景颜色风格。
    4. 图片文件夹将image改成了image_bigscreen,以便和其他系统区分。
    5. 布局文件夹将layout改成了layout_bigscreen,以便和其他系统区分。
    6. 默认布局文件夹是1920x1080分辨率。用户可以自己在不同分辨率下调整好布局生成布局文件,然后拷贝布局文件夹进行备份。
    7. 将其他几种分辨率布局文件夹删除,去掉了这种机制,后期采用不同用户对应不同布局文件夹的形式。
    8. 将相关文档和布局文件移动到源码下的doc目录。
    9. 系统设置新增全屏模式参数,默认全屏,不全屏则采用最大化显示,有些系统为了不遮挡任务栏需要最大化显示,也方便截图。
    10. 增加悬浮窗体分隔条样式,限定宽度和颜色等。

    V20210323

    1. 编写开发和使用说明书。
    2. 系统设置增加视频拉伸、视频循环播放等配置参数。
    3. 增加多屏幕支持,自动识别多个屏幕。
    4. 新增2K分辨率布局文件夹。
    5. 增加示例自定义添加多个窗体。
    6. 重新设计配置参数界面,重新拆分配置参数分组,使得更清晰明了。
    7. 新增停靠窗体默认尺寸占比,这样在没有布局文件以及新建布局文件的时候自动按照这个尺寸设置停靠窗体的位置,之前没有布局文件默认是挤在一块的。
    8. 配置文件密码改成密文存储。

    0.3 相关站点

    1. 国内站点:https://gitee.com/feiyangqingyun
    2. 国际站点:https://github.com/feiyangqingyun
    3. 个人主页:https://blog.csdn.net/feiyangqingyun
    4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun
    5. 产品主页:https://blog.csdn.net/feiyangqingyun/article/details/97565652
    6. 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/bigscreen/
    7. 体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_bigscreen.zip。
    8. 文章导航:https://qtchina.blog.csdn.net/article/details/121327452

    0.4 功能特点

    1. 采用分层设计,整体总共分三级界面,一级界面是整体布局,二级界面是单个功能模块,三级界面是单个控件。
    2. 子控件包括饼图、圆环图、曲线图、柱状图、柱状分组图、横向柱状图、横向柱状分组图、合格率控件、百分比控件、进度控件、设备状态面板、表格数据、地图控件、视频控件等。
    3. 二级界面可以自由拖动悬浮,支持最小化隐藏、最大化关闭、响应双击自定义标题栏。
    4. 数据源支持模拟数据(默认)、数据库采集、串口通信(需定制)、网络通信(需定制)、网络请求等,可自由设定每个子界面的采集间隔即数据刷新频率。
    5. 采用纯QWidget编写,亲测Qt4.6到Qt6.2任意版本,理论上支持后续其他Qt版本。
    6. 超强跨平台,亲测windows、linux、mac、国产uos、国产银河麒麟kylin等系统,效果完美,同时还支持嵌入式linux比如树莓派、香橙派、全志、imx6等。
    7. 同时集成了自定义控件、qchart饼图、echart地图等功能。
    8. 内置多套配色风格样式(紫色、蓝色、深蓝、黑色),默认紫色,自适应任意分辨率。
    9. 可设置系统标题、目标分辨率、布局方案,启动立即应用。
    10. 可设置主背景颜色、面板颜色、十字线游标颜色等各种颜色。
    11. 可设置多条曲线不同颜色,没有设置颜色的情况下内置多套精美颜色随机应用。
    12. 可设置标题栏背景颜色、文字颜色。
    13. 可设置曲线图表背景颜色、文字颜色、网格颜色。
    14. 可设置正常颜色、警戒颜色、报警颜色、禁用颜色、百分比进度颜色。
    15. 可分别设置各种字体大小,比如全局字体、软件名称、标题栏、子标题栏、加粗标签等。
    16. 可设置标题栏高度、表头高度、行高度。
    17. 曲线支持游标、定位线、悬停高亮数据点、悬停显示值。
    18. 柱状图支持顶部(可设置顶端、上部、中间、底部)显示数据,全部自适应计算位置。
    19. 支持平滑曲线,内置多种平滑曲线算法,还支持面积图平滑。
    20. 面积图填充颜色可选多种规则比如单色透明度填充、透明度渐变填充等。
    21. 数据库支持sqlite、mysql、postgresql、oracle、国产人大金仓等数据库。
    22. 主界面直接鼠标右键切换布局、配色方案、关闭开启某个二级窗体。
    23. 自动记忆所有子窗口的大小和位置,下次启动立即应用。
    24. 动态加载布局方案菜单,可以动态新建布局、恢复布局、保存布局、另存布局等,用户可以制造任意布局。
    25. 二级窗体,双击从主窗体分离出来浮动,可以自由调整大小。再次双击标题栏最大化,再次双击还原。
    26. 子模块也可以全屏显示作为一个大屏,这样就可以一个大屏拓展出多个子大屏,放大查看子模块的数据详情,适用多屏展示。
    27. 每个模块都可以自定义采集速度,如果是数据库采集会自动排队处理,后期还可以拓展每个子模块都独立的数据库采集。
    28. 提供系统设置模块进行整体的配置参数设置,效果立即应用。
    29. 提供精美炫酷的大屏地图模块,包括静态图片、闪烁效果、迁徙效果、世界地图、区域地图等,可指定点的经纬度坐标,识别单击响应,可以做地图跳转等,每个点都可以不同的颜色和提示信息。
    30. 除了提供大屏系统外,还将每个模块都做了独立的模块示例界面,每个模块都可以独立学习使用,里面用到的控件也单独做了控件示例界面,方便学习每个控件如何使用。
    31. 非常详细的开发和使用手册,其中包括数据库说明、模块对照图、控件对照图、项目结构、代码说明(精确到每个类)、演示demo、使用方法等。

    1 操作说明

    1.1 使用方法

      系统支持多种数据源,比如数据库采集、http请求、串口通信、网络通信、模拟数据等,为了简化测试过程,默认内置采用的是模拟数据。

    1.1.1 启动窗体

      系统内置了多种启动窗体,默认大屏系统,可以通过鼠标右键菜单进入系统设置,启动窗体下拉框选择进行切换,切换后会自动重启应用,还可选择控件演示、模块演示,在控件演示和模块演示窗体中,左侧是对应子窗体导航,会自动记住最后选中的子界面索引。 +

    1.1.1.1 大屏系统

    1.1.1.2 模块演示

    1.1.1.3 控件演示

    1.1.2 系统菜单

    +

    在大屏的顶部中间标题栏或者子模块以外的标题栏,鼠标右键弹出的是系统的菜单,包括布局切换和样式切换等。

    1.1.3 模块菜单

    +

    在模块的标题栏,鼠标右键弹出的是模块可视化的菜单,这个是Qt内置生成的,加载了多少个子模块就会生成多少个菜单项,可以对每个模块进行显示隐藏切换。

    1.1.4 布局切换

    在弹出的系统菜单选择布局方案,在弹出的二级菜单选择默认已经设置好的布局方案,直接切换即可。

    1.1.5 新建布局

    在弹出的系统菜单选择新建布局,在弹出的框中输入布局名称,确认后,自由拖动调整模块位置,打开模块、隐藏模块,之后单击保存布局即可。

    1.1.6 全局换肤

    在弹出的系统菜单选择配色方案,在弹出的二级菜单选择对应的配色方案,默认有四种:紫色风格、蓝色风格、深蓝风格、黑色风格。

    1.1.7 模块拖动

    鼠标移动到子模块的标题栏,鼠标按下可以拖动这个模块到任意位置,模块也可以拖动独立位置展示,也可以嵌入到对应布局中,拖动好位置以后自动保存到布局方案,下次启动自动应用。双击模块标题栏可以剥离窗体使之悬浮。

    1.1.8 调整间距

    鼠标移动到模块与模块的边缘,鼠标变成调整间距样式,可以左右或者上下拉动,调整好间距以后自动保存到布局方案,下次启动自动应用。

    1.2 系统设置

    系统设置中的参数,可能会不定期做调整和修改及增加,下面的图示和参数描述未必全部一致,以最新的为准。

    1.2.1 基本设置

    参数说明

    1. 开机启动:默认关闭,开启后软件会随系统启动而启动。
    2. 模块拖动:默认开启,开启后模块可以自由拖动到合适的位置松开,一般在布局固定后在关闭,防止使用者在现场又托乱了。
    3. 切左下角:开启裁掉左下角以后,左侧底部和整体底部合并为一体,作为全局底部的一部分,就可以拖动模块到左侧底部,否则左侧底部作为左侧的一部分。
    4. 切右下角:开启裁掉右下角以后,右侧底部和整体底部合并为一体,作为全局底部的一部分,就可以拖动模块到右侧底部,否则右侧底部作为右侧的一部分。
    5. 定位线条:系统中曲线图表内置了定位线条,比如1月份,方便查看,可以开启。
    6. 百分符号:系统中曲线图表Y轴,有时候需要按照 100% 后面带百分比符号显示。
    7. 隐藏鼠标:鼠标未操作多久自动隐藏鼠标指针,默认5秒钟。
    8. 启动窗体:选择程序运行的启动窗体,默认大屏系统,还可选择控件演示、模块演示。
    9. 工作模式:默认工作模式是模拟数据,还可以选择数据库采集、串口采集(未实现)、网络采集(未实现)、网络请求。
    10. 地图样式:可选择静态图片、闪烁效果、迁徙效果、世界地图、区域地图多种样式,如果没有开启浏览器模块则自动采用静态图片的方式,区域地图默认是江西省吉安市,可以在代码中修改。
    11. 布局方案:和系统右键菜单中的布局方案功能一样。
    12. 软件标题:软件的标题文字,显示在软件中间顶部。
    13. 请求地址:工作模式选择网络请求的时候发送的网络请求地址。

    1.2.2 视频设置

    参数说明

    1. 视频循环:开启后设定的视频打开后会循环播放。
    2. 视频拉伸:开启后视频会填充整个窗体拉伸图像,否则按照比例自动拉伸。
    3. 视频回调:开启后采用CPU绘制图像,部分设备没有GPU需要开启。
    4. 视频循环:开启后会不断循环播放视频文件。
    5. 视频地址:视频窗体对应的视频地址,可以下拉选择内置的一些地址,也可以手动填写,如果多个视频窗口则自己增加对应的配置参数,支持本地视频文件、USB摄像头、网络摄像头、视频流地址等各种。

    1.2.3 采集间隔设置

    采集间隔设置不用做说明,一看就懂,单位毫秒,可定制每个模块都对应自己的采集方式、数据库、间隔等。

    1.2.4 数据库设置

    理论上支持Qt支持的所有数据库,和具体程序无关,只要有对应的数据库的动态库和插件库就行,或者支持odbc数据源也可以,程序打通了odbc数据源的通信方式,所以支持各种数据库,可以先自己用对应的数据库工具连接数据库试试,通了数据库正常后在来测试程序。

    亲测 Sqlite(Qt内置无需额外动态库)、MySql(高版本Qt需要自行编译插件)、PostgreSQL(开源免费的数据库,很好用)、SqlServer(需要设置ODBC数据源)、kingbase(国产人大金仓数据库,该数据库其实是基于PostgreSQL改的,通过odbc数据源方式测试无误)。

    连接测试用来测试当前选择的数据库类型以及数据库信息,是否能连接数据库正常,可以避免数据库不通的情况下用来检测是否信息填写正确。

    初始化数据库按钮用来执行sql脚本来生成对应的数据库,部分数据库支持数据库文件不存在的情况下通过sql语句来创建数据库,比如mysql、postgres等就支持直接sql语句新建数据库,有部分数据库可能不支持,需要手动先在数据库管理工具中新建好数据库,然后再来这里执行初始化数据库用来新建表和初始数据。

    1.3 工作模式

    本系统支持多种工作模式,以便适应各种需求,默认采用随机模拟数据,大屏基础版本也采用此工作模式。

    1.3.1 模拟数据

    如果工作模式选择的是模拟数据,则采用随机数模拟生成数据并设置。

    1.3.2 数据库采集

    具体数据库表字段说明参见后面的数据库说明。

    如果工作模式选择的是数据库采集,则会自动连接设置的数据库,可以用对应的数据库管理工具连接数据库,打开对应的表,然后更改其中的数据,保存,可看到对应的数据反应到界面上。

    系统支持一个系统下的软件远程访问另一个系统下的数据库,比如linux系统或者mac系统远程访问win系统上的mysql数据库,数据库也可以放在云端比如阿里云(亲测无误),只要对应IP和端口可达就行,验证是否可达可以用对应的数据库管理工具连接即可。

    理论上odbc的方式支持多种数据库,比如sql server,oracle,postgresql等,所以如果没有插件支持的数据库可以考虑用odbc的方式,odbc也是跨平台的。

    如果需要远程访问mysql数据库,mysql数据库需要设置用户 root@% + +sql server数据库的配置规则,下面的链接只是参考,基本上正常电脑安装好以后都不需要下面的配置。 +https://blog.csdn.net/mozhi111/article/details/80281388 +https://blog.csdn.net/happymagic/article/details/8673476

    远程访问sql server数据库,需要在运行软件的电脑上也需要配置数据源,不然很可能无法访问。

    sql server数据库配置步骤

    1. 第一步:安装好sql server数据库,比如sql server 2014,设置混合验证模式并设置密码。
    2. 第二步:打开sql server management studio,左侧,新建数据库bigscreen。
    3. 第三步:新建odbc数据源,cmd执行命令odbcad32打开数据源配置,命名为bigscreen,关联到数据库bigscreen。 +切记:Qt中连接sqlserver数据库采用的odbc方式,数据库名填写的是数据源中的名称,而不是数据库中的数据库名称,比如数据源名字是aaa,关联到数据库bbb,连接的数据库名称是填写aaa而不是bbb。

    安装PostgreSQL数据库之后,默认只能本地访问连接。如果想在其他主机上访问PostgreSQL数据库服务器,就需要进行相应的配置。 +https://blog.csdn.net/weixin_36816337/article/details/81739819 + +人大金仓数据库kingbase,其实就是postgresql数据库改的,如果是WIN10系统建议安装在系统盘以外,不然没有权限,导致奇奇怪怪的问题。

    特别提示

    1.3.3 串口采集

    需要定制协议,比如RS232、RS485、Modbus、Mqtt等

    1.3.4 网络采集

    需要定制协议,比如tcp client、tcp server、udp client、udp server、websocket等。

    1.3.5 网络请求

    找到bigscreen可执行文件所在目录下的httpserver文件,双击运行,切换到网络请求服务器页面,回复数据选择文件内容,单击启动服务器,左侧消息栏可以看到实时打印的数据,从json文件读取的数据,实际中可以是从数据库中采集的数据等。网络请求客户端/服务器工具httpserver,也是纯Qt编写的工具。

    功能特点

    1. 支持多个客户端连接并发同时处理,100个毫无压力。
    2. 可设置http请求是长连接还是短连接,默认长连接。
    3. 支持多种回复数据格式,其中包括网页内容、json数据等。
    4. 服务端示例中同时包含读取文件回复、读取数据库回复。
    5. 支持8种配色方案(暗黑、灰黑、深绿、浅黄、深蓝、深黑、暗蓝、默认)。
    6. 客户端可指定请求地址,服务端可指定网卡和端口进行监听。
    7. 所有请求和连接都有计数,所有在线请求的IP和端口都显示在表格中。
    8. 可以提供一个简易的网页配置服务,包括交互,作为设备的web配置。
    9. 可自由拓展增加权限校验等,作为一个http请求服务器。
    10. 纯Qt实现,代码框架整洁,注释完整,支持任意Qt版本、任意编译器、任意操作系统。

    1.3.6 请求格式

    请求地址:http://127.0.0.1:6000 可以自行在系统设置中更改。

    1.3.6.1 请求数据

    其他表请求格式完全一致。 +tag=t_1_1_mold_prod_total&tableName=t_1_1_mold_prod_total&columnName=name,prod_1,prod_2

    名称说明
    tag标识符,用于服务端接收到请求后按照这个标识符返回数据,这里内容填的是具体的表名,方便收到数据直接解析并发送信号到对应模块窗体显示数据。
    tableName要查询的表名。
    columnName对应表的字段名称集合,用英文逗号隔开。
    1.3.6.2 返回数据
    名称说明
    tag唯一标识符,用于标识当前接收到哪个请求的回复数据,对方请求的时候会发过来。
    result结果数组,内容按照表格行一行行包装的数据。
    1.3.6.3 整体流程

    客户端发送请求,指定了唯一标识符+表名+要查询的字段名称集合,服务器收到请求后,解析表名+字段名称集合,从数据库中查询对应的内容组成json字符串返回,带上唯一标识符。

    具体解析数据在datahttp类中,如果是自定义的表和字段,则需要在datahttp类中的initTable方法自行添加表名和字段名即可,非常方便,一个表只需要增加一行代码。

    1.3.7 拓展构想

    现在数据采集无论是数据库采集还是网络请求采集,对应的表名和字段名都是写死在代码中,尽管目前已经封装好了可以自行添加表和字段,但是还不够通用,后期打算通过从配置文件读取。

    1.4 其他说明

    1. 可执行文件同级文件夹有layout+layout_1440+layout_1920,程序默认自动识别分辨率并加载对应的布局文件夹,比如1920分辨率则从layout_1920文件夹加载布局,并作为整体布局文件夹。
    2. 如果发现布局拖动乱了,可以直接鼠标右键选择恢复布局即可,在保存布局以前。
    3. 在中间地图模块鼠标右键可以弹出菜单,切换布局和配色方案等。
    4. 在模块的标题栏上右键可以弹出默认的dock菜单,用来显示和隐藏各模块。
    5. 软件关闭过程中会自动保存布局,下次启动以后自动应用。
    6. 如果使用的默认的配色方案比如紫色风格,则配置文件中的颜色全部无效,会自动应用代码中的颜色,如果需要启用自定义的颜色,则需要先将配置文件的皮肤参数修改成 Theme=\x81ea\x5b9a\x4e49\x98ce\x683c 即可。此时打开软件会应用配置文件中的颜色。
    7. 右键菜单可以截图保存,默认命名为 配色方案名称_布局方案名称.png 保存在snap目录下。
    8. 在二级窗体的标题栏上右键弹出模块菜单,可以对单个模块打开关闭,其他地方右键全局菜单。

    2 数据库说明

    数据库表的设计按照模块的顺序,比如frmmodule1主模块中包括4个子模块,每个子模块都对应一个表,所有表名的前缀是 t_ 以便区分,第一个数字表示主模块编号,第二个数字表示子模块编号。

    表名格式如下:

    源码目录下的bigscreen.sql为数据库脚本,可以在系统设置中单击初始化数据来执行。 +如果是需要对接自己的系统,可能涉及到部分数据不一致的情况,你可以: +第一:尽量用现有的表,现有的表各种各样都有,你找到你类似的往里面填数据就行。 +第二:如果没有合适的表,则需要调整对应的模块代码。

    2.1 产量汇总模块

    子模块表名对应表:

    子模块标题子模块表名
    模具产量t_1_1_mold_prod_total
    每月模具产量趋势图t_1_2_mold_prod_monthly
    零件产量t_1_3_wp_prod_total
    每月零件产量趋势图t_1_4_wp_prod_monthly

    2.1.1 模具产量

    表名:t_1_1_mold_prod_total

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    name名称VARCHAR255不为空
    prod_1系列1INTEGER11 
    prod_2系列2INTEGER11 

    默认数据:

    internal_idnameprod_1prod_2
    1设变1412
    2修模2025
    3新模4025

    2.1.2 每月模具产量趋势图

    表名:t_1_2_mold_prod_monthly

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    year年份INTEGER4不为空
    month月份INTEGER4不为空
    prod_1系列1INTEGER11 
    prod_2系列2INTEGER11 
    prod_3系列3INTEGER11 

    默认数据:

    internal_idyearmonthprod_1prod_2prod_3
    120185月325480
    220186月423433
    320187月456244
    420188月233865
    520189月121277
    6201810月223334
    7201811月234522
    8201812月326543
    920191月122365
    1020192月217755
    1120193月228733
    1220194月234534

    2.1.3 零件产量

    表名:t_1_3_wp_prod_total

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    name名称VARCHAR255不为空
    prod_1系列1INTEGER11 
    prod_2系列2INTEGER11 

    默认数据:

    internal_idnameprod_1prod_2
    1其他854410000
    2钢件10005002
    3电极20003000

    2.1.4 每月零件产量趋势图

    表名:t_1_4_wp_prod_monthly

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    year年份INTEGER4不为空
    month月份INTEGER4不为空
    prod_1系列1INTEGER11 
    prod_2系列2INTEGER11 
    prod_3系列3INTEGER11 

    默认数据:

    internal_idyearmonthprod_1prod_2prod_3
    120185月325423
    220186月423430
    320187月456244
    420188月233865
    520189月121277
    6201810月223334
    7201811月234522
    8201812月326543
    920191月122365
    1020192月217755
    1120193月228733
    1220194月234534

    2.2 当月计划模块

    子模块表名对应表:

    子模块标题子模块表名
    模具达成率t_2_1_mold_achie_rate
    零件达成率t_2_2_wp_achie_rate
    零件数t_2_3_wp_achie_number
    每日工序达成数t_2_4_process_achie_number

    2.2.1 模具达成率

    表名:t_2_1_mold_achie_rate

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    plan计划数INTEGER11 
    achieved达成数INTEGER11 

    默认数据:1 200 110

    2.2.2 零件达成率

    表名:t_2_2_wp_achie_rate

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    name名称VARCHAR255不为空
    plan计划数INTEGER11 
    achieved达成数INTEGER11 

    默认数据:

    internal_idnameplanachieved
    1模仁100200
    2镶件122100
    3辅件300500
    4电极155200

    2.2.3 零件数

    表名:t_2_3_wp_achie_number

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    wp_achie_number零件数INTEGER11 

    默认数据:1 1234

    2.2.4 每日工序达成数

    表名:t_2_4_process_achie_number

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    day日期VARCHAR2 
    green绿色数量INTEGER11 
    blue蓝色数量INTEGER11 
    red红色数量INTEGER11 

    默认数据:

    internal_iddaygreenbluered
    112030
    222020
    332330
    443240
    554350
    662330
    774405
    881205
    995404
    10104203
    11114760
    12123440
    13132530
    14143860
    15154304
    16165603
    17176540
    18184350
    19193405
    20205530
    21214760
    22223440
    23232530
    24243860
    25254304
    26265603
    27276540
    28284350
    29293405
    30305530
    31314203

    2.3 设备监控模块

    子模块表名对应表:

    子模块标题子模块表名
    设备运行状态t_3_1_device_runtime
    稼动率t_3_2_oee

    2.3.1 设备运行状态

    表名:t_3_1_device_runtime

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    group_name分组名称VARCHAR4不为空
    no_id分组编号INTEGER11不为空
    name名称VARCHAR255不为空
    text_1文字1VARCHAR255 
    text_2文字2VARCHAR255 
    status状态 1-开机 2-待机 3-维护 4-空INTEGER1不为空
    progress进度INTEGER3 
    flicker是否闪烁INTEGER1 

    默认数据:

    internal_idgroup_nameno_idnametext_1text_2statusprogressflicker
    1CNC1CNC1190411PID11100
    2CNC2CNC2190412PID12100
    3CNC3CNC3190413PID13100
    4CNC4CNC4190414PID14200
    5CNC5CNC5190415PID15100
    6CNC6CNC6190416PID16200
    7CNC7CNC7190417PID17100
    8CNC8   400
    9EDM1EDM1190421PID21100
    10EDM2EDM2190422PID23200
    11EDM3EDM3190423PID23100
    12EDM4EDM4190424PID24300
    13EDM5EDM5190425PID25100
    14EDM6EDM6190426PID26100
    15EDM7EDM7190427PID27100
    16EDM8EDM8190428PID28200
    17WEDM1WEDM1190431PID28100
    18WEDM2WEDM2190432PID28300
    19WEDM3WEDM3190434PID29200
    20WEDM4WEDM4190435PID30100
    21WEDM5WEDM5190436PID36100
    22WEDM6WEDM6190437PID37300
    23WEDM7   400
    24WEDM8   400

    2.3.2 稼动率

    表名:t_3_2_oee

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    cnc类别-cncINTEGER3不为空
    edm类别-edmINTEGER3不为空
    wedm类别-wedmINTEGER3不为空

    默认数据:1 110 90 90

    2.4 模具进度模块

    子模块表名对应表:

    子模块标题子模块表名
    模具进度t_4_1_mold_progress
    模具状态统计t_4_2_mold_status_parcent
    加工中模具数量t_4_3_mold_processing_num

    2.4.1 模具进度

    表名:t_3_2_oee

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    mold_no模具编号VARCHAR11 
    tn_no版本号VARCHAR11 
    type类型VARCHAR255 
    status状态VARCHAR255 
    product_name产品名称VARCHAR255 
    plan_date计划交期VARCHAR255 
    green当前进度绿色INTEGER11 
    yellow当前进度黄色INTEGER11 
    red当前进度红色INTEGER11 

    默认数据:

    internal_idmold_notn_notypestatusproduct_nameplan_dategreenyellowred
    1IK19001T0新模加工中后盖2019/3/29602020
    2IK19002T1修模加工中前盖2019/4/350500
    3IK29003T2修模加工中外壳2019/4/830700
    4IK19004T0新模加工中侧边2019/4/189055
    5IK19005T3修模加工中边框2019/4/360400
    6IK19006T0新模加工中后盖2019/4/2670255
    7IK19007T0新模加工中面板2019/4/7252550
    8IK19008T0新模加工中插件2019/3/31204040
    9IK19009T1修模加工中面板2019/3/12106030
    10IK19010T2修模加工中后盖2019/2/1201000

    2.4.2 模具状态统计

    表名:t_4_2_mold_status_parcent

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    finished正常交付百分比INTEGER11不为空
    processing加工中百分比INTEGER11不为空
    delay延期百分比INTEGER11不为空

    默认数据: +1 60 25 15

    2.4.3 加工中模具数量

    表名:t_4_3_mold_processing_num

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    mold_processing_number加工中数量INTEGER11不为空

    默认数据:87

    2.5 负荷分布模块

    子模块表名对应表:

    子模块标题子模块表名
    工序计划负荷t_5_1_work_load
    当日负荷t_5_2_work_load_today
    负荷百分比t_5_3_work_load_percent

    2.5.1 工序计划负荷

    表名:t_5_1_work_load

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    process_name工序名称VARCHAR255 
    work_load_1第1天负荷VARCHAR255 
    work_load_x第x天负荷VARCHAR255 
    work_load_7第7天负荷VARCHAR255 

    默认数据:

    internal_idprocess_namework_load_1work_load_2work_load_3work_load_4work_load_5work_load_6work_load_7
    1CNC粗101H81H90H120H30H60H120H
    2CNC精102H102H120H81H45H102H81H
    3EDM77H102H90H102H45H90H120H
    4WEDM87H102H120H45H102H102H90H
    5抛光45H102H102H90H81H81H81H
    6钳工89H90H45H120H120H120H102H
    7组装77H90H81H102H45H102H81H

    表名:t_5_1_work_load_table_head +这个设计很巧妙,相当于动态的日期和数据,日期作为标题。

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    date_1第1天日期VARCHAR255 
    date_2第2天日期VARCHAR255 
    date_3第3天日期VARCHAR255 
    date_4第4天日期VARCHAR255 
    date_5第5天日期VARCHAR255 
    date_6第6天日期VARCHAR255 
    date_7第7天日期VARCHAR255 

    默认数据:

    internal_iddate_1date_2date_3date_4date_5date_6date_7
    12019-04-302019-05-012019-05-022019-05-032019-05-042019-05-052019-05-06

    2.5.2 当日负荷

    表名:t_5_2_work_load_today

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    group_name分组名称REAL11小数位精度1
    green绿色值REAL11小数位精度1
    red红色值REAL11小数位精度1

    默认数据:

    internal_idgroup_namegreenred
    1CNC粗2020
    2CNC精4020
    3EDM600
    4WEDM30.22
    5铣床400
    6磨床3050

    2.5.3 负荷百分比

    表名:t_5_3_work_load_percent

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    group_name分组名称VARCHAR255 
    day_1第1天INTEGER3 
    day_x第x天INTEGER3 
    day_7第7天INTEGER3 

    默认数据:

    internal_idgroup_nameday_1day_2day_3day_4day_5day_6day_7
    1CNC粗70809070509980
    2CNC精1201001301409010085
    3EDM12010012080904050
    4WEDM1001201201001008070
    5铣床90807540123010
    6磨床80705060405030

    2.6 送检合格模块

    子模块表名对应表:

    子模块标题子模块表名
    钢件合格率t_6_1_wp_qual_rate
    电极合格率t_6_2_ele_qual_rate
    当天合格率t_6_3_qual_rate_today
    模具零件合格率t_6_4_mold_qual_rate

    2.6.1 钢件合格率

    表名:t_6_1_wp_qual_rate

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    date_1第1天合格率INTEGER3 
    date_x第x天合格率INTEGER3 
    date_15第15天合格率INTEGER3 

    默认数据: +1, 100, 99, 89, 95, 95, 92, 98, 100, 96, 97, 98, 99, 90, 85, 84

    2.6.2 电极合格率

    表名:t_6_2_ele_qual_rate

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    date_1第1天合格率INTEGER3 
    date_x第x天合格率INTEGER3 
    date_15第15天合格率INTEGER3 

    默认数据: +1, 100, 99, 89, 95, 95, 92, 98, 100, 96, 97, 98, 99, 90, 85, 84

    2.6.3 当天合格率

    表名:t_6_3_qual_rate_today

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    qual_rate合格率INTEGER3 

    默认数据:90

    2.6.4 模具零件合格率

    表名:t_6_4_mold_qual_rate

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    mold_name模块名称VARCHAR255 
    qual_rate合格率INTEGER3 

    默认数据:

    internal_idmold_namequal_rate
    1IK1900195
    2IK1900288
    3IK1900394
    4IK1900475
    5IK1900594
    6IK1900689

    2.7 品质统计模块

    子模块表名对应表:

    子模块标题子模块表名
    品质占比t_7_1_qual_percent
    班组合格率t_7_2_group_qual_rate
    每日合格率统计t_7_3_qual_rate_daily

    2.7.1 品质占比

    表名:t_7_1_qual_percent

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    green绿色百分比INTEGER3 
    blue蓝色百分比INTEGER3 
    yellow黄色百分比INTEGER3 
    red红色百分比INTEGER3 

    默认数据: +1 45 30 15 10

    2.7.2 班组合格率

    表名:t_7_2_group_qual_rate

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    group_name分组名称VARCHAR255 
    qual_rate合格率INTEGER3 

    默认数据:

    internal_idgroup_namequal_rate
    1CNC90
    2EDM85
    3WEDM92
    4磨床94
    5铣床93
    6外协92

    2.7.3 每日合格率统计

    表名:t_7_3_qual_rate_daily

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    group_name分组名称VARCHAR255 
    day_1第1天INTEGER3 
    day_x第x天INTEGER3 
    day_31第31天INTEGER3 

    默认数据: +1, 'all', 90, 90, 97, 91, 92, 88, 89, 90, 78, 87, 86, 90, 80, 97, 87, 87, 88, 89, 90, 90, 89, 86, 90, 80, 97, 87, 87, 89, 89, 89, 90

    2.8 物料管理模块

    子模块表名对应表:

    子模块标题子模块表名
    库存占比t_8_1_key_invt
    主要零件库存t_8_2_invt_table

    2.8.1 库存占比

    表名:t_8_1_key_invt

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    name名称VARCHAR255 
    upper_bound上限INTEGER11 
    current库存INTEGER11 

    默认数据:

    internal_idnameupper_boundcurrent
    1刀具A1200110
    2顶针B10070
    3线割丝C100300
    4树脂D10010

    2.8.2 主要零件库存

    表名:t_8_2_invt_table

    字段名中文名类型长度说明
    internal_id序号INTEGER11主键自增
    invt_no编号VARCHAR255 
    name品名VARCHAR255 
    spec规格VARCHAR255 
    mat材料VARCHAR255 
    size尺寸VARCHAR255 
    target目标库存INTEGER11 
    current当前库存INTEGER11 

    默认数据:

    internal_idinvt_nonamespecmatsizetargetcurrent
    1SSDDS1品名1规格1材料134542020090
    2SSDDS2品名2规格2材料2345420100120
    3SSDDS3品名3规格3材料334542010067
    4SSDDS4品名4规格4材料434542010088
    5SSDDS5品名5规格5材料534542010045
    6SSDDS6品名6规格6材料634542010087
    7SSDDS7品名7规格7材料73454201009
    8SSDDS8品名8规格8材料834542010044
    9SSDDS9品名9规格9材料9345420100100

    3 配置参数说明

    3.1 基本配置1

    字段描述默认值
    IndexStart启动窗体索引 0-大屏系统 1-控件演示 2-模块演示0-大屏系统
    IndexControl控件演示窗体选中子窗体索引0
    IndexModule模块演示窗体选中子窗体索引0
    WorkMode工作模式timer
    MapStyle中间地图样式point
    Title软件标题,默认值:数字化工厂信息中心 
    Ratio分辨率,目前无意义,备用参数1920*1080
    Layout布局方案,每次切换布局方案以后都会保存完整布局
    Theme配色方案,每次切换配色方案以后都会保存紫色风格
    HttpUrl网络请求地址,默认http://127.0.0.1:6000 

    工作模式

    地图样式

    3.2 基本设置2

    字段描述默认值
    AutoRun是否开机启动false
    MoveEnable模块是否可以拖动,启用以后模块可以任意拖动true
    CutLeftBottom底部布局左侧是否切掉true
    CutRightBottom底部布局右侧是否切掉true
    StaticLine是否绘制静态定位线,为假则绘制游标十字线false
    ShowPercentY轴是否显示百分比false
    StepYY轴大尺度步长6
    CursorHideTime用户不操作鼠标自动隐藏鼠标的时间间隔,单位秒5

    3.3 视频设置

    字段描述默认值
    VideoFillImage视频缩放,拉伸填充整个窗体false
    VideoCallback视频回调,开启后采用painter走GPU绘制视频false
    VideoPlayAudio播放音频,开启后视频同步播放音频true
    VideoPlayRepeat视频循环播放,开启后视频会循环播放false
    VideoUrl视频流地址,视频模块播放的视频地址变动的

    3.4 颜色配置1

    字段描述默认值
    ColorMainBg主背景颜色QColor(4, 7, 38)
    ColorPanelBg面板背景颜色QColor(26, 29, 60)
    ColorLine十字线定位线颜色QColor(255, 0, 0)
    ColorLine1线条1颜色QColor(0, 176, 180)
    ColorLine2线条2颜色QColor(32, 159, 223)
    ColorLine3线条3颜色QColor(255, 192, 0)

    3.5 颜色配置2

    字段描述默认值
    ColorTitleBg标题栏背景颜色QColor(48, 48, 85)
    ColorTitleText标题栏文字颜色QColor(255, 255, 255)
    ColorChartBg曲线图表背景颜色QColor(38, 41, 74)
    ColorChartText曲线图表文字颜色QColor(250, 250, 250)
    ColorChartGrid曲线图表网格颜色QColor(180, 180, 180)

    3.6 颜色配置3

    字段描述默认值
    ColorOk正常颜色QColor(0, 176, 180)
    ColorLow警戒颜色QColor(255, 192, 0)
    ColorAlarm报警颜色QColor(214, 77, 84)
    ColorDisable禁用背景颜色QColor(210, 210, 210)
    ColorPercent环形百分比背景颜色QColor(0, 254, 254)

    3.7 字体配置

    字段描述默认值
    MainFont全局字号微软雅黑,12
    NameFont软件名称字号19
    LabFont加粗标签字号12
    DeviceFont设备面板字号12
    SubTitleFont模块子标题栏字号13
    TitleFont模块标题栏字号15

    3.8 尺寸配置

    字段描述默认值
    TitleHeight模块标题栏高度23
    HeadHeight表格表头高度28
    RowHeight表格行高度25
    LayoutSpacing布局空隙间隔6
    SwitchBtnWidth开关按钮宽度65
    SwitchBtnHeight开关按钮高度26
    ScrollWidth滚动条宽度15

    3.9 采集速度

    字段描述默认值
    IntervalModule1模块1采集间隔,单位毫秒5000
    IntervalModule2模块2采集间隔,单位毫秒5100
    IntervalModule3模块3采集间隔,单位毫秒5200
    IntervalModule4模块4采集间隔,单位毫秒5300
    IntervalModule5模块5采集间隔,单位毫秒5400
    IntervalModule6模块6采集间隔,单位毫秒5500
    IntervalModule7模块7采集间隔,单位毫秒5600
    IntervalModule8模块8采集间隔,单位毫秒5700

    3.10 数据库配置

    字段描述默认值
    LocalDBType本地数据库类型,Sqlite、Mysql等Sqlite
    LocalDBIP本地数据库主机地址127.0.0.1
    LocalDBPort本地数据库端口3306
    LocalDBName本地数据库名称bigscreen
    LocalUserName本地数据库用户名root
    LocalUserPwd本地数据库密码,以密文存储root

    4 程序框架说明

    4.1 整体代码结构

    整个大屏系统就是由一个个子模块组成,每个子模块都用到了一些自定义控件,再打通数据库采集和网络请求采集等,将采集到的数据设置到对应的模块界面上。

    4.2 主模块说明

    主模块说明
    3rd一些第三方开源的类库,比如图表qcustomplot。
    class存放系统初始化、样式控制、自定义控件等。
    core本人一直持续更新完善的通用的类库,比如ffmpeg视频监控。
    ui所有的界面都分门别类放在这里。

    4.3 子模块说明

    主模块子模块说明
    3rd3rd_qcustomplot大名鼎鼎的第三方开源的图表组件。
    classapi存放数据库表映射成对应的全局队列数据、通用的辅助函数类。
    classapp全局配置参数管理类、秘钥管理类、通用函数。
    classusercontrol当前系统的自定义控件全部放在这里,其中包括自定义饼图控件、进度仪表盘、百分比仪表盘、环形进度条、三态进度条等控件。
    corecore_common通用函数,包括通用秘钥、通用导航、通用样式、声音播放、日志记录、运行时间记录等。
    corecore_control通用自定义控件,很多系统经常用到的控件全部放在这里。
    corecore_customplot继承自qcustomplot类的自定义图表组件,专为大屏系统定制的各种图表组件。
    corecore_db数据库集成应用组件,比如数据库管理线程类、数据库清理线程类、数据库采集类、网络请求采集类等。
    corecore_form通用的用户登录、用户退出、用户管理、数据库配置界面类等。
    corecore_map地图内核,包括了百度echart封装类,区域轮廓数据转换js函数封装类,百度地图封装类等。
    corecore_qui通用的辅助类,包括自定义对话框,全局辅助函数,图形字体等。
    corecore_video视频播放核心类,包括了监控画面切换控件、视频回放控件、视频播放组件结构体、视频播放辅助函数、视频解码线程类、视频显示控件类等。
    corecore_videobase视频相关基类,包括音视频文件保存基类、视频解码基类、视频控件基类、视频悬浮工具栏、视频控件结构体等。
    corecore_videoffmpeg视频监控内核ffmpeg版本,本系统默认采用的内核。
    corecore_videoopenglopengl封装类,支持打开yuv/nv12文件,绘制yuv/nv12帧数据,一般搭配ffmpeg视频内核显示视频,直接走GPU绘制。
    corecore_webview通用浏览器控件类,同时支持webkit、wenengine、miniblink三种内核,打通了所有的Qt版本。
    uifrmconfig系统设置界面,包括常规设置、数据库设置、采集间隔设置、视频参数设置等。
    uifrmcontrol大屏控件演示示例,每个功能演示都是个独立的窗体,方便查看代码学习如何使用。
    uifrmmain主界面模块,包括了系统配置界面、大屏主界面、大屏指定分辨率用于截图的主界面、设备面板窗体。
    uifrmmodule大屏子模块,包括了产量汇总、当月计划、设备监控、模具进度、负荷分布、送检合格率、品质管理、物料管理、视频监控、大屏地图等。

    4.4 辅助处理

    4.4.1 数据库表映射

    将对应的用户表映射到变量队列存储,以便用户登录和整体判断权限等。

    4.4.2 通用辅助函数类

    这个类就像万能胶一样,在本人写的所有的项目中都有,本类就是将平时常用的一些通用函数都丢在这里,不断完善和持续改进,包括了16进制数据转换、图形字体设置、自定义消息框、错误框、提示框等,集成设置窗体居中显示、设置翻译文件、设置编码、设置延时、设置系统时间等静态方法。

    4.4.3 初始化及辅助

    名称说明
    appconfig配置参数类,整个系统的配置参数存放在ini文件中,跨平台,所有参数都对应一个变量,读取配置参数的时候将值赋值给变量,写入的时候将变量值写入到配置文件。
    appfun辅助函数类,比如重启,获取随机数、从多个数组中取出最大值等。
    appinit程序初始化类,在main函数中,会先执行这个初始化的类,比如初始化皮肤、字体、数据库、样式等操作,这些都是要优先在窗体加载前执行的,执行完毕以后再打开窗体主界面。
    appkey通用秘钥管理类。

    4.4.4 自定义控件

    名称说明
    customchart自定义图表控件
    custompie自定义饼状图,纯painter绘制,弥补qchart组件不支持qt4等版本。
    customtitlebar自定义模块标题栏
    gaugepercent百分比仪表盘
    gaugespeed速度仪表盘
    progressring环形进度条
    progressthree三态进度条
    switchbutton开关按钮

    + + + + + + +

    4.5 内核模块

    4.5.1 通用自定义控件

    名称说明
    bottomwidget通用底部状态栏控件,可以设置软件名称、版本号、运行时间等。
    colorcombobox颜色下拉框控件,在系统设置中有。
    cpumemorylabelCPU和内存使用情况标签控件,主界面右上角显示。
    customtitlebar停靠窗体自定义标题栏控件。
    devicebutton设备按钮控件,比如图片地图模块中用到,可设置不同的图标样式和状态等,双击发出信号进行相应处理比如弹出对应视频预览等。
    framelesswidget无边框窗体管理类,无边框拖动+拉伸,主界面就用到了这个类。
    lcddatetime软件右上角显示时间的控件。
    panelwidget面板容器控件,主界面子模块表格消息,就用到此控件,用于将一堆widget放到此容器进行管理,自动形成滚动条等。
    switchbutton开关按钮控件,在系统设置中存在大量该控件。
    xslider滑动条控件,在原有滑动条基础上增加了鼠标按下立即定位等。

    4.5.2 图表组件内核

    名称说明
    customplot自定义图表组件类。
    customplotbarh自定义形状-横向柱状图。
    customplotbarv自定义形状-垂直柱状图。
    customplothead当前组件通用头文件。
    customplothelper当前组件通用辅助函数文件。
    customplotline自定义形状-平滑曲线图。
    customplottracer自定义图层绘制十字线,也叫游标,定位线。
    smoothcurve平滑曲线算法类,内置多种平滑算法,可以自行增加其他算法。

    4.5.3 数据库应用内核

    本系统只用到了该类库中的dbconnthread、dbhttpthread。 +dbconnthread:封装的一个通用的数据库通信类,支持sqlite、mysql、PostgreSQL等数据库,功能包括了数据库的打开和关闭,线程执行sql语句队列信号发出执行结果等,支持重连。 +dbhttpthread:本系统除了支持数据库采集模式以外,还支持发送http网络请求的方式来采集数据,请求中带对应要查询的表,字段等信息,这个类就是专门的请求类,请求结果自动过滤运算并信号发出去,返回数据的信号和数据库采集的信号完全一致,使得主界面关联到同一个槽函数就能正常工作。

    名称说明
    dbcleanthread自动清理数据线程类。
    dbconnthread数据库通信管理线程类。
    dbdelegate自定义委托全家桶,包括复选框、下拉框、密码框、按钮等。
    dbhead当前组件通用头文件。
    dbhelper各种数据库应用函数封装,比如初始化数据库、执行sql语句等。
    dbhttpthread网络请求数据采集类。
    dbpage数据库通用翻页类。
    dbpagemodel数据库翻页类数据模型。
    navpage分页导航控件。

    4.5.4 大屏地图内核

    名称说明
    echartjsechart模块中用到的json文件转js文件,获取js文件中的名字和经纬度等处理。
    echartsechart封装类,可加载仪表盘、闪烁点图、迁徙图、世界地图、区域地图等,每个点可自定义颜色和提示信息等。
    mapbaidu百度地图封装类,支持在线和离线两种模式。

    4.5.5 视频监控内核

    4.5.5.1 视频播放组件
    名称说明
    videobox监控画面切换控件,将所有通道切换处理全部集中到一个类,通用异形布局切换函数,可以参考进行自定义异形布局,通道布局切换发出信号通知,支持自定义子菜单布局内容。
    videohelper视频播放内核辅助函数,比如根据url地址取出ip地址、校验网络地址是否可达、检查地址是否正常、加载解析内核到下拉框、根据地址获取本地摄像头参数、创建视频采集类、对采集线程设置参数等。
    videomanage视频线程管理类,全局单例,将所有视频控件发给此类管理,负责挨个打开视频、应用录像计划等。
    videoplayback视频回放控件,支持多个通道,显示每个通道对应的视频段。
    videostruct视频播放组件结构体定义类,包括解析内核枚举值、视频类型枚举值、解码策略枚举值、视频采集参数结构体。
    videotask视频任务线程类,全局单例,可以随时插入一些视频相关的任务进行处理,比如vlc录制视频后需要重命名文件,mpv内核关闭视频后鼠标指针打圈圈需要复位。
    videothread视频解码线程类,内置了共享解码线程处理逻辑,可以打开视频、关闭视频、设置视频宽高比例、获取文件总时长、获取媒体信息、获取和设置播放位置、获取和设置播放速度、获取和设置音量大小、获取和设置静音状态等。
    videourl视频地址相关静态函数,可以读取和写入地址到文本文件,用作历史记录,内置了各种类型(rtsp、http、音频文件、视频文件、网络文件、本地USB摄像头)的测试音视频地址集合。
    videowidgetx视频播放控件,一个控件对应一个解码线程,提供播放成功、播放结束、收到截图、工具栏按钮单击等处理,提供开始播放、停止播放、暂停播放、继续播放、抓拍截图、开始录制、暂停录制、停止录制等接口。
    4.5.5.2 视频基类组件
    名称说明
    abstractsavethread音视频存储基类,可以设置需要保存的音视频文件类型,比如音频文件类型有pcm、wav、aac,视频文件类型有yuv、h264、mp4,提供开始保存、暂停保存、停止保存等接口。
    abstractvideosurface视频回调基类,用于Qt中的QCamera和QMedia类播放后拿到回调视频数据,这样可以取到一张张图片。
    abstractvideothread视频解码线程基类,摄像头采集线程和视频采集线程都继承自此类,将各种公用的变量、函数、接口、信号槽全部放在基类,包括了停止线程标志位、打开是否成功标志位、暂停采集标志位、开始截图标志位、正在录制标志位,提供了虚函数开始播放、停止播放、暂停播放、继续播放、抓拍截图、截图完成、开始录制、暂停录制、停止录制等,提供写入视频数据到文件、写入音频数据到文件槽函数。
    abstractvideowidget视频显示控件基类,
    audioplayer音频播放类,空的,纯粹为了在没有Qt音频播放类QAudioOutput的时候使用,有些Qt版本或者嵌入式板子环境未必有这个类,但是又不能影响整个组件的运行,于是定义了空的类,函数正常调用但是不做任何处理。
    bannerwidget悬浮工具栏控件,可以设置各种颜色、按钮图标集合、按钮名称集合、按钮提示信息集合等,悬浮条位置支持上下左右四个方位。
    imagelabel图片标签控件,多线程绘制传入的图片,性能比setpixmap更优。
    widgethelper窗体相关辅助函数,包括传入图片尺寸和窗体区域及边框大小返回居中区域(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充)、绘制矩形区域比如人脸框、绘制点集合多边形路径比如三角形、绘制路径集合、显示截图预览等。
    4.5.5.3 视频监控ffmpeg组件
    名称说明
    ffmpeghelper相关辅助函数,包括打印输出各种信息、打印设备列表和参数、格式枚举值转字符串、视频帧旋转、通用硬解码、通用软解码、通用软编码、释放数据帧数据包、超时回调(包括打开超时和读取超时)等。
    ffmpegrun执行ffmpeg命令,包括yuv420p文件转mp4文件、mp4文件转yuv420p文件、wav文件转aac文件、合并aac以及h264文件或者mp4文件到带声音的mp4文件、转换视频文件到mp4文件等。
    ffmpegrunthread执行ffmpeg命令行线程,可以设置执行完成是否删除转换前的文件、可执行文件路径,传入需要执行的指令即可。
    ffmpegsave视频存储类,用于保存h264和mp4文件。
    ffmpegsync音视频同步线程类,解码后的音视频数据发给本类进行时间同步处理,采用的外部时钟同步策略。音视频播放的进度也在本类中。
    ffmpegthread视频解码线程核心,从打开地址、分配解码器、初始化参数、取出音视频数据解码、关闭并释放资源等都在本类实现。
    4.5.5.4 视频绘制组件
    名称说明
    openglinclude当前组件头文件。
    nv12glwidget空类,用于没有opengl的Qt版本中保证程序能够继续运行。
    nv12openglwidget继承自QOpenGLWidget的NV12格式OPENGL绘制窗体。
    yuvglwidget空类,用于没有opengl的Qt版本中保证程序能够继续运行。
    yuvopenglwidget继承自QOpenGLWidget的YUV格式OPENGL绘制窗体。

    4.5.6 通用浏览器内核

    名称说明
    webcore.pri通用的根据不同的Qt版本、不同的编译器环境、不同的操作系统,加载对应的浏览器内核模块和定义不同的变量。
    miniblinkminiblink封装处理类。
    webhelper经纬度转换、获取小数点经纬度值等常用处理函数。
    webjsdata通用的浏览器控件和Qt程序交互数据中转类。
    webview通用浏览器控件,支持webkit、webengine、miniblink。

    4.6 界面模块

    4.6.1 大屏控件演示

    名称说明
    frmcontrol大屏控件演示主界面,负责加载所有控件演示子窗体。
    frmplotarea曲线面积图。
    frmplotbarh横向柱状图。
    frmplotbarhs横向分组图。
    frmplotbars柱状堆积图。
    frmplotbarv标准柱状图。
    frmplotbarvs柱状分组图。
    frmplotdata数据转曲线。
    frmplotnormal标准曲线图。
    frmplotsin模拟曲线图。
    frmplotsmooth平滑曲线图。

    4.6.2 大屏模块演示

    名称说明
    frmmodule大屏子模块演示主界面,负责加载所有子模块界面。
    frmmodule1年度产量汇总。
    frmmodule2当月计划达成率。
    frmmodule3设备监控。
    frmmodule4模具进度。
    frmmodule5负荷分布。
    frmmodule6送检一次合格率。
    frmmodule7品质管理。
    frmmodule8物料管理。
    frmmodule9备用模块。
    frmmodulecenter中心窗体。
    frmmodulemap大屏地图。
    frmmodulevideo视频监控。

    4.6.3 主界面模块

    名称说明
    frmdevice设备面板界面。
    frmmain大屏主界面。
    frmmain2以特定分辨率设置的大屏主界面用于截图。

    5 效果图

    5.1 布局方案

    5.1.1 自定义布局1

    5.1.2 自定义布局2

    5.1.3 自定义布局3

    5.1.4 自定义布局4

    5.1.5 自定义布局5

    5.1.6 自定义布局6

    5.1.7 自定义布局7

    5.1.8 自定义布局8

    5.2 配色方案

    5.2.1 紫色风格

    5.2.2 蓝色风格

    5.2.3 深蓝风格

    5.2.4 黑色风格

    5.3 模块效果图

    5.3.1 产量汇总

    5.3.2 当月计划

    5.3.3 设备监控

    5.3.4 模具进度

    5.3.5 负荷分布

    5.3.6 送检合格

    5.3.7 品质管理

    5.3.8 物料管理

    5.3.9 视频监控

    5.3.10 大屏地图

    5.3.10.1闪烁效果

    5.3.10.2 迁徙效果

    5.3.10.3 世界地图

    5.3.10.4 区域地图

    5.3.11 系统设置

    5.4 控件效果图

    5.4.1 标准曲线

    5.4.2 曲线面积

    5.4.3 模拟曲线

    5.4.4 标准柱状

    5.4.5 柱状堆积

    5.4.6 柱状分组

    5.4.7 横向柱状

    5.4.8 横向分组

    5.4.9 数据曲线

    5.4.10 平滑曲线

    5.4.11 多坐标轴

    5.4.12 多曲线图

    5.5 数据库效果图

    5.5.1 数据库-sqlite

    5.5.2 数据库-mysql

    5.5.3 数据库-sqlserver

    5.5.4 数据库-postgresql

    5.5.5 数据库-oracle

    5.5.6 数据库-kingbase

    人大金仓数据库-kingbase,其实就是postgresql数据库改的,配置文件都一样,所以可以用连接postgresql数据库的方式进行处理。

    5.5.7 数据库-远程访问

    5.5.8 数据库-odbc

    ODBC连接字符串格式如上图所示。

    5.6 各系统运行图

    5.6.1 windows-mingw

    5.6.2 windows-msvc

    5.6.3 linux-ubuntu

    5.6.4 linux-uos

    5.6.5 linux-kylin

    5.6.6 linux-neokylin

    5.6.7 linux-fedoar

    5.6.8 unix-mac

    + + + \ No newline at end of file diff --git a/docs/bigscreen/snap/1-1-1-1.jpg b/docs/bigscreen/snap/1-1-1-1.jpg new file mode 100644 index 0000000..c430b38 Binary files /dev/null and b/docs/bigscreen/snap/1-1-1-1.jpg differ diff --git a/docs/bigscreen/snap/1-1-1-2.jpg b/docs/bigscreen/snap/1-1-1-2.jpg new file mode 100644 index 0000000..cec5d57 Binary files /dev/null and b/docs/bigscreen/snap/1-1-1-2.jpg differ diff --git a/docs/bigscreen/snap/1-1-1-3.jpg b/docs/bigscreen/snap/1-1-1-3.jpg new file mode 100644 index 0000000..6345715 Binary files /dev/null and b/docs/bigscreen/snap/1-1-1-3.jpg differ diff --git a/docs/bigscreen/snap/1-1-1-4.jpg b/docs/bigscreen/snap/1-1-1-4.jpg new file mode 100644 index 0000000..426c2a4 Binary files /dev/null and b/docs/bigscreen/snap/1-1-1-4.jpg differ diff --git a/docs/bigscreen/snap/1-1-2-1.jpg b/docs/bigscreen/snap/1-1-2-1.jpg new file mode 100644 index 0000000..4aa8386 Binary files /dev/null and b/docs/bigscreen/snap/1-1-2-1.jpg differ diff --git a/docs/bigscreen/snap/1-1-2-2.jpg b/docs/bigscreen/snap/1-1-2-2.jpg new file mode 100644 index 0000000..a9ec780 Binary files /dev/null and b/docs/bigscreen/snap/1-1-2-2.jpg differ diff --git a/docs/bigscreen/snap/1-1-3-1.jpg b/docs/bigscreen/snap/1-1-3-1.jpg new file mode 100644 index 0000000..dc3a203 Binary files /dev/null and b/docs/bigscreen/snap/1-1-3-1.jpg differ diff --git a/docs/bigscreen/snap/1-1-3-2.jpg b/docs/bigscreen/snap/1-1-3-2.jpg new file mode 100644 index 0000000..96a5907 Binary files /dev/null and b/docs/bigscreen/snap/1-1-3-2.jpg differ diff --git a/docs/bigscreen/snap/1-2-0.jpg b/docs/bigscreen/snap/1-2-0.jpg new file mode 100644 index 0000000..d7b7d0d Binary files /dev/null and b/docs/bigscreen/snap/1-2-0.jpg differ diff --git a/docs/bigscreen/snap/1-2-1.jpg b/docs/bigscreen/snap/1-2-1.jpg new file mode 100644 index 0000000..4b406c4 Binary files /dev/null and b/docs/bigscreen/snap/1-2-1.jpg differ diff --git a/docs/bigscreen/snap/1-2-2.jpg b/docs/bigscreen/snap/1-2-2.jpg new file mode 100644 index 0000000..2fe2963 Binary files /dev/null and b/docs/bigscreen/snap/1-2-2.jpg differ diff --git a/docs/bigscreen/snap/1-2-3.jpg b/docs/bigscreen/snap/1-2-3.jpg new file mode 100644 index 0000000..f820fc3 Binary files /dev/null and b/docs/bigscreen/snap/1-2-3.jpg differ diff --git a/docs/bigscreen/snap/1-2-4.jpg b/docs/bigscreen/snap/1-2-4.jpg new file mode 100644 index 0000000..8943705 Binary files /dev/null and b/docs/bigscreen/snap/1-2-4.jpg differ diff --git a/docs/bigscreen/snap/1-3-2.jpg b/docs/bigscreen/snap/1-3-2.jpg new file mode 100644 index 0000000..15f999a Binary files /dev/null and b/docs/bigscreen/snap/1-3-2.jpg differ diff --git a/docs/bigscreen/snap/1-3-3.jpg b/docs/bigscreen/snap/1-3-3.jpg new file mode 100644 index 0000000..f0153ff Binary files /dev/null and b/docs/bigscreen/snap/1-3-3.jpg differ diff --git a/docs/bigscreen/snap/1-3-5.jpg b/docs/bigscreen/snap/1-3-5.jpg new file mode 100644 index 0000000..a749a18 Binary files /dev/null and b/docs/bigscreen/snap/1-3-5.jpg differ diff --git a/docs/bigscreen/snap/2-1-0.jpg b/docs/bigscreen/snap/2-1-0.jpg new file mode 100644 index 0000000..52af03e Binary files /dev/null and b/docs/bigscreen/snap/2-1-0.jpg differ diff --git a/docs/bigscreen/snap/2-1-1.jpg b/docs/bigscreen/snap/2-1-1.jpg new file mode 100644 index 0000000..f1f6c5d Binary files /dev/null and b/docs/bigscreen/snap/2-1-1.jpg differ diff --git a/docs/bigscreen/snap/2-1-2.jpg b/docs/bigscreen/snap/2-1-2.jpg new file mode 100644 index 0000000..5846292 Binary files /dev/null and b/docs/bigscreen/snap/2-1-2.jpg differ diff --git a/docs/bigscreen/snap/2-1-3.jpg b/docs/bigscreen/snap/2-1-3.jpg new file mode 100644 index 0000000..f6a96b9 Binary files /dev/null and b/docs/bigscreen/snap/2-1-3.jpg differ diff --git a/docs/bigscreen/snap/2-1-4.jpg b/docs/bigscreen/snap/2-1-4.jpg new file mode 100644 index 0000000..b1cb265 Binary files /dev/null and b/docs/bigscreen/snap/2-1-4.jpg differ diff --git a/docs/bigscreen/snap/2-2-0.jpg b/docs/bigscreen/snap/2-2-0.jpg new file mode 100644 index 0000000..e80f352 Binary files /dev/null and b/docs/bigscreen/snap/2-2-0.jpg differ diff --git a/docs/bigscreen/snap/2-2-1.jpg b/docs/bigscreen/snap/2-2-1.jpg new file mode 100644 index 0000000..81fa33c Binary files /dev/null and b/docs/bigscreen/snap/2-2-1.jpg differ diff --git a/docs/bigscreen/snap/2-2-2.jpg b/docs/bigscreen/snap/2-2-2.jpg new file mode 100644 index 0000000..e49ce1a Binary files /dev/null and b/docs/bigscreen/snap/2-2-2.jpg differ diff --git a/docs/bigscreen/snap/2-2-3.jpg b/docs/bigscreen/snap/2-2-3.jpg new file mode 100644 index 0000000..0d9e958 Binary files /dev/null and b/docs/bigscreen/snap/2-2-3.jpg differ diff --git a/docs/bigscreen/snap/2-2-4.jpg b/docs/bigscreen/snap/2-2-4.jpg new file mode 100644 index 0000000..1cef72b Binary files /dev/null and b/docs/bigscreen/snap/2-2-4.jpg differ diff --git a/docs/bigscreen/snap/2-3-0.jpg b/docs/bigscreen/snap/2-3-0.jpg new file mode 100644 index 0000000..f5c7c64 Binary files /dev/null and b/docs/bigscreen/snap/2-3-0.jpg differ diff --git a/docs/bigscreen/snap/2-3-1.jpg b/docs/bigscreen/snap/2-3-1.jpg new file mode 100644 index 0000000..9642f24 Binary files /dev/null and b/docs/bigscreen/snap/2-3-1.jpg differ diff --git a/docs/bigscreen/snap/2-3-2.jpg b/docs/bigscreen/snap/2-3-2.jpg new file mode 100644 index 0000000..265dc6d Binary files /dev/null and b/docs/bigscreen/snap/2-3-2.jpg differ diff --git a/docs/bigscreen/snap/2-3-3.jpg b/docs/bigscreen/snap/2-3-3.jpg new file mode 100644 index 0000000..cbd8c06 Binary files /dev/null and b/docs/bigscreen/snap/2-3-3.jpg differ diff --git a/docs/bigscreen/snap/2-3-4.jpg b/docs/bigscreen/snap/2-3-4.jpg new file mode 100644 index 0000000..3a816cd Binary files /dev/null and b/docs/bigscreen/snap/2-3-4.jpg differ diff --git a/docs/bigscreen/snap/2-4-0.jpg b/docs/bigscreen/snap/2-4-0.jpg new file mode 100644 index 0000000..50a54fa Binary files /dev/null and b/docs/bigscreen/snap/2-4-0.jpg differ diff --git a/docs/bigscreen/snap/2-4-1.jpg b/docs/bigscreen/snap/2-4-1.jpg new file mode 100644 index 0000000..c6809c1 Binary files /dev/null and b/docs/bigscreen/snap/2-4-1.jpg differ diff --git a/docs/bigscreen/snap/2-4-2.jpg b/docs/bigscreen/snap/2-4-2.jpg new file mode 100644 index 0000000..f23565d Binary files /dev/null and b/docs/bigscreen/snap/2-4-2.jpg differ diff --git a/docs/bigscreen/snap/2-4-3.jpg b/docs/bigscreen/snap/2-4-3.jpg new file mode 100644 index 0000000..ebf50c6 Binary files /dev/null and b/docs/bigscreen/snap/2-4-3.jpg differ diff --git a/docs/bigscreen/snap/2-5-0.jpg b/docs/bigscreen/snap/2-5-0.jpg new file mode 100644 index 0000000..46e79f7 Binary files /dev/null and b/docs/bigscreen/snap/2-5-0.jpg differ diff --git a/docs/bigscreen/snap/2-5-1.jpg b/docs/bigscreen/snap/2-5-1.jpg new file mode 100644 index 0000000..1487c17 Binary files /dev/null and b/docs/bigscreen/snap/2-5-1.jpg differ diff --git a/docs/bigscreen/snap/2-5-2.jpg b/docs/bigscreen/snap/2-5-2.jpg new file mode 100644 index 0000000..27e750d Binary files /dev/null and b/docs/bigscreen/snap/2-5-2.jpg differ diff --git a/docs/bigscreen/snap/2-5-3.jpg b/docs/bigscreen/snap/2-5-3.jpg new file mode 100644 index 0000000..4a97b44 Binary files /dev/null and b/docs/bigscreen/snap/2-5-3.jpg differ diff --git a/docs/bigscreen/snap/2-6-0.jpg b/docs/bigscreen/snap/2-6-0.jpg new file mode 100644 index 0000000..b942c45 Binary files /dev/null and b/docs/bigscreen/snap/2-6-0.jpg differ diff --git a/docs/bigscreen/snap/2-6-1.jpg b/docs/bigscreen/snap/2-6-1.jpg new file mode 100644 index 0000000..4f3bf7c Binary files /dev/null and b/docs/bigscreen/snap/2-6-1.jpg differ diff --git a/docs/bigscreen/snap/2-6-2.jpg b/docs/bigscreen/snap/2-6-2.jpg new file mode 100644 index 0000000..7e44dd3 Binary files /dev/null and b/docs/bigscreen/snap/2-6-2.jpg differ diff --git a/docs/bigscreen/snap/2-6-3.jpg b/docs/bigscreen/snap/2-6-3.jpg new file mode 100644 index 0000000..f272060 Binary files /dev/null and b/docs/bigscreen/snap/2-6-3.jpg differ diff --git a/docs/bigscreen/snap/2-6-4.jpg b/docs/bigscreen/snap/2-6-4.jpg new file mode 100644 index 0000000..ae01ebd Binary files /dev/null and b/docs/bigscreen/snap/2-6-4.jpg differ diff --git a/docs/bigscreen/snap/2-7-0.jpg b/docs/bigscreen/snap/2-7-0.jpg new file mode 100644 index 0000000..0d33233 Binary files /dev/null and b/docs/bigscreen/snap/2-7-0.jpg differ diff --git a/docs/bigscreen/snap/2-7-1.jpg b/docs/bigscreen/snap/2-7-1.jpg new file mode 100644 index 0000000..5e63fc5 Binary files /dev/null and b/docs/bigscreen/snap/2-7-1.jpg differ diff --git a/docs/bigscreen/snap/2-7-2.jpg b/docs/bigscreen/snap/2-7-2.jpg new file mode 100644 index 0000000..70dfa2e Binary files /dev/null and b/docs/bigscreen/snap/2-7-2.jpg differ diff --git a/docs/bigscreen/snap/2-7-3.jpg b/docs/bigscreen/snap/2-7-3.jpg new file mode 100644 index 0000000..18366b9 Binary files /dev/null and b/docs/bigscreen/snap/2-7-3.jpg differ diff --git a/docs/bigscreen/snap/2-8-0.jpg b/docs/bigscreen/snap/2-8-0.jpg new file mode 100644 index 0000000..96ccd2d Binary files /dev/null and b/docs/bigscreen/snap/2-8-0.jpg differ diff --git a/docs/bigscreen/snap/2-8-1.jpg b/docs/bigscreen/snap/2-8-1.jpg new file mode 100644 index 0000000..436e644 Binary files /dev/null and b/docs/bigscreen/snap/2-8-1.jpg differ diff --git a/docs/bigscreen/snap/2-8-2.jpg b/docs/bigscreen/snap/2-8-2.jpg new file mode 100644 index 0000000..9dae28a Binary files /dev/null and b/docs/bigscreen/snap/2-8-2.jpg differ diff --git a/docs/bigscreen/snap/4-1-1.jpg b/docs/bigscreen/snap/4-1-1.jpg new file mode 100644 index 0000000..ca4357e Binary files /dev/null and b/docs/bigscreen/snap/4-1-1.jpg differ diff --git a/docs/bigscreen/snap/4-4-1.jpg b/docs/bigscreen/snap/4-4-1.jpg new file mode 100644 index 0000000..9990548 Binary files /dev/null and b/docs/bigscreen/snap/4-4-1.jpg differ diff --git a/docs/bigscreen/snap/4-4-3.jpg b/docs/bigscreen/snap/4-4-3.jpg new file mode 100644 index 0000000..29d957a Binary files /dev/null and b/docs/bigscreen/snap/4-4-3.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-1.jpg b/docs/bigscreen/snap/4-4-4-1.jpg new file mode 100644 index 0000000..03860ec Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-1.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-2.jpg b/docs/bigscreen/snap/4-4-4-2.jpg new file mode 100644 index 0000000..634bb05 Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-2.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-3.jpg b/docs/bigscreen/snap/4-4-4-3.jpg new file mode 100644 index 0000000..62c8312 Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-3.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-4.jpg b/docs/bigscreen/snap/4-4-4-4.jpg new file mode 100644 index 0000000..e99067f Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-4.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-5.jpg b/docs/bigscreen/snap/4-4-4-5.jpg new file mode 100644 index 0000000..b8f4f80 Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-5.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-6.jpg b/docs/bigscreen/snap/4-4-4-6.jpg new file mode 100644 index 0000000..65755ba Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-6.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-7.jpg b/docs/bigscreen/snap/4-4-4-7.jpg new file mode 100644 index 0000000..9aaa3aa Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-7.jpg differ diff --git a/docs/bigscreen/snap/4-4-4-8.jpg b/docs/bigscreen/snap/4-4-4-8.jpg new file mode 100644 index 0000000..c70060d Binary files /dev/null and b/docs/bigscreen/snap/4-4-4-8.jpg differ diff --git a/docs/bigscreen/snap/4-4-4.jpg b/docs/bigscreen/snap/4-4-4.jpg new file mode 100644 index 0000000..9fc579a Binary files /dev/null and b/docs/bigscreen/snap/4-4-4.jpg differ diff --git a/docs/bigscreen/snap/4-5-2.jpg b/docs/bigscreen/snap/4-5-2.jpg new file mode 100644 index 0000000..bf6eeb7 Binary files /dev/null and b/docs/bigscreen/snap/4-5-2.jpg differ diff --git a/docs/bigscreen/snap/4-5-3.jpg b/docs/bigscreen/snap/4-5-3.jpg new file mode 100644 index 0000000..1e4567a Binary files /dev/null and b/docs/bigscreen/snap/4-5-3.jpg differ diff --git a/docs/bigscreen/snap/4-5-4.jpg b/docs/bigscreen/snap/4-5-4.jpg new file mode 100644 index 0000000..c58fbc5 Binary files /dev/null and b/docs/bigscreen/snap/4-5-4.jpg differ diff --git a/docs/bigscreen/snap/4-5-5.jpg b/docs/bigscreen/snap/4-5-5.jpg new file mode 100644 index 0000000..83aa751 Binary files /dev/null and b/docs/bigscreen/snap/4-5-5.jpg differ diff --git a/docs/bigscreen/snap/4-5-6.jpg b/docs/bigscreen/snap/4-5-6.jpg new file mode 100644 index 0000000..91197cd Binary files /dev/null and b/docs/bigscreen/snap/4-5-6.jpg differ diff --git a/docs/bigscreen/snap/4-6-1.jpg b/docs/bigscreen/snap/4-6-1.jpg new file mode 100644 index 0000000..cc84b1f Binary files /dev/null and b/docs/bigscreen/snap/4-6-1.jpg differ diff --git a/docs/bigscreen/snap/4-6-2.jpg b/docs/bigscreen/snap/4-6-2.jpg new file mode 100644 index 0000000..2e3818f Binary files /dev/null and b/docs/bigscreen/snap/4-6-2.jpg differ diff --git a/docs/bigscreen/snap/4-6-3.jpg b/docs/bigscreen/snap/4-6-3.jpg new file mode 100644 index 0000000..036a9fa Binary files /dev/null and b/docs/bigscreen/snap/4-6-3.jpg differ diff --git a/docs/bigscreen/snap/5-1-1.jpg b/docs/bigscreen/snap/5-1-1.jpg new file mode 100644 index 0000000..a6655a0 Binary files /dev/null and b/docs/bigscreen/snap/5-1-1.jpg differ diff --git a/docs/bigscreen/snap/5-1-2.jpg b/docs/bigscreen/snap/5-1-2.jpg new file mode 100644 index 0000000..f44fe8d Binary files /dev/null and b/docs/bigscreen/snap/5-1-2.jpg differ diff --git a/docs/bigscreen/snap/5-1-3.jpg b/docs/bigscreen/snap/5-1-3.jpg new file mode 100644 index 0000000..612b562 Binary files /dev/null and b/docs/bigscreen/snap/5-1-3.jpg differ diff --git a/docs/bigscreen/snap/5-1-4.jpg b/docs/bigscreen/snap/5-1-4.jpg new file mode 100644 index 0000000..b5e22ec Binary files /dev/null and b/docs/bigscreen/snap/5-1-4.jpg differ diff --git a/docs/bigscreen/snap/5-1-5.jpg b/docs/bigscreen/snap/5-1-5.jpg new file mode 100644 index 0000000..cc74ae1 Binary files /dev/null and b/docs/bigscreen/snap/5-1-5.jpg differ diff --git a/docs/bigscreen/snap/5-1-6.jpg b/docs/bigscreen/snap/5-1-6.jpg new file mode 100644 index 0000000..19d3913 Binary files /dev/null and b/docs/bigscreen/snap/5-1-6.jpg differ diff --git a/docs/bigscreen/snap/5-1-7.jpg b/docs/bigscreen/snap/5-1-7.jpg new file mode 100644 index 0000000..fdcc0da Binary files /dev/null and b/docs/bigscreen/snap/5-1-7.jpg differ diff --git a/docs/bigscreen/snap/5-1-8.jpg b/docs/bigscreen/snap/5-1-8.jpg new file mode 100644 index 0000000..1e85304 Binary files /dev/null and b/docs/bigscreen/snap/5-1-8.jpg differ diff --git a/docs/bigscreen/snap/5-2-1.jpg b/docs/bigscreen/snap/5-2-1.jpg new file mode 100644 index 0000000..c5e0907 Binary files /dev/null and b/docs/bigscreen/snap/5-2-1.jpg differ diff --git a/docs/bigscreen/snap/5-2-2.jpg b/docs/bigscreen/snap/5-2-2.jpg new file mode 100644 index 0000000..6be7f54 Binary files /dev/null and b/docs/bigscreen/snap/5-2-2.jpg differ diff --git a/docs/bigscreen/snap/5-2-3.jpg b/docs/bigscreen/snap/5-2-3.jpg new file mode 100644 index 0000000..af4bcbf Binary files /dev/null and b/docs/bigscreen/snap/5-2-3.jpg differ diff --git a/docs/bigscreen/snap/5-2-4.jpg b/docs/bigscreen/snap/5-2-4.jpg new file mode 100644 index 0000000..ec54037 Binary files /dev/null and b/docs/bigscreen/snap/5-2-4.jpg differ diff --git a/docs/bigscreen/snap/5-3-1.jpg b/docs/bigscreen/snap/5-3-1.jpg new file mode 100644 index 0000000..5adad5c Binary files /dev/null and b/docs/bigscreen/snap/5-3-1.jpg differ diff --git a/docs/bigscreen/snap/5-3-10-1.jpg b/docs/bigscreen/snap/5-3-10-1.jpg new file mode 100644 index 0000000..ba69e83 Binary files /dev/null and b/docs/bigscreen/snap/5-3-10-1.jpg differ diff --git a/docs/bigscreen/snap/5-3-10-2.jpg b/docs/bigscreen/snap/5-3-10-2.jpg new file mode 100644 index 0000000..babb0aa Binary files /dev/null and b/docs/bigscreen/snap/5-3-10-2.jpg differ diff --git a/docs/bigscreen/snap/5-3-10-3.jpg b/docs/bigscreen/snap/5-3-10-3.jpg new file mode 100644 index 0000000..1b29097 Binary files /dev/null and b/docs/bigscreen/snap/5-3-10-3.jpg differ diff --git a/docs/bigscreen/snap/5-3-10-4.jpg b/docs/bigscreen/snap/5-3-10-4.jpg new file mode 100644 index 0000000..a569fba Binary files /dev/null and b/docs/bigscreen/snap/5-3-10-4.jpg differ diff --git a/docs/bigscreen/snap/5-3-11.jpg b/docs/bigscreen/snap/5-3-11.jpg new file mode 100644 index 0000000..768df42 Binary files /dev/null and b/docs/bigscreen/snap/5-3-11.jpg differ diff --git a/docs/bigscreen/snap/5-3-2.jpg b/docs/bigscreen/snap/5-3-2.jpg new file mode 100644 index 0000000..e9b3d12 Binary files /dev/null and b/docs/bigscreen/snap/5-3-2.jpg differ diff --git a/docs/bigscreen/snap/5-3-3.jpg b/docs/bigscreen/snap/5-3-3.jpg new file mode 100644 index 0000000..cfc6e84 Binary files /dev/null and b/docs/bigscreen/snap/5-3-3.jpg differ diff --git a/docs/bigscreen/snap/5-3-4.jpg b/docs/bigscreen/snap/5-3-4.jpg new file mode 100644 index 0000000..b13d973 Binary files /dev/null and b/docs/bigscreen/snap/5-3-4.jpg differ diff --git a/docs/bigscreen/snap/5-3-5.jpg b/docs/bigscreen/snap/5-3-5.jpg new file mode 100644 index 0000000..bc812e0 Binary files /dev/null and b/docs/bigscreen/snap/5-3-5.jpg differ diff --git a/docs/bigscreen/snap/5-3-6.jpg b/docs/bigscreen/snap/5-3-6.jpg new file mode 100644 index 0000000..2945980 Binary files /dev/null and b/docs/bigscreen/snap/5-3-6.jpg differ diff --git a/docs/bigscreen/snap/5-3-7.jpg b/docs/bigscreen/snap/5-3-7.jpg new file mode 100644 index 0000000..1c3e984 Binary files /dev/null and b/docs/bigscreen/snap/5-3-7.jpg differ diff --git a/docs/bigscreen/snap/5-3-8.jpg b/docs/bigscreen/snap/5-3-8.jpg new file mode 100644 index 0000000..11d1856 Binary files /dev/null and b/docs/bigscreen/snap/5-3-8.jpg differ diff --git a/docs/bigscreen/snap/5-3-9.jpg b/docs/bigscreen/snap/5-3-9.jpg new file mode 100644 index 0000000..7e299e3 Binary files /dev/null and b/docs/bigscreen/snap/5-3-9.jpg differ diff --git a/docs/bigscreen/snap/5-4-1.jpg b/docs/bigscreen/snap/5-4-1.jpg new file mode 100644 index 0000000..f5f35d0 Binary files /dev/null and b/docs/bigscreen/snap/5-4-1.jpg differ diff --git a/docs/bigscreen/snap/5-4-10.jpg b/docs/bigscreen/snap/5-4-10.jpg new file mode 100644 index 0000000..7207f61 Binary files /dev/null and b/docs/bigscreen/snap/5-4-10.jpg differ diff --git a/docs/bigscreen/snap/5-4-11.jpg b/docs/bigscreen/snap/5-4-11.jpg new file mode 100644 index 0000000..233e93a Binary files /dev/null and b/docs/bigscreen/snap/5-4-11.jpg differ diff --git a/docs/bigscreen/snap/5-4-12.jpg b/docs/bigscreen/snap/5-4-12.jpg new file mode 100644 index 0000000..aa50e63 Binary files /dev/null and b/docs/bigscreen/snap/5-4-12.jpg differ diff --git a/docs/bigscreen/snap/5-4-2.jpg b/docs/bigscreen/snap/5-4-2.jpg new file mode 100644 index 0000000..882fdb0 Binary files /dev/null and b/docs/bigscreen/snap/5-4-2.jpg differ diff --git a/docs/bigscreen/snap/5-4-3.jpg b/docs/bigscreen/snap/5-4-3.jpg new file mode 100644 index 0000000..5983bc6 Binary files /dev/null and b/docs/bigscreen/snap/5-4-3.jpg differ diff --git a/docs/bigscreen/snap/5-4-4.jpg b/docs/bigscreen/snap/5-4-4.jpg new file mode 100644 index 0000000..156393e Binary files /dev/null and b/docs/bigscreen/snap/5-4-4.jpg differ diff --git a/docs/bigscreen/snap/5-4-5.jpg b/docs/bigscreen/snap/5-4-5.jpg new file mode 100644 index 0000000..6a1815a Binary files /dev/null and b/docs/bigscreen/snap/5-4-5.jpg differ diff --git a/docs/bigscreen/snap/5-4-6.jpg b/docs/bigscreen/snap/5-4-6.jpg new file mode 100644 index 0000000..1d99573 Binary files /dev/null and b/docs/bigscreen/snap/5-4-6.jpg differ diff --git a/docs/bigscreen/snap/5-4-7.jpg b/docs/bigscreen/snap/5-4-7.jpg new file mode 100644 index 0000000..2e404a9 Binary files /dev/null and b/docs/bigscreen/snap/5-4-7.jpg differ diff --git a/docs/bigscreen/snap/5-4-8.jpg b/docs/bigscreen/snap/5-4-8.jpg new file mode 100644 index 0000000..c43ff25 Binary files /dev/null and b/docs/bigscreen/snap/5-4-8.jpg differ diff --git a/docs/bigscreen/snap/5-4-9.jpg b/docs/bigscreen/snap/5-4-9.jpg new file mode 100644 index 0000000..db5cc9e Binary files /dev/null and b/docs/bigscreen/snap/5-4-9.jpg differ diff --git a/docs/bigscreen/snap/5-5-1.jpg b/docs/bigscreen/snap/5-5-1.jpg new file mode 100644 index 0000000..8dc1a8c Binary files /dev/null and b/docs/bigscreen/snap/5-5-1.jpg differ diff --git a/docs/bigscreen/snap/5-5-2.jpg b/docs/bigscreen/snap/5-5-2.jpg new file mode 100644 index 0000000..a7d7b40 Binary files /dev/null and b/docs/bigscreen/snap/5-5-2.jpg differ diff --git a/docs/bigscreen/snap/5-5-3.jpg b/docs/bigscreen/snap/5-5-3.jpg new file mode 100644 index 0000000..ecdcc9b Binary files /dev/null and b/docs/bigscreen/snap/5-5-3.jpg differ diff --git a/docs/bigscreen/snap/5-5-4.jpg b/docs/bigscreen/snap/5-5-4.jpg new file mode 100644 index 0000000..db461b1 Binary files /dev/null and b/docs/bigscreen/snap/5-5-4.jpg differ diff --git a/docs/bigscreen/snap/5-5-6.jpg b/docs/bigscreen/snap/5-5-6.jpg new file mode 100644 index 0000000..33806d3 Binary files /dev/null and b/docs/bigscreen/snap/5-5-6.jpg differ diff --git a/docs/bigscreen/snap/5-5-7.jpg b/docs/bigscreen/snap/5-5-7.jpg new file mode 100644 index 0000000..0259a34 Binary files /dev/null and b/docs/bigscreen/snap/5-5-7.jpg differ diff --git a/docs/bigscreen/snap/5-5-8.jpg b/docs/bigscreen/snap/5-5-8.jpg new file mode 100644 index 0000000..bb464db Binary files /dev/null and b/docs/bigscreen/snap/5-5-8.jpg differ diff --git a/docs/bigscreen/snap/5-6-1.jpg b/docs/bigscreen/snap/5-6-1.jpg new file mode 100644 index 0000000..f43ed6d Binary files /dev/null and b/docs/bigscreen/snap/5-6-1.jpg differ diff --git a/docs/bigscreen/snap/5-6-2.jpg b/docs/bigscreen/snap/5-6-2.jpg new file mode 100644 index 0000000..0396d03 Binary files /dev/null and b/docs/bigscreen/snap/5-6-2.jpg differ diff --git a/docs/bigscreen/snap/5-6-3.jpg b/docs/bigscreen/snap/5-6-3.jpg new file mode 100644 index 0000000..7a10850 Binary files /dev/null and b/docs/bigscreen/snap/5-6-3.jpg differ diff --git a/docs/bigscreen/snap/5-6-4.jpg b/docs/bigscreen/snap/5-6-4.jpg new file mode 100644 index 0000000..c26d5ba Binary files /dev/null and b/docs/bigscreen/snap/5-6-4.jpg differ diff --git a/docs/bigscreen/snap/5-6-5.jpg b/docs/bigscreen/snap/5-6-5.jpg new file mode 100644 index 0000000..c4ada12 Binary files /dev/null and b/docs/bigscreen/snap/5-6-5.jpg differ diff --git a/docs/bigscreen/snap/5-6-6.jpg b/docs/bigscreen/snap/5-6-6.jpg new file mode 100644 index 0000000..d5cf834 Binary files /dev/null and b/docs/bigscreen/snap/5-6-6.jpg differ diff --git a/docs/bigscreen/snap/5-6-7.jpg b/docs/bigscreen/snap/5-6-7.jpg new file mode 100644 index 0000000..ff6bb5f Binary files /dev/null and b/docs/bigscreen/snap/5-6-7.jpg differ diff --git a/docs/bigscreen/snap/5-6-8.jpg b/docs/bigscreen/snap/5-6-8.jpg new file mode 100644 index 0000000..38c50ed Binary files /dev/null and b/docs/bigscreen/snap/5-6-8.jpg differ diff --git a/docs/examples.js b/docs/examples.js new file mode 100644 index 0000000..2f1f5ea --- /dev/null +++ b/docs/examples.js @@ -0,0 +1 @@ +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var STACK_ALIGN=16;function dynamicAlloc(size){var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;if(end>_emscripten_get_heap_size()){abort()}HEAP32[DYNAMICTOP_PTR>>2]=end;return ret}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0,"getNativeTypeSize invalid bits "+bits+", type "+type);return bits/8}else{return 0}}}}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}function convertJsFunctionToWasm(func,sig){if(typeof WebAssembly.Function==="function"){var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":11826,"maximum":11826+0,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>2]=0}stop=ret+size;while(ptr>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){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;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function UTF16ToString(ptr){var endPtr=ptr;var idx=endPtr>>1;while(HEAP16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder){return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr))}else{var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)return str;++i;str+=String.fromCharCode(codeUnit)}}}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr){var i=0;var str="";while(1){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)return str;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}}function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){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]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function allocateUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8Array(str,HEAP8,ret,size);return ret}function allocateUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var STACK_BASE=16562768,DYNAMIC_BASE=16562768,DYNAMICTOP_PTR=11319712;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_TOTAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();SOCKFS.root=FS.mount(SOCKFS,{},null);callRuntimeCallbacks(__ATINIT__)}function preMain(){FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);FS.quit();TTY.shutdown();runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function unSign(value,bits,ignore){if(value>=0){return value}return bits<=32?2*Math.abs(1<=half&&(bits<=32||value>half)){value=-2*half+value}return value}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="examples.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"env":asmLibraryArg,"wasi_snapshot_preview1":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;__ATINIT__.push({func:function(){___wasm_call_ctors()}});function demangle(func){return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ___cxa_allocate_exception(size){return _malloc(size)}function _atexit(func,arg){__ATEXIT__.unshift({func:func,arg:arg})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function ___cxa_thread_atexit(){return _atexit.apply(null,arguments)}var ___exception_infos={};var ___exception_last=0;function ___cxa_throw(ptr,type,destructor){___exception_infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};___exception_last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exceptions=1}else{__ZSt18uncaught_exceptionv.uncaught_exceptions++}throw ptr}function ___lock(){}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}function ___map_file(pathname,size){___setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(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:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(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:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[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.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(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;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){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}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){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;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=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+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(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:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(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:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}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:function(parent,name,mode,rdev){if(!FS.FSNode){FS.FSNode=function(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};FS.FSNode.prototype={};var readMode=292|73;var writeMode=146;Object.defineProperties(FS.FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}})}var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(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:function(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:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}})}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(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(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(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:type,opts:opts,mountpoint: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:function(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(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(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:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";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]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_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=function(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);if(typeof Uint8Array!="undefined")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||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(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};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;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url: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(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}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>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});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},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:0,get:function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(){var ret=UTF8ToString(SYSCALLS.get());return ret},getStreamFromFD:function(fd){if(fd===undefined)fd=SYSCALLS.get();var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(){var low=SYSCALLS.get(),high=SYSCALLS.get();return low},getZero:function(){SYSCALLS.get()}};function ___syscall10(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr();FS.unlink(path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}var ERRNO_CODES={EPERM:63,ENOENT:44,ESRCH:71,EINTR:27,EIO:29,ENXIO:60,E2BIG:1,ENOEXEC:45,EBADF:8,ECHILD:12,EAGAIN:6,EWOULDBLOCK:6,ENOMEM:48,EACCES:2,EFAULT:21,ENOTBLK:105,EBUSY:10,EEXIST:20,EXDEV:75,ENODEV:43,ENOTDIR:54,EISDIR:31,EINVAL:28,ENFILE:41,EMFILE:33,ENOTTY:59,ETXTBSY:74,EFBIG:22,ENOSPC:51,ESPIPE:70,EROFS:69,EMLINK:34,EPIPE:64,EDOM:18,ERANGE:68,ENOMSG:49,EIDRM:24,ECHRNG:106,EL2NSYNC:156,EL3HLT:107,EL3RST:108,ELNRNG:109,EUNATCH:110,ENOCSI:111,EL2HLT:112,EDEADLK:16,ENOLCK:46,EBADE:113,EBADR:114,EXFULL:115,ENOANO:104,EBADRQC:103,EBADSLT:102,EDEADLOCK:16,EBFONT:101,ENOSTR:100,ENODATA:116,ETIME:117,ENOSR:118,ENONET:119,ENOPKG:120,EREMOTE:121,ENOLINK:47,EADV:122,ESRMNT:123,ECOMM:124,EPROTO:65,EMULTIHOP:36,EDOTDOT:125,EBADMSG:9,ENOTUNIQ:126,EBADFD:127,EREMCHG:128,ELIBACC:129,ELIBBAD:130,ELIBSCN:131,ELIBMAX:132,ELIBEXEC:133,ENOSYS:52,ENOTEMPTY:55,ENAMETOOLONG:37,ELOOP:32,EOPNOTSUPP:138,EPFNOSUPPORT:139,ECONNRESET:15,ENOBUFS:42,EAFNOSUPPORT:5,EPROTOTYPE:67,ENOTSOCK:57,ENOPROTOOPT:50,ESHUTDOWN:140,ECONNREFUSED:14,EADDRINUSE:3,ECONNABORTED:13,ENETUNREACH:40,ENETDOWN:38,ETIMEDOUT:73,EHOSTDOWN:142,EHOSTUNREACH:23,EINPROGRESS:26,EALREADY:7,EDESTADDRREQ:17,EMSGSIZE:35,EPROTONOSUPPORT:66,ESOCKTNOSUPPORT:137,EADDRNOTAVAIL:4,ENETRESET:39,EISCONN:30,ENOTCONN:53,ETOOMANYREFS:141,EUSERS:136,EDQUOT:19,ESTALE:72,ENOTSUP:138,ENOMEDIUM:148,EILSEQ:25,EOVERFLOW:61,ECANCELED:11,ENOTRECOVERABLE:56,EOWNERDEAD:62,ESTRPIPE:135};var SOCKFS={mount:function(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:function(family,type,protocol){var streaming=type==1;if(protocol){assert(streaming==(protocol==6))}var sock={family:family,type:type,protocol: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:node,flags:FS.modeStringToFlags("r+"),seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket:function(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll:function(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl:function(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read:function(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:function(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close:function(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname:function(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return"socket["+SOCKFS.nextname.current+++"]"},websocket_sock_ops:{createPeer:function(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=ENVIRONMENT_IS_NODE?{"protocol":subProtocols.toString()}:subProtocols}if(runtimeConfig&&null===Module["websocket"]["subprotocol"]){subProtocols="null";opts=undefined}var WebSocketConstructor;if(ENVIRONMENT_IS_NODE){WebSocketConstructor=require("ws")}else if(ENVIRONMENT_IS_WEB){WebSocketConstructor=window["WebSocket"]}else{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH)}}var peer={addr:addr,port:port,socket:ws,dgram_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.dgram_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:function(sock,addr,port){return sock.peers[addr+":"+port]},addPeer:function(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer:function(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents:function(sock,peer){var first=true;var handleOpen=function(){Module["websocket"].emit("open",sock.stream.fd);try{var queued=peer.dgram_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.dgram_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}else{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:data});Module["websocket"].emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,flags){if(!flags.binary){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=ERRNO_CODES.ECONNREFUSED;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=ERRNO_CODES.ECONNREFUSED;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll:function(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:function(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]=bytes;return 0;default:return ERRNO_CODES.EINVAL}},close:function(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i>>0}function __inet_pton6_raw(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.indexOf("::")===0){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]=parseInt(words[words.length-4])+parseInt(words[words.length-3])*256;words[words.length-3]=parseInt(words[words.length-2])+parseInt(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255)}function __inet_ntop6_raw(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=__inet_ntop4_raw(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>1];var port=_ntohs(HEAPU16[sa+2>>1]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>2];addr=__inet_ntop4_raw(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>2],HEAP32[sa+12>>2],HEAP32[sa+16>>2],HEAP32[sa+20>>2]];addr=__inet_ntop6_raw(addr);break;default:return{errno:5}}return{family:family,addr:addr,port:port}}function __write_sockaddr(sa,family,addr,port){switch(family){case 2:addr=__inet_pton4_raw(addr);HEAP16[sa>>1]=family;HEAP32[sa+4>>2]=addr;HEAP16[sa+2>>1]=_htons(port);break;case 10:addr=__inet_pton6_raw(addr);HEAP32[sa>>2]=family;HEAP32[sa+8>>2]=addr[0];HEAP32[sa+12>>2]=addr[1];HEAP32[sa+16>>2]=addr[2];HEAP32[sa+20>>2]=addr[3];HEAP16[sa+2>>1]=_htons(port);HEAP32[sa+4>>2]=0;HEAP32[sa+24>>2]=0;break;default:return{errno:5}}return{}}function ___syscall102(which,varargs){SYSCALLS.varargs=varargs;try{var call=SYSCALLS.get(),socketvararg=SYSCALLS.get();SYSCALLS.varargs=socketvararg;var getSocketFromFD=function(){var socket=SOCKFS.getSocket(SYSCALLS.get());if(!socket)throw new FS.ErrnoError(8);return socket};var getSocketAddress=function(allowNull){var addrp=SYSCALLS.get(),addrlen=SYSCALLS.get();if(allowNull&&addrp===0)return null;var info=__read_sockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};switch(call){case 1:{var domain=SYSCALLS.get(),type=SYSCALLS.get(),protocol=SYSCALLS.get();var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}case 2:{var sock=getSocketFromFD(),info=getSocketAddress();sock.sock_ops.bind(sock,info.addr,info.port);return 0}case 3:{var sock=getSocketFromFD(),info=getSocketAddress();sock.sock_ops.connect(sock,info.addr,info.port);return 0}case 4:{var sock=getSocketFromFD(),backlog=SYSCALLS.get();sock.sock_ops.listen(sock,backlog);return 0}case 5:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var newsock=sock.sock_ops.accept(sock);if(addr){var res=__write_sockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport)}return newsock.stream.fd}case 6:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport);return 0}case 7:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();if(!sock.daddr){return-53}var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport);return 0}case 11:{var sock=getSocketFromFD(),message=SYSCALLS.get(),length=SYSCALLS.get(),flags=SYSCALLS.get(),dest=getSocketAddress(true);if(!dest){return FS.write(sock.stream,HEAP8,message,length)}else{return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}}case 12:{var sock=getSocketFromFD(),buf=SYSCALLS.get(),len=SYSCALLS.get(),flags=SYSCALLS.get(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port)}HEAPU8.set(msg.buffer,buf);return msg.buffer.byteLength}case 14:{return-50}case 15:{var sock=getSocketFromFD(),level=SYSCALLS.get(),optname=SYSCALLS.get(),optval=SYSCALLS.get(),optlen=SYSCALLS.get();if(level===1){if(optname===4){HEAP32[optval>>2]=sock.error;HEAP32[optlen>>2]=4;sock.error=null;return 0}}return-50}case 16:{var sock=getSocketFromFD(),message=SYSCALLS.get(),flags=SYSCALLS.get();var iov=HEAP32[message+8>>2];var num=HEAP32[message+12>>2];var addr,port;var name=HEAP32[message>>2];var namelen=HEAP32[message+4>>2];if(name){var info=__read_sockaddr(name,namelen);if(info.errno)return-info.errno;port=info.port;addr=DNS.lookup_addr(info.addr)||info.addr}var total=0;for(var i=0;i>2]}var view=new Uint8Array(total);var offset=0;for(var i=0;i>2];var iovlen=HEAP32[iov+(8*i+4)>>2];for(var j=0;j>0]}}return sock.sock_ops.sendmsg(sock,view,0,total,addr,port)}case 17:{var sock=getSocketFromFD(),message=SYSCALLS.get(),flags=SYSCALLS.get();var iov=HEAP32[message+8>>2];var num=HEAP32[message+12>>2];var total=0;for(var i=0;i>2]}var msg=sock.sock_ops.recvmsg(sock,total);if(!msg)return 0;var name=HEAP32[message>>2];if(name){var res=__write_sockaddr(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];var iovlen=HEAP32[iov+(8*i+4)>>2];if(!iovlen){continue}var length=Math.min(iovlen,bytesRemaining);var buf=msg.buffer.subarray(bytesRead,bytesRead+length);HEAPU8.set(buf,iovbase+bytesRead);bytesRead+=length;bytesRemaining-=length}return bytesRead}default:{return-52}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall122(which,varargs){SYSCALLS.varargs=varargs;try{var buf=SYSCALLS.get();if(!buf)return-21;var layout={"__size__":390,"sysname":0,"nodename":65,"release":130,"version":195,"machine":260,"domainname":325};var copyString=function(element,value){var offset=layout[element];writeAsciiToMemory(value,buf+offset)};copyString("sysname","Emscripten");copyString("nodename","emscripten");copyString("release","1.0");copyString("version","#1");copyString("machine","x86-JS");return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall15(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),mode=SYSCALLS.get();FS.chmod(path,mode);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall168(which,varargs){SYSCALLS.varargs=varargs;try{var fds=SYSCALLS.get(),nfds=SYSCALLS.get(),timeout=SYSCALLS.get();var nonzero=0;for(var i=0;i>2];var events=HEAP16[pollfd+4>>1];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){mask=stream.stream_ops.poll(stream)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>1]=mask}return nonzero}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall183(which,varargs){SYSCALLS.varargs=varargs;try{var buf=SYSCALLS.get(),size=SYSCALLS.get();if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd);if(size=67){while((ptr&3)!=0){HEAP8[ptr>>0]=value;ptr=ptr+1|0}aligned_end=end&-4|0;value4=value|value<<8|value<<16|value<<24;block_aligned_end=aligned_end-64|0;while((ptr|0)<=(block_aligned_end|0)){HEAP32[ptr>>2]=value4;HEAP32[ptr+4>>2]=value4;HEAP32[ptr+8>>2]=value4;HEAP32[ptr+12>>2]=value4;HEAP32[ptr+16>>2]=value4;HEAP32[ptr+20>>2]=value4;HEAP32[ptr+24>>2]=value4;HEAP32[ptr+28>>2]=value4;HEAP32[ptr+32>>2]=value4;HEAP32[ptr+36>>2]=value4;HEAP32[ptr+40>>2]=value4;HEAP32[ptr+44>>2]=value4;HEAP32[ptr+48>>2]=value4;HEAP32[ptr+52>>2]=value4;HEAP32[ptr+56>>2]=value4;HEAP32[ptr+60>>2]=value4;ptr=ptr+64|0}while((ptr|0)<(aligned_end|0)){HEAP32[ptr>>2]=value4;ptr=ptr+4|0}}while((ptr|0)<(end|0)){HEAP8[ptr>>0]=value;ptr=ptr+1|0}return end-num|0}function __emscripten_syscall_mmap2(addr,len,prot,flags,fd,off){off<<=12;var ptr;var allocated=false;if((flags&16)!==0&&addr%16384!==0){return-28}if((flags&32)!==0){ptr=_memalign(16384,len);if(!ptr)return-48;_memset(ptr,0,len);allocated=true}else{var info=FS.getStream(fd);if(!info)return-8;var res=FS.mmap(info,HEAPU8,addr,len,off,prot,flags);ptr=res.ptr;allocated=res.allocated}SYSCALLS.mappings[ptr]={malloc:ptr,len:len,allocated:allocated,fd:fd,flags:flags,offset:off};return ptr}function ___syscall192(which,varargs){SYSCALLS.varargs=varargs;try{var addr=SYSCALLS.get(),len=SYSCALLS.get(),prot=SYSCALLS.get(),flags=SYSCALLS.get(),fd=SYSCALLS.get(),off=SYSCALLS.get();return __emscripten_syscall_mmap2(addr,len,prot,flags,fd,off)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall193(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),zero=SYSCALLS.getZero(),length=SYSCALLS.get64();FS.truncate(path,length);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall194(which,varargs){SYSCALLS.varargs=varargs;try{var fd=SYSCALLS.get(),zero=SYSCALLS.getZero(),length=SYSCALLS.get64();FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall195(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),buf=SYSCALLS.get();return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall196(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),buf=SYSCALLS.get();return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall197(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),buf=SYSCALLS.get();return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall202(which,varargs){SYSCALLS.varargs=varargs;try{return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall199(a0,a1){return ___syscall202(a0,a1)}var PROCINFO={ppid:1,pid:42,sid:42,pgid:42};function ___syscall20(which,varargs){SYSCALLS.varargs=varargs;try{return PROCINFO.pid}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall201(a0,a1){return ___syscall202(a0,a1)}function ___syscall220(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),dirp=SYSCALLS.get(),count=SYSCALLS.get();if(!stream.getdents){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>>0,(tempDouble=id,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos>>2]=tempI64[0],HEAP32[dirp+pos+4>>2]=tempI64[1];tempI64=[(idx+1)*struct_size>>>0,(tempDouble=(idx+1)*struct_size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos+8>>2]=tempI64[0],HEAP32[dirp+pos+12>>2]=tempI64[1];HEAP16[dirp+pos+16>>1]=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 instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall221(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),cmd=SYSCALLS.get();switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 12:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0;case 16:case 8:return-28;case 9:___setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall3(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),buf=SYSCALLS.get(),count=SYSCALLS.get();return FS.read(stream,HEAP8,buf,count)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall320(which,varargs){SYSCALLS.varargs=varargs;try{var dirfd=SYSCALLS.get(),path=SYSCALLS.getStr(),times=SYSCALLS.get(),flags=SYSCALLS.get();path=SYSCALLS.calculateAt(dirfd,path);var seconds=HEAP32[times>>2];var nanoseconds=HEAP32[times+4>>2];var atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=8;seconds=HEAP32[times>>2];nanoseconds=HEAP32[times+4>>2];var mtime=seconds*1e3+nanoseconds/(1e3*1e3);FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall33(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),amode=SYSCALLS.get();return SYSCALLS.doAccess(path,amode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall38(which,varargs){SYSCALLS.varargs=varargs;try{var old_path=SYSCALLS.getStr(),new_path=SYSCALLS.getStr();FS.rename(old_path,new_path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall39(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),mode=SYSCALLS.get();return SYSCALLS.doMkdir(path,mode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall4(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),buf=SYSCALLS.get(),count=SYSCALLS.get();return FS.write(stream,HEAP8,buf,count)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall40(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr();FS.rmdir(path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall5(which,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(),flags=SYSCALLS.get(),mode=SYSCALLS.get();var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall54(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),op=SYSCALLS.get();switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort("bad ioctl syscall "+op)}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall83(which,varargs){SYSCALLS.varargs=varargs;try{var target=SYSCALLS.getStr(),linkpath=SYSCALLS.getStr();FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall85(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),buf=SYSCALLS.get(),bufsize=SYSCALLS.get();return SYSCALLS.doReadlink(path,buf,bufsize)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall9(which,varargs){SYSCALLS.varargs=varargs;try{var oldpath=SYSCALLS.get(),newpath=SYSCALLS.get();return-34}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function __emscripten_syscall_munmap(addr,len){if(addr===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset);FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___syscall91(which,varargs){SYSCALLS.varargs=varargs;try{var addr=SYSCALLS.get(),len=SYSCALLS.get();return __emscripten_syscall_munmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall94(which,varargs){SYSCALLS.varargs=varargs;try{var fd=SYSCALLS.get(),mode=SYSCALLS.get();FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___unlock(){}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function 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=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return new Function("body","return function "+name+"() {\n"+' "use strict";'+" return body.apply(this, arguments);\n"+"};\n")(body)}function 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 BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(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>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function new_(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError("new_ called with constructor type "+typeof constructor+" which is not a function")}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i>2)+i])}return array}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,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+4+i]=charCode}}else{for(var i=0;i>2];var HEAP=getHeap();var str;var endChar=HEAP[value+4+length*charSize>>shift];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAP[value+4+length*charSize>>shift]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(HEAP[currentBytePtr>>shift]==0){var stringSegment=decodeString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}if(endCharSwap!=0)HEAP[value+4+length*charSize>>shift]=endCharSwap;_free(value);return str},"toWireType":function(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]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_as(handle,returnType,destructorsRef){handle=requireHandle(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=__emval_register(destructors);HEAP32[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)}function __emval_lookupTypes(argCount,argTypes,argWireTypes){var a=new Array(argCount);for(var i=0;i>2)+i],"parameter "+i)}return a}function __emval_call(handle,argCount,argTypes,argv){handle=requireHandle(handle);var types=__emval_lookupTypes(argCount,argTypes);var args=new Array(argCount);for(var i=0;i>2]=__emval_register(destructors);return destructors}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_method(caller,handle,methodName,destructorsRef,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);return caller(handle,methodName,__emval_allocateDestructors(destructorsRef),args)}function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function __emval_equals(first,second){first=requireHandle(first);second=requireHandle(second);return first==second}function emval_get_global(){if(typeof globalThis==="object"){return globalThis}return function(){return Function}()("return this")()}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map(function(t){return t.name}).join("_")+"$";var params=["retType"];var args=[retType];var argsList="";for(var i=0;i4){emval_handle_array[handle].refcount+=1}}function __emval_is_string(handle){handle=requireHandle(handle);return typeof handle==="string"}function craftEmvalAllocator(argCount){var argsList="";for(var i=0;i> 2) + "+i+'], "parameter '+i+'");\n'+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return __emval_register(obj);\n"+"}\n";return new Function("requireRegisteredType","Module","__emval_register",functionBody)(requireRegisteredType,Module,__emval_register)}var emval_newers={};function __emval_new(handle,argCount,argTypes,args){handle=requireHandle(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_new_object(){return __emval_register({})}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle=requireHandle(handle);key=requireHandle(key);value=requireHandle(value);handle[key]=value}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _abort(){abort()}function _emscripten_get_now(){abort()}var _emscripten_get_now_is_monotonic=0||ENVIRONMENT_IS_NODE||typeof dateNow!=="undefined"||1;function _clock_gettime(clk_id,tp){var now;if(clk_id===0){now=Date.now()}else if((clk_id===1||clk_id===4)&&_emscripten_get_now_is_monotonic){now=_emscripten_get_now()}else{___setErrNo(28);return-1}HEAP32[tp>>2]=now/1e3|0;HEAP32[tp+4>>2]=now%1e3*1e3*1e3|0;return 0}function _dlopen(){abort("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")}function _dlclose(){return _dlopen.apply(null,arguments)}function _dlerror(){return _dlopen.apply(null,arguments)}function _dlsym(){return _dlopen.apply(null,arguments)}function _emscripten_set_main_loop_timing(mode,value){Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof setImmediate==="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=function(event){if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop,arg,noSetTiming){noExitRuntime=true;assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=func;Browser.mainLoop.arg=arg;var browserIterationFunc;if(typeof arg!=="undefined"){browserIterationFunc=function(){Module["dynCall_vi"](func,arg)}}else{browserIterationFunc=function(){Module["dynCall_v"](func)}}var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;Browser.mainLoop.runner=function Browser_mainLoop_runner(){if(ABORT)return;if(Browser.mainLoop.queue.length>0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}console.log('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(thisMainLoopId1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}GL.newRenderingFrameStarted();Browser.mainLoop.runIter(browserIterationFunc);if(thisMainLoopId0)_emscripten_set_main_loop_timing(0,1e3/fps);else _emscripten_set_main_loop_timing(1,1);Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;_emscripten_set_main_loop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining=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;Browser.safeSetTimeout(function(){finish(audio)},1e4)}else{return fail()}};Module["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"]||function(){};canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||function(){};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",function(ev){if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext:function(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){if(!useWebGL)assert(typeof GLctx==="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas,vrDevice){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;Browser.vrDevice=vrDevice;if(typeof Browser.lockPointer==="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas==="undefined")Browser.resizeCanvas=false;if(typeof Browser.vrDevice==="undefined")Browser.vrDevice=null;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)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])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"]?function(){canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null)||(canvasContainer["webkitRequestFullScreen"]?function(){canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null);if(vrDevice){canvasContainer.requestFullscreen({vrDisplay:vrDevice})}else{canvasContainer.requestFullscreen()}},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||function(){};CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame==="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeCallback:function(func){return function(){if(!ABORT)return func.apply(null,arguments)}},allowAsyncCallbacks:true,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=false},resumeAsyncCallbacks:function(){Browser.allowAsyncCallbacks=true;if(Browser.queuedAsyncCallbacks.length>0){var callbacks=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[];callbacks.forEach(function(func){func()})}},safeRequestAnimationFrame:function(func){return Browser.requestAnimationFrame(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}})},safeSetTimeout:function(func,timeout){noExitRuntime=true;return setTimeout(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}},timeout)},safeSetInterval:function(func,timeout){noExitRuntime=true;return setInterval(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}},timeout)},getMimetype:function(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:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(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:{},calculateMouseEvent:function(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)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{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;if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};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];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},asyncLoad:function(url,onload,onerror,noRunDep){var dep=!noRunDep?getUniqueRunDependency("al "+url):"";readAsync(url,function(arrayBuffer){assert(arrayBuffer,'Loading data file "'+url+'" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},function(event){if(onerror){onerror()}else{throw'Loading data file "'+url+'" failed.'}});if(dep)addRunDependency(dep)},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(function(listener){listener(canvas.width,canvas.height)})},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(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/h>2];if(param==12321){var alphaSize=HEAP32[attribList+4>>2];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>2];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>2];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>2];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>2]=1}if(config&&config_size>0){HEAP32[config>>2]=62002}EGL.setErrorCode(12288);return 1}};function _eglGetProcAddress(name_){return _emscripten_GetProcAddress(name_)}function _emscripten_async_call(func,arg,millis){noExitRuntime=true;function wrapper(){getFuncWrapper(func,"vi")(arg)}if(millis>=0){Browser.safeSetTimeout(wrapper,millis)}else{Browser.safeRequestAnimationFrame(wrapper)}}function _emscripten_date_now(){return Date.now()}function _emscripten_force_exit(status){noExitRuntime=false;exit(status)}var JSEvents={keyEvent:0,mouseEvent:0,wheelEvent:0,uiEvent:0,focusEvent:0,deviceOrientationEvent:0,deviceMotionEvent:0,fullscreenChangeEvent:0,pointerlockChangeEvent:0,visibilityChangeEvent:0,touchEvent:0,previousFullscreenElement:null,previousScreenX:null,previousScreenY:null,removeEventListenersRegistered:false,removeAllEventListeners:function(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners:function(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall:function(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 i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort(function(x,y){return x.precedence>3]=rect.width;HEAPF64[height>>3]=rect.height;return 0}function _emscripten_get_heap_size(){return HEAPU8.length}function _emscripten_get_sbrk_ptr(){return 11319712}function __webgl_acquireInstancedArraysExtension(ctx){var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=function(index,divisor){ext["vertexAttribDivisorANGLE"](index,divisor)};ctx["drawArraysInstanced"]=function(mode,first,count,primcount){ext["drawArraysInstancedANGLE"](mode,first,count,primcount)};ctx["drawElementsInstanced"]=function(mode,count,type,indices,primcount){ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount)}}}function __webgl_acquireVertexArrayObjectExtension(ctx){var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=function(){return ext["createVertexArrayOES"]()};ctx["deleteVertexArray"]=function(vao){ext["deleteVertexArrayOES"](vao)};ctx["bindVertexArray"]=function(vao){ext["bindVertexArrayOES"](vao)};ctx["isVertexArray"]=function(vao){return ext["isVertexArrayOES"](vao)}}}function __webgl_acquireDrawBuffersExtension(ctx){var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=function(n,bufs){ext["drawBuffersWEBGL"](n,bufs)}}}var GL={counter:1,lastError:0,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],uniforms:[],shaders:[],vaos:[],contexts:{},currentContext:null,offscreenCanvases:{},timerQueriesEXT:[],queries:[],samplers:[],transformFeedbacks:[],syncs:[],currArrayBuffer:0,currElementArrayBuffer:0,byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],programInfos:{},stringCache:{},stringiCache:{},unpackAlignment:4,init:function(){var miniTempFloatBuffer=new Float32Array(GL.MINI_TEMP_BUFFER_SIZE);for(var i=0;i>1;var quadIndexes=new Uint16Array(numIndexes);var i=0,v=0;while(1){quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+1;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v+3;if(i>=numIndexes)break;v+=4}context.GLctx.bufferData(34963,quadIndexes,35044);context.GLctx.bindBuffer(34963,null)}},getTempVertexBuffer:function getTempVertexBuffer(sizeBytes){var idx=GL.log2ceilLookup(sizeBytes);var ringbuffer=GL.currentContext.tempVertexBuffers1[idx];var nextFreeBufferIndex=GL.currentContext.tempVertexBufferCounters1[idx];GL.currentContext.tempVertexBufferCounters1[idx]=GL.currentContext.tempVertexBufferCounters1[idx]+1&GL.numTempVertexBuffersPerSize-1;var vbo=ringbuffer[nextFreeBufferIndex];if(vbo){return vbo}var prevVBO=GLctx.getParameter(34964);ringbuffer[nextFreeBufferIndex]=GLctx.createBuffer();GLctx.bindBuffer(34962,ringbuffer[nextFreeBufferIndex]);GLctx.bufferData(34962,1<>2]:-1;source+=UTF8ToString(HEAP32[string+i*4>>2],len<0?undefined:len)}return source},calcBufLength:function calcBufLength(size,type,stride,count){if(stride>0){return count*stride}var typeSize=GL.byteSizeByType[type-GL.byteSizeByTypeRoot];return size*typeSize*count},usedTempBuffers:[],preDrawHandleClientVertexAttribBindings:function preDrawHandleClientVertexAttribBindings(count){GL.resetBufferBinding=false;for(var i=0;i1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:function(ctx,webGLContextAttributes){var handle=_malloc(8);var context={handle: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)}context.maxVertexAttribs=context.GLctx.getParameter(34921);context.clientBuffers=[];for(var i=0;i=2){if(data){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}}function _emscripten_glBufferSubData(target,offset,size,data){if(GL.currentContext.version>=2){GLctx.bufferSubData(target,offset,HEAPU8,data,size);return}GLctx.bufferSubData(target,offset,HEAPU8.subarray(data,data+size))}function _emscripten_glCheckFramebufferStatus(x0){return GLctx["checkFramebufferStatus"](x0)}function _emscripten_glClear(x0){GLctx["clear"](x0)}function _emscripten_glClearBufferfi(x0,x1,x2,x3){GLctx["clearBufferfi"](x0,x1,x2,x3)}function _emscripten_glClearBufferfv(buffer,drawbuffer,value){GLctx["clearBufferfv"](buffer,drawbuffer,HEAPF32,value>>2)}function _emscripten_glClearBufferiv(buffer,drawbuffer,value){GLctx["clearBufferiv"](buffer,drawbuffer,HEAP32,value>>2)}function _emscripten_glClearBufferuiv(buffer,drawbuffer,value){GLctx["clearBufferuiv"](buffer,drawbuffer,HEAPU32,value>>2)}function _emscripten_glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _emscripten_glClearDepthf(x0){GLctx["clearDepth"](x0)}function _emscripten_glClearStencil(x0){GLctx["clearStencil"](x0)}function convertI32PairToI53(lo,hi){return(lo>>>0)+hi*4294967296}function _emscripten_glClientWaitSync(sync,flags,timeoutLo,timeoutHi){return GLctx.clientWaitSync(GL.syncs[sync],flags,convertI32PairToI53(timeoutLo,timeoutHi))}function _emscripten_glColorMask(red,green,blue,alpha){GLctx.colorMask(!!red,!!green,!!blue,!!alpha)}function _emscripten_glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _emscripten_glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,imageSize,data)}else{GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,HEAPU8,data,imageSize)}return}GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexImage3D(target,level,internalFormat,width,height,depth,border,imageSize,data){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)}}function _emscripten_glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,imageSize,data)}else{GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,HEAPU8,data,imageSize)}return}GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data){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)}}function _emscripten_glCopyBufferSubData(x0,x1,x2,x3,x4){GLctx["copyBufferSubData"](x0,x1,x2,x3,x4)}function _emscripten_glCopyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexSubImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage3D(x0,x1,x2,x3,x4,x5,x6,x7,x8){GLctx["copyTexSubImage3D"](x0,x1,x2,x3,x4,x5,x6,x7,x8)}function _emscripten_glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;GL.programs[id]=program;return id}function _emscripten_glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _emscripten_glCullFace(x0){GLctx["cullFace"](x0)}function _emscripten_glDeleteBuffers(n,buffers){for(var i=0;i>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GL.currArrayBuffer)GL.currArrayBuffer=0;if(id==GL.currElementArrayBuffer)GL.currElementArrayBuffer=0;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _emscripten_glDeleteFramebuffers(n,framebuffers){for(var i=0;i>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _emscripten_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;GL.programInfos[id]=null}function _emscripten_glDeleteQueries(n,ids){for(var i=0;i>2];var query=GL.queries[id];if(!query)continue;GLctx["deleteQuery"](query);GL.queries[id]=null}}function _emscripten_glDeleteQueriesEXT(n,ids){for(var i=0;i>2];var query=GL.timerQueriesEXT[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.timerQueriesEXT[id]=null}}function _emscripten_glDeleteRenderbuffers(n,renderbuffers){for(var i=0;i>2];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}function _emscripten_glDeleteSamplers(n,samplers){for(var i=0;i>2];var sampler=GL.samplers[id];if(!sampler)continue;GLctx["deleteSampler"](sampler);sampler.name=0;GL.samplers[id]=null}}function _emscripten_glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _emscripten_glDeleteSync(id){if(!id)return;var sync=GL.syncs[id];if(!sync){GL.recordError(1281);return}GLctx.deleteSync(sync);sync.name=0;GL.syncs[id]=null}function _emscripten_glDeleteTextures(n,textures){for(var i=0;i>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _emscripten_glDeleteTransformFeedbacks(n,ids){for(var i=0;i>2];var transformFeedback=GL.transformFeedbacks[id];if(!transformFeedback)continue;GLctx["deleteTransformFeedback"](transformFeedback);transformFeedback.name=0;GL.transformFeedbacks[id]=null}}function _emscripten_glDeleteVertexArrays(n,vaos){for(var i=0;i>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDeleteVertexArraysOES(n,vaos){for(var i=0;i>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDepthFunc(x0){GLctx["depthFunc"](x0)}function _emscripten_glDepthMask(flag){GLctx.depthMask(!!flag)}function _emscripten_glDepthRangef(x0,x1){GLctx["depthRange"](x0,x1)}function _emscripten_glDetachShader(program,shader){GLctx.detachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glDisable(x0){GLctx["disable"](x0)}function _emscripten_glDisableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=false;GLctx.disableVertexAttribArray(index)}function _emscripten_glDrawArrays(mode,first,count){GL.preDrawHandleClientVertexAttribBindings(first+count);GLctx.drawArrays(mode,first,count);GL.postDrawHandleClientVertexAttribBindings()}function _emscripten_glDrawArraysInstanced(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedANGLE(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedARB(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedEXT(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedNV(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}var __tempFixedLengthArray=[];function _emscripten_glDrawBuffers(n,bufs){var bufArray=__tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawBuffersEXT(n,bufs){var bufArray=__tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawBuffersWEBGL(n,bufs){var bufArray=__tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawElements(mode,count,type,indices){var buf;if(!GL.currElementArrayBuffer){var size=GL.calcBufLength(1,type,0,count);buf=GL.getTempIndexBuffer(size);GLctx.bindBuffer(34963,buf);GLctx.bufferSubData(34963,0,HEAPU8.subarray(indices,indices+size));indices=0}GL.preDrawHandleClientVertexAttribBindings(count);GLctx.drawElements(mode,count,type,indices);GL.postDrawHandleClientVertexAttribBindings(count);if(!GL.currElementArrayBuffer){GLctx.bindBuffer(34963,null)}}function _emscripten_glDrawElementsInstanced(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedANGLE(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedARB(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedEXT(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedNV(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _glDrawElements(mode,count,type,indices){var buf;if(!GL.currElementArrayBuffer){var size=GL.calcBufLength(1,type,0,count);buf=GL.getTempIndexBuffer(size);GLctx.bindBuffer(34963,buf);GLctx.bufferSubData(34963,0,HEAPU8.subarray(indices,indices+size));indices=0}GL.preDrawHandleClientVertexAttribBindings(count);GLctx.drawElements(mode,count,type,indices);GL.postDrawHandleClientVertexAttribBindings(count);if(!GL.currElementArrayBuffer){GLctx.bindBuffer(34963,null)}}function _emscripten_glDrawRangeElements(mode,start,end,count,type,indices){_glDrawElements(mode,count,type,indices)}function _emscripten_glEnable(x0){GLctx["enable"](x0)}function _emscripten_glEnableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=true;GLctx.enableVertexAttribArray(index)}function _emscripten_glEndQuery(x0){GLctx["endQuery"](x0)}function _emscripten_glEndQueryEXT(target){GLctx.disjointTimerQueryExt["endQueryEXT"](target)}function _emscripten_glEndTransformFeedback(){GLctx["endTransformFeedback"]()}function _emscripten_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}else{return 0}}function _emscripten_glFinish(){GLctx["finish"]()}function _emscripten_glFlush(){GLctx["flush"]()}function emscriptenWebGLGetBufferBinding(target){switch(target){case 34962:target=34964;break;case 34963:target=34965;break;case 35051:target=35053;break;case 35052:target=35055;break;case 35982:target=35983;break;case 36662:target=36662;break;case 36663:target=36663;break;case 35345:target=35368;break}var buffer=GLctx.getParameter(target);if(buffer)return buffer.name|0;else return 0}function emscriptenWebGLValidateMapBufferTarget(target){switch(target){case 34962:case 34963:case 36662:case 36663:case 35051:case 35052:case 35882:case 35982:case 35345:return true;default:return false}}function _emscripten_glFlushMappedBufferRange(target,offset,length){if(!emscriptenWebGLValidateMapBufferTarget(target)){GL.recordError(1280);err("GL_INVALID_ENUM in glFlushMappedBufferRange");return}var mapping=GL.mappedBuffers[emscriptenWebGLGetBufferBinding(target)];if(!mapping){GL.recordError(1282);Module.printError("buffer was never mapped in glFlushMappedBufferRange");return}if(!(mapping.access&16)){GL.recordError(1282);Module.printError("buffer was not mapped with GL_MAP_FLUSH_EXPLICIT_BIT in glFlushMappedBufferRange");return}if(offset<0||length<0||offset+length>mapping.length){GL.recordError(1281);Module.printError("invalid range in glFlushMappedBufferRange");return}GLctx.bufferSubData(target,mapping.offset,HEAPU8.subarray(mapping.mem+offset,mapping.mem+offset+length))}function _emscripten_glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer){GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])}function _emscripten_glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _emscripten_glFramebufferTextureLayer(target,attachment,texture,level,layer){GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)}function _emscripten_glFrontFace(x0){GLctx["frontFace"](x0)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i>2]=id}}function _emscripten_glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _emscripten_glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _emscripten_glGenQueries(n,ids){__glGenObject(n,ids,"createQuery",GL.queries)}function _emscripten_glGenQueriesEXT(n,ids){for(var i=0;i>2]=0;return}var id=GL.getNewId(GL.timerQueriesEXT);query.name=id;GL.timerQueriesEXT[id]=query;HEAP32[ids+i*4>>2]=id}}function _emscripten_glGenRenderbuffers(n,renderbuffers){__glGenObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}function _emscripten_glGenSamplers(n,samplers){__glGenObject(n,samplers,"createSampler",GL.samplers)}function _emscripten_glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _emscripten_glGenTransformFeedbacks(n,ids){__glGenObject(n,ids,"createTransformFeedback",GL.transformFeedbacks)}function _emscripten_glGenVertexArrays(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenVertexArraysOES(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function _emscripten_glGetActiveAttrib(program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx.getActiveAttrib(program,index);if(!info)return;var numBytesWrittenExclNull=bufSize>0&&name?stringToUTF8(info.name,name,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull;if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}function _emscripten_glGetActiveUniform(program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx.getActiveUniform(program,index);if(!info)return;var numBytesWrittenExclNull=bufSize>0&&name?stringToUTF8(info.name,name,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull;if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}function _emscripten_glGetActiveUniformBlockName(program,uniformBlockIndex,bufSize,length,uniformBlockName){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]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>2]=0}}function _emscripten_glGetActiveUniformBlockiv(program,uniformBlockIndex,pname,params){if(!params){GL.recordError(1281);return}program=GL.programs[program];switch(pname){case 35393:var name=GLctx["getActiveUniformBlockName"](program,uniformBlockIndex);HEAP32[params>>2]=name.length+1;return;default:var result=GLctx["getActiveUniformBlockParameter"](program,uniformBlockIndex,pname);if(!result)return;if(typeof result=="number"){HEAP32[params>>2]=result}else{for(var i=0;i>2]=result[i]}}}}function _emscripten_glGetActiveUniformsiv(program,uniformCount,uniformIndices,pname,params){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])}var result=GLctx["getActiveUniforms"](program,ids,pname);if(!result)return;var len=result.length;for(var i=0;i>2]=result[i]}}function _emscripten_glGetAttachedShaders(program,maxCount,count,shaders){var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>2]=len;for(var i=0;i>2]=id}}function _emscripten_glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function writeI53ToI64(ptr,num){HEAPU32[ptr>>2]=num;HEAPU32[ptr+4>>2]=(num-HEAPU32[ptr>>2])/4294967296}function 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}var exts=GLctx.getSupportedExtensions()||[];ret=2*exts.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 35097:case 36389: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]=result[i];break;case 2:HEAPF32[p+i*4>>2]=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]=ret;break;case 2:HEAPF32[p>>2]=ret;break;case 4:HEAP8[p>>0]=ret?1:0;break}}function _emscripten_glGetBooleanv(name_,p){emscriptenWebGLGet(name_,p,4)}function _emscripten_glGetBufferParameteri64v(target,value,data){if(!data){GL.recordError(1281);return}writeI53ToI64(data,GLctx.getBufferParameter(target,value))}function _emscripten_glGetBufferParameteriv(target,value,data){if(!data){GL.recordError(1281);return}HEAP32[data>>2]=GLctx.getBufferParameter(target,value)}function _emscripten_glGetBufferPointerv(target,pname,params){if(pname==35005){var ptr=0;var mappedBuffer=GL.mappedBuffers[emscriptenWebGLGetBufferBinding(target)];if(mappedBuffer){ptr=mappedBuffer.mem}HEAP32[params>>2]=ptr}else{GL.recordError(1280);err("GL_INVALID_ENUM in glGetBufferPointerv")}}function _emscripten_glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function _emscripten_glGetFloatv(name_,p){emscriptenWebGLGet(name_,p,2)}function _emscripten_glGetFragDataLocation(program,name){return GLctx["getFragDataLocation"](GL.programs[program],UTF8ToString(name))}function _emscripten_glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>2]=result}function 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]=ret;break;case 2:HEAPF32[data>>2]=ret;break;case 4:HEAP8[data>>0]=ret?1:0;break;default:throw"internal emscriptenWebGLGetIndexed() error, bad type: "+type}}function _emscripten_glGetInteger64i_v(target,index,data){emscriptenWebGLGetIndexed(target,index,data,1)}function _emscripten_glGetInteger64v(name_,p){emscriptenWebGLGet(name_,p,1)}function _emscripten_glGetIntegeri_v(target,index,data){emscriptenWebGLGetIndexed(target,index,data,0)}function _emscripten_glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _emscripten_glGetInternalformativ(target,internalformat,pname,bufSize,params){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]=ret[i]}}function _emscripten_glGetProgramBinary(program,bufSize,length,binaryFormat,binary){GL.recordError(1282)}function _emscripten_glGetProgramInfoLog(program,maxLength,length,infoLog){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]=numBytesWrittenExclNull}function _emscripten_glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}var ptable=GL.programInfos[program];if(!ptable){GL.recordError(1282);return}if(pname==35716){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){HEAP32[p>>2]=ptable.maxUniformLength}else if(pname==35722){if(ptable.maxAttributeLength==-1){program=GL.programs[program];var numAttribs=GLctx.getProgramParameter(program,35721);ptable.maxAttributeLength=0;for(var i=0;i>2]=ptable.maxAttributeLength}else if(pname==35381){if(ptable.maxUniformBlockNameLength==-1){program=GL.programs[program];var numBlocks=GLctx.getProgramParameter(program,35382);ptable.maxUniformBlockNameLength=0;for(var i=0;i>2]=ptable.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(GL.programs[program],pname)}}function _emscripten_glGetQueryObjecti64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryObjectui64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectuiv(id,pname,params){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]=ret}function _emscripten_glGetQueryObjectuivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryiv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx["getQuery"](target,pname)}function _emscripten_glGetQueryivEXT(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}function _emscripten_glGetRenderbufferParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getRenderbufferParameter(target,pname)}function _emscripten_glGetSamplerParameterfv(sampler,pname,params){if(!params){GL.recordError(1281);return}sampler=GL.samplers[sampler];HEAPF32[params>>2]=GLctx["getSamplerParameter"](sampler,pname)}function _emscripten_glGetSamplerParameteriv(sampler,pname,params){if(!params){GL.recordError(1281);return}sampler=GL.samplers[sampler];HEAP32[params>>2]=GLctx["getSamplerParameter"](sampler,pname)}function _emscripten_glGetShaderInfoLog(shader,maxLength,length,infoLog){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]=numBytesWrittenExclNull}function _emscripten_glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>2]=result.rangeMin;HEAP32[range+4>>2]=result.rangeMax;HEAP32[precision>>2]=result.precision}function _emscripten_glGetShaderSource(shader,bufSize,length,source){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]=numBytesWrittenExclNull}function _emscripten_glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source===null||source.length==0?0:source.length+1;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function stringToNewUTF8(jsString){var length=lengthBytesUTF8(jsString)+1;var cString=_malloc(length);stringToUTF8(jsString,cString,length);return cString}function _emscripten_glGetString(name_){if(GL.stringCache[name_])return GL.stringCache[name_];var ret;switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);if(GL.currentContext.version>=2)glVersion="OpenGL ES 3.0 ("+glVersion+")";else{glVersion="OpenGL ES 2.0 ("+glVersion+")"}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);return 0}GL.stringCache[name_]=ret;return ret}function _emscripten_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=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));exts=exts.map(function(e){return stringToNewUTF8(e)});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}}function _emscripten_glGetSynciv(sync,pname,bufSize,length,values){if(bufSize<0){GL.recordError(1281);return}if(!values){GL.recordError(1281);return}var ret=GLctx.getSyncParameter(GL.syncs[sync],pname);HEAP32[length>>2]=ret;if(ret!==null&&length)HEAP32[length>>2]=1}function _emscripten_glGetTexParameterfv(target,pname,params){if(!params){GL.recordError(1281);return}HEAPF32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTexParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTransformFeedbackVarying(program,index,bufSize,length,size,type,name){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]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>2]=0}if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}function _emscripten_glGetUniformBlockIndex(program,uniformBlockName){return GLctx["getUniformBlockIndex"](GL.programs[program],UTF8ToString(uniformBlockName))}function _emscripten_glGetUniformIndices(program,uniformCount,uniformNames,uniformIndices){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]));var result=GLctx["getUniformIndices"](program,names);if(!result)return;var len=result.length;for(var i=0;i>2]=result[i]}}function _emscripten_glGetUniformLocation(program,name){name=UTF8ToString(name);var arrayIndex=0;if(name[name.length-1]=="]"){var leftBrace=name.lastIndexOf("[");arrayIndex=name[leftBrace+1]!="]"?parseInt(name.slice(leftBrace+1)):0;name=name.slice(0,leftBrace)}var uniformInfo=GL.programInfos[program]&&GL.programInfos[program].uniforms[name];if(uniformInfo&&arrayIndex>=0&&arrayIndex>2]=data;break;case 2:HEAPF32[params>>2]=data;break;default:throw"internal emscriptenWebGLGetUniform() error, bad type: "+type}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break;default:throw"internal emscriptenWebGLGetUniform() error, bad type: "+type}}}}function _emscripten_glGetUniformfv(program,location,params){emscriptenWebGLGetUniform(program,location,params,2)}function _emscripten_glGetUniformiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function _emscripten_glGetUniformuiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function emscriptenWebGLGetVertexAttrib(index,pname,params,type){if(!params){GL.recordError(1281);return}if(GL.currentContext.clientBuffers[index].enabled){err("glGetVertexAttrib*v on client-side array: not supported, bad data returned")}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>2]=data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>2]=data;break;case 2:HEAPF32[params>>2]=data;break;case 5:HEAP32[params>>2]=Math.fround(data);break;default:throw"internal emscriptenWebGLGetVertexAttrib() error, bad type: "+type}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break;case 5:HEAP32[params+i*4>>2]=Math.fround(data[i]);break;default:throw"internal emscriptenWebGLGetVertexAttrib() error, bad type: "+type}}}}function _emscripten_glGetVertexAttribIiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,0)}function _emscripten_glGetVertexAttribIuiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,0)}function _emscripten_glGetVertexAttribPointerv(index,pname,pointer){if(!pointer){GL.recordError(1281);return}if(GL.currentContext.clientBuffers[index].enabled){err("glGetVertexAttribPointer on client-side array: not supported, bad data returned")}HEAP32[pointer>>2]=GLctx.getVertexAttribOffset(index,pname)}function _emscripten_glGetVertexAttribfv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,2)}function _emscripten_glGetVertexAttribiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,5)}function _emscripten_glHint(x0,x1){GLctx["hint"](x0,x1)}function _emscripten_glInvalidateFramebuffer(target,numAttachments,attachments){var list=__tempFixedLengthArray[numAttachments];for(var i=0;i>2]}GLctx["invalidateFramebuffer"](target,list)}function _emscripten_glInvalidateSubFramebuffer(target,numAttachments,attachments,x,y,width,height){var list=__tempFixedLengthArray[numAttachments];for(var i=0;i>2]}GLctx["invalidateSubFramebuffer"](target,list,x,y,width,height)}function _emscripten_glIsBuffer(buffer){var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)}function _emscripten_glIsEnabled(x0){return GLctx["isEnabled"](x0)}function _emscripten_glIsFramebuffer(framebuffer){var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)}function _emscripten_glIsProgram(program){program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)}function _emscripten_glIsQuery(id){var query=GL.queries[id];if(!query)return 0;return GLctx["isQuery"](query)}function _emscripten_glIsQueryEXT(id){var query=GL.timerQueriesEXT[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)}function _emscripten_glIsRenderbuffer(renderbuffer){var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)}function _emscripten_glIsSampler(id){var sampler=GL.samplers[id];if(!sampler)return 0;return GLctx["isSampler"](sampler)}function _emscripten_glIsShader(shader){var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)}function _emscripten_glIsSync(sync){return GLctx.isSync(GL.syncs[sync])}function _emscripten_glIsTexture(id){var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)}function _emscripten_glIsTransformFeedback(id){return GLctx["isTransformFeedback"](GL.transformFeedbacks[id])}function _emscripten_glIsVertexArray(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glIsVertexArrayOES(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glLineWidth(x0){GLctx["lineWidth"](x0)}function _emscripten_glLinkProgram(program){GLctx.linkProgram(GL.programs[program]);GL.populateUniformTable(program)}function _emscripten_glMapBufferRange(target,offset,length,access){if(access!=26&&access!=10){err("glMapBufferRange is only supported when access is MAP_WRITE|INVALIDATE_BUFFER");return 0}if(!emscriptenWebGLValidateMapBufferTarget(target)){GL.recordError(1280);err("GL_INVALID_ENUM in glMapBufferRange");return 0}var mem=_malloc(length);if(!mem)return 0;GL.mappedBuffers[emscriptenWebGLGetBufferBinding(target)]={offset:offset,length:length,mem:mem,access:access};return mem}function _emscripten_glPauseTransformFeedback(){GLctx["pauseTransformFeedback"]()}function _emscripten_glPixelStorei(pname,param){if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)}function _emscripten_glPolygonOffset(x0,x1){GLctx["polygonOffset"](x0,x1)}function _emscripten_glProgramBinary(program,binaryFormat,binary,length){GL.recordError(1280)}function _emscripten_glProgramParameteri(program,pname,value){GL.recordError(1280)}function _emscripten_glQueryCounterEXT(id,target){GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.timerQueriesEXT[id],target)}function _emscripten_glReadBuffer(x0){GLctx["readBuffer"](x0)}function __computeUnpackAlignedImageSize(width,height,sizePerPixel,alignment){function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize}function __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}function __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}function __heapAccessShiftForWebGLHeap(heap){return 31-Math.clz32(heap.BYTES_PER_ELEMENT)}function emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat){var heap=__heapObjectForWebGLType(type);var shift=__heapAccessShiftForWebGLHeap(heap);var byteSize=1<>shift,pixels+bytes>>shift)}function _emscripten_glReadPixels(x,y,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=__heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}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)}function _emscripten_glReleaseShaderCompiler(){}function _emscripten_glRenderbufferStorage(x0,x1,x2,x3){GLctx["renderbufferStorage"](x0,x1,x2,x3)}function _emscripten_glRenderbufferStorageMultisample(x0,x1,x2,x3,x4){GLctx["renderbufferStorageMultisample"](x0,x1,x2,x3,x4)}function _emscripten_glResumeTransformFeedback(){GLctx["resumeTransformFeedback"]()}function _emscripten_glSampleCoverage(value,invert){GLctx.sampleCoverage(value,!!invert)}function _emscripten_glSamplerParameterf(sampler,pname,param){GLctx["samplerParameterf"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameterfv(sampler,pname,params){var param=HEAPF32[params>>2];GLctx["samplerParameterf"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameteri(sampler,pname,param){GLctx["samplerParameteri"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameteriv(sampler,pname,params){var param=HEAP32[params>>2];GLctx["samplerParameteri"](GL.samplers[sampler],pname,param)}function _emscripten_glScissor(x0,x1,x2,x3){GLctx["scissor"](x0,x1,x2,x3)}function _emscripten_glShaderBinary(){GL.recordError(1280)}function _emscripten_glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _emscripten_glStencilFunc(x0,x1,x2){GLctx["stencilFunc"](x0,x1,x2)}function _emscripten_glStencilFuncSeparate(x0,x1,x2,x3){GLctx["stencilFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glStencilMask(x0){GLctx["stencilMask"](x0)}function _emscripten_glStencilMaskSeparate(x0,x1){GLctx["stencilMaskSeparate"](x0,x1)}function _emscripten_glStencilOp(x0,x1,x2){GLctx["stencilOp"](x0,x1,x2)}function _emscripten_glStencilOpSeparate(x0,x1,x2,x3){GLctx["stencilOpSeparate"](x0,x1,x2,x3)}function _emscripten_glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _emscripten_glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,null)}}function _emscripten_glTexParameterf(x0,x1,x2){GLctx["texParameterf"](x0,x1,x2)}function _emscripten_glTexParameterfv(target,pname,params){var param=HEAPF32[params>>2];GLctx.texParameterf(target,pname,param)}function _emscripten_glTexParameteri(x0,x1,x2){GLctx["texParameteri"](x0,x1,x2)}function _emscripten_glTexParameteriv(target,pname,params){var param=HEAP32[params>>2];GLctx.texParameteri(target,pname,param)}function _emscripten_glTexStorage2D(x0,x1,x2,x3,x4){GLctx["texStorage2D"](x0,x1,x2,x3,x4)}function _emscripten_glTexStorage3D(x0,x1,x2,x3,x4,x5){GLctx["texStorage3D"](x0,x1,x2,x3,x4,x5)}function _emscripten_glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _emscripten_glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){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,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}function _emscripten_glTransformFeedbackVaryings(program,count,varyings,bufferMode){program=GL.programs[program];var vars=[];for(var i=0;i>2]));GLctx["transformFeedbackVaryings"](program,vars,bufferMode)}function _emscripten_glUniform1f(location,v0){GLctx.uniform1f(GL.uniforms[location],v0)}function _emscripten_glUniform1fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform1fv(GL.uniforms[location],HEAPF32,value>>2,count);return}if(count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[count-1];for(var i=0;i>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1fv(GL.uniforms[location],view)}function _emscripten_glUniform1i(location,v0){GLctx.uniform1i(GL.uniforms[location],v0)}function _emscripten_glUniform1iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform1iv(GL.uniforms[location],HEAP32,value>>2,count);return}if(count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[count-1];for(var i=0;i>2]}}else{var view=HEAP32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1iv(GL.uniforms[location],view)}function _emscripten_glUniform1ui(location,v0){GLctx.uniform1ui(GL.uniforms[location],v0)}function _emscripten_glUniform1uiv(location,count,value){GLctx.uniform1uiv(GL.uniforms[location],HEAPU32,value>>2,count)}function _emscripten_glUniform2f(location,v0,v1){GLctx.uniform2f(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform2fv(GL.uniforms[location],HEAPF32,value>>2,count*2);return}if(2*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(GL.uniforms[location],view)}function _emscripten_glUniform2i(location,v0,v1){GLctx.uniform2i(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform2iv(GL.uniforms[location],HEAP32,value>>2,count*2);return}if(2*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2iv(GL.uniforms[location],view)}function _emscripten_glUniform2ui(location,v0,v1){GLctx.uniform2ui(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2uiv(location,count,value){GLctx.uniform2uiv(GL.uniforms[location],HEAPU32,value>>2,count*2)}function _emscripten_glUniform3f(location,v0,v1,v2){GLctx.uniform3f(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform3fv(GL.uniforms[location],HEAPF32,value>>2,count*3);return}if(3*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3fv(GL.uniforms[location],view)}function _emscripten_glUniform3i(location,v0,v1,v2){GLctx.uniform3i(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform3iv(GL.uniforms[location],HEAP32,value>>2,count*3);return}if(3*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3iv(GL.uniforms[location],view)}function _emscripten_glUniform3ui(location,v0,v1,v2){GLctx.uniform3ui(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3uiv(location,count,value){GLctx.uniform3uiv(GL.uniforms[location],HEAPU32,value>>2,count*3)}function _emscripten_glUniform4f(location,v0,v1,v2,v3){GLctx.uniform4f(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform4fv(GL.uniforms[location],HEAPF32,value>>2,count*4);return}if(4*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(GL.uniforms[location],view)}function _emscripten_glUniform4i(location,v0,v1,v2,v3){GLctx.uniform4i(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform4iv(GL.uniforms[location],HEAP32,value>>2,count*4);return}if(4*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(GL.uniforms[location],view)}function _emscripten_glUniform4ui(location,v0,v1,v2,v3){GLctx.uniform4ui(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4uiv(location,count,value){GLctx.uniform4uiv(GL.uniforms[location],HEAPU32,value>>2,count*4)}function _emscripten_glUniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding){program=GL.programs[program];GLctx["uniformBlockBinding"](program,uniformBlockIndex,uniformBlockBinding)}function _emscripten_glUniformMatrix2fv(location,count,transpose,value){if(GL.currentContext.version>=2){GLctx.uniformMatrix2fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*4);return}if(4*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniformMatrix2fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix2x3fv(location,count,transpose,value){GLctx.uniformMatrix2x3fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*6)}function _emscripten_glUniformMatrix2x4fv(location,count,transpose,value){GLctx.uniformMatrix2x4fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*8)}function _emscripten_glUniformMatrix3fv(location,count,transpose,value){if(GL.currentContext.version>=2){GLctx.uniformMatrix3fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*9);return}if(9*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[9*count-1];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*36>>2)}GLctx.uniformMatrix3fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix3x2fv(location,count,transpose,value){GLctx.uniformMatrix3x2fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*6)}function _emscripten_glUniformMatrix3x4fv(location,count,transpose,value){GLctx.uniformMatrix3x4fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*12)}function _emscripten_glUniformMatrix4fv(location,count,transpose,value){if(GL.currentContext.version>=2){GLctx.uniformMatrix4fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*16);return}if(16*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[16*count-1];for(var i=0;i<16*count;i+=16){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2];view[i+9]=HEAPF32[value+(4*i+36)>>2];view[i+10]=HEAPF32[value+(4*i+40)>>2];view[i+11]=HEAPF32[value+(4*i+44)>>2];view[i+12]=HEAPF32[value+(4*i+48)>>2];view[i+13]=HEAPF32[value+(4*i+52)>>2];view[i+14]=HEAPF32[value+(4*i+56)>>2];view[i+15]=HEAPF32[value+(4*i+60)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix4x2fv(location,count,transpose,value){GLctx.uniformMatrix4x2fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*8)}function _emscripten_glUniformMatrix4x3fv(location,count,transpose,value){GLctx.uniformMatrix4x3fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*12)}function _emscripten_glUnmapBuffer(target){if(!emscriptenWebGLValidateMapBufferTarget(target)){GL.recordError(1280);err("GL_INVALID_ENUM in glUnmapBuffer");return 0}var buffer=emscriptenWebGLGetBufferBinding(target);var mapping=GL.mappedBuffers[buffer];if(!mapping){GL.recordError(1282);Module.printError("buffer was never mapped in glUnmapBuffer");return 0}GL.mappedBuffers[buffer]=null;if(!(mapping.access&16))if(GL.currentContext.version>=2){GLctx.bufferSubData(target,mapping.offset,HEAPU8,mapping.mem,mapping.length)}else{GLctx.bufferSubData(target,mapping.offset,HEAPU8.subarray(mapping.mem,mapping.mem+mapping.length))}_free(mapping.mem);return 1}function _emscripten_glUseProgram(program){GLctx.useProgram(GL.programs[program])}function _emscripten_glValidateProgram(program){GLctx.validateProgram(GL.programs[program])}function _emscripten_glVertexAttrib1f(x0,x1){GLctx["vertexAttrib1f"](x0,x1)}function _emscripten_glVertexAttrib1fv(index,v){GLctx.vertexAttrib1f(index,HEAPF32[v>>2])}function _emscripten_glVertexAttrib2f(x0,x1,x2){GLctx["vertexAttrib2f"](x0,x1,x2)}function _emscripten_glVertexAttrib2fv(index,v){GLctx.vertexAttrib2f(index,HEAPF32[v>>2],HEAPF32[v+4>>2])}function _emscripten_glVertexAttrib3f(x0,x1,x2,x3){GLctx["vertexAttrib3f"](x0,x1,x2,x3)}function _emscripten_glVertexAttrib3fv(index,v){GLctx.vertexAttrib3f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2])}function _emscripten_glVertexAttrib4f(x0,x1,x2,x3,x4){GLctx["vertexAttrib4f"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttrib4fv(index,v){GLctx.vertexAttrib4f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2],HEAPF32[v+12>>2])}function _emscripten_glVertexAttribDivisor(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorANGLE(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorARB(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorEXT(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorNV(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribI4i(x0,x1,x2,x3,x4){GLctx["vertexAttribI4i"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttribI4iv(index,v){GLctx.vertexAttribI4i(index,HEAP32[v>>2],HEAP32[v+4>>2],HEAP32[v+8>>2],HEAP32[v+12>>2])}function _emscripten_glVertexAttribI4ui(x0,x1,x2,x3,x4){GLctx["vertexAttribI4ui"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttribI4uiv(index,v){GLctx.vertexAttribI4ui(index,HEAPU32[v>>2],HEAPU32[v+4>>2],HEAPU32[v+8>>2],HEAPU32[v+12>>2])}function _emscripten_glVertexAttribIPointer(index,size,type,stride,ptr){var cb=GL.currentContext.clientBuffers[index];if(!GL.currArrayBuffer){cb.size=size;cb.type=type;cb.normalized=false;cb.stride=stride;cb.ptr=ptr;cb.clientside=true;cb.vertexAttribPointerAdaptor=function(index,size,type,normalized,stride,ptr){this.vertexAttribIPointer(index,size,type,stride,ptr)};return}cb.clientside=false;GLctx["vertexAttribIPointer"](index,size,type,stride,ptr)}function _emscripten_glVertexAttribPointer(index,size,type,normalized,stride,ptr){var cb=GL.currentContext.clientBuffers[index];if(!GL.currArrayBuffer){cb.size=size;cb.type=type;cb.normalized=normalized;cb.stride=stride;cb.ptr=ptr;cb.clientside=true;cb.vertexAttribPointerAdaptor=function(index,size,type,normalized,stride,ptr){this.vertexAttribPointer(index,size,type,normalized,stride,ptr)};return}cb.clientside=false;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _emscripten_glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}function _emscripten_glWaitSync(sync,flags,timeoutLo,timeoutHi){GLctx.waitSync(GL.syncs[sync],flags,convertI32PairToI53(timeoutLo,timeoutHi))}var IDBStore={indexedDB:function(){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:function(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=function(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=function(){db=req.result;IDBStore.dbs[name]=db;callback(null,db)};req.onerror=function(e){callback(this.error);e.preventDefault()}},getStore:function(dbName,type,callback){IDBStore.getDB(dbName,function(error,db){if(error)return callback(error);var transaction=db.transaction([IDBStore.DB_STORE_NAME],type);transaction.onerror=function(e){callback(this.error||"unknown error");e.preventDefault()};var store=transaction.objectStore(IDBStore.DB_STORE_NAME);callback(null,store)})},getFile:function(dbName,id,callback){IDBStore.getStore(dbName,"readonly",function(err,store){if(err)return callback(err);var req=store.get(id);req.onsuccess=function(event){var result=event.target.result;if(!result){return callback("file "+id+" not found")}else{return callback(null,result)}};req.onerror=function(error){callback(error)}})},setFile:function(dbName,id,data,callback){IDBStore.getStore(dbName,"readwrite",function(err,store){if(err)return callback(err);var req=store.put(data,id);req.onsuccess=function(event){callback()};req.onerror=function(error){callback(error)}})},deleteFile:function(dbName,id,callback){IDBStore.getStore(dbName,"readwrite",function(err,store){if(err)return callback(err);var req=store.delete(id);req.onsuccess=function(event){callback()};req.onerror=function(error){callback(error)}})},existsFile:function(dbName,id,callback){IDBStore.getStore(dbName,"readonly",function(err,store){if(err)return callback(err);var req=store.count(id);req.onsuccess=function(event){callback(null,event.target.result>0)};req.onerror=function(error){callback(error)}})}};function _emscripten_idb_async_delete(db,id,arg,ondelete,onerror){IDBStore.deleteFile(UTF8ToString(db),UTF8ToString(id),function(error){if(error){if(onerror)dynCall_vi(onerror,arg);return}if(ondelete)dynCall_vi(ondelete,arg)})}function _emscripten_idb_async_exists(db,id,arg,oncheck,onerror){IDBStore.existsFile(UTF8ToString(db),UTF8ToString(id),function(error,exists){if(error){if(onerror)dynCall_vi(onerror,arg);return}if(oncheck)dynCall_vii(oncheck,arg,exists)})}function _emscripten_idb_async_load(db,id,arg,onload,onerror){IDBStore.getFile(UTF8ToString(db),UTF8ToString(id),function(error,byteArray){if(error){if(onerror)dynCall_vi(onerror,arg);return}var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer);dynCall_viii(onload,arg,buffer,byteArray.length);_free(buffer)})}function _emscripten_idb_async_store(db,id,ptr,num,arg,onstore,onerror){IDBStore.setFile(UTF8ToString(db),UTF8ToString(id),new Uint8Array(HEAPU8.subarray(ptr,ptr+num)),function(error){if(error){if(onerror)dynCall_vi(onerror,arg);return}if(onstore)dynCall_vi(onstore,arg)})}function _emscripten_is_webgl_context_lost(target){return!GL.contexts[target]||GL.contexts[target].GLctx.isContextLost()}function __reallyNegative(x){return x<0||x===0&&1/x===-Infinity}function convertU32PairToI53(lo,hi){return(lo>>>0)+(hi>>>0)*4294967296}function __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];argIndex+=8}else if(type=="i64"){ret=[HEAP32[argIndex>>2],HEAP32[argIndex+4>>2]];argIndex+=8}else{type="i32";ret=HEAP32[argIndex>>2];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,1).toString(10)}else if(next==117){argText=unSign(currArg,8*argSize,1).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.lengthexponent&&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].indexOf(".")!=-1&&(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.length>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]=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 __emscripten_traverse_stack(args){if(!args||!args.callee||!args.callee.name){return[null,"",""]}var funstr=args.callee.toString();var funcname=args.callee.name;var str="(";var first=true;for(var i in args){var a=args[i];if(!first){str+=", "}first=false;if(typeof a==="number"||typeof a==="string"){str+=a}else{str+="("+typeof a+")"}}str+=")";var caller=args.callee.caller;args=caller?caller.arguments:[];if(first)str="";return[args,funcname,str]}function _emscripten_get_callstack_js(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 stack_args=null;if(flags&128){stack_args=__emscripten_traverse_stack(arguments);while(stack_args[1].indexOf("_emscripten_")>=0)stack_args=__emscripten_traverse_stack(stack_args[0])}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 jsSymbolName="";var file="";var lineno=0;var column=0;var parts=chromeRe.exec(line);if(parts&&parts.length==5){jsSymbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]}else{parts=newFirefoxRe.exec(line);if(!parts)parts=firefoxRe.exec(line);if(parts&&parts.length>=4){jsSymbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]|0}else{callstack+=line+"\n";continue}}var cSymbolName=flags&32?demangle(jsSymbolName):jsSymbolName;if(!cSymbolName){cSymbolName=jsSymbolName}var haveSourceMap=false;if(flags&8){var orig=emscripten_source_map.originalPositionFor({line:lineno,column:column});haveSourceMap=orig&&orig.source;if(haveSourceMap){if(flags&64){orig.source=orig.source.substring(orig.source.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=" at "+cSymbolName+" ("+orig.source+":"+orig.line+":"+orig.column+")\n"}}if(flags&16||!haveSourceMap){if(flags&64){file=file.substring(file.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=(haveSourceMap?" = "+jsSymbolName:" at "+cSymbolName)+" ("+file+":"+lineno+":"+column+")\n"}if(flags&128&&stack_args[0]){if(stack_args[1]==jsSymbolName&&stack_args[2].length>0){callstack=callstack.replace(/\s+$/,"");callstack+=" with values: "+stack_args[1]+stack_args[2]+"\n"}stack_args=__emscripten_traverse_stack(stack_args[0])}}callstack=callstack.replace(/\s+$/,"");return callstack}function _emscripten_log_js(flags,str){if(flags&24){str=str.replace(/\s+$/,"");str+=(str.length>0?"\n":"")+_emscripten_get_callstack_js(flags)}if(flags&1){if(flags&4){console.error(str)}else if(flags&2){console.warn(str)}else{console.log(str)}}else if(flags&6){err(str)}else{out(str)}}function _emscripten_log(flags,varargs){var format=HEAP32[varargs>>2];varargs+=4;var str="";if(format){var result=__formatString(format,varargs);for(var i=0;i>2]=setjmpId;while((i|0)<(size|0)){if((HEAP32[table+(i<<3)>>2]|0)==0){HEAP32[table+(i<<3)>>2]=setjmpId;HEAP32[table+((i<<3)+4)>>2]=label;HEAP32[table+((i<<3)+8)>>2]=0;setTempRet0(size|0);return table|0}i=i+1|0}size=size*2|0;table=_realloc(table|0,8*(size+1|0)|0)|0;table=_saveSetjmp(env|0,label|0,table|0,size|0)|0;setTempRet0(size|0);return table|0}function _testSetjmp(id,table,size){id=id|0;table=table|0;size=size|0;var i=0,curr=0;while((i|0)<(size|0)){curr=HEAP32[table+(i<<3)>>2]|0;if((curr|0)==0)break;if((curr|0)==(id|0)){return HEAP32[table+((i<<3)+4)>>2]|0}i=i+1|0}return 0}function _longjmp(env,value){_setThrew(env,value||1);throw"longjmp"}function _emscripten_longjmp(env,value){_longjmp(env,value)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function _emscripten_pause_main_loop(){Browser.mainLoop.pause()}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var maxHeapSize=2147483648-PAGE_MULTIPLE;if(requestedSize>maxHeapSize){return false}var minHeapSize=16777216;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,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),PAGE_MULTIPLE));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}function _emscripten_resume_main_loop(){Browser.mainLoop.resume()}function __registerFocusEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.focusEvent)JSEvents.focusEvent=_malloc(256);var focusEventHandlerFunc=function(ev){var e=ev||event;var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(dynCall_iiii(callbackfunc,eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:__findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread);return 0}function __registerKeyEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.keyEvent)JSEvents.keyEvent=_malloc(164);var keyEventHandlerFunc=function(ev){var e=ev||event;var keyEventData=JSEvents.keyEvent;stringToUTF8(e.key?e.key:"",keyEventData+0,32);stringToUTF8(e.code?e.code:"",keyEventData+32,32);HEAP32[keyEventData+64>>2]=e.location;HEAP32[keyEventData+68>>2]=e.ctrlKey;HEAP32[keyEventData+72>>2]=e.shiftKey;HEAP32[keyEventData+76>>2]=e.altKey;HEAP32[keyEventData+80>>2]=e.metaKey;HEAP32[keyEventData+84>>2]=e.repeat;stringToUTF8(e.locale?e.locale:"",keyEventData+88,32);stringToUTF8(e.char?e.char:"",keyEventData+120,32);HEAP32[keyEventData+152>>2]=e.charCode;HEAP32[keyEventData+156>>2]=e.keyCode;HEAP32[keyEventData+160>>2]=e.which;if(dynCall_iiii(callbackfunc,eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:__findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread);return 0}function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread);return 0}function _emscripten_set_main_loop_arg(func,arg,fps,simulateInfiniteLoop){_emscripten_set_main_loop(func,fps,simulateInfiniteLoop,arg)}function __fillMouseEventData(eventStruct,e,target){HEAP32[eventStruct>>2]=e.screenX;HEAP32[eventStruct+4>>2]=e.screenY;HEAP32[eventStruct+8>>2]=e.clientX;HEAP32[eventStruct+12>>2]=e.clientY;HEAP32[eventStruct+16>>2]=e.ctrlKey;HEAP32[eventStruct+20>>2]=e.shiftKey;HEAP32[eventStruct+24>>2]=e.altKey;HEAP32[eventStruct+28>>2]=e.metaKey;HEAP16[eventStruct+32>>1]=e.button;HEAP16[eventStruct+34>>1]=e.buttons;var movementX=e["movementX"]||e.screenX-JSEvents.previousScreenX;var movementY=e["movementY"]||e.screenY-JSEvents.previousScreenY;HEAP32[eventStruct+36>>2]=movementX;HEAP32[eventStruct+40>>2]=movementY;var rect=__specialEventTargets.indexOf(target)<0?__getBoundingClientRect(target):{"left":0,"top":0};HEAP32[eventStruct+44>>2]=e.clientX-rect.left;HEAP32[eventStruct+48>>2]=e.clientY-rect.top;if(e.type!=="wheel"&&e.type!=="mousewheel"){JSEvents.previousScreenX=e.screenX;JSEvents.previousScreenY=e.screenY}}function __registerMouseEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.mouseEvent)JSEvents.mouseEvent=_malloc(64);target=__findEventTarget(target);var mouseEventHandlerFunc=function(ev){var e=ev||event;__fillMouseEventData(JSEvents.mouseEvent,e,target);if(dynCall_iiii(callbackfunc,eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread);return 0}function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread);return 0}function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread);return 0}function __registerUiEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.uiEvent)JSEvents.uiEvent=_malloc(36);target=__findEventTarget(target);var uiEventHandlerFunc=function(ev){var e=ev||event;if(e.target!=target){return}var uiEvent=JSEvents.uiEvent;var b=document.body;HEAP32[uiEvent>>2]=e.detail;HEAP32[uiEvent+4>>2]=b.clientWidth;HEAP32[uiEvent+8>>2]=b.clientHeight;HEAP32[uiEvent+12>>2]=innerWidth;HEAP32[uiEvent+16>>2]=innerHeight;HEAP32[uiEvent+20>>2]=outerWidth;HEAP32[uiEvent+24>>2]=outerHeight;HEAP32[uiEvent+28>>2]=pageXOffset;HEAP32[uiEvent+32>>2]=pageYOffset;if(dynCall_iiii(callbackfunc,eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",targetThread);return 0}function __registerTouchEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.touchEvent)JSEvents.touchEvent=_malloc(1684);target=__findEventTarget(target);var touchEventHandlerFunc=function(ev){var e=ev||event;var touches={};for(var i=0;i>2]=e.ctrlKey;HEAP32[ptr+8>>2]=e.shiftKey;HEAP32[ptr+12>>2]=e.altKey;HEAP32[ptr+16>>2]=e.metaKey;ptr+=20;var targetRect=__getBoundingClientRect(target);var numTouches=0;for(var i in touches){var t=touches[i];HEAP32[ptr>>2]=t.identifier;HEAP32[ptr+4>>2]=t.screenX;HEAP32[ptr+8>>2]=t.screenY;HEAP32[ptr+12>>2]=t.clientX;HEAP32[ptr+16>>2]=t.clientY;HEAP32[ptr+20>>2]=t.pageX;HEAP32[ptr+24>>2]=t.pageY;HEAP32[ptr+28>>2]=t.changed;HEAP32[ptr+32>>2]=t.onTarget;HEAP32[ptr+36>>2]=t.clientX-targetRect.left;HEAP32[ptr+40>>2]=t.clientY-targetRect.top;ptr+=52;if(++numTouches>=32){break}}HEAP32[touchEvent>>2]=numTouches;if(dynCall_iiii(callbackfunc,eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_touchcancel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,25,"touchcancel",targetThread);return 0}function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread);return 0}function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread);return 0}function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread);return 0}function __registerWheelEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.wheelEvent)JSEvents.wheelEvent=_malloc(96);var wheelHandlerFunc=function(ev){var e=ev||event;var wheelEvent=JSEvents.wheelEvent;__fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+64>>3]=e["deltaX"];HEAPF64[wheelEvent+72>>3]=e["deltaY"];HEAPF64[wheelEvent+80>>3]=e["deltaZ"];HEAP32[wheelEvent+88>>2]=e["deltaMode"];if(dynCall_iiii(callbackfunc,eventTypeId,wheelEvent,userData))e.preventDefault()};var mouseWheelHandlerFunc=function(ev){var e=ev||event;__fillMouseEventData(JSEvents.wheelEvent,e,target);HEAPF64[JSEvents.wheelEvent+64>>3]=e["wheelDeltaX"]||0;var wheelDeltaY=-(e["wheelDeltaY"]||e["wheelDelta"]);HEAPF64[JSEvents.wheelEvent+72>>3]=wheelDeltaY;HEAPF64[JSEvents.wheelEvent+80>>3]=0;HEAP32[JSEvents.wheelEvent+88>>2]=0;var shouldCancel=dynCall_iiii(callbackfunc,eventTypeId,JSEvents.wheelEvent,userData);if(shouldCancel){e.preventDefault()}};var eventHandler={target:target,allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:eventTypeString=="wheel"?wheelHandlerFunc:mouseWheelHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target=__findEventTarget(target);if(typeof target.onwheel!=="undefined"){__registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread);return 0}else if(typeof target.onmousewheel!=="undefined"){__registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"mousewheel",targetThread);return 0}else{return-1}}function _emscripten_sleep(){throw"Please compile your program with async support in order to use asynchronous operations like emscripten_sleep"}var __emscripten_webgl_power_preferences=["default","low-power","high-performance"];function __findCanvasEventTarget(target){return __findEventTarget(target)}function _emscripten_webgl_do_create_context(target,attributes){var contextAttributes={};var a=attributes>>2;contextAttributes["alpha"]=!!HEAP32[a+(0>>2)];contextAttributes["depth"]=!!HEAP32[a+(4>>2)];contextAttributes["stencil"]=!!HEAP32[a+(8>>2)];contextAttributes["antialias"]=!!HEAP32[a+(12>>2)];contextAttributes["premultipliedAlpha"]=!!HEAP32[a+(16>>2)];contextAttributes["preserveDrawingBuffer"]=!!HEAP32[a+(20>>2)];var powerPreference=HEAP32[a+(24>>2)];contextAttributes["powerPreference"]=__emscripten_webgl_power_preferences[powerPreference];contextAttributes["failIfMajorPerformanceCaveat"]=!!HEAP32[a+(28>>2)];contextAttributes.majorVersion=HEAP32[a+(32>>2)];contextAttributes.minorVersion=HEAP32[a+(36>>2)];contextAttributes.enableExtensionsByDefault=HEAP32[a+(40>>2)];contextAttributes.explicitSwapControl=HEAP32[a+(44>>2)];contextAttributes.proxyContextToMainThread=HEAP32[a+(48>>2)];contextAttributes.renderViaOffscreenBackBuffer=HEAP32[a+(52>>2)];var canvas=__findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}function _emscripten_webgl_create_context(a0,a1){return _emscripten_webgl_do_create_context(a0,a1)}function _emscripten_webgl_destroy_context_calling_thread(contextHandle){if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}function _emscripten_webgl_destroy_context(a0){return _emscripten_webgl_destroy_context_calling_thread(a0)}function _emscripten_webgl_init_context_attributes(attributes){var a=attributes>>2;for(var i=0;i<56>>2;++i){HEAP32[a+i]=0}HEAP32[a+(0>>2)]=HEAP32[a+(4>>2)]=HEAP32[a+(12>>2)]=HEAP32[a+(16>>2)]=HEAP32[a+(32>>2)]=HEAP32[a+(40>>2)]=1}function _emscripten_webgl_make_context_current(contextHandle){var success=GL.makeContextCurrent(contextHandle);return success?0:-5}Module["_emscripten_webgl_make_context_current"]=_emscripten_webgl_make_context_current;var ENV={};function __getExecutableName(){return thisProgram||"./this.program"}function _emscripten_get_environ(){if(!_emscripten_get_environ.strings){var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8","_":__getExecutableName()};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}_emscripten_get_environ.strings=strings}return _emscripten_get_environ.strings}function _environ_get(__environ,environ_buf){var strings=_emscripten_get_environ();var bufSize=0;strings.forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=_emscripten_get_environ();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _exit(status){exit(status)}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_fdstat_get(fd,pbuf){try{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;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops&&stream.stream_ops.fsync){return-stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _flock(fd,operation){return 0}var GAI_ERRNO_MESSAGES={};function _gai_strerror(val){var buflen=256;if(!_gai_strerror.buffer){_gai_strerror.buffer=_malloc(buflen);GAI_ERRNO_MESSAGES["0"]="Success";GAI_ERRNO_MESSAGES[""+-1]="Invalid value for 'ai_flags' field";GAI_ERRNO_MESSAGES[""+-2]="NAME or SERVICE is unknown";GAI_ERRNO_MESSAGES[""+-3]="Temporary failure in name resolution";GAI_ERRNO_MESSAGES[""+-4]="Non-recoverable failure in name res";GAI_ERRNO_MESSAGES[""+-6]="'ai_family' not supported";GAI_ERRNO_MESSAGES[""+-7]="'ai_socktype' not supported";GAI_ERRNO_MESSAGES[""+-8]="SERVICE not supported for 'ai_socktype'";GAI_ERRNO_MESSAGES[""+-10]="Memory allocation failure";GAI_ERRNO_MESSAGES[""+-11]="System error returned in 'errno'";GAI_ERRNO_MESSAGES[""+-12]="Argument buffer overflow"}var msg="Unknown error";if(val in GAI_ERRNO_MESSAGES){if(GAI_ERRNO_MESSAGES[val].length>buflen-1){msg="Message too long"}else{msg=GAI_ERRNO_MESSAGES[val]}}writeAsciiToMemory(msg,_gai_strerror.buffer);return _gai_strerror.buffer}function _getTempRet0(){return getTempRet0()|0}function _getaddrinfo(node,service,hint,out){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 res;salen=family===10?28:16;addr=family===10?__inet_ntop6_raw(addr):__inet_ntop4_raw(addr);sa=_malloc(salen);res=__write_sockaddr(sa,family,addr,port);assert(!res.errno);ai=_malloc(32);HEAP32[ai+4>>2]=family;HEAP32[ai+8>>2]=type;HEAP32[ai+12>>2]=proto;HEAP32[ai+24>>2]=canon;HEAP32[ai+20>>2]=sa;if(family===10){HEAP32[ai+16>>2]=28}else{HEAP32[ai+16>>2]=16}HEAP32[ai+28>>2]=0;return ai}if(hint){flags=HEAP32[hint>>2];family=HEAP32[hint+4>>2];type=HEAP32[hint+8>>2];proto=HEAP32[hint+12>>2]}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]&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,1]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAP32[out>>2]=ai;return 0}node=UTF8ToString(node);addr=__inet_pton4_raw(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=__inet_pton6_raw(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);HEAP32[out>>2]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=__inet_pton4_raw(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAP32[out>>2]=ai;return 0}function _getnameinfo(sa,salen,node,nodelen,serv,servlen,flags){var info=__read_sockaddr(sa,salen);if(info.errno){return-6}var port=info.port;var addr=info.addr;var overflowed=false;if(node&&nodelen){var lookup;if(flags&1||!(lookup=DNS.lookup_addr(addr))){if(flags&8){return-2}}else{addr=lookup}var numBytesWrittenExclNull=stringToUTF8(addr,node,nodelen);if(numBytesWrittenExclNull+1>=nodelen){overflowed=true}}if(serv&&servlen){port=""+port;var numBytesWrittenExclNull=stringToUTF8(port,serv,servlen);if(numBytesWrittenExclNull+1>=servlen){overflowed=true}}if(overflowed){return-12}return 0}function _getpagesize(){return 16384}function _getpwnam(){throw"getpwnam: TODO"}function _gettimeofday(ptr){var now=Date.now();HEAP32[ptr>>2]=now/1e3|0;HEAP32[ptr+4>>2]=now%1e3*1e3|0;return 0}function _glActiveTexture(x0){GLctx["activeTexture"](x0)}function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,imageSize,data)}else{GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,HEAPU8,data,imageSize)}return}GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,imageSize,data)}else{GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,HEAPU8,data,imageSize)}return}GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}function _kill(pid,sig){___setErrNo(ERRNO_CODES.EPERM);return-1}var ___tm_current=11319728;var ___tm_timezone=(stringToUTF8("GMT",11319776,4),11319776);function _tzset(){if(_tzset.called)return;_tzset.called=true;HEAP32[__get_timezone()>>2]=(new Date).getTimezoneOffset()*60;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);HEAP32[__get_daylight()>>2]=Number(winter.getTimezoneOffset()!=summer.getTimezoneOffset());function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=allocateUTF8(winterName);var summerNamePtr=allocateUTF8(summerName);if(summer.getTimezoneOffset()>2]=winterNamePtr;HEAP32[__get_tzname()+4>>2]=summerNamePtr}else{HEAP32[__get_tzname()>>2]=summerNamePtr;HEAP32[__get_tzname()+4>>2]=winterNamePtr}}function _localtime_r(time,tmPtr){_tzset();var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var start=new Date(date.getFullYear(),0,1);var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);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]=dst;var zonePtr=HEAP32[__get_tzname()+(dst?4:0)>>2];HEAP32[tmPtr+40>>2]=zonePtr;return tmPtr}function _localtime(time){return _localtime_r(time,___tm_current)}function _mktime(tmPtr){_tzset();var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];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]=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]=date.getDay();var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;return date.getTime()/1e3|0}function _usleep(useconds){var start=_emscripten_get_now();while(_emscripten_get_now()-start>2];var nanoseconds=HEAP32[rqtp+4>>2];if(nanoseconds<0||nanoseconds>999999999||seconds<0){___setErrNo(28);return-1}if(rmtp!==0){HEAP32[rmtp>>2]=0;HEAP32[rmtp+4>>2]=0}return _usleep(seconds*1e6+nanoseconds/1e3)}function _fpathconf(fildes,name){switch(name){case 0:return 32e3;case 1:case 2:case 3:return 255;case 4:case 5:case 16:case 17:case 18:return 4096;case 6:case 7:case 20:return 1;case 8:return 0;case 9:case 10:case 11:case 12:case 14:case 15:case 19:return-1;case 13:return 64}___setErrNo(28);return-1}function _pathconf(){return _fpathconf.apply(null,arguments)}function _round(d){d=+d;return d>=+0?+Math_floor(d+ +.5):+Math_ceil(d-+.5)}function _setTempRet0($i){setTempRet0($i|0)}function _sigaction(signum,act,oldact){return 0}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]);return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}function _system(command){___setErrNo(6);return-1}FS.staticInit();embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");if(ENVIRONMENT_IS_NODE){_emscripten_get_now=function _emscripten_get_now_actual(){var t=process["hrtime"]();return t[0]*1e3+t[1]/1e6}}else if(typeof dateNow!=="undefined"){_emscripten_get_now=dateNow}else _emscripten_get_now=function(){return performance["now"]()};Module["requestFullscreen"]=function Module_requestFullscreen(lockPointer,resizeCanvas,vrDevice){Browser.requestFullscreen(lockPointer,resizeCanvas,vrDevice)};Module["requestAnimationFrame"]=function Module_requestAnimationFrame(func){Browser.requestAnimationFrame(func)};Module["setCanvasSize"]=function Module_setCanvasSize(width,height,noUpdates){Browser.setCanvasSize(width,height,noUpdates)};Module["pauseMainLoop"]=function Module_pauseMainLoop(){Browser.mainLoop.pause()};Module["resumeMainLoop"]=function Module_resumeMainLoop(){Browser.mainLoop.resume()};Module["getUserMedia"]=function Module_getUserMedia(){Browser.getUserMedia()};Module["createContext"]=function Module_createContext(canvas,useWebGL,setInModule,webGLContextAttributes){return Browser.createContext(canvas,useWebGL,setInModule,webGLContextAttributes)};var GLctx;GL.init();for(var i=0;i<32;i++)__tempFixedLengthArray.push(new Array(i));var ASSERTIONS=false;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 asmLibraryArg={"__assert_fail":___assert_fail,"__cxa_allocate_exception":___cxa_allocate_exception,"__cxa_atexit":___cxa_atexit,"__cxa_thread_atexit":___cxa_thread_atexit,"__cxa_throw":___cxa_throw,"__lock":___lock,"__map_file":___map_file,"__syscall10":___syscall10,"__syscall102":___syscall102,"__syscall122":___syscall122,"__syscall15":___syscall15,"__syscall168":___syscall168,"__syscall183":___syscall183,"__syscall192":___syscall192,"__syscall193":___syscall193,"__syscall194":___syscall194,"__syscall195":___syscall195,"__syscall196":___syscall196,"__syscall197":___syscall197,"__syscall199":___syscall199,"__syscall20":___syscall20,"__syscall201":___syscall201,"__syscall220":___syscall220,"__syscall221":___syscall221,"__syscall3":___syscall3,"__syscall320":___syscall320,"__syscall33":___syscall33,"__syscall38":___syscall38,"__syscall39":___syscall39,"__syscall4":___syscall4,"__syscall40":___syscall40,"__syscall5":___syscall5,"__syscall54":___syscall54,"__syscall83":___syscall83,"__syscall85":___syscall85,"__syscall9":___syscall9,"__syscall91":___syscall91,"__syscall94":___syscall94,"__unlock":___unlock,"_embind_register_bool":__embind_register_bool,"_embind_register_emval":__embind_register_emval,"_embind_register_float":__embind_register_float,"_embind_register_function":__embind_register_function,"_embind_register_integer":__embind_register_integer,"_embind_register_memory_view":__embind_register_memory_view,"_embind_register_std_string":__embind_register_std_string,"_embind_register_std_wstring":__embind_register_std_wstring,"_embind_register_void":__embind_register_void,"_emval_as":__emval_as,"_emval_call":__emval_call,"_emval_call_method":__emval_call_method,"_emval_call_void_method":__emval_call_void_method,"_emval_decref":__emval_decref,"_emval_equals":__emval_equals,"_emval_get_global":__emval_get_global,"_emval_get_method_caller":__emval_get_method_caller,"_emval_get_module_property":__emval_get_module_property,"_emval_get_property":__emval_get_property,"_emval_incref":__emval_incref,"_emval_is_string":__emval_is_string,"_emval_new":__emval_new,"_emval_new_cstring":__emval_new_cstring,"_emval_new_object":__emval_new_object,"_emval_run_destructors":__emval_run_destructors,"_emval_set_property":__emval_set_property,"_emval_take_value":__emval_take_value,"abort":_abort,"clock_gettime":_clock_gettime,"dlclose":_dlclose,"dlerror":_dlerror,"dlopen":_dlopen,"dlsym":_dlsym,"eglGetProcAddress":_eglGetProcAddress,"emscripten_async_call":_emscripten_async_call,"emscripten_date_now":_emscripten_date_now,"emscripten_force_exit":_emscripten_force_exit,"emscripten_get_element_css_size":_emscripten_get_element_css_size,"emscripten_get_sbrk_ptr":_emscripten_get_sbrk_ptr,"emscripten_glActiveTexture":_emscripten_glActiveTexture,"emscripten_glAttachShader":_emscripten_glAttachShader,"emscripten_glBeginQuery":_emscripten_glBeginQuery,"emscripten_glBeginQueryEXT":_emscripten_glBeginQueryEXT,"emscripten_glBeginTransformFeedback":_emscripten_glBeginTransformFeedback,"emscripten_glBindAttribLocation":_emscripten_glBindAttribLocation,"emscripten_glBindBuffer":_emscripten_glBindBuffer,"emscripten_glBindBufferBase":_emscripten_glBindBufferBase,"emscripten_glBindBufferRange":_emscripten_glBindBufferRange,"emscripten_glBindFramebuffer":_emscripten_glBindFramebuffer,"emscripten_glBindRenderbuffer":_emscripten_glBindRenderbuffer,"emscripten_glBindSampler":_emscripten_glBindSampler,"emscripten_glBindTexture":_emscripten_glBindTexture,"emscripten_glBindTransformFeedback":_emscripten_glBindTransformFeedback,"emscripten_glBindVertexArray":_emscripten_glBindVertexArray,"emscripten_glBindVertexArrayOES":_emscripten_glBindVertexArrayOES,"emscripten_glBlendColor":_emscripten_glBlendColor,"emscripten_glBlendEquation":_emscripten_glBlendEquation,"emscripten_glBlendEquationSeparate":_emscripten_glBlendEquationSeparate,"emscripten_glBlendFunc":_emscripten_glBlendFunc,"emscripten_glBlendFuncSeparate":_emscripten_glBlendFuncSeparate,"emscripten_glBlitFramebuffer":_emscripten_glBlitFramebuffer,"emscripten_glBufferData":_emscripten_glBufferData,"emscripten_glBufferSubData":_emscripten_glBufferSubData,"emscripten_glCheckFramebufferStatus":_emscripten_glCheckFramebufferStatus,"emscripten_glClear":_emscripten_glClear,"emscripten_glClearBufferfi":_emscripten_glClearBufferfi,"emscripten_glClearBufferfv":_emscripten_glClearBufferfv,"emscripten_glClearBufferiv":_emscripten_glClearBufferiv,"emscripten_glClearBufferuiv":_emscripten_glClearBufferuiv,"emscripten_glClearColor":_emscripten_glClearColor,"emscripten_glClearDepthf":_emscripten_glClearDepthf,"emscripten_glClearStencil":_emscripten_glClearStencil,"emscripten_glClientWaitSync":_emscripten_glClientWaitSync,"emscripten_glColorMask":_emscripten_glColorMask,"emscripten_glCompileShader":_emscripten_glCompileShader,"emscripten_glCompressedTexImage2D":_emscripten_glCompressedTexImage2D,"emscripten_glCompressedTexImage3D":_emscripten_glCompressedTexImage3D,"emscripten_glCompressedTexSubImage2D":_emscripten_glCompressedTexSubImage2D,"emscripten_glCompressedTexSubImage3D":_emscripten_glCompressedTexSubImage3D,"emscripten_glCopyBufferSubData":_emscripten_glCopyBufferSubData,"emscripten_glCopyTexImage2D":_emscripten_glCopyTexImage2D,"emscripten_glCopyTexSubImage2D":_emscripten_glCopyTexSubImage2D,"emscripten_glCopyTexSubImage3D":_emscripten_glCopyTexSubImage3D,"emscripten_glCreateProgram":_emscripten_glCreateProgram,"emscripten_glCreateShader":_emscripten_glCreateShader,"emscripten_glCullFace":_emscripten_glCullFace,"emscripten_glDeleteBuffers":_emscripten_glDeleteBuffers,"emscripten_glDeleteFramebuffers":_emscripten_glDeleteFramebuffers,"emscripten_glDeleteProgram":_emscripten_glDeleteProgram,"emscripten_glDeleteQueries":_emscripten_glDeleteQueries,"emscripten_glDeleteQueriesEXT":_emscripten_glDeleteQueriesEXT,"emscripten_glDeleteRenderbuffers":_emscripten_glDeleteRenderbuffers,"emscripten_glDeleteSamplers":_emscripten_glDeleteSamplers,"emscripten_glDeleteShader":_emscripten_glDeleteShader,"emscripten_glDeleteSync":_emscripten_glDeleteSync,"emscripten_glDeleteTextures":_emscripten_glDeleteTextures,"emscripten_glDeleteTransformFeedbacks":_emscripten_glDeleteTransformFeedbacks,"emscripten_glDeleteVertexArrays":_emscripten_glDeleteVertexArrays,"emscripten_glDeleteVertexArraysOES":_emscripten_glDeleteVertexArraysOES,"emscripten_glDepthFunc":_emscripten_glDepthFunc,"emscripten_glDepthMask":_emscripten_glDepthMask,"emscripten_glDepthRangef":_emscripten_glDepthRangef,"emscripten_glDetachShader":_emscripten_glDetachShader,"emscripten_glDisable":_emscripten_glDisable,"emscripten_glDisableVertexAttribArray":_emscripten_glDisableVertexAttribArray,"emscripten_glDrawArrays":_emscripten_glDrawArrays,"emscripten_glDrawArraysInstanced":_emscripten_glDrawArraysInstanced,"emscripten_glDrawArraysInstancedANGLE":_emscripten_glDrawArraysInstancedANGLE,"emscripten_glDrawArraysInstancedARB":_emscripten_glDrawArraysInstancedARB,"emscripten_glDrawArraysInstancedEXT":_emscripten_glDrawArraysInstancedEXT,"emscripten_glDrawArraysInstancedNV":_emscripten_glDrawArraysInstancedNV,"emscripten_glDrawBuffers":_emscripten_glDrawBuffers,"emscripten_glDrawBuffersEXT":_emscripten_glDrawBuffersEXT,"emscripten_glDrawBuffersWEBGL":_emscripten_glDrawBuffersWEBGL,"emscripten_glDrawElements":_emscripten_glDrawElements,"emscripten_glDrawElementsInstanced":_emscripten_glDrawElementsInstanced,"emscripten_glDrawElementsInstancedANGLE":_emscripten_glDrawElementsInstancedANGLE,"emscripten_glDrawElementsInstancedARB":_emscripten_glDrawElementsInstancedARB,"emscripten_glDrawElementsInstancedEXT":_emscripten_glDrawElementsInstancedEXT,"emscripten_glDrawElementsInstancedNV":_emscripten_glDrawElementsInstancedNV,"emscripten_glDrawRangeElements":_emscripten_glDrawRangeElements,"emscripten_glEnable":_emscripten_glEnable,"emscripten_glEnableVertexAttribArray":_emscripten_glEnableVertexAttribArray,"emscripten_glEndQuery":_emscripten_glEndQuery,"emscripten_glEndQueryEXT":_emscripten_glEndQueryEXT,"emscripten_glEndTransformFeedback":_emscripten_glEndTransformFeedback,"emscripten_glFenceSync":_emscripten_glFenceSync,"emscripten_glFinish":_emscripten_glFinish,"emscripten_glFlush":_emscripten_glFlush,"emscripten_glFlushMappedBufferRange":_emscripten_glFlushMappedBufferRange,"emscripten_glFramebufferRenderbuffer":_emscripten_glFramebufferRenderbuffer,"emscripten_glFramebufferTexture2D":_emscripten_glFramebufferTexture2D,"emscripten_glFramebufferTextureLayer":_emscripten_glFramebufferTextureLayer,"emscripten_glFrontFace":_emscripten_glFrontFace,"emscripten_glGenBuffers":_emscripten_glGenBuffers,"emscripten_glGenFramebuffers":_emscripten_glGenFramebuffers,"emscripten_glGenQueries":_emscripten_glGenQueries,"emscripten_glGenQueriesEXT":_emscripten_glGenQueriesEXT,"emscripten_glGenRenderbuffers":_emscripten_glGenRenderbuffers,"emscripten_glGenSamplers":_emscripten_glGenSamplers,"emscripten_glGenTextures":_emscripten_glGenTextures,"emscripten_glGenTransformFeedbacks":_emscripten_glGenTransformFeedbacks,"emscripten_glGenVertexArrays":_emscripten_glGenVertexArrays,"emscripten_glGenVertexArraysOES":_emscripten_glGenVertexArraysOES,"emscripten_glGenerateMipmap":_emscripten_glGenerateMipmap,"emscripten_glGetActiveAttrib":_emscripten_glGetActiveAttrib,"emscripten_glGetActiveUniform":_emscripten_glGetActiveUniform,"emscripten_glGetActiveUniformBlockName":_emscripten_glGetActiveUniformBlockName,"emscripten_glGetActiveUniformBlockiv":_emscripten_glGetActiveUniformBlockiv,"emscripten_glGetActiveUniformsiv":_emscripten_glGetActiveUniformsiv,"emscripten_glGetAttachedShaders":_emscripten_glGetAttachedShaders,"emscripten_glGetAttribLocation":_emscripten_glGetAttribLocation,"emscripten_glGetBooleanv":_emscripten_glGetBooleanv,"emscripten_glGetBufferParameteri64v":_emscripten_glGetBufferParameteri64v,"emscripten_glGetBufferParameteriv":_emscripten_glGetBufferParameteriv,"emscripten_glGetBufferPointerv":_emscripten_glGetBufferPointerv,"emscripten_glGetError":_emscripten_glGetError,"emscripten_glGetFloatv":_emscripten_glGetFloatv,"emscripten_glGetFragDataLocation":_emscripten_glGetFragDataLocation,"emscripten_glGetFramebufferAttachmentParameteriv":_emscripten_glGetFramebufferAttachmentParameteriv,"emscripten_glGetInteger64i_v":_emscripten_glGetInteger64i_v,"emscripten_glGetInteger64v":_emscripten_glGetInteger64v,"emscripten_glGetIntegeri_v":_emscripten_glGetIntegeri_v,"emscripten_glGetIntegerv":_emscripten_glGetIntegerv,"emscripten_glGetInternalformativ":_emscripten_glGetInternalformativ,"emscripten_glGetProgramBinary":_emscripten_glGetProgramBinary,"emscripten_glGetProgramInfoLog":_emscripten_glGetProgramInfoLog,"emscripten_glGetProgramiv":_emscripten_glGetProgramiv,"emscripten_glGetQueryObjecti64vEXT":_emscripten_glGetQueryObjecti64vEXT,"emscripten_glGetQueryObjectivEXT":_emscripten_glGetQueryObjectivEXT,"emscripten_glGetQueryObjectui64vEXT":_emscripten_glGetQueryObjectui64vEXT,"emscripten_glGetQueryObjectuiv":_emscripten_glGetQueryObjectuiv,"emscripten_glGetQueryObjectuivEXT":_emscripten_glGetQueryObjectuivEXT,"emscripten_glGetQueryiv":_emscripten_glGetQueryiv,"emscripten_glGetQueryivEXT":_emscripten_glGetQueryivEXT,"emscripten_glGetRenderbufferParameteriv":_emscripten_glGetRenderbufferParameteriv,"emscripten_glGetSamplerParameterfv":_emscripten_glGetSamplerParameterfv,"emscripten_glGetSamplerParameteriv":_emscripten_glGetSamplerParameteriv,"emscripten_glGetShaderInfoLog":_emscripten_glGetShaderInfoLog,"emscripten_glGetShaderPrecisionFormat":_emscripten_glGetShaderPrecisionFormat,"emscripten_glGetShaderSource":_emscripten_glGetShaderSource,"emscripten_glGetShaderiv":_emscripten_glGetShaderiv,"emscripten_glGetString":_emscripten_glGetString,"emscripten_glGetStringi":_emscripten_glGetStringi,"emscripten_glGetSynciv":_emscripten_glGetSynciv,"emscripten_glGetTexParameterfv":_emscripten_glGetTexParameterfv,"emscripten_glGetTexParameteriv":_emscripten_glGetTexParameteriv,"emscripten_glGetTransformFeedbackVarying":_emscripten_glGetTransformFeedbackVarying,"emscripten_glGetUniformBlockIndex":_emscripten_glGetUniformBlockIndex,"emscripten_glGetUniformIndices":_emscripten_glGetUniformIndices,"emscripten_glGetUniformLocation":_emscripten_glGetUniformLocation,"emscripten_glGetUniformfv":_emscripten_glGetUniformfv,"emscripten_glGetUniformiv":_emscripten_glGetUniformiv,"emscripten_glGetUniformuiv":_emscripten_glGetUniformuiv,"emscripten_glGetVertexAttribIiv":_emscripten_glGetVertexAttribIiv,"emscripten_glGetVertexAttribIuiv":_emscripten_glGetVertexAttribIuiv,"emscripten_glGetVertexAttribPointerv":_emscripten_glGetVertexAttribPointerv,"emscripten_glGetVertexAttribfv":_emscripten_glGetVertexAttribfv,"emscripten_glGetVertexAttribiv":_emscripten_glGetVertexAttribiv,"emscripten_glHint":_emscripten_glHint,"emscripten_glInvalidateFramebuffer":_emscripten_glInvalidateFramebuffer,"emscripten_glInvalidateSubFramebuffer":_emscripten_glInvalidateSubFramebuffer,"emscripten_glIsBuffer":_emscripten_glIsBuffer,"emscripten_glIsEnabled":_emscripten_glIsEnabled,"emscripten_glIsFramebuffer":_emscripten_glIsFramebuffer,"emscripten_glIsProgram":_emscripten_glIsProgram,"emscripten_glIsQuery":_emscripten_glIsQuery,"emscripten_glIsQueryEXT":_emscripten_glIsQueryEXT,"emscripten_glIsRenderbuffer":_emscripten_glIsRenderbuffer,"emscripten_glIsSampler":_emscripten_glIsSampler,"emscripten_glIsShader":_emscripten_glIsShader,"emscripten_glIsSync":_emscripten_glIsSync,"emscripten_glIsTexture":_emscripten_glIsTexture,"emscripten_glIsTransformFeedback":_emscripten_glIsTransformFeedback,"emscripten_glIsVertexArray":_emscripten_glIsVertexArray,"emscripten_glIsVertexArrayOES":_emscripten_glIsVertexArrayOES,"emscripten_glLineWidth":_emscripten_glLineWidth,"emscripten_glLinkProgram":_emscripten_glLinkProgram,"emscripten_glMapBufferRange":_emscripten_glMapBufferRange,"emscripten_glPauseTransformFeedback":_emscripten_glPauseTransformFeedback,"emscripten_glPixelStorei":_emscripten_glPixelStorei,"emscripten_glPolygonOffset":_emscripten_glPolygonOffset,"emscripten_glProgramBinary":_emscripten_glProgramBinary,"emscripten_glProgramParameteri":_emscripten_glProgramParameteri,"emscripten_glQueryCounterEXT":_emscripten_glQueryCounterEXT,"emscripten_glReadBuffer":_emscripten_glReadBuffer,"emscripten_glReadPixels":_emscripten_glReadPixels,"emscripten_glReleaseShaderCompiler":_emscripten_glReleaseShaderCompiler,"emscripten_glRenderbufferStorage":_emscripten_glRenderbufferStorage,"emscripten_glRenderbufferStorageMultisample":_emscripten_glRenderbufferStorageMultisample,"emscripten_glResumeTransformFeedback":_emscripten_glResumeTransformFeedback,"emscripten_glSampleCoverage":_emscripten_glSampleCoverage,"emscripten_glSamplerParameterf":_emscripten_glSamplerParameterf,"emscripten_glSamplerParameterfv":_emscripten_glSamplerParameterfv,"emscripten_glSamplerParameteri":_emscripten_glSamplerParameteri,"emscripten_glSamplerParameteriv":_emscripten_glSamplerParameteriv,"emscripten_glScissor":_emscripten_glScissor,"emscripten_glShaderBinary":_emscripten_glShaderBinary,"emscripten_glShaderSource":_emscripten_glShaderSource,"emscripten_glStencilFunc":_emscripten_glStencilFunc,"emscripten_glStencilFuncSeparate":_emscripten_glStencilFuncSeparate,"emscripten_glStencilMask":_emscripten_glStencilMask,"emscripten_glStencilMaskSeparate":_emscripten_glStencilMaskSeparate,"emscripten_glStencilOp":_emscripten_glStencilOp,"emscripten_glStencilOpSeparate":_emscripten_glStencilOpSeparate,"emscripten_glTexImage2D":_emscripten_glTexImage2D,"emscripten_glTexImage3D":_emscripten_glTexImage3D,"emscripten_glTexParameterf":_emscripten_glTexParameterf,"emscripten_glTexParameterfv":_emscripten_glTexParameterfv,"emscripten_glTexParameteri":_emscripten_glTexParameteri,"emscripten_glTexParameteriv":_emscripten_glTexParameteriv,"emscripten_glTexStorage2D":_emscripten_glTexStorage2D,"emscripten_glTexStorage3D":_emscripten_glTexStorage3D,"emscripten_glTexSubImage2D":_emscripten_glTexSubImage2D,"emscripten_glTexSubImage3D":_emscripten_glTexSubImage3D,"emscripten_glTransformFeedbackVaryings":_emscripten_glTransformFeedbackVaryings,"emscripten_glUniform1f":_emscripten_glUniform1f,"emscripten_glUniform1fv":_emscripten_glUniform1fv,"emscripten_glUniform1i":_emscripten_glUniform1i,"emscripten_glUniform1iv":_emscripten_glUniform1iv,"emscripten_glUniform1ui":_emscripten_glUniform1ui,"emscripten_glUniform1uiv":_emscripten_glUniform1uiv,"emscripten_glUniform2f":_emscripten_glUniform2f,"emscripten_glUniform2fv":_emscripten_glUniform2fv,"emscripten_glUniform2i":_emscripten_glUniform2i,"emscripten_glUniform2iv":_emscripten_glUniform2iv,"emscripten_glUniform2ui":_emscripten_glUniform2ui,"emscripten_glUniform2uiv":_emscripten_glUniform2uiv,"emscripten_glUniform3f":_emscripten_glUniform3f,"emscripten_glUniform3fv":_emscripten_glUniform3fv,"emscripten_glUniform3i":_emscripten_glUniform3i,"emscripten_glUniform3iv":_emscripten_glUniform3iv,"emscripten_glUniform3ui":_emscripten_glUniform3ui,"emscripten_glUniform3uiv":_emscripten_glUniform3uiv,"emscripten_glUniform4f":_emscripten_glUniform4f,"emscripten_glUniform4fv":_emscripten_glUniform4fv,"emscripten_glUniform4i":_emscripten_glUniform4i,"emscripten_glUniform4iv":_emscripten_glUniform4iv,"emscripten_glUniform4ui":_emscripten_glUniform4ui,"emscripten_glUniform4uiv":_emscripten_glUniform4uiv,"emscripten_glUniformBlockBinding":_emscripten_glUniformBlockBinding,"emscripten_glUniformMatrix2fv":_emscripten_glUniformMatrix2fv,"emscripten_glUniformMatrix2x3fv":_emscripten_glUniformMatrix2x3fv,"emscripten_glUniformMatrix2x4fv":_emscripten_glUniformMatrix2x4fv,"emscripten_glUniformMatrix3fv":_emscripten_glUniformMatrix3fv,"emscripten_glUniformMatrix3x2fv":_emscripten_glUniformMatrix3x2fv,"emscripten_glUniformMatrix3x4fv":_emscripten_glUniformMatrix3x4fv,"emscripten_glUniformMatrix4fv":_emscripten_glUniformMatrix4fv,"emscripten_glUniformMatrix4x2fv":_emscripten_glUniformMatrix4x2fv,"emscripten_glUniformMatrix4x3fv":_emscripten_glUniformMatrix4x3fv,"emscripten_glUnmapBuffer":_emscripten_glUnmapBuffer,"emscripten_glUseProgram":_emscripten_glUseProgram,"emscripten_glValidateProgram":_emscripten_glValidateProgram,"emscripten_glVertexAttrib1f":_emscripten_glVertexAttrib1f,"emscripten_glVertexAttrib1fv":_emscripten_glVertexAttrib1fv,"emscripten_glVertexAttrib2f":_emscripten_glVertexAttrib2f,"emscripten_glVertexAttrib2fv":_emscripten_glVertexAttrib2fv,"emscripten_glVertexAttrib3f":_emscripten_glVertexAttrib3f,"emscripten_glVertexAttrib3fv":_emscripten_glVertexAttrib3fv,"emscripten_glVertexAttrib4f":_emscripten_glVertexAttrib4f,"emscripten_glVertexAttrib4fv":_emscripten_glVertexAttrib4fv,"emscripten_glVertexAttribDivisor":_emscripten_glVertexAttribDivisor,"emscripten_glVertexAttribDivisorANGLE":_emscripten_glVertexAttribDivisorANGLE,"emscripten_glVertexAttribDivisorARB":_emscripten_glVertexAttribDivisorARB,"emscripten_glVertexAttribDivisorEXT":_emscripten_glVertexAttribDivisorEXT,"emscripten_glVertexAttribDivisorNV":_emscripten_glVertexAttribDivisorNV,"emscripten_glVertexAttribI4i":_emscripten_glVertexAttribI4i,"emscripten_glVertexAttribI4iv":_emscripten_glVertexAttribI4iv,"emscripten_glVertexAttribI4ui":_emscripten_glVertexAttribI4ui,"emscripten_glVertexAttribI4uiv":_emscripten_glVertexAttribI4uiv,"emscripten_glVertexAttribIPointer":_emscripten_glVertexAttribIPointer,"emscripten_glVertexAttribPointer":_emscripten_glVertexAttribPointer,"emscripten_glViewport":_emscripten_glViewport,"emscripten_glWaitSync":_emscripten_glWaitSync,"emscripten_idb_async_delete":_emscripten_idb_async_delete,"emscripten_idb_async_exists":_emscripten_idb_async_exists,"emscripten_idb_async_load":_emscripten_idb_async_load,"emscripten_idb_async_store":_emscripten_idb_async_store,"emscripten_is_webgl_context_lost":_emscripten_is_webgl_context_lost,"emscripten_log":_emscripten_log,"emscripten_longjmp":_emscripten_longjmp,"emscripten_memcpy_big":_emscripten_memcpy_big,"emscripten_pause_main_loop":_emscripten_pause_main_loop,"emscripten_resize_heap":_emscripten_resize_heap,"emscripten_resume_main_loop":_emscripten_resume_main_loop,"emscripten_set_focus_callback_on_thread":_emscripten_set_focus_callback_on_thread,"emscripten_set_keydown_callback_on_thread":_emscripten_set_keydown_callback_on_thread,"emscripten_set_keyup_callback_on_thread":_emscripten_set_keyup_callback_on_thread,"emscripten_set_main_loop_arg":_emscripten_set_main_loop_arg,"emscripten_set_mousedown_callback_on_thread":_emscripten_set_mousedown_callback_on_thread,"emscripten_set_mousemove_callback_on_thread":_emscripten_set_mousemove_callback_on_thread,"emscripten_set_mouseup_callback_on_thread":_emscripten_set_mouseup_callback_on_thread,"emscripten_set_resize_callback_on_thread":_emscripten_set_resize_callback_on_thread,"emscripten_set_touchcancel_callback_on_thread":_emscripten_set_touchcancel_callback_on_thread,"emscripten_set_touchend_callback_on_thread":_emscripten_set_touchend_callback_on_thread,"emscripten_set_touchmove_callback_on_thread":_emscripten_set_touchmove_callback_on_thread,"emscripten_set_touchstart_callback_on_thread":_emscripten_set_touchstart_callback_on_thread,"emscripten_set_wheel_callback_on_thread":_emscripten_set_wheel_callback_on_thread,"emscripten_sleep":_emscripten_sleep,"emscripten_webgl_create_context":_emscripten_webgl_create_context,"emscripten_webgl_destroy_context":_emscripten_webgl_destroy_context,"emscripten_webgl_init_context_attributes":_emscripten_webgl_init_context_attributes,"emscripten_webgl_make_context_current":_emscripten_webgl_make_context_current,"environ_get":_environ_get,"environ_sizes_get":_environ_sizes_get,"exit":_exit,"fd_close":_fd_close,"fd_fdstat_get":_fd_fdstat_get,"fd_seek":_fd_seek,"fd_sync":_fd_sync,"fd_write":_fd_write,"flock":_flock,"gai_strerror":_gai_strerror,"getTempRet0":_getTempRet0,"getaddrinfo":_getaddrinfo,"getnameinfo":_getnameinfo,"getpagesize":_getpagesize,"getpwnam":_getpwnam,"gettimeofday":_gettimeofday,"glActiveTexture":_glActiveTexture,"glCompressedTexImage2D":_glCompressedTexImage2D,"glCompressedTexSubImage2D":_glCompressedTexSubImage2D,"glGenerateMipmap":_glGenerateMipmap,"glTexSubImage2D":_glTexSubImage2D,"glViewport":_glViewport,"invoke_fi":invoke_fi,"invoke_ii":invoke_ii,"invoke_iii":invoke_iii,"invoke_iiii":invoke_iiii,"invoke_iiiif":invoke_iiiif,"invoke_iiiii":invoke_iiiii,"invoke_iiiiii":invoke_iiiiii,"invoke_iiiiiii":invoke_iiiiiii,"invoke_iiiiiiif":invoke_iiiiiiif,"invoke_iiiiiiiiii":invoke_iiiiiiiiii,"invoke_iiiiiiiiiii":invoke_iiiiiiiiiii,"invoke_iij":invoke_iij,"invoke_ji":invoke_ji,"invoke_v":invoke_v,"invoke_vi":invoke_vi,"invoke_vidd":invoke_vidd,"invoke_vii":invoke_vii,"invoke_viid":invoke_viid,"invoke_viii":invoke_viii,"invoke_viiif":invoke_viiif,"invoke_viiii":invoke_viiii,"invoke_viiiii":invoke_viiiii,"invoke_viiiiii":invoke_viiiiii,"invoke_viiiiiii":invoke_viiiiiii,"invoke_viiiiiiiii":invoke_viiiiiiiii,"kill":_kill,"localtime":_localtime,"memory":wasmMemory,"mktime":_mktime,"nanosleep":_nanosleep,"pathconf":_pathconf,"round":_round,"saveSetjmp":_saveSetjmp,"setTempRet0":_setTempRet0,"sigaction":_sigaction,"strftime_l":_strftime_l,"system":_system,"table":wasmTable,"testSetjmp":_testSetjmp,"tzset":_tzset};var asm=createWasm();Module["asm"]=asm;var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["__wasm_call_ctors"]).apply(null,arguments)};var _main=Module["_main"]=function(){return(_main=Module["_main"]=Module["asm"]["main"]).apply(null,arguments)};var _strlen=Module["_strlen"]=function(){return(_strlen=Module["_strlen"]=Module["asm"]["strlen"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["free"]).apply(null,arguments)};var _strstr=Module["_strstr"]=function(){return(_strstr=Module["_strstr"]=Module["asm"]["strstr"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["malloc"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["__errno_location"]).apply(null,arguments)};var _realloc=Module["_realloc"]=function(){return(_realloc=Module["_realloc"]=Module["asm"]["realloc"]).apply(null,arguments)};var _fflush=Module["_fflush"]=function(){return(_fflush=Module["_fflush"]=Module["asm"]["fflush"]).apply(null,arguments)};var _htonl=Module["_htonl"]=function(){return(_htonl=Module["_htonl"]=Module["asm"]["htonl"]).apply(null,arguments)};var _htons=Module["_htons"]=function(){return(_htons=Module["_htons"]=Module["asm"]["htons"]).apply(null,arguments)};var _ntohs=Module["_ntohs"]=function(){return(_ntohs=Module["_ntohs"]=Module["asm"]["ntohs"]).apply(null,arguments)};var __get_tzname=Module["__get_tzname"]=function(){return(__get_tzname=Module["__get_tzname"]=Module["asm"]["_get_tzname"]).apply(null,arguments)};var __get_daylight=Module["__get_daylight"]=function(){return(__get_daylight=Module["__get_daylight"]=Module["asm"]["_get_daylight"]).apply(null,arguments)};var __get_timezone=Module["__get_timezone"]=function(){return(__get_timezone=Module["__get_timezone"]=Module["asm"]["_get_timezone"]).apply(null,arguments)};var _setThrew=Module["_setThrew"]=function(){return(_setThrew=Module["_setThrew"]=Module["asm"]["setThrew"]).apply(null,arguments)};var __ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=function(){return(__ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=Module["asm"]["_ZSt18uncaught_exceptionv"]).apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return(___getTypeName=Module["___getTypeName"]=Module["asm"]["__getTypeName"]).apply(null,arguments)};var ___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=function(){return(___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=Module["asm"]["__embind_register_native_and_builtin_types"]).apply(null,arguments)};var _emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=function(){return(_emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=Module["asm"]["emscripten_GetProcAddress"]).apply(null,arguments)};var _memalign=Module["_memalign"]=function(){return(_memalign=Module["_memalign"]=Module["asm"]["memalign"]).apply(null,arguments)};var _emscripten_builtin_free=Module["_emscripten_builtin_free"]=function(){return(_emscripten_builtin_free=Module["_emscripten_builtin_free"]=Module["asm"]["emscripten_builtin_free"]).apply(null,arguments)};var _emscripten_builtin_memalign=Module["_emscripten_builtin_memalign"]=function(){return(_emscripten_builtin_memalign=Module["_emscripten_builtin_memalign"]=Module["asm"]["emscripten_builtin_memalign"]).apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return(dynCall_v=Module["dynCall_v"]=Module["asm"]["dynCall_v"]).apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return(dynCall_vi=Module["dynCall_vi"]=Module["asm"]["dynCall_vi"]).apply(null,arguments)};var dynCall_vii=Module["dynCall_vii"]=function(){return(dynCall_vii=Module["dynCall_vii"]=Module["asm"]["dynCall_vii"]).apply(null,arguments)};var dynCall_viii=Module["dynCall_viii"]=function(){return(dynCall_viii=Module["dynCall_viii"]=Module["asm"]["dynCall_viii"]).apply(null,arguments)};var dynCall_viiii=Module["dynCall_viiii"]=function(){return(dynCall_viiii=Module["dynCall_viiii"]=Module["asm"]["dynCall_viiii"]).apply(null,arguments)};var dynCall_viiiii=Module["dynCall_viiiii"]=function(){return(dynCall_viiiii=Module["dynCall_viiiii"]=Module["asm"]["dynCall_viiiii"]).apply(null,arguments)};var dynCall_viiiiii=Module["dynCall_viiiiii"]=function(){return(dynCall_viiiiii=Module["dynCall_viiiiii"]=Module["asm"]["dynCall_viiiiii"]).apply(null,arguments)};var dynCall_viiiiiii=Module["dynCall_viiiiiii"]=function(){return(dynCall_viiiiiii=Module["dynCall_viiiiiii"]=Module["asm"]["dynCall_viiiiiii"]).apply(null,arguments)};var dynCall_viiiiiiiii=Module["dynCall_viiiiiiiii"]=function(){return(dynCall_viiiiiiiii=Module["dynCall_viiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiii"]).apply(null,arguments)};var dynCall_viiif=Module["dynCall_viiif"]=function(){return(dynCall_viiif=Module["dynCall_viiif"]=Module["asm"]["dynCall_viiif"]).apply(null,arguments)};var dynCall_viid=Module["dynCall_viid"]=function(){return(dynCall_viid=Module["dynCall_viid"]=Module["asm"]["dynCall_viid"]).apply(null,arguments)};var dynCall_vidd=Module["dynCall_vidd"]=function(){return(dynCall_vidd=Module["dynCall_vidd"]=Module["asm"]["dynCall_vidd"]).apply(null,arguments)};var dynCall_ii=Module["dynCall_ii"]=function(){return(dynCall_ii=Module["dynCall_ii"]=Module["asm"]["dynCall_ii"]).apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return(dynCall_iii=Module["dynCall_iii"]=Module["asm"]["dynCall_iii"]).apply(null,arguments)};var dynCall_iiii=Module["dynCall_iiii"]=function(){return(dynCall_iiii=Module["dynCall_iiii"]=Module["asm"]["dynCall_iiii"]).apply(null,arguments)};var dynCall_iiiii=Module["dynCall_iiiii"]=function(){return(dynCall_iiiii=Module["dynCall_iiiii"]=Module["asm"]["dynCall_iiiii"]).apply(null,arguments)};var dynCall_iiiiii=Module["dynCall_iiiiii"]=function(){return(dynCall_iiiiii=Module["dynCall_iiiiii"]=Module["asm"]["dynCall_iiiiii"]).apply(null,arguments)};var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=function(){return(dynCall_iiiiiii=Module["dynCall_iiiiiii"]=Module["asm"]["dynCall_iiiiiii"]).apply(null,arguments)};var dynCall_iiiiiiiiii=Module["dynCall_iiiiiiiiii"]=function(){return(dynCall_iiiiiiiiii=Module["dynCall_iiiiiiiiii"]=Module["asm"]["dynCall_iiiiiiiiii"]).apply(null,arguments)};var dynCall_iiiiiiiiiii=Module["dynCall_iiiiiiiiiii"]=function(){return(dynCall_iiiiiiiiiii=Module["dynCall_iiiiiiiiiii"]=Module["asm"]["dynCall_iiiiiiiiiii"]).apply(null,arguments)};var dynCall_iiiiiiif=Module["dynCall_iiiiiiif"]=function(){return(dynCall_iiiiiiif=Module["dynCall_iiiiiiif"]=Module["asm"]["dynCall_iiiiiiif"]).apply(null,arguments)};var dynCall_iiiif=Module["dynCall_iiiif"]=function(){return(dynCall_iiiif=Module["dynCall_iiiif"]=Module["asm"]["dynCall_iiiif"]).apply(null,arguments)};var dynCall_iij=Module["dynCall_iij"]=function(){return(dynCall_iij=Module["dynCall_iij"]=Module["asm"]["dynCall_iij"]).apply(null,arguments)};var dynCall_ji=Module["dynCall_ji"]=function(){return(dynCall_ji=Module["dynCall_ji"]=Module["asm"]["dynCall_ji"]).apply(null,arguments)};var dynCall_fi=Module["dynCall_fi"]=function(){return(dynCall_fi=Module["dynCall_fi"]=Module["asm"]["dynCall_fi"]).apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return(stackSave=Module["stackSave"]=Module["asm"]["stackSave"]).apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return(stackAlloc=Module["stackAlloc"]=Module["asm"]["stackAlloc"]).apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return(stackRestore=Module["stackRestore"]=Module["asm"]["stackRestore"]).apply(null,arguments)};var __growWasmMemory=Module["__growWasmMemory"]=function(){return(__growWasmMemory=Module["__growWasmMemory"]=Module["asm"]["__growWasmMemory"]).apply(null,arguments)};var dynCall_vid=Module["dynCall_vid"]=function(){return(dynCall_vid=Module["dynCall_vid"]=Module["asm"]["dynCall_vid"]).apply(null,arguments)};var dynCall_viidd=Module["dynCall_viidd"]=function(){return(dynCall_viidd=Module["dynCall_viidd"]=Module["asm"]["dynCall_viidd"]).apply(null,arguments)};var dynCall_viiddd=Module["dynCall_viiddd"]=function(){return(dynCall_viiddd=Module["dynCall_viiddd"]=Module["asm"]["dynCall_viiddd"]).apply(null,arguments)};var dynCall_i=Module["dynCall_i"]=function(){return(dynCall_i=Module["dynCall_i"]=Module["asm"]["dynCall_i"]).apply(null,arguments)};var dynCall_di=Module["dynCall_di"]=function(){return(dynCall_di=Module["dynCall_di"]=Module["asm"]["dynCall_di"]).apply(null,arguments)};var dynCall_iiidi=Module["dynCall_iiidi"]=function(){return(dynCall_iiidi=Module["dynCall_iiidi"]=Module["asm"]["dynCall_iiidi"]).apply(null,arguments)};var dynCall_viddiii=Module["dynCall_viddiii"]=function(){return(dynCall_viddiii=Module["dynCall_viddiii"]=Module["asm"]["dynCall_viddiii"]).apply(null,arguments)};var dynCall_iid=Module["dynCall_iid"]=function(){return(dynCall_iid=Module["dynCall_iid"]=Module["asm"]["dynCall_iid"]).apply(null,arguments)};var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=function(){return(dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=Module["asm"]["dynCall_iiiiiiii"]).apply(null,arguments)};var dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=function(){return(dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=Module["asm"]["dynCall_viiiiiiii"]).apply(null,arguments)};var dynCall_jiji=Module["dynCall_jiji"]=function(){return(dynCall_jiji=Module["dynCall_jiji"]=Module["asm"]["dynCall_jiji"]).apply(null,arguments)};var dynCall_viij=Module["dynCall_viij"]=function(){return(dynCall_viij=Module["dynCall_viij"]=Module["asm"]["dynCall_viij"]).apply(null,arguments)};var dynCall_viiiiiiiiiiii=Module["dynCall_viiiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiiii=Module["dynCall_viiiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiiii"]).apply(null,arguments)};var dynCall_jiiii=Module["dynCall_jiiii"]=function(){return(dynCall_jiiii=Module["dynCall_jiiii"]=Module["asm"]["dynCall_jiiii"]).apply(null,arguments)};var dynCall_diiii=Module["dynCall_diiii"]=function(){return(dynCall_diiii=Module["dynCall_diiii"]=Module["asm"]["dynCall_diiii"]).apply(null,arguments)};var dynCall_diiiiiiii=Module["dynCall_diiiiiiii"]=function(){return(dynCall_diiiiiiii=Module["dynCall_diiiiiiii"]=Module["asm"]["dynCall_diiiiiiii"]).apply(null,arguments)};var dynCall_dii=Module["dynCall_dii"]=function(){return(dynCall_dii=Module["dynCall_dii"]=Module["asm"]["dynCall_dii"]).apply(null,arguments)};var dynCall_diii=Module["dynCall_diii"]=function(){return(dynCall_diii=Module["dynCall_diii"]=Module["asm"]["dynCall_diii"]).apply(null,arguments)};var dynCall_fii=Module["dynCall_fii"]=function(){return(dynCall_fii=Module["dynCall_fii"]=Module["asm"]["dynCall_fii"]).apply(null,arguments)};var dynCall_viiiid=Module["dynCall_viiiid"]=function(){return(dynCall_viiiid=Module["dynCall_viiiid"]=Module["asm"]["dynCall_viiiid"]).apply(null,arguments)};var dynCall_vij=Module["dynCall_vij"]=function(){return(dynCall_vij=Module["dynCall_vij"]=Module["asm"]["dynCall_vij"]).apply(null,arguments)};var dynCall_viji=Module["dynCall_viji"]=function(){return(dynCall_viji=Module["dynCall_viji"]=Module["asm"]["dynCall_viji"]).apply(null,arguments)};var dynCall_viijii=Module["dynCall_viijii"]=function(){return(dynCall_viijii=Module["dynCall_viijii"]=Module["asm"]["dynCall_viijii"]).apply(null,arguments)};var dynCall_viiji=Module["dynCall_viiji"]=function(){return(dynCall_viiji=Module["dynCall_viiji"]=Module["asm"]["dynCall_viiji"]).apply(null,arguments)};var dynCall_viiiiiiiiii=Module["dynCall_viiiiiiiiii"]=function(){return(dynCall_viiiiiiiiii=Module["dynCall_viiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiii"]).apply(null,arguments)};var dynCall_viiddi=Module["dynCall_viiddi"]=function(){return(dynCall_viiddi=Module["dynCall_viiddi"]=Module["asm"]["dynCall_viiddi"]).apply(null,arguments)};var dynCall_vddddddi=Module["dynCall_vddddddi"]=function(){return(dynCall_vddddddi=Module["dynCall_vddddddi"]=Module["asm"]["dynCall_vddddddi"]).apply(null,arguments)};var dynCall_vddi=Module["dynCall_vddi"]=function(){return(dynCall_vddi=Module["dynCall_vddi"]=Module["asm"]["dynCall_vddi"]).apply(null,arguments)};var dynCall_iiddddi=Module["dynCall_iiddddi"]=function(){return(dynCall_iiddddi=Module["dynCall_iiddddi"]=Module["asm"]["dynCall_iiddddi"]).apply(null,arguments)};var dynCall_viiiiiiiiiii=Module["dynCall_viiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiii=Module["dynCall_viiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiii"]).apply(null,arguments)};var dynCall_viiiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiiiiii"]).apply(null,arguments)};var dynCall_viiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiiiii"]).apply(null,arguments)};var dynCall_viiiiif=Module["dynCall_viiiiif"]=function(){return(dynCall_viiiiif=Module["dynCall_viiiiif"]=Module["asm"]["dynCall_viiiiif"]).apply(null,arguments)};var dynCall_viiid=Module["dynCall_viiid"]=function(){return(dynCall_viiid=Module["dynCall_viiid"]=Module["asm"]["dynCall_viiid"]).apply(null,arguments)};var dynCall_jiij=Module["dynCall_jiij"]=function(){return(dynCall_jiij=Module["dynCall_jiij"]=Module["asm"]["dynCall_jiij"]).apply(null,arguments)};var dynCall_jij=Module["dynCall_jij"]=function(){return(dynCall_jij=Module["dynCall_jij"]=Module["asm"]["dynCall_jij"]).apply(null,arguments)};var dynCall_jiijii=Module["dynCall_jiijii"]=function(){return(dynCall_jiijii=Module["dynCall_jiijii"]=Module["asm"]["dynCall_jiijii"]).apply(null,arguments)};var dynCall_jiiji=Module["dynCall_jiiji"]=function(){return(dynCall_jiiji=Module["dynCall_jiiji"]=Module["asm"]["dynCall_jiiji"]).apply(null,arguments)};var dynCall_dd=Module["dynCall_dd"]=function(){return(dynCall_dd=Module["dynCall_dd"]=Module["asm"]["dynCall_dd"]).apply(null,arguments)};var dynCall_did=Module["dynCall_did"]=function(){return(dynCall_did=Module["dynCall_did"]=Module["asm"]["dynCall_did"]).apply(null,arguments)};var dynCall_iidiiii=Module["dynCall_iidiiii"]=function(){return(dynCall_iidiiii=Module["dynCall_iidiiii"]=Module["asm"]["dynCall_iidiiii"]).apply(null,arguments)};var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=function(){return(dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=Module["asm"]["dynCall_iiiiiiiii"]).apply(null,arguments)};var dynCall_iiiiij=Module["dynCall_iiiiij"]=function(){return(dynCall_iiiiij=Module["dynCall_iiiiij"]=Module["asm"]["dynCall_iiiiij"]).apply(null,arguments)};var dynCall_iiiiid=Module["dynCall_iiiiid"]=function(){return(dynCall_iiiiid=Module["dynCall_iiiiid"]=Module["asm"]["dynCall_iiiiid"]).apply(null,arguments)};var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=function(){return(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=Module["asm"]["dynCall_iiiiijj"]).apply(null,arguments)};var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=function(){return(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=Module["asm"]["dynCall_iiiiiijj"]).apply(null,arguments)};var dynCall_vffff=Module["dynCall_vffff"]=function(){return(dynCall_vffff=Module["dynCall_vffff"]=Module["asm"]["dynCall_vffff"]).apply(null,arguments)};var dynCall_vf=Module["dynCall_vf"]=function(){return(dynCall_vf=Module["dynCall_vf"]=Module["asm"]["dynCall_vf"]).apply(null,arguments)};var dynCall_vff=Module["dynCall_vff"]=function(){return(dynCall_vff=Module["dynCall_vff"]=Module["asm"]["dynCall_vff"]).apply(null,arguments)};var dynCall_vfi=Module["dynCall_vfi"]=function(){return(dynCall_vfi=Module["dynCall_vfi"]=Module["asm"]["dynCall_vfi"]).apply(null,arguments)};var dynCall_viif=Module["dynCall_viif"]=function(){return(dynCall_viif=Module["dynCall_viif"]=Module["asm"]["dynCall_viif"]).apply(null,arguments)};var dynCall_vif=Module["dynCall_vif"]=function(){return(dynCall_vif=Module["dynCall_vif"]=Module["asm"]["dynCall_vif"]).apply(null,arguments)};var dynCall_viff=Module["dynCall_viff"]=function(){return(dynCall_viff=Module["dynCall_viff"]=Module["asm"]["dynCall_viff"]).apply(null,arguments)};var dynCall_vifff=Module["dynCall_vifff"]=function(){return(dynCall_vifff=Module["dynCall_vifff"]=Module["asm"]["dynCall_vifff"]).apply(null,arguments)};var dynCall_viffff=Module["dynCall_viffff"]=function(){return(dynCall_viffff=Module["dynCall_viffff"]=Module["asm"]["dynCall_viffff"]).apply(null,arguments)};var dynCall_viifi=Module["dynCall_viifi"]=function(){return(dynCall_viifi=Module["dynCall_viifi"]=Module["asm"]["dynCall_viifi"]).apply(null,arguments)};function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return dynCall_iii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_iiiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{dynCall_viii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return dynCall_ii(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_iiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{dynCall_vii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9){var sp=stackSave();try{return dynCall_iiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{dynCall_vi(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return dynCall_iiiiiii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{dynCall_v(index)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{dynCall_viiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return dynCall_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiif(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return dynCall_iiiiiiif(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiif(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_iiiif(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vidd(index,a1,a2,a3){var sp=stackSave();try{dynCall_vidd(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiif(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viiif(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return dynCall_iiiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9){var sp=stackSave();try{dynCall_viiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viid(index,a1,a2,a3){var sp=stackSave();try{dynCall_viid(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_fi(index,a1){var sp=stackSave();try{return dynCall_fi(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{dynCall_viiiiii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{dynCall_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ji(index,a1){var sp=stackSave();try{return dynCall_ji(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iij(index,a1,a2,a3){var sp=stackSave();try{return dynCall_iij(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}Module["asm"]=asm;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}var calledMain=false;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args){var entryFunction=Module["_main"];args=args||[];var argc=args.length+1;var argv=stackAlloc((argc+1)*4);HEAP32[argv>>2]=allocateUTF8OnStack(thisProgram);for(var i=1;i>2)+i]=allocateUTF8OnStack(args[i-1])}HEAP32[(argv>>2)+argc]=0;try{var ret=entryFunction(argc,argv);exit(ret,true)}catch(e){if(e instanceof ExitStatus){return}else if(e=="unwind"){noExitRuntime=true;return}else{var toLog=e;if(e&&typeof e==="object"&&e.stack){toLog=[e,e.stack]}err("exception thrown: "+toLog);quit_(1,e)}}finally{calledMain=true}}function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&noExitRuntime&&status===0){return}if(noExitRuntime){}else{ABORT=true;EXITSTATUS=status;exitRuntime();if(Module["onExit"])Module["onExit"](status)}quit_(status,new ExitStatus(status))}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(); diff --git a/docs/examples.wasm b/docs/examples.wasm new file mode 100644 index 0000000..9e04bac Binary files /dev/null and b/docs/examples.wasm differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..ba19340 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,72 @@ + + + + + + + + + + examples + + + +
    +
    + + Qt for WebAssembly: examples +
    + +
    +
    + + + + + + diff --git a/docs/iotsystem.html b/docs/iotsystem.html new file mode 100644 index 0000000..0e5b8d2 --- /dev/null +++ b/docs/iotsystem.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/iotsystem/index.html b/docs/iotsystem/index.html new file mode 100644 index 0000000..c3d7c0b --- /dev/null +++ b/docs/iotsystem/index.html @@ -0,0 +1,696 @@ + + + + + +物联网平台开发及使用手册 + +
    +
  • 0 前言说明

    0.1 编译说明

    1. 编译完成后记得将源码下的file目录下(切记是file目录下而不是file目录)的所有文件复制到可执行文件同一目录。可执行文件目录bin在当前源码下,和一堆core开头的目录同级别,编译后会自动生成bin目录。
    2. 打开pro文件,修改DEFINES中的 iottool1 为 iottool,则编译出来的是设备模拟工具,用于没有外接硬件设备时候模拟设备数据测试用。
    3. 编译完成后,先双击打开iottool.exe,这个是设备模拟工具,再打开iotsystem.exe,这个是主程序,主程序建议添加两个通信端口,一个串口端口和一个网络端口,设备模拟工具会自动打开串口和网络进行数据的模拟。
    4. db目录下的 iotsystem.mbs 为modbus模拟数据模板,可以用modbus slave软件打开。
    5. db目录为数据库文件夹,iotsystem.db为sqlite数据库文件,sql结尾的为建库脚本,可以自行改成mysql数据库。
    6. 在端口设置中如果不填写串口号则取网络地址,填了串口号则以串口号优先。
    7. 如果导出的数据到excel以后,打开文件有提示,请先执行db目录下的excel禁止提示.reg文件。
    8. 系统中的组态模块用到了designer模块,有些linux系统安装的Qt开发环境可能会不自带这个模块,编译的时候报错提示 Project ERROR: Unknown module(s) in QT: designer,需要手动打命令安装下,sudo apt-get install libqt5designer5 或者 sudo apt-get install qttools5-dev 。

    0.2 功能特点

    0.2.1 软件模块

    1. 设备监控模块,包括数据监控(表格形式展示)、设备面板(面板形式展示)、地图监控(地图形式展示)、曲线监控(曲线形式展示)。
    2. 数据查询模块,包括报警记录、运行记录、操作记录。
    3. 系统设置模块,包括基本设置、端口管理、控制器管理、探测器管理、报警联动、类型设置等。
    4. 其他设置模块,包括用户管理、地图管理、位置调整、组态设计、设备调试等。

    0.2.2 基础功能

    1. 设备数据采集,支持串口、网络,串口可设置串口号、波特率,网络可设置IP地址、通讯端口。
    2. 每个端口支持采集周期时间,默认1秒钟一个设备。
    3. 支持设置通讯超时次数,默认3次。
    4. 支持最大重连时间,用于重新读取离线的设备。
    5. 控制器信息,能够添加控制器名称,选择控制器地址、控制器型号,设置该控制器下面的探测器数量。
    6. 探测器信息,能够添加位号、探测器型号、气体种类、气体符号、高报值、低报值、缓冲值、清零值、是否启用、报警声音、背景地图、存储周期、数值换算小数点位数、报警延时时间、报警的类型(HH,LL,HL)等。
    7. 类型管理可配置控制器型号、探测器型号、气体种类、气体符号等。
    8. 地图支持导入和删除,所有的探测器在地图上的位置可自由拖动保存。
    9. 端口信息、控制器信息、探测器信息、类型信息、用户信息等,都支持导入、导出、导出到excel、打印。
    10. 运行记录、报警记录、操作记录,都支持多条件组合查询,比如时间段、控制器、探测器等,所有记录支持导出到excel/pdf和打印。
    11. 运行记录、报警记录、操作记录都可删除指定时间范围内的数据。
    12. 系统设置可选择对应表最大保存记录数,自动清理早期数据,留出足够的空间存储重要的数据。
    13. 报警短信转发,支持多个接收手机号码,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,短信内容过长,自动拆分多条短信。
    14. 报警邮件转发,支持多个接收邮箱,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,支持附件发送。
    15. 设置软件的中文标题、英文标题、logo路径、版权所有等。
    16. 开关设置开机运行、报警声音、自动登录、记住密码等。
    17. 报警声音可设置播放次数,界面风格样式提供18套皮肤文件选择。
    18. 用户管理,包括用户权限配置,不同用户可以有不同模块的权限。
    19. 用户登录和用户退出,可以记住密码和自动登录,超过三次报错提示并关闭程序。
    20. 四种监控模式,设备面板监控、地图监控、表格数据监控、曲线数据监控,可自由切换,四种模式下都实时展示采集到的数据,报警闪烁等。
    21. 报警继电器联动,一个位号可以跨串口联动多个模块和继电器号,支持多对多。

    0.2.3 特色功能

    1. 通信协议支持modbus_com、modbus_tcp_rtu,后期拓展mqtt等协议。
    2. 数据源除了真实的硬件设备采集,还可选数据库采集,这样用户可以安排其他程序员比如java程序员将前端采集好的数据放到数据库,本系统直接从数据库采集即可。数据库采集模式可以作为通用的系统使用,更适合多人多系统协作。
    3. 智能跳过超时的设备,加快对在线设备的采集速度,当设备数量很多的时候尤其有用。
    4. 对智能跳过的超时的设备,在设定的重连时间自动采集一次,以便探测设备是否又重新上线。
    5. 每个探测器可控是否启用,不启用则不会采集,也不会在界面显示,相当于运行阶段临时关闭。
    6. 探测器可设置缓冲值和报警延时时间,在该值附近波动产生的报警,不计入报警,只有持续处于报警值且超过报警延时时间才算真正报警,这样可以规避很多波动导致的误报。
    7. 探测器可设置存储周期,按照设定的时间来存储一条运行记录,可以按照重要程度对重要性高的设定存储周期短一些,不重要的设定大一些,这样可以节省不少的存储空间,也保证了重要的数据及时存储。
    8. 探测器可设置清零值,在一些高精度高灵敏的设备可能出厂的时候默认值未必是0,需要设定清零值来表示初始值。
    9. 探测器可设置小数点,用于计算后的真实数据控制小数点点位显示,相当于除以10、除以100、除以1000,这样大部分的探测器数据直接通过小数点位设置控制真实换算后的值,极个别的需要特殊转换的可以在通信协议中约定。
    10. 探测器报警的类型支持多种,有些设备是高于某个值高报,低于某个值低报,而有些设备是在最小值最大值范围内是高报,低于最小值低报,高于最大值正常。这样可以分情况处理,涵盖各种报警类型。
    11. 原创数据导入、导出、打印机制,跨平台不依赖任何组件,瞬间导出数据。
    12. 导出到excel的记录支持所有excel、wps等表格文件版本,不依赖excel等软件。
    13. 高报颜色、低报颜色、正常颜色、默认值颜色等,都可以自由设置。
    14. 支持云端数据同步,将本地采集到的数据实时同步到云端。
    15. 支持网络转发和网络接收,网络接收开启后,软件从udp接收数据进行解析。网络转发支持多个目标IP,这样就实现了本地采集的软件,自由将数据转到客户端,随时查看采集到的数据。
    16. 自动记住用户最后停留的界面以及其他配置信息,重启后自动应用。
    17. 报警自动切换到对应的地图,探测器按钮闪烁,表格数据对应颜色显示。
    18. 双击探测器图标,弹出对应探测器详细信息,可以根据需要定制回控操作。
    19. 数据库支持多种,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金仓等。
    20. 本地设备采集到的数据实时上传到云端,以便手机APP或者web等其他方式提取。
    21. 自带设备模拟工具,支持不同型号的多个设备数据模拟,支持串口和网络,同时还带数据库数据模拟,以便在没有设备的时候测试数据。
    22. 标准modbus协议,各种控制器类型、探测器类型、种类、符号等全部自定义,非常灵活和强大,通信协议示例数据非常完整,通用各种modbus协议系统,适用于各种应用场景接入。
    23. 同时集成了串口通信、网络通信、数据库通信、数据导入导出打印、通信协议解析、界面UI、全局换肤等众多组件和知识点,非常适合新手入门和进阶。
    24. 支持xp、win7、win10、、win11、linux、mac、树莓派、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。
    25. 注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。

    0.3 相关站点

    1. 国内站点:https://gitee.com/feiyangqingyun
    2. 国际站点:https://github.com/feiyangqingyun
    3. 个人主页:https://blog.csdn.net/feiyangqingyun
    4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun
    5. 产品主页:https://blog.csdn.net/feiyangqingyun/article/details/97565652
    6. 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/iotsystem/
    7. 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_iotsystem.zip。
    8. 文章导航:https://qtchina.blog.csdn.net/article/details/121330922

    0.4 特别说明

    1. 主界面顶部为一级菜单导航,单击切换页面,软件的左侧为二级菜单导航。
    2. 在左侧菜单中,单击按钮可以切换到对应的页面。
    3. 软件会记住最后停留的页面,下次启动后自动切换。
    4. 发现数据不对或者有误,可以直接在设备调试界面查看具体的通信数据。
    5. 离线状态下双击设备面板或者设备按钮会主动立即重连一次,在线双击弹出详细信息。
    6. 本系统中的控制器相当于主设备,探测器相当于子设备节点。软件采集是和控制器之间通信。
    7. 系统采用纯QtWidget(非qml)编写,所有源码开放,并非有封装的库。
    8. 同时集成了数据库、多线程、串口通信、网络通信、协议解析、界面美化、UI布局等众多知识点。
    9. 未经本人许可不可将本项目源码扩散,如有发现本人将追究法律责任,谢谢配合。
    10. 高分屏缩放设置说明 https://qtchina.blog.csdn.net/article/details/124860909

    0.5 简易操作

    1. 第一步:从顶部一级菜单切换到系统设置,然后左侧二级菜单切换到端口管理。
    2. 第二步:添加好端口信息。
    3. 第三步:切换到控制器管理,添加好控制器信息。
    4. 第四步:切换到探测器管理,添加好探测器信息。
    5. 第五步:如果需要地图,则切换到地图管理,导入地图,默认已经有5张地图。
    6. 第六步:重启软件。

    0.6 版本说明

    V20220625

    1. 报警记录界面增加右键菜单选择全部、取消选中,和之前的批量删除一起。
    2. 测试批量删除sql语句in关键字在所有数据库中的表现,比如sqlite、mysql、postgres、sqlserver等全部测试通过。
    3. 优化报警邮件转发流程,过滤空报警信息只发送报警日志xls文件。
    4. 修复在postgresql数据库和oracle数据库下,QSqlTableModel对应setTable设置表名严格区分大小写的BUG。
    5. 大幅度优化mysql数据库分页查询效率,百万级别以上数据量下测试速度提升500倍+。
    6. 分页查询增加查询用时,每次翻页的查询都有用时计算。

    V20220522

    1. 增加配置参数记录设备模拟工具是否已经通过主程序调用,已经打开了则不用重复打开。
    2. 修正数据库脚本文件,以便支持其他数据库,其他数据库全部测试过一遍。
    3. 增加各种数据库效果图,同步更新文档。
    4. 增加网络转发和云端数据库同步说明及效果图。
    5. 网络转发将分隔符改成字段数据用 , 分隔,行数据用 ; 分隔,最前面标识符用 | 分隔。
    6. 判断模拟工具是否打开算法再次改进,从命令行执行结果查看是否存在该程序。
    7. 所有数据库执行出错打印增加打印错误信息和对应的sql语句。
    8. 修复开启自动行数的时候,如果默认页面停留在其他页面,消息行数计算不准确的BUG。改成了默认采用左侧堆栈控件的高度作为参照标准,因为该控件永远显示,可以拿到正确的高度。
    9. 报警记录表格增加支持多选删除,可以批量删除选中的记录。
    10. 修复报警声音播放的BUG,在Qt5中默认播放首次设置的声音文件成功其余有杂音。
    11. 修复设备按钮报警颜色中低报和高报颜色搞反了的BUG。

    V20220508

    1. 设备地图按钮增加报警颜色选项,低报黄色闪烁,高报红色闪烁,其他报警紫色闪烁,正常绿色。
    2. 修正低分辨率比如1366x768情况下默认配置文件窗体尺寸过大的问题。
    3. 修复设备面板在仪表盘样式情况下文字颜色没有和系统样式统一的BUG。
    4. 将设备面板统一到一个类,多种样式选择,普通样式、仪表样式等。
    5. 说明书中通信协议举例,重新整理,更丰富更完整。
    6. 消息栏改成0表示自动设置行数,100表示设置0行,其他表示选择的行数。
    7. 将面板样式切换直接移到主界面,方便直接切换立即应用。
    8. 删减合并一些冗余的代码。
    9. 修复离线后仪表盘的值没有清零的BUG。
    10. 修复有部分权限页面控制不准的BUG。
    11. 新增自启动设备模拟工具配置参数,可以在系统设置中功能激活启用。
    12. 将模拟工具启动放在主窗体加载完成后,之前的main函数中不妥当,会导致用户还没登录就运行了设备模拟工具。
    13. 探测器节点信息,系统设置新增排序规则,可以按照位号排序,或者种类+位号等方式。
    14. 增加在win以外的其他系统,自动new出来设备模拟工具。
    15. 改进默认地图算法,取第一个有背景地图的设备的图片作为默认图片,可能默认图片不存在则取图片列表中的第一张。

    V20220428

    1. 将项目统一命名为iotsystem,对应设备模拟工具iottool。
    2. 将多个模块提炼成通用模块,比如用户登录退出、数据库设置、用户管理等,这样可以和其他系统完全公用模块。
    3. 统一调整项目模块,统一规划。
    4. 重新截图,重新编写说明书和开发使用手册。
    5. 权限控制增加用户管理、组态设计等,替换之前备用的模块A、模块B。
    6. 将用户管理、组态设计、设备调试等模块移动到其他设置大类,方便管理。
    7. 修复非最大化界面,拖动设备按钮会触发界面移动并且乱跳的BUG。
    8. 修复本地电脑开启网络代理的情况下,网络链接本地IP地址报错提示 The proxy type is invalid for this operation 的BUG。
    9. 模拟工具增加一键复位和一键报警按钮,用于设置没有报警的值和报警的值。
    10. 修复Qt6中报警后重复触发报警声音会崩溃的BUG。
    11. 统一梳理所有数据库字段长度,留有足够的余地。
    12. 修复设备面板在低报高报互相切换状态的时候报警颜色不正确的BUG。

    V20190712

    1. 控制器型号+探测器型号+气体种类+气体符号改成表格存储,新增探测器数量字段。
    2. 当节点数量小于列数时候会宽度变宽的BUG。
    3. 新增阿里云数据库同步,数据库采集模式会将数据库数据实时同步到阿里云。

    V20190624

    1. nodeinfo表新增nodezero字段,用于存储消零值,小于该值则显示为0,大于则显示真实值。
    2. alarmlog表增加confirmuser、confirmtime、confirmcontent三个字段,存储报警记录的确认用户、确认时间、确认内容。
    3. 新增了数据库读取模式,用于数据库采集显示数据。
    4. 修复了Qt5.10版本以上,数据清理线程提示不能运行的BUG。不能在线程中用主线程创建的数据库。
    5. 改进了部分代码。
    6. 模拟器新增数据库模拟。
    7. 配置文件新增模拟器的配置信息。
    8. 修复表格中设置了单独的文字颜色,在选中时会被覆盖的BUG。
    9. 新增报警右下角弹框。可以配置文件更改是否开启以及显示多久,默认开启。
    10. 新增报警记录鼠标右键删除记录,支持多选批量删除。
    11. 设备表格,按照气体种类升序+位号升序排列,以前是按照位号。
    12. 控制器对应的最大探测器数量,已禁用,直接选择好探测器类型自动设置。

    1 用户登录退出

    1.1 用户登录

    +

    系统启动后,首先会弹出用户登录界面,从用户姓名的下拉框选择用户名,然后输入密码(默认用户名密码都是admin),单击登录按钮,密码正确则会进入到系统主界面,错误会弹出提示,错误超过三次自动关闭,需要重新打开软件。

    在登录界面可以勾选是否记住密码,是否自动登录,如果勾选了记住密码,则下次启用软件会自动填入最后用户的密码,勾选了自动登录(以最后的用户信息作为当前登录用户)则启动后直接进入主界面。如果开启了自动登录,不会弹出登录界面,可以在系统设置中关闭自动登录和记住密码。

    1.2 用户退出

    在主界面单击右上角的关闭按钮,会弹出用户退出界面,需要输入密码验证防止误关闭,会自动填入登录的用户名,密码输入正确才会退出软件。用户登录和退出都内置了超级密码a防止管理员忘记密码。

    2 系统设置

    2.1 基本设置

    2.1.1 常规设置

    基本设置中有部分参数的切换会自动重启应用。

    参数说明

    1. 开机运行:开启以后自动随着系统启动运行,默认开启。
    2. 自动登录:开启以后会自动以最后登录的用户信息登录到系统,默认关闭。
    3. 记住密码:开启以后会自动填入最后登录的用户信息到登录窗体,默认关闭。
    4. 中文标题:软件左上角标题栏的中文标题,改动立即应用。
    5. 英文标题:软件左上角标题栏的英文标题,改动立即应用。
    6. 版权所有:当前软件版权所有的公司,显示在软件的底部信息栏中。
    7. 调试日志:开启后会将打印日志输出到日志文件,默认关闭,日志文件存放在可执行文件夹下的log目录下。
    8. 运行时间:开启后会实时记录系统的运行时间,记录当前软件启动后运行了多久,运行时间文件存放在可执行文件夹下的log目录下。
    9. 工作模式:默认设备采集,可选数据库采集、数据库读取、设备采集2等,一般都是特殊定制需求的在这里切换工作模式。
    10. 导航样式:用于选择顶部导航栏和左侧导航栏的样式,上侧+左侧表示顶部导航栏上侧样式(图标在上面,文字在下面),左侧导航栏左侧样式(图标在左侧,文字在右侧)。
    11. 界面样式:系统自带17套皮肤,可以在这里自动换肤,默认视频黑。
    12. 软件图标:自动从logo文件夹读取,可以自行选择对应的logo文件。
    13. 报警声音:开启后当探测器报警后,会播放报警声音,默认开启。
    14. 播放次数:播放报警声音的次数,默认1次。
    15. 警情行数:主界面运行监测左侧显示报警信息的最大行数。新警情自动追加在最前面。0表示自动根据尺寸填充,100表示禁用。
    16. 自动确认:开启后自动确认警情存入报警记录,默认开启。
    17. 设备列数:设备监控主界面设备面板的列数。
    18. 记录行数:在数据查询的表格中,显示的记录的行数。

    工作模式

    1. 设备采集:本地直接采集网络和串口过来的数据,每个数据位2字节表示一个含义。
    2. 数据库采集:定时器读取数据库表NodeData,具体字段含义见数据库表说明。
    3. 数据库采集2:和数据库采集逻辑一样,就是具体的报警标志位含义不一样。
    4. 设备采集2:用户定制的一套解析协议,和上面设备采集的区别是收发协议两样,带有电源、报警标志位,每个探测器4寄存器=8字节。
    • 设备采集模式 nodeStatus 0-低报 1-低报恢复 2-高报 3-高报恢复 5-其他报警 6-其他报警恢复
    • 数据库采集模式 nodeStatus 0-离线 1-在线 2-低报 3-高报
    • 数据库采集2模式 nodeStatus 0-离线 1-正常 2-报警 3-高报 4-失效
    • 设备采集2模式 nodeStatus 0-预热中 1-工作中 2-低限报警 3-高限报警 4-传感器故障 7-探测器离线

    2.1.2 本地数据库设置

    参数说明

    1. 远程同步:开启后将会启用云端数据同步功能,将本地数据实时同步到远程数据库中。
    2. 主机类型:和本地数据库设置一样,可选多种。
    3. 数据库名:对应数据库的数据库名称,一个数据库系统中可以有多个数据库实例。
    4. 主机地址:数据库所在的网络地址,可以是IP地址或者网址。
    5. 通信端口:数据库开放通信的端口,不同数据库默认端口不同,比如mysql是3306,postgres是5432,sqlserver是1433。
    6. 用户名称:登录到网络数据库对应的用户名称,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    7. 用户密码:登录到网络数据库对应的用户密码,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    8. 连接测试:单击后主动连接一次当前填入的数据库信息,连接成功与失败都会弹框提示。
    9. 初始数据:单击后会执行sql脚本文件,重置数据库,会将原来的数据一并清空。务必记得只有需要的时候才执行。

    其他说明

    1. 默认提供了数据库脚本文件(拓展名sql结尾的文件)。
    2. 单击初始化数据按钮可以对整个数据库进行新建和重置,相当于恢复出厂。
    3. 系统支持多种数据库,默认sqlite(Qt内置的数据库,无需安装),可选mysql、postgresql、oracle、人大金仓等。
    4. 具体还需要对应Qt版本有数据库插件支持,没有插件支持可以自行编译对应缺失的插件比如mysql,也可选直接通过万能的ODBC来连接。
    5. 除了sqlite数据库外,其余数据库都需要输入数据库名称、主机地址、通信端口、用户名称、用户密码信息,输入好以后可以单击连接测试按钮测试下是否正常。
    6. 默认提供的是mysql的动态库libmysql.dll,需要放到可执行文件同一目录,严格区分32位和64位的动态库。

    2.1.3 云端数据库同步

    参数说明

    1. 远程同步:开启后将会启用云端数据同步功能,将本地数据实时同步到远程数据库中。
    2. 主机类型:和本地数据库设置一样,可选多种。
    3. 数据库名:对应数据库的数据库名称,一个数据库系统中可以有多个数据库实例。
    4. 主机地址:数据库所在的网络地址,可以是IP地址或者网址。
    5. 通信端口:数据库开放通信的端口,不同数据库默认端口不同,比如mysql是3306,postgres是5432,sqlserver是1433。
    6. 用户名称:登录到网络数据库对应的用户名称,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    7. 用户密码:登录到网络数据库对应的用户密码,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    8. 连接测试:单击后主动连接一次当前填入的数据库信息,连接成功与失败都会弹框提示。
    9. 初始数据:单击后会执行sql脚本文件,重置数据库,会将原来的数据一并清空。务必记得只有需要的时候才执行。

    2.1.4 日志设置

    参数说明

    1. 报警记录:报警记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。
    2. 运行记录:运行记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。
    3. 操作记录:操作记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。
    4. 记录排序:在报警记录查询界面中,按照何种方式排序,默认按照时间降序,相当于最新的记录在最前面。
    5. 报警弹框:报警触发后在右下角弹框信息停留时间,0秒表示一直停留直到手动关闭,10000秒表示不弹出。
    6. 小数点位:设备采集到的数据,最后按照几位小数点显示。

    2.1.5 网络转发设置

    网络转发的功能,是用来将本地的采集的所有设备的数据,通过UDP协议转发到指定的IP和端口,对方只要开启网络接收即可查看到设备的实时运行数据。网络转发和网络接收不能同时开启,本地负责采集的软件开启网络转发,远程需要查看数据的电脑开启网络接收,转发的端口和接收的端口必须保持一致,支持多个IP,中间用英文的分号 ; 隔开。单击同步数据的按钮会将本地的端口+设备+节点信息传送到接收端,不需要手动设置。这样就保证了本地的信息和远程的信息完全一致。远程的IP必须保证可达,比如ping的通。

    参数说明

    1. 网络转发:开启后会将本地的数据通过udp协议发到指定的网络地址和端口。
    2. IP及端口:网络转发要去达的网络地址和端口,用英文冒号 : 隔开。
    3. 网络接收:开启后将采用接收端形式运行,接收转发过来的设备数据作为采集源。
    4. 接收端口:网络接收端口。
    5. 同步数据:开启网络转发后,单击该按钮,会将本地的端口信息、控制器信息、探测器信息发送到远端,这样远端接收到数据后不用手动添加。

    2.1.6 告警短信转发

    当探测器发生报警后,如果开启了短信告警,会将报警信息以短信的形式发送到预先设定的接收者的手机号码上,短信内容格式为:位号: AT400001 控制器: 控制器A 探测器: 探测器A 触发值: 70.8 PPM 类型: 浓度上限报警 时间: 2019-01-05 12:12:12。需要本地发短信的硬件支持。

    参数说明

    1. 串口名称:短信猫设备接入的串口号。
    2. 波 特 率:短信猫设备通信所使用的波特率。
    3. 接收号码:接收者的手机号码,可以填写多个,中间用英文的分号 ; 隔开。
    4. 发送间隔:短信发送的间隔,默认10000表示不开启,0表示实时发送。
    5. 测试短信:单击该按钮会立即发送一条测试短信到接收者手机用于测试功能是否正常。

    2.1.7 告警邮件转发

    当探测器发生报警后,如果开启了邮件转发告警,会将报警信息以邮件的形式发送到预先设定的接收者的邮箱中,邮件内容格式为:位号: AT400001 控制器: 控制器A 探测器: 探测器A 触发值: 70.8 PPM 类型: 浓度上限报警 时间: 2019-01-05 12:12:12。后期会将警情统计的报表数据以excel表格的形式发送到接收者邮箱。如果发现邮箱登录失败等,请先在邮箱后台设置开启smtp和pop3。

    参数说明

    1. 发件邮箱:发件人的邮箱地址,必须保证该邮箱开启过POP3。
    2. 发件密码:发件人的邮箱的密码,会以加密的形式存储在配置文件。
    3. 接收邮箱:接收者的邮箱地址,支持多个,用英文的分号 ; 隔开。
    4. 发送间隔:邮件发送的间隔,默认10000表示不开启,0表示实时发送。
    5. 测试邮件:单击该按钮会立即发送一条测试邮件到接收者邮箱用于测试功能是否正常。

    2.1.8 系统时间设置

    用来设置本地电脑的系统时间,为什么需要这个设置,因为软件很可能在嵌入式linux上运行,需要手动设置时间。

    2.1.9 功能激活

    参数说明

    1. 表格联动:开启后在数据监控的表格中会自动实时显示采集的设备数据。
    2. 面板联动:开启后在设备面板对应的设备会自动显示采集的设备数据。
    3. 按钮联动:开启后在地图监控上对应的按钮会自动显示采集的设备数据。
    4. 设备地图:开启后会显示设备地图模块,默认关闭,大部分场景用不上,只需要表格展示数据,最高效。

    2.1.10 颜色设置

    参数说明

    1. 离线颜色:探测器离线后对应文字显示的颜色。
    2. 高报颜色:探测器发生上限报警(高报)后对应文字显示的颜色。
    3. 低报颜色:探测器发生下限报警(低报)后对应文字显示的颜色。
    4. 正常颜色:探测器运行正常时对应文字显示的颜色。
    5. 曲线背景:探测器实时曲线界面背景颜色。
    6. 曲线文字:探测器实时曲线界面文字颜色。
    7. 曲线颜色:探测器实时曲线界面曲线的颜色。
    8. 待定颜色:目前备用的颜色。

    2.2 端口管理

    本系统支持串口接入和网络接入两种方式,对应的端口需要提前设置,后期可能还会新增mqtt等方式,选择不同的协议类型即可。

    字段说明

    1. 端口编号:端口的编号,从1开始。
    2. 端口名称:端口的别名,方便记忆。
    3. 协议类型:默认Modbus_Com为串口通信,TCP通信选择Modbus_Tcp_Rtu。
    4. 串 口 号:如果用的是串口通信,这里填入串口号即可。
    5. 波 特 率:串口通信使用的波特率。
    6. IP 地 址:设备的IP地址。
    7. 通讯端口:该设备网络通信所使用的端口,默认502,即modbus通信的端口。
    8. 采集周期:该通讯处理中对每个控制器轮询的间隔时间。单位秒,如果要0.2s=200毫秒则填0.2即可,默认浮点数处理。
    9. 通讯超时:该通讯处理中大于几次未收到回应消息则判断为离线,默认3次。
    10. 重连时间:如果某个设备离线状态,最大多长时间重新读取一次,默认60秒。

    2.2.1 端口添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.2.2 端口删除

    如果要删除某个端口信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.2.3 端口清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.2.4 端口信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.2.5 端口信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.2.6 端口信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.2.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.3 控制器管理

    字段说明

    1. 控制器编号:控制器的编号,从1开始。
    2. 通 讯 端口:通讯所采用的通讯端口名称,和端口管理中的端口名称一致。
    3. 控制器名称:控制器的别名,以便记忆。
    4. 控制器地址:控制器的地址,最大255。
    5. 控制器型号:控制器的型号,不一样的控制器可能通信的协议不一致。
    6. 探测器数量:该控制器下面挂载的探测器的数量,必须和真实安装的数量完全一致。

    2.3.1 控制器添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.3.2 控制器删除

    如果要删除某个控制器信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.3.3 控制器清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.3.4 控制器信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.3.5 控制器信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.3.6 控制器信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.3.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.4 探测器管理

    字段说明

    1. 编 号:节点的编号,从1开始。
    2. 位 号:探测器的位置编号,用于唯一标识一个探测器。
    3. 控 制 器:对应挂载的主设备名称。
    4. 探 测 器:探测器的名称,方便记忆,可以填写地理位置。
    5. 地 址:探测器对应在控制器的编号索引。
    6. 型 号:探测器的型号,从下拉框选择。
    7. 气体种类:探测器对应采集的气体的种类。
    8. 气体型号:探测器对应采集气体的型号。
    9. 上 限 值:报警的上限值。
    10. 下 限 值:报警的下限值
    11. 最 大 值:最大的警戒值,超过该值则显示为该值。
    12. 消 零:最小的警戒值,小于该值则显示0,大于显示真实值。
    13. 量 程:假设量程0.25则 实际数=模拟量/4000x量程 模拟量就是采集的值。
    14. 状 态:默认启用,当某个探测器未接时候可以选择禁用。
    15. 声 音:报警后对应的声音文件。
    16. 地 图:探测器所位于的地图文件。
    17. 存 储:探测器记录存储的周期,单位分钟。即隔多久存储一次记录到本地。
    18. 小 数 点:计算解析数据的数据位对应的小数点位数。
    19. 报警延时:报警后,延时多久处理,以便过滤数据抖动偏差造成的误报。默认0。
    20. 报警类型:HH LL HL。
    21. X坐 标:探测器位于地图上的X坐标。
    22. Y坐 标:探测器位于地图上的Y坐标。

    报警类型

    • 根据设定的不同的报警类型处理,假定上限值100,下限值25。
    • HH表示超过25是低报,超过100是高报,低于25正常。
    • HL表示低于25是低报,超过100是高报,25到100之间正常。
    • LL表示低于25是高报,低于100是低报,大于100正常。

    2.4.1 探测器添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.4.2 探测器删除

    如果要删除某个探测器信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.4.3 探测器清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.4.4 探测器信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.4.5 探测器信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.4.6 探测器信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.4.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.5 报警联动

    在报警联动设置中,可以设置每个位号报警后,对应的继电器联动,支持探测器串口和新独立的串口(如果是和探测器并用的串口则不会重新打开串口,直接用原有的串口发数据联动,如果是新的串口则会重新打开串口),模块地址为继电器板子的地址,联动地址集合为需要联动报警的位,支持多个,多对多关系,一个探测器报警可以联动多个联动模块上的多个继电器地址,中间丨杠隔开。

    字段说明

    1. 位置编号:下拉选择,从探测器信息表取,表示哪个位置的探测器报警。
    2. 串 口 号:串口号,可以是之前端口信息中的串口,会自动检测切换。
    3. 波 特 率:报警端口转发串口对应的波特率,默认9600。
    4. 模块地址:对应联动模块的地址,挂在总线上的联动模块的唯一地址,该模块专门用来做继电器联动。
    5. 联动地址:联动模块上有一排继电器地址,对应报警后,可以触发联动一个或者多个继电器,需要哪个地址就填哪些地址。
    6. 启 用:可以动态关闭不需要的联动信息,但是不删除,这样只需要这里取消启用即可,而不是删除,不然又要重新添加。

    2.5.1 联动添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.5.2 联动删除

    如果要删除某个联动信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.5.3 联动清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.5.4 联动信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.5.5 联动信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.5.6 联动信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.5.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.6 类型设置

    参数说明

    • 本表格中的数据并不是严格的对应关系。
    • 其中控制器信号、探测器数量是一对,其余全部独立。
    • 用来在系统设置中对应下拉框中的信息。
    • 这样就非常灵活,用户后期增加了新的产品直接在这里添加好就行,其他地方都是自动下拉选择。

    2.6.1 类型添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.6.2 类型删除

    如果要删除某个类型信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.6.3 类型清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.6.4 类型信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.6.5 类型信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.6.6 类型信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.6.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    3 其他设置

    3.1 用户管理

    用户管理是后面增加的一个模块,用于设置不同的用户不同的类型+权限,可以细分到每个模块的权限,勾选表示具有该权限,内置了7种权限选择,后期还可以在此基础上增加其他权限等。

    3.1.1 用户添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    3.1.2 用户删除

    如果要删除某个用户信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。不允许删除内置的admin用户。

    3.1.3 用户清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    3.1.4 用户信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    3.1.5 用户信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。

    3.1.6 用户信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    3.1.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    3.1.8 权限验证

    +

    假设设置了用户没有系统设置和删除记录的权限,则关闭系统的时候会弹出错误信息提示当前用户没有权限。

    3.2 地图管理

    在地图管理中,可以导入和删除地图。

    3.3 位置调整

    位置调整中,可以拖动探测器到正确的位置,右侧单击地图切换可以看到对应的该地图对应的探测器,全部位置调整好之后,单击右下角保存按钮即可,会立即应用。

    3.4 组态设计

    组态设计模块中提供的是简单的示例,演示如何加载自定义控件动态库、将控件拖曳到背景地图上,配置好对应控件的属性,可定义用户属性,可导出控件的配置信息到xml文件,并支持导入xml文件自动加载上次保存的控件配置信息。目前是一个简单的组态雏形,等后期架构好如何应用再重写整个模块。

    本系统默认不包括里面控件的源码,提供动态库的形式使用,如果还想学习自定义控件大全的源码(目前共202个控件卖700元),需要额外单独购买。

    3.5 设备调试

    可以自行选择通讯端口+设备名称进行数据的过滤,可查看所有的通信数据。不同收发数据不同颜色,还可以指定关键字过滤数据,每个收发数据都有对应的中文解释。能够很方便的对运行中的系统查看设备数据,规避是下位机还是上位机问题扯皮的事情。

    4 设备监控

    设备监控界面主要包括4个模块,分别是数据监控、设备面板、地图监控、曲线监控,设备的实时数据可以同时反应到四个模块上面,相当于以4种不同的表现形式展现采集到的数据。

    模式说明

    • 数据监控:表格形式一行行展示数据。
    • 设备面板:每个探测器都是个独立的一个面板展示数据和信息。
    • 地图监控:设备按钮放在对应地图上,长条状显示数据和符号单位。
    • 曲线监控:对每个设备过滤曲线显示采集到的数据。
    • 设备报警后,如果设置了报警弹窗,则右下角都会弹出对应的报警信息。
    • 设备报警后,对应表格行、设备面板、地图按钮等都会突出颜色显示。

    4.1 数据监控

    本页面会是使用频率最高的页面,默认就是停留在本页面实时查看所有探测器的数据。左侧为警情信息栏,分别显示时间、位号、报警值。如果有探测器报警,则消息自动追加到最前面。 +表格依次显示序号、位号、控制器名称、控制器型号、探测器名称、探测器型号、气体种类、浓度值、气体符号。

    4.2 设备面板

    面板说明

    1. 探测器作为一个个独立的设备面板控件。
    2. 有多少个探测器就会生成多少个面板,放在面板容器中。
    3. 可以在系统设置中选择设备列数,按照该设备列数来排列,超过会自动产生滚动条拖动查看。
    4. 报警后整个设备面板会突出颜色显示比如高报是红色、低报是黄色等。
    5. 双击探测器面板,会跳转到该探测器的详细信息界面,在该界面上后期可以按照实际用户需求定制回控操作。
    6. 面板有多种样式可供选择,比如普通样式、仪表样式。可直接在右侧切换立即运用。

    4.2.1 普通样式

    4.2.2 仪表样式

    4.2.3 仪表样式2

    4.3 地图监控

    本页面以地图的形式显示所有探测器,右侧单击对应地图可以手动切换地图,当探测器报警后会自动切换到当前地图,探测器图标红色闪烁,探测器图标实时显示当前的浓度值。双击探测器按钮图标,会跳转到该探测器的详细信息界面,在该界面上后期可以按照实际用户需求定制回控操作。

    4.4 曲线监控

    在本页面可以查看某个探测器的实时曲线,第一步先选择通信端口,第二步选择控制器,第三步选择探测器,然后就可以在左侧看到实时曲线,颜色可以在系统设置中设置。单击打印按钮会将当前曲线以截图的形式打印出来。勾选暂停显示记录数据复选框会暂停显示当前的数据。

    4.4.1 实时曲线

    4.4.2 历史曲线

    5 数据查询

    5.1 报警记录

    在本页面,可以指定日期范围查询报警记录,还可以查询单个的控制器或者探测器的报警记录。也可以手动输入探测器的位号进行查询,下拉选择探测器后会自动填入位号。还可以选择报警类型(浓度上限报警、浓度下限报警)查询对应的类型,也可以输入报警值进行精准查询。

    如果数据超过一页,会自动分页处理,单击右侧的上一页、下一页、第一页、末一页进行翻页查看,所有查询的数据可以导出到excel表格,也可以直接打印。单击删除按钮会弹出时间范围选择框,选择该时间段后确定,会删除该时间段的所有记录。

    双击对应的报警记录可以打开警情确认对话框,重新填写确认意见,鼠标右键弹出删除记录菜单,可以删除当前选中的记录,支持多选,例如按住Ctrl键选择多个记录。

    5.1.1 记录查询

    5.1.2 记录打印

    5.1.3 记录导出

    +

    5.2 运行记录

    在本页面,可以指定日期范围查询运行记录,还可以查询单个的控制器或者探测器的运行记录。也可以手动输入探测器的位号进行查询,下拉选择探测器后会自动填入位号。

    如果数据超过一页,会自动分页处理,单击右侧的上一页、下一页、第一页、末一页进行翻页查看,所有查询的数据可以导出到excel表格,也可以直接打印。单击删除按钮会弹出时间范围选择框,选择该时间段后确定,会删除该时间段的所有记录。

    5.2.1 记录查询

    5.2.2 记录打印

    5.2.3 记录导出

    +

    5.3 操作记录

    所有的用户操作都会记录到系统数据库,包括清空报警记录、删除记录、清空报警信息等操作。可以在本界面选择时间段范围查询,也可以选择日志类型(用户操作、设备上报)进行查询。

    如果数据超过一页,会自动分页处理,单击右侧的上一页、下一页、第一页、末一页进行翻页查看,所有查询的数据可以导出到excel表格,也可以直接打印。单击删除按钮会弹出时间范围选择框,选择该时间段后确定,会删除该时间段的所有记录。

    5.3.1 记录查询

    5.3.2 记录打印

    5.3.3 记录导出

    +

    6 通信协议

    6.1 通信流程

    1. 整体的结构是:控制器挂在通信端口,一个控制器下有多个探测器节点,相当于主设备、子设备。
    2. 因为是需要遍历轮询,所以一个通信端口上的控制器地址不能重复。
    3. 不同通信端口,控制器地址可以重复,所以如果控制器数量较多可以分在不同的通信端口。
    4. 一个控制器可以挂多个探测器,控制器平时也在不断轮询探测器的数据并记录,等待上位机程序的轮询命令后,将探测器数据一起打包发回。
    5. 本软件只和控制器通信,不和探测器通信,控制器负责和探测器通信。为何这样设计?因为这种架构最通用,可接的设备数量也是最大的。
    6. 本系统默认按照标准modbus协议进行通信,modbus是标准的通信框架协议,支持串口和网络等通信方式,至于具体是通过串口还是网络通信根据设备厂家选择。
    7. modbus是通信协议框架,至于具体数据位的每个字节对应的数据含义,每个厂家不一样,都是厂家自定义,一般2个字节表示一个数据。
    8. 端口可以是串口和网络,在添加端口时候可选择不同通信解析协议。

    6.1.1 FC1003-1

    6.1.2 FC1003-8

    6.1.3 FC1003-16

    6.1.4 FC1103显示板

    6.1.5 SAMS-4128

    6.1.6 FT21047P

    6.2 协议解释

    1. 主机发送是软件发送数据给设备,主动发送。
    2. 从机应答是设备根据收到的数据后作出应答数据,被动回复。
    3. 一条发送命令会对应一条应答命令。
    4. 寄存器地址2字节,高位在前低位在后。
    5. 读取长度2字节,高位在前低位在后。
    6. 数据位2字节,高位在前低位在后。
    7. CRC校验2字节,低位在前高位在后。
    8. 功能码有 03(读只读寄存器)、04(读可读可写寄存器)、06(写读写寄存器)。
    9. 主机发送的功能码和从机应答的功能码相同。

    6.2.1 主机发送

    地址功能码寄存器地址寄存器个数CRC校验
    010300 0000 0444 09

    6.2.2 从机应答

    地址功能码长度数据位1数据位2数据位3数据位4CRC校验
    01030800 0000 0000 0000 0095 D7

    6.2.3 读取长度

    设备型号长度说明
    FC1003-101 
    FC1003-808 
    FC1003-1608 08相当与两台FC1003-8,设备地址不同。
    FC1003显示板40长度根据所接设备数量不同需要调整,最大为64个。
    FC1003底板04 
    FT2104P01 
    SAMS-412808 

    6.2.4 数据举例

    提示说明

    1. 以下举例数据CRC校验位统一用 XX XX 表示,懒得计算。
    2. 本系统中填写的地址都是从1开始计数,所以填1则表示从0开始读取。
    3. 如果寄存器地址 01 01 ,则0101=257,本系统中要填258,填258实际是-1=257=0101发送。
    4. 寄存器个数,也可以说是节点设备的数量。
    5. 一个数据位或者说一个节点的数据是2个字节数据。
    6. 读取长度1则会返回1个数据位共2字节数据。
    7. 读取长度2则会返回2个数据位共4字节数据。
    8. 读取长度3则会返回3个数据位共6字节数据。

    示例数据1

    • 发送:01 03 00 00 00 02 XX XX
    • 解释:从寄存器地址0(00 00 = 0)开始,读取2个寄存器。
    • 返回:01 03 04 42 C7 FF EA XX XX
    • 解释:返回4字节数据 42 C7 FF EA ,对应寄存器地址 0、1 的数据。
    • 配置:控制器地址1,探测器地址1、2。

    示例数据2

    • 发送:01 03 01 01 00 01 XX XX
    • 解释:从寄存器地址257(01 01 = 257)开始,读取1个寄存器。
    • 返回:01 03 02 02 EF XX XX
    • 解释:返回2字节数据 02 EF ,对应寄存器地址257的数据。
    • 配置:控制器地址1,探测器地址258。

    示例数据3

    • 发送:AA 03 AA BB 00 04 XX XX
    • 解释:从寄存器地址43707(AA BB = 43707)开始,读取4个寄存器。
    • 返回:AA 03 08 55 AC 23 65 84 77 C3 3F XX XX
    • 解释:返回8字节数据 55 AC 23 65 84 77 C3 3F ,对应寄存器地址43707、43708、43709、43710的数据。
    • 配置:控制器地址170(AA = 170),探测器地址43708、43709、43710、43711。

    6.2.5 继电器联动

    发送返回说明
    01 03 00 00 00 01 84 0A01 03 02 00 00 B8 44读取设备状态
    01 06 00 00 00 01 48 0A01 06 00 00 00 01 48 0A打开继电器1
    01 06 00 00 00 03 C9 CB01 06 00 00 00 03 C9 CB打开继电器1、2
    01 06 00 00 00 07 C8 0801 06 00 00 00 07 C8 08打开继电器1、2、3
    01 06 00 00 00 06 09 C801 06 00 00 00 06 09 C8关闭继电器1
    01 06 00 00 00 04 88 0901 06 00 00 00 04 88 09关闭继电器1、2
    01 06 00 00 00 00 89 CA01 06 00 00 00 00 89 CA关闭继电器1、2、3

    7 各系统运行图

    7.0 样式风格

    + + + + +

    7.1 windows-mingw

    7.2 windows-msvc

    7.3 linux-ubuntu

    7.4 linux-uos

    7.5 linux-kylin

    7.6 linux-neokylin

    7.7 linux-centos

    7.8 linux-fedora

    7.9 unix-mac

    8 程序框架说明

    • 下面的截图和说明未必是最新的,但是大部分是一致的。
    • 整体的框架不会改变,可能会有新增加子模块和代码,具体以最新的代码为准。
    • 程序会一直更新完善,不断迭代中。

    8.1 整体代码结构

    本系统采用模块化的设备,有用到第三方开源类库比如串口通信qextserialport,全部放在3rd下面,有用到很多自己封装完善的通用类库比如数据导入导出组件,全部放在core下面,设备通信和辅助处理全部放在class下面,所有界面全部放在ui下面,相当于一个个小的组件合起来,最终形成了整个监控系统的完整代码。

    8.2 主模块说明

    名称说明
    3rd一些第三方开源的类库,比如串口通信qextserialport。
    class存放系统初始化、样式控制、自定义控件、设备通信等。
    core本人一直持续更新完善的通用的类库,比如数据导入导出组件。
    ui所有的界面都分门别类放在这里。

    8.3 子模块说明

    8.3.1 第三方类库

    这里放的全部是第三方开源的轮子,感谢开源、感谢github、gitee等开源社区。具体代码不做过多说明,网上会有很多介绍和使用说明。

    名称说明
    3rd_qcustomplot第三方精美图表控件qcustomplot,Qt自带的qchart功能有限而且不支持大量数据。
    3rd_qextserialport第三方串口通信qextserialport,这个类比较稳定可靠,经过了几十个项目持续数十年运行的考验,不用Qt自带的串口类。
    3rd_qtpropertybrowser第三方属性控件,指定控件自动读取对应的属性形成属性栏。
    3rd_smtpclient第三方发送邮件组件,走底层socket协议发送邮件。

    8.3.2 通信及辅助类

    这里放的都是一些系统初始化、设备通信相关的类。

    名称说明
    api存放数据库表映射成对应的全局队列数据、数据库查询类,告警短信转发及告警邮件转发类。
    app全局配置参数管理类、全局变量类、全局事件转发器,通用函数等。
    device设备通信管理,比如设备采集处理、数据库采集、报警联动等。
    usercontrol当前系统的用到的自定义控件全部放在这里,项目通用的自定义控件放在core_control中。
    8.3.2.1 模块-api

    名称说明
    dbdata将数据库表映射到全局变量数据队列,比如将端口信息表portinfo转成QStringList存放一行行数据,这样在程序中运算比较速度极快,直接内存比较,不用每次都去读取数据库。
    dbquery所有的数据库查询插入更新等操作都在这里,比如查询探测器信息表、控制器信息表、插入日志记录等。
    sendserver通用的发送短信和邮件管理类,因为发送的内容是一致的所有统一一个类来管理,调用同一个函数就行。
    8.3.2.2 模块-app

    名称说明
    appconfig配置参数类,整个系统的配置参数存放在ini文件中,跨平台,所有参数都对应一个变量,读取配置参数的时候将值赋值给变量,写入的时候将变量值写入到配置文件。
    appdata全局变量类,系统中无可避免需要一些全局变量方便处理,都放在此类,比如版本号、当前用户信息、地图宽度高度、左侧右侧顶部底部宽高等。
    appevent全局事件转发类,系统越复杂信号需要传递的层级越多,所以需要一个全局事件转发类,用来中转这些事件,这样永远只需要两层就可以收到信号进行处理,而且整个系统看起来干净整洁,不会说一个信号传递到了N个地方乱七八糟,建议需要跨层级传递的信号都放在这里中转。比如软件退出信号,可能多个界面需要收到退出信号进行保存和其他处理,如果从关闭界面发出信号传递给需要的界面,那不知道要中间层层传递多少次,有了这个全局事件转发类,你只需要将事件传给appevent,需要接收事件的地方关联这个信号就行,appevent为全局单例类,整个系统唯一。 通用的一些信号有软件退出、全局样式改变、主窗体变化(0-最小化 1-最大化 2-恢复 3-关闭 4-移动 5-尺寸变化)等。
    appinit程序初始化类,在main函数中,会先执行这个初始化的类,比如初始化皮肤、字体、数据库、样式等操作,这些都是要优先在窗体加载前执行的,执行完毕以后再打开窗体主界面。
    appstyle全局样式管理类,整个系统的样式全部放在这里,一般加载流程是先读取样式表文件,然后将本系统独特的样式(比如开关按钮、视频监控、云台仪表盘)内容追加到后面,最后统一设置全局样式,在main函数中加载,和appinit类一样放在最前面执行。
    8.3.2.3 模块-device

    名称说明
    alarmlink报警联动处理类,探测器报警后,根据联动设置中设置的规则,将发送联动指令到总线上的设备。
    dbreceive数据库采集类,通过数据库采集的方式来读取设备的状态和值,系统默认是设备采集,通过485总线modbus协议等去轮询设备的状态,为了拓展兼容性,还有一种场景是用户自己有自己的采集和算法,然后将结果存储到了数据库表中,需要用UI界面将数据库中的值展现出来。
    deviceclient设备采集类,本系统的核心,所有的通信解析都在此类中,因为数据内容格式一致,所以串口和网络通信收发都放在一起,这样解析起来完全一致。
    devicedata获取采集发送指令类,为了应对不同的场景,针对不同的工作模式,会有发送不同的采集指令。
    devicehelper整个系统设备管理辅助类,比如插入窗口消息、加载设备列表、加载图片地图、加载设备按钮等。
    devicemap设备图片地图管理类,相当于一次性加载所有图片到内存,当要切换或者显示的时候,直接从内存取出来设置即可,速度极快,瞬间相应,纯粹是为了加快相应速度以及可能在图片上进行绘制增加的功能,比从文件系统读取图片文件显示快N倍。
    deviceserver设备通信服务类,对应上面的deviceclient类,这里面负责从数据库查询有多少个端口和设备,实例化对应的client,关联信号进行统一的处理,同时还包括定时器处理记录的存储,定时器处理报警等。
    udpreceive数据转发UDP接收端,接收到转发的数据以后解析并反映到界面上。
    udpsend数据转发UDP发送端,负责将采集到的数据转发出去。
    8.3.2.4 模块-usercontrol

    名称说明
    gaugecar汽车仪表盘,用来指示气体的值。
    gaugespeed速度仪表盘,用来指示气体的值。
    selectwidget描点跟随窗体控件,用在属性设计过程中拖曳控件,然后拉伸拖动。

    8.3.3 核心通用类库

    这里放的全部是个人一直持续更新完善的独创的轮子,所有的项目都公用这些轮子,用到哪个就包含哪个进来,更新只需要更新轮子代码就行。

    名称说明
    core_common通用函数,包括通用秘钥、通用导航、通用样式、声音播放、日志记录、运行时间记录等。
    core_control通用自定义控件,很多系统经常用到的控件全部放在这里,比如开关按钮、设备容器、设备按钮、颜色下拉框等。
    core_customplot继承自qcustomplot类的自定义图表组件,同时兼容各种qcustomplot版本,这样就可以在任意的Qt版本使用图表控件。
    core_dataout数据导入导出到xls/pdf和打印类库,极速、跨平台、无依赖。
    core_db数据库通用类库比如数据库线程管理、数据清理、数据采集等。
    core_form通用的窗体相关的组件,包括用户登录、用户退出、用户管理、权限管理、数据库管理,同时还包括封装的项目上直接用的导入导出、打印等。
    core_qui通用的辅助类,包括自定义对话框,全局辅助函数,图形字体等。
    core_send多线程短信发送和邮件发送类,功能类似所有放在一起。
    8.3.3.1 模块-core_common

    名称说明
    base64helper图片及文字和base64编码之间转换的类。
    commonkey通用秘钥管理类,指定校验秘钥文件,可设置运行时间、设备数量等限制,支持根据硬件指纹特征生成机器码文件等。
    commonnav通用菜单导航管理类,用来控制和显示顶部导航栏、左侧导航栏的样式。很多子界面需要用到,所以封装成一个专门管理这个的类。
    commonstyle通用样式管理类,比如Qt自带类窗体样式、自定义控件样式、分页导航样式、导航按钮样式、开关按钮样式等。相当于将多个项目常用的自定义样式封装一起做成通用。
    framelesswidget2无边框窗体拉伸类,边框四周八个方位都可以自由拉伸,可设置是否允许拖动和拉伸。
    playwav声音文件播放类,通用Qt456,自动识别当前Qt版本使用对应的类,Qt4采用QSound,Qt5以上采用QSoundEffect,嵌入式采用对应的命令行aplay、mpv来播放。
    savelog日志钩子类,将系统中所有的打印信息转为日志存储或者输出到网络等,可以开启用来打印输出日志信息。
    saveruntime保存运行时间类,用来存储系统启动后每隔一段时间就输出一条记录用来记录启动后软件运行了多久,方便分析问题。
    8.3.3.2 模块-core_control

    名称说明
    bottomwidget通用底部状态栏控件,可以设置软件名称、版本号、运行时间等。
    colorcombobox颜色下拉框控件,在系统设置中有。
    cpumemorylabelCPU和内存使用情况标签控件,主界面右上角显示。
    customtitlebar停靠窗体自定义标题栏控件。
    devicebutton设备按钮控件,比如图片地图模块中用到,可设置不同的图标样式和状态等,双击发出信号进行相应处理比如弹出对应窗体等。
    lcddatetime软件右上角显示时间的控件。
    panelwidget面板容器控件,主界面子模块表格消息,就用到此控件,用于将一堆widget放到此容器进行管理,自动形成滚动条等。
    switchbutton开关按钮控件,在系统设置中存在大量该控件。
    xslider滑动条控件,在原有滑动条基础上增加了鼠标按下立即定位等。
    8.3.3.3 模块-core_customplot

    名称说明
    customplot自定义图表控件主类,使用的时候只要new这个类就行。
    customplotbarh自定义形状-横向柱状图。
    customplotbarv自定义形状-垂直柱状图。
    customplothead当前组件通用头文件。
    customplothelper当前组件通用辅助函数文件。
    customplotline自定义形状-平滑曲线图。
    customplottracer自定义图层绘制十字线,也叫游标,定位线。
    smoothcurve平滑曲线算法类,内置多种平滑算法,可以自行增加其他算法。
    8.3.3.4 模块-core_dataout

    名称说明
    datacreat通用数据报表内容创建类,比如生成表格格式的html内容,然后赋值给dataprint直接打印,里面举例了图文混排的报告内容,后期会不断增加其他模板,也可以自行增加其他模板数据。
    datacsv导入导出数据,csv格式,可设置分隔符。拓展名。过滤条件等。
    datahead当前组件通用头文件。
    datahelper辅助类,比如校验规则函数,通用数据导出+打印函数。
    dataprint数据打印到pdf及纸张,支持多线程。
    dataxls数据导出到xls类,支持多线程导出。
    8.3.3.5 模块-core_db

    名称说明
    dbcleanthread自动清理数据线程类。
    dbconnthread数据库通信管理线程类。
    dbdelegate自定义委托全家桶,包括复选框、下拉框、密码框、按钮等。
    dbhead当前组件通用头文件。
    dbhelper各种数据库应用函数封装,比如初始化数据库、执行sql语句等。
    dbhttpthread网络请求数据采集类。
    dbpage数据库通用翻页类。
    dbpagemodel数据库翻页类数据模型。
    navpage分页导航控件。
    8.3.3.6 模块-core_form

    名称说明
    formhelper封装的导入导出、导出数据到xls/pdf和打印数据、自动备份数据、保存最后打开的文件夹等。
    frmconfigdb通用数据库管理界面类,可选不同的数据库类型,填入用户信息,执行检测连接和初始化数据操作。
    frmconfiguser通用用户管理界面类,可添加、删除、修改用户信息,包括权限分配等,可导入导出打印用户信息。
    frmlogin通用用户登录界面类,包括自动登录和记住密码复选框,多次密码错误校验,记住当前用户信息等。三次错误关闭,下拉可选用户,内置超级密码。
    frmlogout通用用户退出界面类,三次错误关闭,下拉可选用户,内置超级密码。
    userhelper通用用户权限管理类,内置7种类型权限,对应权限名称可自定义,一般在用户切换对应界面或者单击了对应功能按钮的时候触发。
    8.3.3.7 模块-core_qui

    本组件涵盖的功能较多,所以采用了分层管理代码结构。

    名称说明
    iconhelper万能图形字体类,可传入多种图形字体文件,一个类通用所有图形字体。
    quiconfig存储当前组件的配置参数信息,比如全局的字体名称、字号、无边框窗体的最小化最大化关闭等图标、样式表的颜色值。
    quihead当前组件通用头文件。
    quistyle当前组件通用样式设置管理类,可以指定枚举类型样式、传入样式内容设置、获取样式表文件对应的颜色值等。当前组件样式相关的处理函数都放在这里,统一管理。
    名称说明
    quiabout关于系统对话框,可传入软件标题、版本、版权、网址等信息。
    quidateselect自定义日期范围选择对话框。
    quiinputbox自定义输入框窗体,可指定不同的输入类型比如文本框、下拉框等。
    quimessagebox自定义信息消息框窗体,可设置关闭倒计时,不同的类型比如信息框、询问框、错误框等。
    quisplash自定义弹出提示信息,提示完自动消息关闭。
    quitipbox自定义右下角信息对话框,可设置对齐方式、关闭倒计时等。
    quiwidget自定义无边框窗体,可设置标题,各种图标等。
    名称说明
    quihelper项目通用辅助类,各种常用函数的封装,比如获取当前屏幕分辨率、设置字体、设置编码、加载翻译文件、各种进制数据转换、弹出各种对话框、设置延时时间等。
    quihelpercore获取当前桌面分辨率,设置编码、字体、翻译文件等。
    quihelperdata16进制、2进制、10进制互相转换,16进制字符串、字节数组互相转换,字节数组转int和short,CRC校验等。
    quihelperfile选择文件、保存文件、选择目录等对话框,复制文件、删除文件等。
    quihelperform设置无边框窗体、边框阴影,弹出信息框、错误框、询问框、日期选择框、关于对话框、中间提示框等。
    quihelperimage获取等比例缩放图片,通用设置logo图片,支持资源文件、本地图片、图形字体、svg自动变色等多种形式。
    quihelpernet获取本机IP地址集合,获取外网IP地址,判断IP、MAC等是否合法,下载网络文件,IP地址字符串与整型互相转换。
    quihelperother初始化数据库文件,设置系统时间、开机启动,设置图标到按钮,写入临时消息的文本文件等。
    8.3.3.8 模块-core_send
    名称说明
    sendemailthread多线程发送邮件类,支持附件,可设置多个抄送。
    sendmsgthread多线程收发短信类,支持长短信发送和多个收件人。

    8.3.4 界面UI

    界面说明

    • 这里分门别类存放的各种功能集合的界面类。
    • 每个类都一个ui文件、一个h头文件、一个cpp实现文件。
    • 可以方便快速查找对应功能的界面,也方便拓展增加界面。
    • 不仅分文件夹存放的,而且命名也尽量按照对应功能打头,比如系统设置模块中的都用frmconfig打头。
    • 外层文件夹是整齐的,内部代码也是整齐的。
    名称说明
    frmconfig系统设置模块,包括基本设置、端口管理、控制器管理、探测器管理、联动设置、类型管理等。
    frmconfig2其他设置模块,包括地图管理、用户管理、组态设计、设备调试等。
    frmdata日志查询模块,包括用户日志、运行日志、报警日志等。
    frmmain主界面模块,包括软件主界面、模拟调试工具等。
    frmother其他模块,包括封装的设备信息面板,设备回控等。
    frmview视图模块,包括数据监控、设备面板、地图监控、曲线监控等。
    8.3.4.1 模块-frmconfig

    名称说明
    frmconfig系统设置模块主界面,采用堆栈窗体形式,加载多个子界面比如控制器管理、探测器管理等。
    frmconfigdbnet远程数据库设置,用于将本地数据实时同步到远程服务器。
    frmconfigdevice控制器管理,可以增加、删除、修改、清空、导入、导出、打印控制器信息。
    frmconfiglink联动管理,可以增加、删除、修改、清空、导入、导出、打印联动信息。具体联动规则依据厂家约定。
    frmconfignode探测器管理,可以增加、删除、修改、清空、导入、导出、打印探测器信息。本系统设备的最终节点,可以设置非常详细的各种参数。
    frmconfigport端口管理,可以增加、删除、修改、清空、导入、导出、打印端口信息。可以下拉选择对应的通信协议模式。
    frmconfigsystem系统设置,包括基本设置、数据库设置、网络转发配置、日志设置、颜色配置、短信告警设置、邮件转发设置等。
    frmconfigtype类型设置,为了增强灵活性拓展性,系统中的控制器类型、探测器类型、气体种类、气体符号等信息都可以在这里自定义。
    8.3.4.2 模块-frmconfig2

    名称说明
    frmconfig2其他设置模块主界面,采用堆栈窗体形式,加载多个子界面比如用户管理、位置调整等。
    frmconfigdebug数据打印调试,所有的设备数据通信都可以在这里看到,可以选择针对某个控制器和探测器,也可以选择只看发送还是接收的数据,所有的数据都有对应的解析文字,方便理解。
    frmconfigmap地图管理,可以添加删除地图图片文件。
    frmconfigposition位置调整,可以对地图上的设备拖动调整到合适的位置。
    frmconfigscada自定义控件属性设计器,演示如何加载自定义控件然后拖曳,导入导出xml文件,自定义用户数据,组态的雏形,目前功能单一。
    8.3.4.3 模块-frmdata

    名称说明
    frmdata日志查询模块主界面,采用堆栈窗体形式,加载多个子界面包括用户日志、运行日志、报警日志等。
    frmdataalarm报警日志,可以按照日期范围、报警类型等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
    frmdatanode运行日志,可以按照日期范围、控制器等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
    frmdatauser用户日志,可以按照日期范围、操作类型等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
    8.3.4.4 模块-frmmain

    名称说明
    frmmain系统主界面,采用堆栈窗体,加载各个子模块。
    frmtool模拟调试工具,可选择设备采集模拟或者数据库模拟。
    frmtimecpu时间和CPU内存模块,一般放在系统的右上角。
    8.3.4.5 模块-frmother

    名称说明
    frmdevicecontrol设备回控模块,目前就显示具体的探测器信息,后期按照用户需求定制。
    frmdevicenode设备面板模块,同时包含了多种面板样式比如普通样式、仪表样式,可以在系统设置中动态切换并立即应用,每个探测器在设备监控界面中都占用这样一个面板,显示具体的信息,包括实时更新值。
    8.3.4.6 模块-frmview

    名称说明
    frmview系统视图主界面,采用堆栈窗体,加载各个子模块。
    frmviewdata数据监控,表格形式展示每个设备的各项数据和单位,报警不同颜色显示,具体颜色可以在系统设置中设置。
    frmviewdevice设备监控,每个探测器都对应一个设备面板,超出则滚动条显示。
    frmviewmap地图监控,设备在图片地图上,报警后红色闪烁,可以双击弹出探测器的详细信息,同时在设备按钮上显示对应的采集到的值。
    frmviewplot曲线监控,可以指定某个探测器设备查看实时曲线,还可以看该设备的历史记录曲线。

    9 数据库设计

    9.1 端口信息-PortInfo

    字段名中文名类型长度说明
    PortID编号INTEGER 主键自增
    PortName端口名称VARCHAR30不为空
    PortType协议类型VARCHAR15不为空
    ComName串口号VARCHAR10 
    BaudRate波特率INTEGER6 
    TcpIP网络地址VARCHAR16 
    TcpPort网络端口INTEGER6 
    ReadInterval采集周期INTEGER4不为空
    ReadTimeout通讯超时次数INTEGER4不为空
    ReadMaxtime超时重连时间INTEGER4不为空
    PortMark备注VARCHAR255 

    9.2 控制器信息-DeviceInfo

    字段名中文名类型长度说明
    DeviceID编号INTEGER 主键自增
    PortName端口名称VARCHAR30不为空
    DeviceName控制器名称VARCHAR30不为空
    DeviceAddr控制器地址INTEGER3不为空
    DeviceType控制器类型VARCHAR20不为空
    NodeNumber探测器数量INTEGER3不为空
    DeviceMark备注VARCHAR255 

    9.3 探测器信息-NodeInfo

    字段名中文名类型长度说明
    NodeID编号INTEGER 主键自增
    positionID位置编号VARCHAR20不为空
    DeviceName控制器名称VARCHAR30不为空
    NodeName探测器名称VARCHAR30不为空
    NodeAddr探测器地址INTEGER3不为空
    NodeType探测器类型VARCHAR20不为空
    NodeClass气体种类VARCHAR20不为空
    NodeSign单位符号VARCHAR20不为空
    NodeUpper上限值VARCHAR10不为空
    NodeLimit下限值VARCHAR10不为空
    NodeMax最大值VARCHAR10不为空
    NodeMin清零值VARCHAR10不为空
    NodeRange缓冲值VARCHAR10不为空
    NodeEnable启用禁用VARCHAR2不为空
    NodeSound报警声音VARCHAR10不为空
    NodeImage背景图片VARCHAR10不为空
    SaveInterval存储周期INTEGER3不为空
    DotCount小数点位数INTEGER1不为空
    AlarmDelay报警延时INTEGER3不为空
    AlarmType报警类型VARCHAR2不为空
    NodeXX坐标INTEGER4不为空
    NodeYY坐标INTEGER4不为空
    NodeMark备注VARCHAR255 
    字段名中文名类型长度说明
    PositionID位置编号VARCHAR20主键自增
    ComName串口名VARCHAR10不为空
    BaudRate波特率INTEGER5不为空
    ModelAddr模块地址INTEGER3不为空
    LinkAddr联动地址集合VARCHAR20不为空
    LinkEnable启用禁用VARCHAR2不为空
    LinkMark备注VARCHAR255 

    9.5 类型信息-TypeInfo

    字段名中文名类型长度说明
    TypeID编号INTEGER 主键自增
    DeviceType控制器类型VARCHAR20 
    NodeNumber探测器数量INTEGER5 
    NodeType探测器类型VARCHAR20 
    NodeClass气体种类VARCHAR20 
    NodeSign气体符号VARCHAR20 

    9.6 节点数据-NodeData

    1. 此表对应数据库采集模式和数据库读取模式。
    2. 节点状态含义:0-离线、1-在线、2-低报、3-高报、4-失效。
    3. 本表用于给其他程序存入采集到的数据,本程序通过读取数据库采集数据。
    字段名中文名类型长度说明
    PositionID位置编号VARCHAR20 
    NodeValue节点数据VARCHAR10不为空
    NodeStatus节点状态INTEGER2不为空
    SaveTime记录时间VARCHAR19不为空

    9.7 用户信息-UserInfo

    字段名中文名类型长度说明
    UserName用户名称VARCHAR20不为空
    UserPwd用户密码VARCHAR10不为空
    UserType用户类型VARCHAR10不为空
    Permission1用户权限1VARCHAR20 
    Permission2用户权限2VARCHAR20 
    Permission3用户权限3VARCHAR20 
    Permission4用户权限4VARCHAR20 
    Permission5用户权限5VARCHAR20 
    Permission6用户权限6VARCHAR20 
    Permission7用户权限7VARCHAR20 
    UserMark备注VARCHAR50 

    9.8 操作记录-UserLog

    字段名中文名类型长度说明
    LogID编号INTEGER 主键自增
    TriggerTime触发时间VARCHAR19 
    UserName用户名称VARCHAR20 
    UserType用户类型VARCHAR10 
    LogType事件类型VARCHAR20 
    LogContent事件内容VARCHAR255 

    9.9 运行记录-NodeLog

    字段名中文名类型长度说明
    LogID编号INTEGER 主键自增
    PositionID位置编号VARCHAR20 
    DeviceName控制器名称VARCHAR30 
    NodeName探测器名称VARCHAR30 
    NodeValue当前值VARCHAR10 
    NodeSign单位符号VARCHAR10 
    SaveTime保存时间VARCHAR19 
    LogMark备注VARCHAR255 

    9.10 报警记录-AlarmLog

    字段名中文名类型长度说明
    LogID编号INTEGER 主键自增
    PositionID位置编号VARCHAR20 
    DeviceName控制器名称VARCHAR30 
    NodeName探测器名称VARCHAR30 
    NodeValue当前值VARCHAR10 
    NodeSign单位符号VARCHAR10 
    Content报警内容VARCHAR20 
    StartTime开始时间VARCHAR19 
    EndTime结束时间VARCHAR19 
    ConfirmUser确认用户VARCHAR20 
    ConfirmTime确认时间VARCHAR19 
    ConfirmContent确认意见VARCHAR255 

    10 其他说明

    10.1 设备模拟工具

    + +

    本系统专门配备了设备模拟工具,用来在没有外接真实设备的时候,模拟modbus协议数据,支持多个设备,支持串口和网络方式,可切换正常数据和报警数据,反应到主程序上。对应主程序中两种端口,一种是串口端口(这个可以用虚拟串口工具 Virtual Serial Port 虚拟一对串口用于测试),一种是网络端口(注意选择的监听主机地址和端口)。数据库模拟对应程序中的数据库采集运行模式,可以勾选自动模拟复选框。随机生成状态字段数据。

    10.2 modbus仿真

    作为国际知名的modbus模拟仿真工具Modbus Slave,本系统也提供了对应的数据配置文件iotsystem.mbs,在db目录下,对应添加FC-1003-8控制器。两边的通信方式必须一致,比如软件上设置的串口则两边都是串口。具体Modbus Slave工具详细使用可以自行搜索,比如这篇文章 https://blog.csdn.net/xuw_xy/article/details/81166305

    10.3 邮件转发设置

    + +

    本系统支持邮件转发,前提是对应的邮箱账号需要开通 POP3/SMTP 等服务,按照图示开启即可,一般开启后会设置独立的管理密码,记得在系统设置那边的邮件转发,填写密码的时候要填的是独立管理密码,而不是邮箱号的密码,这个机制和任何第三方邮箱管理软件都一样。

    10.4 短信转发设置

    本系统支持串口短信发送,需要发短信的硬件支持(俗称DXM),采用通用的标准的AT指令短信发送协议,支持任意厂家的串口短信设备。当设备报警后会自动组建报警短信发送给设定的收件人。支持中文短信发送和长短信发送,可以自行网上GM对应的硬件。

    10.5 代码行数统计

    本系统除去第三方库(串口通信3rd_qextserialport、曲线图表3rd_qcustomplot、属性控件3rd_qtpropertybrowser、邮件发送3rd_smtpclient)的代码,总代码行数约4W行,纯代码行数约3W行。

    10.6 多种数据库支持

    本系统支持多种数据库,包括sqlite、mysql、sqlserver、postgresql、oracle、kingbase等,直接在系统设置中的数据库配置中切换即可,切换完数据库以后记得初始化数据库,否则数据库不存在。

    10.6.1 sqlite

    10.6.2 mysql

    10.6.3 sqlserver

    10.6.4 postgresql

    10.6.5 oracle

    10.6.6 kingbase

    10.7 采集数据转发

    +

    在系统设置中设置好网络转发参数后,可以在接收的地方开启网络数据接收,这样只需要接收数据解析反应到界面就行,相当于数据源不是硬件设备而是网络转发过来的数据,不需要直接接硬件设备。

    网络转发端,单击同步数据会把本地的端口信息、控制器信息、探测器信息发到远端。网络转发模块也可以作为无限级联使用,比如接收端还可以开启转发,继续转发给需要的地方,一个客户端上设置的转发也支持多个,用英文分号 ; 隔开,一对多关系,采用的无连接udp协议,几乎不占用系统资源。

    10.8 云端数据库同步

    + +

    云端数据库同步,相当于把本地采集到的数据实时存储到云端,至于这些记录到了云端后什么用途,一般会用来做web请求访问,或者app请求获取数据,具体应用看用户需求。

    云端数据库也会存储到NodeData表中,意味着任意地方的客户端,都可以选择数据库采集模式,直接连接云端的数据库作为数据源。相当于可以无限级联。

    + + + \ No newline at end of file diff --git a/docs/iotsystem/snap/1-1-1.jpg b/docs/iotsystem/snap/1-1-1.jpg new file mode 100644 index 0000000..664d51c Binary files /dev/null and b/docs/iotsystem/snap/1-1-1.jpg differ diff --git a/docs/iotsystem/snap/1-1-2.jpg b/docs/iotsystem/snap/1-1-2.jpg new file mode 100644 index 0000000..2738254 Binary files /dev/null and b/docs/iotsystem/snap/1-1-2.jpg differ diff --git a/docs/iotsystem/snap/1-2-1.jpg b/docs/iotsystem/snap/1-2-1.jpg new file mode 100644 index 0000000..e7760aa Binary files /dev/null and b/docs/iotsystem/snap/1-2-1.jpg differ diff --git a/docs/iotsystem/snap/10-1-1.jpg b/docs/iotsystem/snap/10-1-1.jpg new file mode 100644 index 0000000..e96ea60 Binary files /dev/null and b/docs/iotsystem/snap/10-1-1.jpg differ diff --git a/docs/iotsystem/snap/10-1-2.jpg b/docs/iotsystem/snap/10-1-2.jpg new file mode 100644 index 0000000..43c2f50 Binary files /dev/null and b/docs/iotsystem/snap/10-1-2.jpg differ diff --git a/docs/iotsystem/snap/10-1-3.jpg b/docs/iotsystem/snap/10-1-3.jpg new file mode 100644 index 0000000..4a7f7bb Binary files /dev/null and b/docs/iotsystem/snap/10-1-3.jpg differ diff --git a/docs/iotsystem/snap/10-2-1.jpg b/docs/iotsystem/snap/10-2-1.jpg new file mode 100644 index 0000000..2da9191 Binary files /dev/null and b/docs/iotsystem/snap/10-2-1.jpg differ diff --git a/docs/iotsystem/snap/10-3-1.jpg b/docs/iotsystem/snap/10-3-1.jpg new file mode 100644 index 0000000..3bb7646 Binary files /dev/null and b/docs/iotsystem/snap/10-3-1.jpg differ diff --git a/docs/iotsystem/snap/10-3-2.jpg b/docs/iotsystem/snap/10-3-2.jpg new file mode 100644 index 0000000..06b280a Binary files /dev/null and b/docs/iotsystem/snap/10-3-2.jpg differ diff --git a/docs/iotsystem/snap/10-3-3.jpg b/docs/iotsystem/snap/10-3-3.jpg new file mode 100644 index 0000000..e4e3ce2 Binary files /dev/null and b/docs/iotsystem/snap/10-3-3.jpg differ diff --git a/docs/iotsystem/snap/10-4-1.jpg b/docs/iotsystem/snap/10-4-1.jpg new file mode 100644 index 0000000..18df235 Binary files /dev/null and b/docs/iotsystem/snap/10-4-1.jpg differ diff --git a/docs/iotsystem/snap/10-5-1.jpg b/docs/iotsystem/snap/10-5-1.jpg new file mode 100644 index 0000000..71e21e7 Binary files /dev/null and b/docs/iotsystem/snap/10-5-1.jpg differ diff --git a/docs/iotsystem/snap/10-6-1.jpg b/docs/iotsystem/snap/10-6-1.jpg new file mode 100644 index 0000000..db6f6f2 Binary files /dev/null and b/docs/iotsystem/snap/10-6-1.jpg differ diff --git a/docs/iotsystem/snap/10-6-2.jpg b/docs/iotsystem/snap/10-6-2.jpg new file mode 100644 index 0000000..b8f4aae Binary files /dev/null and b/docs/iotsystem/snap/10-6-2.jpg differ diff --git a/docs/iotsystem/snap/10-6-3.jpg b/docs/iotsystem/snap/10-6-3.jpg new file mode 100644 index 0000000..a45af8d Binary files /dev/null and b/docs/iotsystem/snap/10-6-3.jpg differ diff --git a/docs/iotsystem/snap/10-6-4.jpg b/docs/iotsystem/snap/10-6-4.jpg new file mode 100644 index 0000000..9f3b655 Binary files /dev/null and b/docs/iotsystem/snap/10-6-4.jpg differ diff --git a/docs/iotsystem/snap/10-6-5.jpg b/docs/iotsystem/snap/10-6-5.jpg new file mode 100644 index 0000000..5033814 Binary files /dev/null and b/docs/iotsystem/snap/10-6-5.jpg differ diff --git a/docs/iotsystem/snap/10-6-6.jpg b/docs/iotsystem/snap/10-6-6.jpg new file mode 100644 index 0000000..1b41b8e Binary files /dev/null and b/docs/iotsystem/snap/10-6-6.jpg differ diff --git a/docs/iotsystem/snap/10-7-1.jpg b/docs/iotsystem/snap/10-7-1.jpg new file mode 100644 index 0000000..af73a0d Binary files /dev/null and b/docs/iotsystem/snap/10-7-1.jpg differ diff --git a/docs/iotsystem/snap/10-7-2.jpg b/docs/iotsystem/snap/10-7-2.jpg new file mode 100644 index 0000000..57990fe Binary files /dev/null and b/docs/iotsystem/snap/10-7-2.jpg differ diff --git a/docs/iotsystem/snap/10-8-1.jpg b/docs/iotsystem/snap/10-8-1.jpg new file mode 100644 index 0000000..bf0b877 Binary files /dev/null and b/docs/iotsystem/snap/10-8-1.jpg differ diff --git a/docs/iotsystem/snap/10-8-2.jpg b/docs/iotsystem/snap/10-8-2.jpg new file mode 100644 index 0000000..6aa9215 Binary files /dev/null and b/docs/iotsystem/snap/10-8-2.jpg differ diff --git a/docs/iotsystem/snap/10-8-3.jpg b/docs/iotsystem/snap/10-8-3.jpg new file mode 100644 index 0000000..a2368f0 Binary files /dev/null and b/docs/iotsystem/snap/10-8-3.jpg differ diff --git a/docs/iotsystem/snap/2-1-0.jpg b/docs/iotsystem/snap/2-1-0.jpg new file mode 100644 index 0000000..8852861 Binary files /dev/null and b/docs/iotsystem/snap/2-1-0.jpg differ diff --git a/docs/iotsystem/snap/2-1-1.jpg b/docs/iotsystem/snap/2-1-1.jpg new file mode 100644 index 0000000..84b2654 Binary files /dev/null and b/docs/iotsystem/snap/2-1-1.jpg differ diff --git a/docs/iotsystem/snap/2-1-10.jpg b/docs/iotsystem/snap/2-1-10.jpg new file mode 100644 index 0000000..71ba226 Binary files /dev/null and b/docs/iotsystem/snap/2-1-10.jpg differ diff --git a/docs/iotsystem/snap/2-1-2.jpg b/docs/iotsystem/snap/2-1-2.jpg new file mode 100644 index 0000000..7b97eb5 Binary files /dev/null and b/docs/iotsystem/snap/2-1-2.jpg differ diff --git a/docs/iotsystem/snap/2-1-3.jpg b/docs/iotsystem/snap/2-1-3.jpg new file mode 100644 index 0000000..92cfa83 Binary files /dev/null and b/docs/iotsystem/snap/2-1-3.jpg differ diff --git a/docs/iotsystem/snap/2-1-4.jpg b/docs/iotsystem/snap/2-1-4.jpg new file mode 100644 index 0000000..1cab9dd Binary files /dev/null and b/docs/iotsystem/snap/2-1-4.jpg differ diff --git a/docs/iotsystem/snap/2-1-5.jpg b/docs/iotsystem/snap/2-1-5.jpg new file mode 100644 index 0000000..699647a Binary files /dev/null and b/docs/iotsystem/snap/2-1-5.jpg differ diff --git a/docs/iotsystem/snap/2-1-6.jpg b/docs/iotsystem/snap/2-1-6.jpg new file mode 100644 index 0000000..9e01b61 Binary files /dev/null and b/docs/iotsystem/snap/2-1-6.jpg differ diff --git a/docs/iotsystem/snap/2-1-7.jpg b/docs/iotsystem/snap/2-1-7.jpg new file mode 100644 index 0000000..cb62e26 Binary files /dev/null and b/docs/iotsystem/snap/2-1-7.jpg differ diff --git a/docs/iotsystem/snap/2-1-8.jpg b/docs/iotsystem/snap/2-1-8.jpg new file mode 100644 index 0000000..a5f2e8d Binary files /dev/null and b/docs/iotsystem/snap/2-1-8.jpg differ diff --git a/docs/iotsystem/snap/2-1-9.jpg b/docs/iotsystem/snap/2-1-9.jpg new file mode 100644 index 0000000..e917e69 Binary files /dev/null and b/docs/iotsystem/snap/2-1-9.jpg differ diff --git a/docs/iotsystem/snap/2-2-1.jpg b/docs/iotsystem/snap/2-2-1.jpg new file mode 100644 index 0000000..77e65c6 Binary files /dev/null and b/docs/iotsystem/snap/2-2-1.jpg differ diff --git a/docs/iotsystem/snap/2-2-6.jpg b/docs/iotsystem/snap/2-2-6.jpg new file mode 100644 index 0000000..a0ff520 Binary files /dev/null and b/docs/iotsystem/snap/2-2-6.jpg differ diff --git a/docs/iotsystem/snap/2-2-7.jpg b/docs/iotsystem/snap/2-2-7.jpg new file mode 100644 index 0000000..02714d2 Binary files /dev/null and b/docs/iotsystem/snap/2-2-7.jpg differ diff --git a/docs/iotsystem/snap/2-3-1.jpg b/docs/iotsystem/snap/2-3-1.jpg new file mode 100644 index 0000000..d7e53b0 Binary files /dev/null and b/docs/iotsystem/snap/2-3-1.jpg differ diff --git a/docs/iotsystem/snap/2-3-6.jpg b/docs/iotsystem/snap/2-3-6.jpg new file mode 100644 index 0000000..0ad7b3d Binary files /dev/null and b/docs/iotsystem/snap/2-3-6.jpg differ diff --git a/docs/iotsystem/snap/2-3-7.jpg b/docs/iotsystem/snap/2-3-7.jpg new file mode 100644 index 0000000..8a6640f Binary files /dev/null and b/docs/iotsystem/snap/2-3-7.jpg differ diff --git a/docs/iotsystem/snap/2-4-1.jpg b/docs/iotsystem/snap/2-4-1.jpg new file mode 100644 index 0000000..d83d05e Binary files /dev/null and b/docs/iotsystem/snap/2-4-1.jpg differ diff --git a/docs/iotsystem/snap/2-4-6.jpg b/docs/iotsystem/snap/2-4-6.jpg new file mode 100644 index 0000000..30c4f38 Binary files /dev/null and b/docs/iotsystem/snap/2-4-6.jpg differ diff --git a/docs/iotsystem/snap/2-4-7.jpg b/docs/iotsystem/snap/2-4-7.jpg new file mode 100644 index 0000000..5116a20 Binary files /dev/null and b/docs/iotsystem/snap/2-4-7.jpg differ diff --git a/docs/iotsystem/snap/2-5-1.jpg b/docs/iotsystem/snap/2-5-1.jpg new file mode 100644 index 0000000..cd4c2c3 Binary files /dev/null and b/docs/iotsystem/snap/2-5-1.jpg differ diff --git a/docs/iotsystem/snap/2-5-6.jpg b/docs/iotsystem/snap/2-5-6.jpg new file mode 100644 index 0000000..f46b456 Binary files /dev/null and b/docs/iotsystem/snap/2-5-6.jpg differ diff --git a/docs/iotsystem/snap/2-5-7.jpg b/docs/iotsystem/snap/2-5-7.jpg new file mode 100644 index 0000000..948e351 Binary files /dev/null and b/docs/iotsystem/snap/2-5-7.jpg differ diff --git a/docs/iotsystem/snap/2-6-1.jpg b/docs/iotsystem/snap/2-6-1.jpg new file mode 100644 index 0000000..3f2e140 Binary files /dev/null and b/docs/iotsystem/snap/2-6-1.jpg differ diff --git a/docs/iotsystem/snap/2-6-6.jpg b/docs/iotsystem/snap/2-6-6.jpg new file mode 100644 index 0000000..1b9c10c Binary files /dev/null and b/docs/iotsystem/snap/2-6-6.jpg differ diff --git a/docs/iotsystem/snap/2-6-7.jpg b/docs/iotsystem/snap/2-6-7.jpg new file mode 100644 index 0000000..59bf927 Binary files /dev/null and b/docs/iotsystem/snap/2-6-7.jpg differ diff --git a/docs/iotsystem/snap/3-1-1.jpg b/docs/iotsystem/snap/3-1-1.jpg new file mode 100644 index 0000000..c220a94 Binary files /dev/null and b/docs/iotsystem/snap/3-1-1.jpg differ diff --git a/docs/iotsystem/snap/3-1-6.jpg b/docs/iotsystem/snap/3-1-6.jpg new file mode 100644 index 0000000..9ccf5d3 Binary files /dev/null and b/docs/iotsystem/snap/3-1-6.jpg differ diff --git a/docs/iotsystem/snap/3-1-7.jpg b/docs/iotsystem/snap/3-1-7.jpg new file mode 100644 index 0000000..7e89fa8 Binary files /dev/null and b/docs/iotsystem/snap/3-1-7.jpg differ diff --git a/docs/iotsystem/snap/3-1-8-1.jpg b/docs/iotsystem/snap/3-1-8-1.jpg new file mode 100644 index 0000000..389dbd1 Binary files /dev/null and b/docs/iotsystem/snap/3-1-8-1.jpg differ diff --git a/docs/iotsystem/snap/3-1-8-2.jpg b/docs/iotsystem/snap/3-1-8-2.jpg new file mode 100644 index 0000000..2ad269e Binary files /dev/null and b/docs/iotsystem/snap/3-1-8-2.jpg differ diff --git a/docs/iotsystem/snap/3-2-1.jpg b/docs/iotsystem/snap/3-2-1.jpg new file mode 100644 index 0000000..72ce086 Binary files /dev/null and b/docs/iotsystem/snap/3-2-1.jpg differ diff --git a/docs/iotsystem/snap/3-3-1.jpg b/docs/iotsystem/snap/3-3-1.jpg new file mode 100644 index 0000000..b287c6d Binary files /dev/null and b/docs/iotsystem/snap/3-3-1.jpg differ diff --git a/docs/iotsystem/snap/3-4-1.jpg b/docs/iotsystem/snap/3-4-1.jpg new file mode 100644 index 0000000..7429e28 Binary files /dev/null and b/docs/iotsystem/snap/3-4-1.jpg differ diff --git a/docs/iotsystem/snap/3-5-1.jpg b/docs/iotsystem/snap/3-5-1.jpg new file mode 100644 index 0000000..8de98ca Binary files /dev/null and b/docs/iotsystem/snap/3-5-1.jpg differ diff --git a/docs/iotsystem/snap/4-0-1.jpg b/docs/iotsystem/snap/4-0-1.jpg new file mode 100644 index 0000000..6afad8d Binary files /dev/null and b/docs/iotsystem/snap/4-0-1.jpg differ diff --git a/docs/iotsystem/snap/4-1-1.jpg b/docs/iotsystem/snap/4-1-1.jpg new file mode 100644 index 0000000..d77b257 Binary files /dev/null and b/docs/iotsystem/snap/4-1-1.jpg differ diff --git a/docs/iotsystem/snap/4-2-1.jpg b/docs/iotsystem/snap/4-2-1.jpg new file mode 100644 index 0000000..75db20e Binary files /dev/null and b/docs/iotsystem/snap/4-2-1.jpg differ diff --git a/docs/iotsystem/snap/4-2-2.jpg b/docs/iotsystem/snap/4-2-2.jpg new file mode 100644 index 0000000..904820e Binary files /dev/null and b/docs/iotsystem/snap/4-2-2.jpg differ diff --git a/docs/iotsystem/snap/4-2-3.jpg b/docs/iotsystem/snap/4-2-3.jpg new file mode 100644 index 0000000..025b040 Binary files /dev/null and b/docs/iotsystem/snap/4-2-3.jpg differ diff --git a/docs/iotsystem/snap/4-3-1.jpg b/docs/iotsystem/snap/4-3-1.jpg new file mode 100644 index 0000000..e28c602 Binary files /dev/null and b/docs/iotsystem/snap/4-3-1.jpg differ diff --git a/docs/iotsystem/snap/4-4-1.jpg b/docs/iotsystem/snap/4-4-1.jpg new file mode 100644 index 0000000..214164e Binary files /dev/null and b/docs/iotsystem/snap/4-4-1.jpg differ diff --git a/docs/iotsystem/snap/4-4-2.jpg b/docs/iotsystem/snap/4-4-2.jpg new file mode 100644 index 0000000..f3e9f82 Binary files /dev/null and b/docs/iotsystem/snap/4-4-2.jpg differ diff --git a/docs/iotsystem/snap/5-1-1.jpg b/docs/iotsystem/snap/5-1-1.jpg new file mode 100644 index 0000000..0aee090 Binary files /dev/null and b/docs/iotsystem/snap/5-1-1.jpg differ diff --git a/docs/iotsystem/snap/5-1-2.jpg b/docs/iotsystem/snap/5-1-2.jpg new file mode 100644 index 0000000..024b7fd Binary files /dev/null and b/docs/iotsystem/snap/5-1-2.jpg differ diff --git a/docs/iotsystem/snap/5-1-3.jpg b/docs/iotsystem/snap/5-1-3.jpg new file mode 100644 index 0000000..5c56d5f Binary files /dev/null and b/docs/iotsystem/snap/5-1-3.jpg differ diff --git a/docs/iotsystem/snap/5-1-4.jpg b/docs/iotsystem/snap/5-1-4.jpg new file mode 100644 index 0000000..30fd1ad Binary files /dev/null and b/docs/iotsystem/snap/5-1-4.jpg differ diff --git a/docs/iotsystem/snap/5-2-1.jpg b/docs/iotsystem/snap/5-2-1.jpg new file mode 100644 index 0000000..8d600af Binary files /dev/null and b/docs/iotsystem/snap/5-2-1.jpg differ diff --git a/docs/iotsystem/snap/5-2-2.jpg b/docs/iotsystem/snap/5-2-2.jpg new file mode 100644 index 0000000..9bff6e1 Binary files /dev/null and b/docs/iotsystem/snap/5-2-2.jpg differ diff --git a/docs/iotsystem/snap/5-2-3.jpg b/docs/iotsystem/snap/5-2-3.jpg new file mode 100644 index 0000000..f4293d1 Binary files /dev/null and b/docs/iotsystem/snap/5-2-3.jpg differ diff --git a/docs/iotsystem/snap/5-2-4.jpg b/docs/iotsystem/snap/5-2-4.jpg new file mode 100644 index 0000000..ce01b6f Binary files /dev/null and b/docs/iotsystem/snap/5-2-4.jpg differ diff --git a/docs/iotsystem/snap/5-3-1.jpg b/docs/iotsystem/snap/5-3-1.jpg new file mode 100644 index 0000000..99212c6 Binary files /dev/null and b/docs/iotsystem/snap/5-3-1.jpg differ diff --git a/docs/iotsystem/snap/5-3-2.jpg b/docs/iotsystem/snap/5-3-2.jpg new file mode 100644 index 0000000..bda3134 Binary files /dev/null and b/docs/iotsystem/snap/5-3-2.jpg differ diff --git a/docs/iotsystem/snap/5-3-3.jpg b/docs/iotsystem/snap/5-3-3.jpg new file mode 100644 index 0000000..bf863c4 Binary files /dev/null and b/docs/iotsystem/snap/5-3-3.jpg differ diff --git a/docs/iotsystem/snap/5-3-4.jpg b/docs/iotsystem/snap/5-3-4.jpg new file mode 100644 index 0000000..e3478a3 Binary files /dev/null and b/docs/iotsystem/snap/5-3-4.jpg differ diff --git a/docs/iotsystem/snap/6-1-1.jpg b/docs/iotsystem/snap/6-1-1.jpg new file mode 100644 index 0000000..8887262 Binary files /dev/null and b/docs/iotsystem/snap/6-1-1.jpg differ diff --git a/docs/iotsystem/snap/6-1-2.jpg b/docs/iotsystem/snap/6-1-2.jpg new file mode 100644 index 0000000..ffcf250 Binary files /dev/null and b/docs/iotsystem/snap/6-1-2.jpg differ diff --git a/docs/iotsystem/snap/6-1-3.jpg b/docs/iotsystem/snap/6-1-3.jpg new file mode 100644 index 0000000..587170c Binary files /dev/null and b/docs/iotsystem/snap/6-1-3.jpg differ diff --git a/docs/iotsystem/snap/6-1-4.jpg b/docs/iotsystem/snap/6-1-4.jpg new file mode 100644 index 0000000..bfbb149 Binary files /dev/null and b/docs/iotsystem/snap/6-1-4.jpg differ diff --git a/docs/iotsystem/snap/6-1-5.jpg b/docs/iotsystem/snap/6-1-5.jpg new file mode 100644 index 0000000..64bb7c0 Binary files /dev/null and b/docs/iotsystem/snap/6-1-5.jpg differ diff --git a/docs/iotsystem/snap/6-1-6.jpg b/docs/iotsystem/snap/6-1-6.jpg new file mode 100644 index 0000000..2c96f84 Binary files /dev/null and b/docs/iotsystem/snap/6-1-6.jpg differ diff --git a/docs/iotsystem/snap/7-0-1.jpg b/docs/iotsystem/snap/7-0-1.jpg new file mode 100644 index 0000000..a148902 Binary files /dev/null and b/docs/iotsystem/snap/7-0-1.jpg differ diff --git a/docs/iotsystem/snap/7-0-10.jpg b/docs/iotsystem/snap/7-0-10.jpg new file mode 100644 index 0000000..0ad1314 Binary files /dev/null and b/docs/iotsystem/snap/7-0-10.jpg differ diff --git a/docs/iotsystem/snap/7-0-11.jpg b/docs/iotsystem/snap/7-0-11.jpg new file mode 100644 index 0000000..11ec0ea Binary files /dev/null and b/docs/iotsystem/snap/7-0-11.jpg differ diff --git a/docs/iotsystem/snap/7-0-12.jpg b/docs/iotsystem/snap/7-0-12.jpg new file mode 100644 index 0000000..9a3f47f Binary files /dev/null and b/docs/iotsystem/snap/7-0-12.jpg differ diff --git a/docs/iotsystem/snap/7-0-13.jpg b/docs/iotsystem/snap/7-0-13.jpg new file mode 100644 index 0000000..8e40344 Binary files /dev/null and b/docs/iotsystem/snap/7-0-13.jpg differ diff --git a/docs/iotsystem/snap/7-0-14.jpg b/docs/iotsystem/snap/7-0-14.jpg new file mode 100644 index 0000000..90f7359 Binary files /dev/null and b/docs/iotsystem/snap/7-0-14.jpg differ diff --git a/docs/iotsystem/snap/7-0-15.jpg b/docs/iotsystem/snap/7-0-15.jpg new file mode 100644 index 0000000..c5ea368 Binary files /dev/null and b/docs/iotsystem/snap/7-0-15.jpg differ diff --git a/docs/iotsystem/snap/7-0-16.jpg b/docs/iotsystem/snap/7-0-16.jpg new file mode 100644 index 0000000..52ac800 Binary files /dev/null and b/docs/iotsystem/snap/7-0-16.jpg differ diff --git a/docs/iotsystem/snap/7-0-17.jpg b/docs/iotsystem/snap/7-0-17.jpg new file mode 100644 index 0000000..f51cfa3 Binary files /dev/null and b/docs/iotsystem/snap/7-0-17.jpg differ diff --git a/docs/iotsystem/snap/7-0-18.jpg b/docs/iotsystem/snap/7-0-18.jpg new file mode 100644 index 0000000..64ed73a Binary files /dev/null and b/docs/iotsystem/snap/7-0-18.jpg differ diff --git a/docs/iotsystem/snap/7-0-2.jpg b/docs/iotsystem/snap/7-0-2.jpg new file mode 100644 index 0000000..aeef23b Binary files /dev/null and b/docs/iotsystem/snap/7-0-2.jpg differ diff --git a/docs/iotsystem/snap/7-0-3.jpg b/docs/iotsystem/snap/7-0-3.jpg new file mode 100644 index 0000000..9760aab Binary files /dev/null and b/docs/iotsystem/snap/7-0-3.jpg differ diff --git a/docs/iotsystem/snap/7-0-4.jpg b/docs/iotsystem/snap/7-0-4.jpg new file mode 100644 index 0000000..9b5bf10 Binary files /dev/null and b/docs/iotsystem/snap/7-0-4.jpg differ diff --git a/docs/iotsystem/snap/7-0-5.jpg b/docs/iotsystem/snap/7-0-5.jpg new file mode 100644 index 0000000..111094e Binary files /dev/null and b/docs/iotsystem/snap/7-0-5.jpg differ diff --git a/docs/iotsystem/snap/7-0-6.jpg b/docs/iotsystem/snap/7-0-6.jpg new file mode 100644 index 0000000..d780ff2 Binary files /dev/null and b/docs/iotsystem/snap/7-0-6.jpg differ diff --git a/docs/iotsystem/snap/7-0-7.jpg b/docs/iotsystem/snap/7-0-7.jpg new file mode 100644 index 0000000..3c9c5aa Binary files /dev/null and b/docs/iotsystem/snap/7-0-7.jpg differ diff --git a/docs/iotsystem/snap/7-0-8.jpg b/docs/iotsystem/snap/7-0-8.jpg new file mode 100644 index 0000000..65bfe72 Binary files /dev/null and b/docs/iotsystem/snap/7-0-8.jpg differ diff --git a/docs/iotsystem/snap/7-0-9.jpg b/docs/iotsystem/snap/7-0-9.jpg new file mode 100644 index 0000000..47b165f Binary files /dev/null and b/docs/iotsystem/snap/7-0-9.jpg differ diff --git a/docs/iotsystem/snap/7-1-1.jpg b/docs/iotsystem/snap/7-1-1.jpg new file mode 100644 index 0000000..c829805 Binary files /dev/null and b/docs/iotsystem/snap/7-1-1.jpg differ diff --git a/docs/iotsystem/snap/7-2-1.jpg b/docs/iotsystem/snap/7-2-1.jpg new file mode 100644 index 0000000..76a14c2 Binary files /dev/null and b/docs/iotsystem/snap/7-2-1.jpg differ diff --git a/docs/iotsystem/snap/7-3-1.jpg b/docs/iotsystem/snap/7-3-1.jpg new file mode 100644 index 0000000..2baee26 Binary files /dev/null and b/docs/iotsystem/snap/7-3-1.jpg differ diff --git a/docs/iotsystem/snap/7-4-1.jpg b/docs/iotsystem/snap/7-4-1.jpg new file mode 100644 index 0000000..f414779 Binary files /dev/null and b/docs/iotsystem/snap/7-4-1.jpg differ diff --git a/docs/iotsystem/snap/7-5-1.jpg b/docs/iotsystem/snap/7-5-1.jpg new file mode 100644 index 0000000..fb9f053 Binary files /dev/null and b/docs/iotsystem/snap/7-5-1.jpg differ diff --git a/docs/iotsystem/snap/7-6-1.jpg b/docs/iotsystem/snap/7-6-1.jpg new file mode 100644 index 0000000..d8fb4c5 Binary files /dev/null and b/docs/iotsystem/snap/7-6-1.jpg differ diff --git a/docs/iotsystem/snap/7-7-1.jpg b/docs/iotsystem/snap/7-7-1.jpg new file mode 100644 index 0000000..c2418ef Binary files /dev/null and b/docs/iotsystem/snap/7-7-1.jpg differ diff --git a/docs/iotsystem/snap/7-8-1.jpg b/docs/iotsystem/snap/7-8-1.jpg new file mode 100644 index 0000000..58faf9d Binary files /dev/null and b/docs/iotsystem/snap/7-8-1.jpg differ diff --git a/docs/iotsystem/snap/7-9-1.jpg b/docs/iotsystem/snap/7-9-1.jpg new file mode 100644 index 0000000..a6d2f95 Binary files /dev/null and b/docs/iotsystem/snap/7-9-1.jpg differ diff --git a/docs/iotsystem/snap/8-1-1.jpg b/docs/iotsystem/snap/8-1-1.jpg new file mode 100644 index 0000000..5dc46a9 Binary files /dev/null and b/docs/iotsystem/snap/8-1-1.jpg differ diff --git a/docs/iotsystem/snap/8-3-1.jpg b/docs/iotsystem/snap/8-3-1.jpg new file mode 100644 index 0000000..ece2aef Binary files /dev/null and b/docs/iotsystem/snap/8-3-1.jpg differ diff --git a/docs/iotsystem/snap/8-3-2-1.jpg b/docs/iotsystem/snap/8-3-2-1.jpg new file mode 100644 index 0000000..52943d9 Binary files /dev/null and b/docs/iotsystem/snap/8-3-2-1.jpg differ diff --git a/docs/iotsystem/snap/8-3-2-2.jpg b/docs/iotsystem/snap/8-3-2-2.jpg new file mode 100644 index 0000000..1ab5bd0 Binary files /dev/null and b/docs/iotsystem/snap/8-3-2-2.jpg differ diff --git a/docs/iotsystem/snap/8-3-2-3.jpg b/docs/iotsystem/snap/8-3-2-3.jpg new file mode 100644 index 0000000..735c005 Binary files /dev/null and b/docs/iotsystem/snap/8-3-2-3.jpg differ diff --git a/docs/iotsystem/snap/8-3-2-4.jpg b/docs/iotsystem/snap/8-3-2-4.jpg new file mode 100644 index 0000000..27a4eb4 Binary files /dev/null and b/docs/iotsystem/snap/8-3-2-4.jpg differ diff --git a/docs/iotsystem/snap/8-3-2.jpg b/docs/iotsystem/snap/8-3-2.jpg new file mode 100644 index 0000000..e04cb17 Binary files /dev/null and b/docs/iotsystem/snap/8-3-2.jpg differ diff --git a/docs/iotsystem/snap/8-3-3-1.jpg b/docs/iotsystem/snap/8-3-3-1.jpg new file mode 100644 index 0000000..c1216c3 Binary files /dev/null and b/docs/iotsystem/snap/8-3-3-1.jpg differ diff --git a/docs/iotsystem/snap/8-3-3-2.jpg b/docs/iotsystem/snap/8-3-3-2.jpg new file mode 100644 index 0000000..930782c Binary files /dev/null and b/docs/iotsystem/snap/8-3-3-2.jpg differ diff --git a/docs/iotsystem/snap/8-3-3-3.jpg b/docs/iotsystem/snap/8-3-3-3.jpg new file mode 100644 index 0000000..a8e4f76 Binary files /dev/null and b/docs/iotsystem/snap/8-3-3-3.jpg differ diff --git a/docs/iotsystem/snap/8-3-3-4.jpg b/docs/iotsystem/snap/8-3-3-4.jpg new file mode 100644 index 0000000..ff8903f Binary files /dev/null and b/docs/iotsystem/snap/8-3-3-4.jpg differ diff --git a/docs/iotsystem/snap/8-3-3-5.jpg b/docs/iotsystem/snap/8-3-3-5.jpg new file mode 100644 index 0000000..305c7c8 Binary files /dev/null and b/docs/iotsystem/snap/8-3-3-5.jpg differ diff --git a/docs/iotsystem/snap/8-3-3-6.jpg b/docs/iotsystem/snap/8-3-3-6.jpg new file mode 100644 index 0000000..0ef349a Binary files /dev/null and b/docs/iotsystem/snap/8-3-3-6.jpg differ diff --git a/docs/iotsystem/snap/8-3-3-7.jpg b/docs/iotsystem/snap/8-3-3-7.jpg new file mode 100644 index 0000000..ef60060 Binary files /dev/null and b/docs/iotsystem/snap/8-3-3-7.jpg differ diff --git a/docs/iotsystem/snap/8-3-3.jpg b/docs/iotsystem/snap/8-3-3.jpg new file mode 100644 index 0000000..229b76b Binary files /dev/null and b/docs/iotsystem/snap/8-3-3.jpg differ diff --git a/docs/iotsystem/snap/8-3-4-1.jpg b/docs/iotsystem/snap/8-3-4-1.jpg new file mode 100644 index 0000000..37f98b9 Binary files /dev/null and b/docs/iotsystem/snap/8-3-4-1.jpg differ diff --git a/docs/iotsystem/snap/8-3-4-2.jpg b/docs/iotsystem/snap/8-3-4-2.jpg new file mode 100644 index 0000000..0602e61 Binary files /dev/null and b/docs/iotsystem/snap/8-3-4-2.jpg differ diff --git a/docs/iotsystem/snap/8-3-4-3.jpg b/docs/iotsystem/snap/8-3-4-3.jpg new file mode 100644 index 0000000..ccd8f0b Binary files /dev/null and b/docs/iotsystem/snap/8-3-4-3.jpg differ diff --git a/docs/iotsystem/snap/8-3-4-4.jpg b/docs/iotsystem/snap/8-3-4-4.jpg new file mode 100644 index 0000000..30ef7ff Binary files /dev/null and b/docs/iotsystem/snap/8-3-4-4.jpg differ diff --git a/docs/iotsystem/snap/8-3-4-5.jpg b/docs/iotsystem/snap/8-3-4-5.jpg new file mode 100644 index 0000000..e856eb4 Binary files /dev/null and b/docs/iotsystem/snap/8-3-4-5.jpg differ diff --git a/docs/iotsystem/snap/8-3-4-6.jpg b/docs/iotsystem/snap/8-3-4-6.jpg new file mode 100644 index 0000000..c479a53 Binary files /dev/null and b/docs/iotsystem/snap/8-3-4-6.jpg differ diff --git a/docs/iotsystem/snap/8-3-4.jpg b/docs/iotsystem/snap/8-3-4.jpg new file mode 100644 index 0000000..69cdb82 Binary files /dev/null and b/docs/iotsystem/snap/8-3-4.jpg differ diff --git a/docs/qcustomplotdemo/index.html b/docs/qcustomplotdemo/index.html new file mode 100644 index 0000000..f31c7ab --- /dev/null +++ b/docs/qcustomplotdemo/index.html @@ -0,0 +1,72 @@ + + + + + + + + + + qcustomplotdemo + + + +
    +
    + + Qt for WebAssembly: qcustomplotdemo +
    + +
    +
    + + + + + + diff --git a/docs/qcustomplotdemo/qcustomplotdemo.js b/docs/qcustomplotdemo/qcustomplotdemo.js new file mode 100644 index 0000000..dc2333b --- /dev/null +++ b/docs/qcustomplotdemo/qcustomplotdemo.js @@ -0,0 +1 @@ +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_HAS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_HAS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_NODE=ENVIRONMENT_HAS_NODE&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){scriptDirectory=__dirname+"/";read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var STACK_ALIGN=16;function dynamicAlloc(size){var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;if(end>_emscripten_get_heap_size()){abort()}HEAP32[DYNAMICTOP_PTR>>2]=end;return ret}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0,"getNativeTypeSize invalid bits "+bits+", type "+type);return bits/8}else{return 0}}}}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}function convertJsFunctionToWasm(func,sig){if(typeof WebAssembly.Function==="function"){var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i>>0)+ +(high>>>0)*4294967296:+(low>>>0)+ +(high|0)*4294967296}function dynCall(sig,ptr,args){if(args&&args.length){return Module["dynCall_"+sig].apply(null,[ptr].concat(args))}else{return Module["dynCall_"+sig].call(null,ptr)}}var tempRet0=0;var setTempRet0=function(value){tempRet0=value};var getTempRet0=function(){return tempRet0};var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){err("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":11148,"maximum":11148+0,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>2]=0}stop=ret+size;while(ptr>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){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;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function UTF16ToString(ptr){var endPtr=ptr;var idx=endPtr>>1;while(HEAP16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder){return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr))}else{var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)return str;++i;str+=String.fromCharCode(codeUnit)}}}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function allocateUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var STACK_BASE=13752112,DYNAMIC_BASE=13752112,DYNAMICTOP_PTR=8509056;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_TOTAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);FS.quit();TTY.shutdown();runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function unSign(value,bits,ignore){if(value>=0){return value}return bits<=32?2*Math.abs(1<=half&&(bits<=32||value>half)){value=-2*half+value}return value}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="qcustomplotdemo.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"env":asmLibraryArg,"wasi_snapshot_preview1":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;__ATINIT__.push({func:function(){___wasm_call_ctors()}});function demangle(func){return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ___cxa_allocate_exception(size){return _malloc(size)}function _atexit(func,arg){__ATEXIT__.unshift({func:func,arg:arg})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function ___cxa_thread_atexit(){return _atexit.apply(null,arguments)}var ___exception_infos={};var ___exception_last=0;function ___cxa_throw(ptr,type,destructor){___exception_infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};___exception_last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exceptions=1}else{__ZSt18uncaught_exceptionv.uncaught_exceptions++}throw ptr}function ___lock(){}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}function ___map_file(pathname,size){___setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(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:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(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:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[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.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(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;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){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}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(new ArrayBuffer(newSize));if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=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+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(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:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(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:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}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:function(parent,name,mode,rdev){if(!FS.FSNode){FS.FSNode=function(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};FS.FSNode.prototype={};var readMode=292|73;var writeMode=146;Object.defineProperties(FS.FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}})}var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(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:function(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:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}})}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(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(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(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:type,opts:opts,mountpoint: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:function(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(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(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:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";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]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_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=function(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);if(typeof Uint8Array!="undefined")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||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(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};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;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url: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(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}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>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=new Uint8Array(HEAPU8.subarray(addr,addr+len));FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});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},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:0,get:function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(){var ret=UTF8ToString(SYSCALLS.get());return ret},getStreamFromFD:function(fd){if(fd===undefined)fd=SYSCALLS.get();var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(){var low=SYSCALLS.get(),high=SYSCALLS.get();return low},getZero:function(){SYSCALLS.get()}};function ___syscall10(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr();FS.unlink(path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall122(which,varargs){SYSCALLS.varargs=varargs;try{var buf=SYSCALLS.get();if(!buf)return-21;var layout={"__size__":390,"sysname":0,"nodename":65,"release":130,"version":195,"machine":260,"domainname":325};var copyString=function(element,value){var offset=layout[element];writeAsciiToMemory(value,buf+offset)};copyString("sysname","Emscripten");copyString("nodename","emscripten");copyString("release","1.0");copyString("version","#1");copyString("machine","x86-JS");return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall15(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),mode=SYSCALLS.get();FS.chmod(path,mode);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall168(which,varargs){SYSCALLS.varargs=varargs;try{var fds=SYSCALLS.get(),nfds=SYSCALLS.get(),timeout=SYSCALLS.get();var nonzero=0;for(var i=0;i>2];var events=HEAP16[pollfd+4>>1];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){mask=stream.stream_ops.poll(stream)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>1]=mask}return nonzero}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall183(which,varargs){SYSCALLS.varargs=varargs;try{var buf=SYSCALLS.get(),size=SYSCALLS.get();if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd);if(size=67){while((ptr&3)!=0){HEAP8[ptr>>0]=value;ptr=ptr+1|0}aligned_end=end&-4|0;value4=value|value<<8|value<<16|value<<24;block_aligned_end=aligned_end-64|0;while((ptr|0)<=(block_aligned_end|0)){HEAP32[ptr>>2]=value4;HEAP32[ptr+4>>2]=value4;HEAP32[ptr+8>>2]=value4;HEAP32[ptr+12>>2]=value4;HEAP32[ptr+16>>2]=value4;HEAP32[ptr+20>>2]=value4;HEAP32[ptr+24>>2]=value4;HEAP32[ptr+28>>2]=value4;HEAP32[ptr+32>>2]=value4;HEAP32[ptr+36>>2]=value4;HEAP32[ptr+40>>2]=value4;HEAP32[ptr+44>>2]=value4;HEAP32[ptr+48>>2]=value4;HEAP32[ptr+52>>2]=value4;HEAP32[ptr+56>>2]=value4;HEAP32[ptr+60>>2]=value4;ptr=ptr+64|0}while((ptr|0)<(aligned_end|0)){HEAP32[ptr>>2]=value4;ptr=ptr+4|0}}while((ptr|0)<(end|0)){HEAP8[ptr>>0]=value;ptr=ptr+1|0}return end-num|0}function __emscripten_syscall_mmap2(addr,len,prot,flags,fd,off){off<<=12;var ptr;var allocated=false;if((flags&16)!==0&&addr%16384!==0){return-28}if((flags&32)!==0){ptr=_memalign(16384,len);if(!ptr)return-48;_memset(ptr,0,len);allocated=true}else{var info=FS.getStream(fd);if(!info)return-8;var res=FS.mmap(info,HEAPU8,addr,len,off,prot,flags);ptr=res.ptr;allocated=res.allocated}SYSCALLS.mappings[ptr]={malloc:ptr,len:len,allocated:allocated,fd:fd,flags:flags,offset:off};return ptr}function ___syscall192(which,varargs){SYSCALLS.varargs=varargs;try{var addr=SYSCALLS.get(),len=SYSCALLS.get(),prot=SYSCALLS.get(),flags=SYSCALLS.get(),fd=SYSCALLS.get(),off=SYSCALLS.get();return __emscripten_syscall_mmap2(addr,len,prot,flags,fd,off)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall193(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),zero=SYSCALLS.getZero(),length=SYSCALLS.get64();FS.truncate(path,length);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall194(which,varargs){SYSCALLS.varargs=varargs;try{var fd=SYSCALLS.get(),zero=SYSCALLS.getZero(),length=SYSCALLS.get64();FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall195(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),buf=SYSCALLS.get();return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall196(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),buf=SYSCALLS.get();return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall197(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),buf=SYSCALLS.get();return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall202(which,varargs){SYSCALLS.varargs=varargs;try{return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall199(a0,a1){return ___syscall202(a0,a1)}var PROCINFO={ppid:1,pid:42,sid:42,pgid:42};function ___syscall20(which,varargs){SYSCALLS.varargs=varargs;try{return PROCINFO.pid}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall201(a0,a1){return ___syscall202(a0,a1)}function ___syscall220(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),dirp=SYSCALLS.get(),count=SYSCALLS.get();if(!stream.getdents){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>>0,(tempDouble=id,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos>>2]=tempI64[0],HEAP32[dirp+pos+4>>2]=tempI64[1];tempI64=[(idx+1)*struct_size>>>0,(tempDouble=(idx+1)*struct_size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos+8>>2]=tempI64[0],HEAP32[dirp+pos+12>>2]=tempI64[1];HEAP16[dirp+pos+16>>1]=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 instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall221(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),cmd=SYSCALLS.get();switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 12:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0;case 16:case 8:return-28;case 9:___setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall3(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),buf=SYSCALLS.get(),count=SYSCALLS.get();return FS.read(stream,HEAP8,buf,count)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall320(which,varargs){SYSCALLS.varargs=varargs;try{var dirfd=SYSCALLS.get(),path=SYSCALLS.getStr(),times=SYSCALLS.get(),flags=SYSCALLS.get();path=SYSCALLS.calculateAt(dirfd,path);var seconds=HEAP32[times>>2];var nanoseconds=HEAP32[times+4>>2];var atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=8;seconds=HEAP32[times>>2];nanoseconds=HEAP32[times+4>>2];var mtime=seconds*1e3+nanoseconds/(1e3*1e3);FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall33(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),amode=SYSCALLS.get();return SYSCALLS.doAccess(path,amode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall38(which,varargs){SYSCALLS.varargs=varargs;try{var old_path=SYSCALLS.getStr(),new_path=SYSCALLS.getStr();FS.rename(old_path,new_path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall39(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),mode=SYSCALLS.get();return SYSCALLS.doMkdir(path,mode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall4(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),buf=SYSCALLS.get(),count=SYSCALLS.get();return FS.write(stream,HEAP8,buf,count)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall40(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr();FS.rmdir(path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall5(which,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(),flags=SYSCALLS.get(),mode=SYSCALLS.get();var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall83(which,varargs){SYSCALLS.varargs=varargs;try{var target=SYSCALLS.getStr(),linkpath=SYSCALLS.getStr();FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall85(which,varargs){SYSCALLS.varargs=varargs;try{var path=SYSCALLS.getStr(),buf=SYSCALLS.get(),bufsize=SYSCALLS.get();return SYSCALLS.doReadlink(path,buf,bufsize)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall9(which,varargs){SYSCALLS.varargs=varargs;try{var oldpath=SYSCALLS.get(),newpath=SYSCALLS.get();return-34}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function __emscripten_syscall_munmap(addr,len){if(addr===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset);FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___syscall91(which,varargs){SYSCALLS.varargs=varargs;try{var addr=SYSCALLS.get(),len=SYSCALLS.get();return __emscripten_syscall_munmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall94(which,varargs){SYSCALLS.varargs=varargs;try{var fd=SYSCALLS.get(),mode=SYSCALLS.get();FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___unlock(){}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function 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=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return new Function("body","return function "+name+"() {\n"+' "use strict";'+" return body.apply(this, arguments);\n"+"};\n")(body)}function 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 BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(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>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function new_(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError("new_ called with constructor type "+typeof constructor+" which is not a function")}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i>2)+i])}return array}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,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+4+i]=charCode}}else{for(var i=0;i>2];var a=new Array(length);var start=value+4>>shift;for(var i=0;i>2]=length;var start=ptr+4>>shift;for(var i=0;i>2]=rd;return returnType["toWireType"](destructors,handle)}function __emval_lookupTypes(argCount,argTypes,argWireTypes){var a=new Array(argCount);for(var i=0;i>2)+i],"parameter "+i)}return a}function __emval_call(handle,argCount,argTypes,argv){handle=requireHandle(handle);var types=__emval_lookupTypes(argCount,argTypes);var args=new Array(argCount);for(var i=0;i>2]=__emval_register(destructors);return destructors}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_method(caller,handle,methodName,destructorsRef,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);return caller(handle,methodName,__emval_allocateDestructors(destructorsRef),args)}function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function __emval_equals(first,second){first=requireHandle(first);second=requireHandle(second);return first==second}function emval_get_global(){if(typeof globalThis==="object"){return globalThis}return function(){return Function}()("return this")()}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map(function(t){return t.name}).join("_")+"$";var params=["retType"];var args=[retType];var argsList="";for(var i=0;i4){emval_handle_array[handle].refcount+=1}}function __emval_is_string(handle){handle=requireHandle(handle);return typeof handle==="string"}function craftEmvalAllocator(argCount){var argsList="";for(var i=0;i> 2) + "+i+'], "parameter '+i+'");\n'+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return __emval_register(obj);\n"+"}\n";return new Function("requireRegisteredType","Module","__emval_register",functionBody)(requireRegisteredType,Module,__emval_register)}var emval_newers={};function __emval_new(handle,argCount,argTypes,args){handle=requireHandle(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_new_object(){return __emval_register({})}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle=requireHandle(handle);key=requireHandle(key);value=requireHandle(value);handle[key]=value}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _abort(){abort()}function _emscripten_get_now(){abort()}var _emscripten_get_now_is_monotonic=0||ENVIRONMENT_IS_NODE||typeof dateNow!=="undefined"||1;function _clock_gettime(clk_id,tp){var now;if(clk_id===0){now=Date.now()}else if(clk_id===1&&_emscripten_get_now_is_monotonic){now=_emscripten_get_now()}else{___setErrNo(28);return-1}HEAP32[tp>>2]=now/1e3|0;HEAP32[tp+4>>2]=now%1e3*1e3*1e3|0;return 0}function _dlopen(){abort("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")}function _dlclose(){return _dlopen.apply(null,arguments)}function _dlerror(){return _dlopen.apply(null,arguments)}function _dlsym(){return _dlopen.apply(null,arguments)}function _emscripten_set_main_loop_timing(mode,value){Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof setImmediate==="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=function(event){if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop,arg,noSetTiming){noExitRuntime=true;assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=func;Browser.mainLoop.arg=arg;var browserIterationFunc;if(typeof arg!=="undefined"){browserIterationFunc=function(){Module["dynCall_vi"](func,arg)}}else{browserIterationFunc=function(){Module["dynCall_v"](func)}}var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;Browser.mainLoop.runner=function Browser_mainLoop_runner(){if(ABORT)return;if(Browser.mainLoop.queue.length>0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}console.log('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(thisMainLoopId1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}GL.newRenderingFrameStarted();Browser.mainLoop.runIter(browserIterationFunc);if(thisMainLoopId0)_emscripten_set_main_loop_timing(0,1e3/fps);else _emscripten_set_main_loop_timing(1,1);Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;_emscripten_set_main_loop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining=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;Browser.safeSetTimeout(function(){finish(audio)},1e4)}else{return fail()}};Module["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"]||function(){};canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||function(){};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",function(ev){if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext:function(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){if(!useWebGL)assert(typeof GLctx==="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas,vrDevice){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;Browser.vrDevice=vrDevice;if(typeof Browser.lockPointer==="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas==="undefined")Browser.resizeCanvas=false;if(typeof Browser.vrDevice==="undefined")Browser.vrDevice=null;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)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])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"]?function(){canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null)||(canvasContainer["webkitRequestFullScreen"]?function(){canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null);if(vrDevice){canvasContainer.requestFullscreen({vrDisplay:vrDevice})}else{canvasContainer.requestFullscreen()}},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||function(){};CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame==="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeCallback:function(func){return function(){if(!ABORT)return func.apply(null,arguments)}},allowAsyncCallbacks:true,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=false},resumeAsyncCallbacks:function(){Browser.allowAsyncCallbacks=true;if(Browser.queuedAsyncCallbacks.length>0){var callbacks=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[];callbacks.forEach(function(func){func()})}},safeRequestAnimationFrame:function(func){return Browser.requestAnimationFrame(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}})},safeSetTimeout:function(func,timeout){noExitRuntime=true;return setTimeout(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}},timeout)},safeSetInterval:function(func,timeout){noExitRuntime=true;return setInterval(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}},timeout)},getMimetype:function(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:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(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:{},calculateMouseEvent:function(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)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{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;if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};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];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},asyncLoad:function(url,onload,onerror,noRunDep){var dep=!noRunDep?getUniqueRunDependency("al "+url):"";readAsync(url,function(arrayBuffer){assert(arrayBuffer,'Loading data file "'+url+'" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},function(event){if(onerror){onerror()}else{throw'Loading data file "'+url+'" failed.'}});if(dep)addRunDependency(dep)},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(function(listener){listener(canvas.width,canvas.height)})},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(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/h>2];if(param==12321){var alphaSize=HEAP32[attribList+4>>2];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>2];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>2];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>2];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>2]=1}if(config&&config_size>0){HEAP32[config>>2]=62002}EGL.setErrorCode(12288);return 1}};function _eglGetProcAddress(name_){return _emscripten_GetProcAddress(name_)}function _emscripten_async_call(func,arg,millis){noExitRuntime=true;function wrapper(){getFuncWrapper(func,"vi")(arg)}if(millis>=0){Browser.safeSetTimeout(wrapper,millis)}else{Browser.safeRequestAnimationFrame(wrapper)}}function _emscripten_date_now(){return Date.now()}function _emscripten_force_exit(status){noExitRuntime=false;exit(status)}var JSEvents={keyEvent:0,mouseEvent:0,wheelEvent:0,uiEvent:0,focusEvent:0,deviceOrientationEvent:0,deviceMotionEvent:0,fullscreenChangeEvent:0,pointerlockChangeEvent:0,visibilityChangeEvent:0,touchEvent:0,previousFullscreenElement:null,previousScreenX:null,previousScreenY:null,removeEventListenersRegistered:false,removeAllEventListeners:function(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners:function(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall:function(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 i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort(function(x,y){return x.precedence>3]=rect.width;HEAPF64[height>>3]=rect.height;return 0}function _emscripten_get_heap_size(){return HEAP8.length}function _emscripten_get_sbrk_ptr(){return 8509056}function __webgl_acquireInstancedArraysExtension(ctx){var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=function(index,divisor){ext["vertexAttribDivisorANGLE"](index,divisor)};ctx["drawArraysInstanced"]=function(mode,first,count,primcount){ext["drawArraysInstancedANGLE"](mode,first,count,primcount)};ctx["drawElementsInstanced"]=function(mode,count,type,indices,primcount){ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount)}}}function __webgl_acquireVertexArrayObjectExtension(ctx){var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=function(){return ext["createVertexArrayOES"]()};ctx["deleteVertexArray"]=function(vao){ext["deleteVertexArrayOES"](vao)};ctx["bindVertexArray"]=function(vao){ext["bindVertexArrayOES"](vao)};ctx["isVertexArray"]=function(vao){return ext["isVertexArrayOES"](vao)}}}function __webgl_acquireDrawBuffersExtension(ctx){var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=function(n,bufs){ext["drawBuffersWEBGL"](n,bufs)}}}var GL={counter:1,lastError:0,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],uniforms:[],shaders:[],vaos:[],contexts:{},currentContext:null,offscreenCanvases:{},timerQueriesEXT:[],queries:[],samplers:[],transformFeedbacks:[],syncs:[],currArrayBuffer:0,currElementArrayBuffer:0,byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],programInfos:{},stringCache:{},stringiCache:{},unpackAlignment:4,init:function(){var miniTempFloatBuffer=new Float32Array(GL.MINI_TEMP_BUFFER_SIZE);for(var i=0;i>1;var quadIndexes=new Uint16Array(numIndexes);var i=0,v=0;while(1){quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+1;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v+3;if(i>=numIndexes)break;v+=4}context.GLctx.bufferData(34963,quadIndexes,35044);context.GLctx.bindBuffer(34963,null)}},getTempVertexBuffer:function getTempVertexBuffer(sizeBytes){var idx=GL.log2ceilLookup(sizeBytes);var ringbuffer=GL.currentContext.tempVertexBuffers1[idx];var nextFreeBufferIndex=GL.currentContext.tempVertexBufferCounters1[idx];GL.currentContext.tempVertexBufferCounters1[idx]=GL.currentContext.tempVertexBufferCounters1[idx]+1&GL.numTempVertexBuffersPerSize-1;var vbo=ringbuffer[nextFreeBufferIndex];if(vbo){return vbo}var prevVBO=GLctx.getParameter(34964);ringbuffer[nextFreeBufferIndex]=GLctx.createBuffer();GLctx.bindBuffer(34962,ringbuffer[nextFreeBufferIndex]);GLctx.bufferData(34962,1<>2]:-1;source+=UTF8ToString(HEAP32[string+i*4>>2],len<0?undefined:len)}return source},calcBufLength:function calcBufLength(size,type,stride,count){if(stride>0){return count*stride}var typeSize=GL.byteSizeByType[type-GL.byteSizeByTypeRoot];return size*typeSize*count},usedTempBuffers:[],preDrawHandleClientVertexAttribBindings:function preDrawHandleClientVertexAttribBindings(count){GL.resetBufferBinding=false;for(var i=0;i1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:function(ctx,webGLContextAttributes){var handle=_malloc(8);var context={handle: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)}context.maxVertexAttribs=context.GLctx.getParameter(34921);context.clientBuffers=[];for(var i=0;i=2){if(data){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}}function _emscripten_glBufferSubData(target,offset,size,data){if(GL.currentContext.version>=2){GLctx.bufferSubData(target,offset,HEAPU8,data,size);return}GLctx.bufferSubData(target,offset,HEAPU8.subarray(data,data+size))}function _emscripten_glCheckFramebufferStatus(x0){return GLctx["checkFramebufferStatus"](x0)}function _emscripten_glClear(x0){GLctx["clear"](x0)}function _emscripten_glClearBufferfi(x0,x1,x2,x3){GLctx["clearBufferfi"](x0,x1,x2,x3)}function _emscripten_glClearBufferfv(buffer,drawbuffer,value){GLctx["clearBufferfv"](buffer,drawbuffer,HEAPF32,value>>2)}function _emscripten_glClearBufferiv(buffer,drawbuffer,value){GLctx["clearBufferiv"](buffer,drawbuffer,HEAP32,value>>2)}function _emscripten_glClearBufferuiv(buffer,drawbuffer,value){GLctx["clearBufferuiv"](buffer,drawbuffer,HEAPU32,value>>2)}function _emscripten_glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _emscripten_glClearDepthf(x0){GLctx["clearDepth"](x0)}function _emscripten_glClearStencil(x0){GLctx["clearStencil"](x0)}function _emscripten_glClientWaitSync(sync,flags,timeoutLo,timeoutHi){timeoutLo=timeoutLo>>>0;timeoutHi=timeoutHi>>>0;var timeout=timeoutLo==4294967295&&timeoutHi==4294967295?-1:makeBigInt(timeoutLo,timeoutHi,true);return GLctx.clientWaitSync(GL.syncs[sync],flags,timeout)}function _emscripten_glColorMask(red,green,blue,alpha){GLctx.colorMask(!!red,!!green,!!blue,!!alpha)}function _emscripten_glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _emscripten_glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,imageSize,data)}else{GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,HEAPU8,data,imageSize)}return}GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexImage3D(target,level,internalFormat,width,height,depth,border,imageSize,data){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)}}function _emscripten_glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,imageSize,data)}else{GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,HEAPU8,data,imageSize)}return}GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data){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)}}function _emscripten_glCopyBufferSubData(x0,x1,x2,x3,x4){GLctx["copyBufferSubData"](x0,x1,x2,x3,x4)}function _emscripten_glCopyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexSubImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage3D(x0,x1,x2,x3,x4,x5,x6,x7,x8){GLctx["copyTexSubImage3D"](x0,x1,x2,x3,x4,x5,x6,x7,x8)}function _emscripten_glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;GL.programs[id]=program;return id}function _emscripten_glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _emscripten_glCullFace(x0){GLctx["cullFace"](x0)}function _emscripten_glDeleteBuffers(n,buffers){for(var i=0;i>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GL.currArrayBuffer)GL.currArrayBuffer=0;if(id==GL.currElementArrayBuffer)GL.currElementArrayBuffer=0;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _emscripten_glDeleteFramebuffers(n,framebuffers){for(var i=0;i>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _emscripten_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;GL.programInfos[id]=null}function _emscripten_glDeleteQueries(n,ids){for(var i=0;i>2];var query=GL.queries[id];if(!query)continue;GLctx["deleteQuery"](query);GL.queries[id]=null}}function _emscripten_glDeleteQueriesEXT(n,ids){for(var i=0;i>2];var query=GL.timerQueriesEXT[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.timerQueriesEXT[id]=null}}function _emscripten_glDeleteRenderbuffers(n,renderbuffers){for(var i=0;i>2];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}function _emscripten_glDeleteSamplers(n,samplers){for(var i=0;i>2];var sampler=GL.samplers[id];if(!sampler)continue;GLctx["deleteSampler"](sampler);sampler.name=0;GL.samplers[id]=null}}function _emscripten_glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _emscripten_glDeleteSync(id){if(!id)return;var sync=GL.syncs[id];if(!sync){GL.recordError(1281);return}GLctx.deleteSync(sync);sync.name=0;GL.syncs[id]=null}function _emscripten_glDeleteTextures(n,textures){for(var i=0;i>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _emscripten_glDeleteTransformFeedbacks(n,ids){for(var i=0;i>2];var transformFeedback=GL.transformFeedbacks[id];if(!transformFeedback)continue;GLctx["deleteTransformFeedback"](transformFeedback);transformFeedback.name=0;GL.transformFeedbacks[id]=null}}function _emscripten_glDeleteVertexArrays(n,vaos){for(var i=0;i>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDeleteVertexArraysOES(n,vaos){for(var i=0;i>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDepthFunc(x0){GLctx["depthFunc"](x0)}function _emscripten_glDepthMask(flag){GLctx.depthMask(!!flag)}function _emscripten_glDepthRangef(x0,x1){GLctx["depthRange"](x0,x1)}function _emscripten_glDetachShader(program,shader){GLctx.detachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glDisable(x0){GLctx["disable"](x0)}function _emscripten_glDisableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=false;GLctx.disableVertexAttribArray(index)}function _emscripten_glDrawArrays(mode,first,count){GL.preDrawHandleClientVertexAttribBindings(first+count);GLctx.drawArrays(mode,first,count);GL.postDrawHandleClientVertexAttribBindings()}function _emscripten_glDrawArraysInstanced(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedANGLE(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedARB(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedEXT(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedNV(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}var __tempFixedLengthArray=[];function _emscripten_glDrawBuffers(n,bufs){var bufArray=__tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawBuffersEXT(n,bufs){var bufArray=__tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawBuffersWEBGL(n,bufs){var bufArray=__tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawElements(mode,count,type,indices){var buf;if(!GL.currElementArrayBuffer){var size=GL.calcBufLength(1,type,0,count);buf=GL.getTempIndexBuffer(size);GLctx.bindBuffer(34963,buf);GLctx.bufferSubData(34963,0,HEAPU8.subarray(indices,indices+size));indices=0}GL.preDrawHandleClientVertexAttribBindings(count);GLctx.drawElements(mode,count,type,indices);GL.postDrawHandleClientVertexAttribBindings(count);if(!GL.currElementArrayBuffer){GLctx.bindBuffer(34963,null)}}function _emscripten_glDrawElementsInstanced(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedANGLE(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedARB(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedEXT(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedNV(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _glDrawElements(mode,count,type,indices){var buf;if(!GL.currElementArrayBuffer){var size=GL.calcBufLength(1,type,0,count);buf=GL.getTempIndexBuffer(size);GLctx.bindBuffer(34963,buf);GLctx.bufferSubData(34963,0,HEAPU8.subarray(indices,indices+size));indices=0}GL.preDrawHandleClientVertexAttribBindings(count);GLctx.drawElements(mode,count,type,indices);GL.postDrawHandleClientVertexAttribBindings(count);if(!GL.currElementArrayBuffer){GLctx.bindBuffer(34963,null)}}function _emscripten_glDrawRangeElements(mode,start,end,count,type,indices){_glDrawElements(mode,count,type,indices)}function _emscripten_glEnable(x0){GLctx["enable"](x0)}function _emscripten_glEnableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=true;GLctx.enableVertexAttribArray(index)}function _emscripten_glEndQuery(x0){GLctx["endQuery"](x0)}function _emscripten_glEndQueryEXT(target){GLctx.disjointTimerQueryExt["endQueryEXT"](target)}function _emscripten_glEndTransformFeedback(){GLctx["endTransformFeedback"]()}function _emscripten_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}else{return 0}}function _emscripten_glFinish(){GLctx["finish"]()}function _emscripten_glFlush(){GLctx["flush"]()}function emscriptenWebGLGetBufferBinding(target){switch(target){case 34962:target=34964;break;case 34963:target=34965;break;case 35051:target=35053;break;case 35052:target=35055;break;case 35982:target=35983;break;case 36662:target=36662;break;case 36663:target=36663;break;case 35345:target=35368;break}var buffer=GLctx.getParameter(target);if(buffer)return buffer.name|0;else return 0}function emscriptenWebGLValidateMapBufferTarget(target){switch(target){case 34962:case 34963:case 36662:case 36663:case 35051:case 35052:case 35882:case 35982:case 35345:return true;default:return false}}function _emscripten_glFlushMappedBufferRange(target,offset,length){if(!emscriptenWebGLValidateMapBufferTarget(target)){GL.recordError(1280);err("GL_INVALID_ENUM in glFlushMappedBufferRange");return}var mapping=GL.mappedBuffers[emscriptenWebGLGetBufferBinding(target)];if(!mapping){GL.recordError(1282);Module.printError("buffer was never mapped in glFlushMappedBufferRange");return}if(!(mapping.access&16)){GL.recordError(1282);Module.printError("buffer was not mapped with GL_MAP_FLUSH_EXPLICIT_BIT in glFlushMappedBufferRange");return}if(offset<0||length<0||offset+length>mapping.length){GL.recordError(1281);Module.printError("invalid range in glFlushMappedBufferRange");return}GLctx.bufferSubData(target,mapping.offset,HEAPU8.subarray(mapping.mem+offset,mapping.mem+offset+length))}function _emscripten_glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer){GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])}function _emscripten_glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _emscripten_glFramebufferTextureLayer(target,attachment,texture,level,layer){GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)}function _emscripten_glFrontFace(x0){GLctx["frontFace"](x0)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i>2]=id}}function _emscripten_glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _emscripten_glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _emscripten_glGenQueries(n,ids){__glGenObject(n,ids,"createQuery",GL.queries)}function _emscripten_glGenQueriesEXT(n,ids){for(var i=0;i>2]=0;return}var id=GL.getNewId(GL.timerQueriesEXT);query.name=id;GL.timerQueriesEXT[id]=query;HEAP32[ids+i*4>>2]=id}}function _emscripten_glGenRenderbuffers(n,renderbuffers){__glGenObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}function _emscripten_glGenSamplers(n,samplers){__glGenObject(n,samplers,"createSampler",GL.samplers)}function _emscripten_glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _emscripten_glGenTransformFeedbacks(n,ids){__glGenObject(n,ids,"createTransformFeedback",GL.transformFeedbacks)}function _emscripten_glGenVertexArrays(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenVertexArraysOES(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function _emscripten_glGetActiveAttrib(program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx.getActiveAttrib(program,index);if(!info)return;var numBytesWrittenExclNull=bufSize>0&&name?stringToUTF8(info.name,name,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull;if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}function _emscripten_glGetActiveUniform(program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx.getActiveUniform(program,index);if(!info)return;var numBytesWrittenExclNull=bufSize>0&&name?stringToUTF8(info.name,name,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull;if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}function _emscripten_glGetActiveUniformBlockName(program,uniformBlockIndex,bufSize,length,uniformBlockName){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]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>2]=0}}function _emscripten_glGetActiveUniformBlockiv(program,uniformBlockIndex,pname,params){if(!params){GL.recordError(1281);return}program=GL.programs[program];switch(pname){case 35393:var name=GLctx["getActiveUniformBlockName"](program,uniformBlockIndex);HEAP32[params>>2]=name.length+1;return;default:var result=GLctx["getActiveUniformBlockParameter"](program,uniformBlockIndex,pname);if(!result)return;if(typeof result=="number"){HEAP32[params>>2]=result}else{for(var i=0;i>2]=result[i]}}}}function _emscripten_glGetActiveUniformsiv(program,uniformCount,uniformIndices,pname,params){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])}var result=GLctx["getActiveUniforms"](program,ids,pname);if(!result)return;var len=result.length;for(var i=0;i>2]=result[i]}}function _emscripten_glGetAttachedShaders(program,maxCount,count,shaders){var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>2]=len;for(var i=0;i>2]=id}}function _emscripten_glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function 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}var exts=GLctx.getSupportedExtensions()||[];ret=2*exts.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 35097:case 36389: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]=result[i];break;case 2:HEAPF32[p+i*4>>2]=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:tempI64=[ret>>>0,(tempDouble=ret,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[p>>2]=tempI64[0],HEAP32[p+4>>2]=tempI64[1];break;case 0:HEAP32[p>>2]=ret;break;case 2:HEAPF32[p>>2]=ret;break;case 4:HEAP8[p>>0]=ret?1:0;break}}function _emscripten_glGetBooleanv(name_,p){emscriptenWebGLGet(name_,p,4)}function _emscripten_glGetBufferParameteri64v(target,value,data){if(!data){GL.recordError(1281);return}tempI64=[GLctx.getBufferParameter(target,value)>>>0,(tempDouble=GLctx.getBufferParameter(target,value),+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[data>>2]=tempI64[0],HEAP32[data+4>>2]=tempI64[1]}function _emscripten_glGetBufferParameteriv(target,value,data){if(!data){GL.recordError(1281);return}HEAP32[data>>2]=GLctx.getBufferParameter(target,value)}function _emscripten_glGetBufferPointerv(target,pname,params){if(pname==35005){var ptr=0;var mappedBuffer=GL.mappedBuffers[emscriptenWebGLGetBufferBinding(target)];if(mappedBuffer){ptr=mappedBuffer.mem}HEAP32[params>>2]=ptr}else{GL.recordError(1280);err("GL_INVALID_ENUM in glGetBufferPointerv")}}function _emscripten_glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function _emscripten_glGetFloatv(name_,p){emscriptenWebGLGet(name_,p,2)}function _emscripten_glGetFragDataLocation(program,name){return GLctx["getFragDataLocation"](GL.programs[program],UTF8ToString(name))}function _emscripten_glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>2]=result}function 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:tempI64=[ret>>>0,(tempDouble=ret,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[data>>2]=tempI64[0],HEAP32[data+4>>2]=tempI64[1];break;case 0:HEAP32[data>>2]=ret;break;case 2:HEAPF32[data>>2]=ret;break;case 4:HEAP8[data>>0]=ret?1:0;break;default:throw"internal emscriptenWebGLGetIndexed() error, bad type: "+type}}function _emscripten_glGetInteger64i_v(target,index,data){emscriptenWebGLGetIndexed(target,index,data,1)}function _emscripten_glGetInteger64v(name_,p){emscriptenWebGLGet(name_,p,1)}function _emscripten_glGetIntegeri_v(target,index,data){emscriptenWebGLGetIndexed(target,index,data,0)}function _emscripten_glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _emscripten_glGetInternalformativ(target,internalformat,pname,bufSize,params){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]=ret[i]}}function _emscripten_glGetProgramBinary(program,bufSize,length,binaryFormat,binary){GL.recordError(1282)}function _emscripten_glGetProgramInfoLog(program,maxLength,length,infoLog){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]=numBytesWrittenExclNull}function _emscripten_glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}var ptable=GL.programInfos[program];if(!ptable){GL.recordError(1282);return}if(pname==35716){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){HEAP32[p>>2]=ptable.maxUniformLength}else if(pname==35722){if(ptable.maxAttributeLength==-1){program=GL.programs[program];var numAttribs=GLctx.getProgramParameter(program,35721);ptable.maxAttributeLength=0;for(var i=0;i>2]=ptable.maxAttributeLength}else if(pname==35381){if(ptable.maxUniformBlockNameLength==-1){program=GL.programs[program];var numBlocks=GLctx.getProgramParameter(program,35382);ptable.maxUniformBlockNameLength=0;for(var i=0;i>2]=ptable.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(GL.programs[program],pname)}}function _emscripten_glGetQueryObjecti64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}tempI64=[ret>>>0,(tempDouble=ret,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[params>>2]=tempI64[0],HEAP32[params+4>>2]=tempI64[1]}function _emscripten_glGetQueryObjectivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryObjectui64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}tempI64=[ret>>>0,(tempDouble=ret,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[params>>2]=tempI64[0],HEAP32[params+4>>2]=tempI64[1]}function _emscripten_glGetQueryObjectuiv(id,pname,params){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]=ret}function _emscripten_glGetQueryObjectuivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryiv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx["getQuery"](target,pname)}function _emscripten_glGetQueryivEXT(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}function _emscripten_glGetRenderbufferParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getRenderbufferParameter(target,pname)}function _emscripten_glGetSamplerParameterfv(sampler,pname,params){if(!params){GL.recordError(1281);return}sampler=GL.samplers[sampler];HEAPF32[params>>2]=GLctx["getSamplerParameter"](sampler,pname)}function _emscripten_glGetSamplerParameteriv(sampler,pname,params){if(!params){GL.recordError(1281);return}sampler=GL.samplers[sampler];HEAP32[params>>2]=GLctx["getSamplerParameter"](sampler,pname)}function _emscripten_glGetShaderInfoLog(shader,maxLength,length,infoLog){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]=numBytesWrittenExclNull}function _emscripten_glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>2]=result.rangeMin;HEAP32[range+4>>2]=result.rangeMax;HEAP32[precision>>2]=result.precision}function _emscripten_glGetShaderSource(shader,bufSize,length,source){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]=numBytesWrittenExclNull}function _emscripten_glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source===null||source.length==0?0:source.length+1;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function stringToNewUTF8(jsString){var length=lengthBytesUTF8(jsString)+1;var cString=_malloc(length);stringToUTF8(jsString,cString,length);return cString}function _emscripten_glGetString(name_){if(GL.stringCache[name_])return GL.stringCache[name_];var ret;switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);if(GL.currentContext.version>=2)glVersion="OpenGL ES 3.0 ("+glVersion+")";else{glVersion="OpenGL ES 2.0 ("+glVersion+")"}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);return 0}GL.stringCache[name_]=ret;return ret}function _emscripten_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=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));exts=exts.map(function(e){return stringToNewUTF8(e)});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}}function _emscripten_glGetSynciv(sync,pname,bufSize,length,values){if(bufSize<0){GL.recordError(1281);return}if(!values){GL.recordError(1281);return}var ret=GLctx.getSyncParameter(GL.syncs[sync],pname);HEAP32[length>>2]=ret;if(ret!==null&&length)HEAP32[length>>2]=1}function _emscripten_glGetTexParameterfv(target,pname,params){if(!params){GL.recordError(1281);return}HEAPF32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTexParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTransformFeedbackVarying(program,index,bufSize,length,size,type,name){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]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>2]=0}if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}function _emscripten_glGetUniformBlockIndex(program,uniformBlockName){return GLctx["getUniformBlockIndex"](GL.programs[program],UTF8ToString(uniformBlockName))}function _emscripten_glGetUniformIndices(program,uniformCount,uniformNames,uniformIndices){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]));var result=GLctx["getUniformIndices"](program,names);if(!result)return;var len=result.length;for(var i=0;i>2]=result[i]}}function _emscripten_glGetUniformLocation(program,name){name=UTF8ToString(name);var arrayIndex=0;if(name[name.length-1]=="]"){var leftBrace=name.lastIndexOf("[");arrayIndex=name[leftBrace+1]!="]"?parseInt(name.slice(leftBrace+1)):0;name=name.slice(0,leftBrace)}var uniformInfo=GL.programInfos[program]&&GL.programInfos[program].uniforms[name];if(uniformInfo&&arrayIndex>=0&&arrayIndex>2]=data;break;case 2:HEAPF32[params>>2]=data;break;default:throw"internal emscriptenWebGLGetUniform() error, bad type: "+type}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break;default:throw"internal emscriptenWebGLGetUniform() error, bad type: "+type}}}}function _emscripten_glGetUniformfv(program,location,params){emscriptenWebGLGetUniform(program,location,params,2)}function _emscripten_glGetUniformiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function _emscripten_glGetUniformuiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function emscriptenWebGLGetVertexAttrib(index,pname,params,type){if(!params){GL.recordError(1281);return}if(GL.currentContext.clientBuffers[index].enabled){err("glGetVertexAttrib*v on client-side array: not supported, bad data returned")}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>2]=data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>2]=data;break;case 2:HEAPF32[params>>2]=data;break;case 5:HEAP32[params>>2]=Math.fround(data);break;default:throw"internal emscriptenWebGLGetVertexAttrib() error, bad type: "+type}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break;case 5:HEAP32[params+i*4>>2]=Math.fround(data[i]);break;default:throw"internal emscriptenWebGLGetVertexAttrib() error, bad type: "+type}}}}function _emscripten_glGetVertexAttribIiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,0)}function _emscripten_glGetVertexAttribIuiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,0)}function _emscripten_glGetVertexAttribPointerv(index,pname,pointer){if(!pointer){GL.recordError(1281);return}if(GL.currentContext.clientBuffers[index].enabled){err("glGetVertexAttribPointer on client-side array: not supported, bad data returned")}HEAP32[pointer>>2]=GLctx.getVertexAttribOffset(index,pname)}function _emscripten_glGetVertexAttribfv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,2)}function _emscripten_glGetVertexAttribiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,5)}function _emscripten_glHint(x0,x1){GLctx["hint"](x0,x1)}function _emscripten_glInvalidateFramebuffer(target,numAttachments,attachments){var list=__tempFixedLengthArray[numAttachments];for(var i=0;i>2]}GLctx["invalidateFramebuffer"](target,list)}function _emscripten_glInvalidateSubFramebuffer(target,numAttachments,attachments,x,y,width,height){var list=__tempFixedLengthArray[numAttachments];for(var i=0;i>2]}GLctx["invalidateSubFramebuffer"](target,list,x,y,width,height)}function _emscripten_glIsBuffer(buffer){var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)}function _emscripten_glIsEnabled(x0){return GLctx["isEnabled"](x0)}function _emscripten_glIsFramebuffer(framebuffer){var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)}function _emscripten_glIsProgram(program){program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)}function _emscripten_glIsQuery(id){var query=GL.queries[id];if(!query)return 0;return GLctx["isQuery"](query)}function _emscripten_glIsQueryEXT(id){var query=GL.timerQueriesEXT[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)}function _emscripten_glIsRenderbuffer(renderbuffer){var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)}function _emscripten_glIsSampler(id){var sampler=GL.samplers[id];if(!sampler)return 0;return GLctx["isSampler"](sampler)}function _emscripten_glIsShader(shader){var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)}function _emscripten_glIsSync(sync){var sync=GL.syncs[sync];if(!sync)return 0;return GLctx.isSync(sync)}function _emscripten_glIsTexture(id){var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)}function _emscripten_glIsTransformFeedback(id){return GLctx["isTransformFeedback"](GL.transformFeedbacks[id])}function _emscripten_glIsVertexArray(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glIsVertexArrayOES(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glLineWidth(x0){GLctx["lineWidth"](x0)}function _emscripten_glLinkProgram(program){GLctx.linkProgram(GL.programs[program]);GL.populateUniformTable(program)}function _emscripten_glMapBufferRange(target,offset,length,access){if(access!=26&&access!=10){err("glMapBufferRange is only supported when access is MAP_WRITE|INVALIDATE_BUFFER");return 0}if(!emscriptenWebGLValidateMapBufferTarget(target)){GL.recordError(1280);err("GL_INVALID_ENUM in glMapBufferRange");return 0}var mem=_malloc(length);if(!mem)return 0;GL.mappedBuffers[emscriptenWebGLGetBufferBinding(target)]={offset:offset,length:length,mem:mem,access:access};return mem}function _emscripten_glPauseTransformFeedback(){GLctx["pauseTransformFeedback"]()}function _emscripten_glPixelStorei(pname,param){if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)}function _emscripten_glPolygonOffset(x0,x1){GLctx["polygonOffset"](x0,x1)}function _emscripten_glProgramBinary(program,binaryFormat,binary,length){GL.recordError(1280)}function _emscripten_glProgramParameteri(program,pname,value){GL.recordError(1280)}function _emscripten_glQueryCounterEXT(id,target){GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.timerQueriesEXT[id],target)}function _emscripten_glReadBuffer(x0){GLctx["readBuffer"](x0)}function __computeUnpackAlignedImageSize(width,height,sizePerPixel,alignment){function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize}function __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}function __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}function __heapAccessShiftForWebGLHeap(heap){return 31-Math.clz32(heap.BYTES_PER_ELEMENT)}function emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat){var heap=__heapObjectForWebGLType(type);var shift=__heapAccessShiftForWebGLHeap(heap);var byteSize=1<>shift,pixels+bytes>>shift)}function _emscripten_glReadPixels(x,y,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=__heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}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)}function _emscripten_glReleaseShaderCompiler(){}function _emscripten_glRenderbufferStorage(x0,x1,x2,x3){GLctx["renderbufferStorage"](x0,x1,x2,x3)}function _emscripten_glRenderbufferStorageMultisample(x0,x1,x2,x3,x4){GLctx["renderbufferStorageMultisample"](x0,x1,x2,x3,x4)}function _emscripten_glResumeTransformFeedback(){GLctx["resumeTransformFeedback"]()}function _emscripten_glSampleCoverage(value,invert){GLctx.sampleCoverage(value,!!invert)}function _emscripten_glSamplerParameterf(sampler,pname,param){GLctx["samplerParameterf"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameterfv(sampler,pname,params){var param=HEAPF32[params>>2];GLctx["samplerParameterf"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameteri(sampler,pname,param){GLctx["samplerParameteri"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameteriv(sampler,pname,params){var param=HEAP32[params>>2];GLctx["samplerParameteri"](GL.samplers[sampler],pname,param)}function _emscripten_glScissor(x0,x1,x2,x3){GLctx["scissor"](x0,x1,x2,x3)}function _emscripten_glShaderBinary(){GL.recordError(1280)}function _emscripten_glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _emscripten_glStencilFunc(x0,x1,x2){GLctx["stencilFunc"](x0,x1,x2)}function _emscripten_glStencilFuncSeparate(x0,x1,x2,x3){GLctx["stencilFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glStencilMask(x0){GLctx["stencilMask"](x0)}function _emscripten_glStencilMaskSeparate(x0,x1){GLctx["stencilMaskSeparate"](x0,x1)}function _emscripten_glStencilOp(x0,x1,x2){GLctx["stencilOp"](x0,x1,x2)}function _emscripten_glStencilOpSeparate(x0,x1,x2,x3){GLctx["stencilOpSeparate"](x0,x1,x2,x3)}function _emscripten_glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _emscripten_glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,null)}}function _emscripten_glTexParameterf(x0,x1,x2){GLctx["texParameterf"](x0,x1,x2)}function _emscripten_glTexParameterfv(target,pname,params){var param=HEAPF32[params>>2];GLctx.texParameterf(target,pname,param)}function _emscripten_glTexParameteri(x0,x1,x2){GLctx["texParameteri"](x0,x1,x2)}function _emscripten_glTexParameteriv(target,pname,params){var param=HEAP32[params>>2];GLctx.texParameteri(target,pname,param)}function _emscripten_glTexStorage2D(x0,x1,x2,x3,x4){GLctx["texStorage2D"](x0,x1,x2,x3,x4)}function _emscripten_glTexStorage3D(x0,x1,x2,x3,x4,x5){GLctx["texStorage3D"](x0,x1,x2,x3,x4,x5)}function _emscripten_glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _emscripten_glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){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,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}function _emscripten_glTransformFeedbackVaryings(program,count,varyings,bufferMode){program=GL.programs[program];var vars=[];for(var i=0;i>2]));GLctx["transformFeedbackVaryings"](program,vars,bufferMode)}function _emscripten_glUniform1f(location,v0){GLctx.uniform1f(GL.uniforms[location],v0)}function _emscripten_glUniform1fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform1fv(GL.uniforms[location],HEAPF32,value>>2,count);return}if(count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[count-1];for(var i=0;i>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1fv(GL.uniforms[location],view)}function _emscripten_glUniform1i(location,v0){GLctx.uniform1i(GL.uniforms[location],v0)}function _emscripten_glUniform1iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform1iv(GL.uniforms[location],HEAP32,value>>2,count);return}if(count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[count-1];for(var i=0;i>2]}}else{var view=HEAP32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1iv(GL.uniforms[location],view)}function _emscripten_glUniform1ui(location,v0){GLctx.uniform1ui(GL.uniforms[location],v0)}function _emscripten_glUniform1uiv(location,count,value){GLctx.uniform1uiv(GL.uniforms[location],HEAPU32,value>>2,count)}function _emscripten_glUniform2f(location,v0,v1){GLctx.uniform2f(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform2fv(GL.uniforms[location],HEAPF32,value>>2,count*2);return}if(2*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(GL.uniforms[location],view)}function _emscripten_glUniform2i(location,v0,v1){GLctx.uniform2i(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform2iv(GL.uniforms[location],HEAP32,value>>2,count*2);return}if(2*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2iv(GL.uniforms[location],view)}function _emscripten_glUniform2ui(location,v0,v1){GLctx.uniform2ui(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2uiv(location,count,value){GLctx.uniform2uiv(GL.uniforms[location],HEAPU32,value>>2,count*2)}function _emscripten_glUniform3f(location,v0,v1,v2){GLctx.uniform3f(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform3fv(GL.uniforms[location],HEAPF32,value>>2,count*3);return}if(3*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3fv(GL.uniforms[location],view)}function _emscripten_glUniform3i(location,v0,v1,v2){GLctx.uniform3i(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform3iv(GL.uniforms[location],HEAP32,value>>2,count*3);return}if(3*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3iv(GL.uniforms[location],view)}function _emscripten_glUniform3ui(location,v0,v1,v2){GLctx.uniform3ui(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3uiv(location,count,value){GLctx.uniform3uiv(GL.uniforms[location],HEAPU32,value>>2,count*3)}function _emscripten_glUniform4f(location,v0,v1,v2,v3){GLctx.uniform4f(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4fv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform4fv(GL.uniforms[location],HEAPF32,value>>2,count*4);return}if(4*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(GL.uniforms[location],view)}function _emscripten_glUniform4i(location,v0,v1,v2,v3){GLctx.uniform4i(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4iv(location,count,value){if(GL.currentContext.version>=2){GLctx.uniform4iv(GL.uniforms[location],HEAP32,value>>2,count*4);return}if(4*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferIntViews[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(GL.uniforms[location],view)}function _emscripten_glUniform4ui(location,v0,v1,v2,v3){GLctx.uniform4ui(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4uiv(location,count,value){GLctx.uniform4uiv(GL.uniforms[location],HEAPU32,value>>2,count*4)}function _emscripten_glUniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding){program=GL.programs[program];GLctx["uniformBlockBinding"](program,uniformBlockIndex,uniformBlockBinding)}function _emscripten_glUniformMatrix2fv(location,count,transpose,value){if(GL.currentContext.version>=2){GLctx.uniformMatrix2fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*4);return}if(4*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniformMatrix2fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix2x3fv(location,count,transpose,value){GLctx.uniformMatrix2x3fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*6)}function _emscripten_glUniformMatrix2x4fv(location,count,transpose,value){GLctx.uniformMatrix2x4fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*8)}function _emscripten_glUniformMatrix3fv(location,count,transpose,value){if(GL.currentContext.version>=2){GLctx.uniformMatrix3fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*9);return}if(9*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[9*count-1];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*36>>2)}GLctx.uniformMatrix3fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix3x2fv(location,count,transpose,value){GLctx.uniformMatrix3x2fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*6)}function _emscripten_glUniformMatrix3x4fv(location,count,transpose,value){GLctx.uniformMatrix3x4fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*12)}function _emscripten_glUniformMatrix4fv(location,count,transpose,value){if(GL.currentContext.version>=2){GLctx.uniformMatrix4fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*16);return}if(16*count<=GL.MINI_TEMP_BUFFER_SIZE){var view=GL.miniTempBufferFloatViews[16*count-1];for(var i=0;i<16*count;i+=16){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2];view[i+9]=HEAPF32[value+(4*i+36)>>2];view[i+10]=HEAPF32[value+(4*i+40)>>2];view[i+11]=HEAPF32[value+(4*i+44)>>2];view[i+12]=HEAPF32[value+(4*i+48)>>2];view[i+13]=HEAPF32[value+(4*i+52)>>2];view[i+14]=HEAPF32[value+(4*i+56)>>2];view[i+15]=HEAPF32[value+(4*i+60)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix4x2fv(location,count,transpose,value){GLctx.uniformMatrix4x2fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*8)}function _emscripten_glUniformMatrix4x3fv(location,count,transpose,value){GLctx.uniformMatrix4x3fv(GL.uniforms[location],!!transpose,HEAPF32,value>>2,count*12)}function _emscripten_glUnmapBuffer(target){if(!emscriptenWebGLValidateMapBufferTarget(target)){GL.recordError(1280);err("GL_INVALID_ENUM in glUnmapBuffer");return 0}var buffer=emscriptenWebGLGetBufferBinding(target);var mapping=GL.mappedBuffers[buffer];if(!mapping){GL.recordError(1282);Module.printError("buffer was never mapped in glUnmapBuffer");return 0}GL.mappedBuffers[buffer]=null;if(!(mapping.access&16))if(GL.currentContext.version>=2){GLctx.bufferSubData(target,mapping.offset,HEAPU8,mapping.mem,mapping.length)}else{GLctx.bufferSubData(target,mapping.offset,HEAPU8.subarray(mapping.mem,mapping.mem+mapping.length))}_free(mapping.mem);return 1}function _emscripten_glUseProgram(program){GLctx.useProgram(GL.programs[program])}function _emscripten_glValidateProgram(program){GLctx.validateProgram(GL.programs[program])}function _emscripten_glVertexAttrib1f(x0,x1){GLctx["vertexAttrib1f"](x0,x1)}function _emscripten_glVertexAttrib1fv(index,v){GLctx.vertexAttrib1f(index,HEAPF32[v>>2])}function _emscripten_glVertexAttrib2f(x0,x1,x2){GLctx["vertexAttrib2f"](x0,x1,x2)}function _emscripten_glVertexAttrib2fv(index,v){GLctx.vertexAttrib2f(index,HEAPF32[v>>2],HEAPF32[v+4>>2])}function _emscripten_glVertexAttrib3f(x0,x1,x2,x3){GLctx["vertexAttrib3f"](x0,x1,x2,x3)}function _emscripten_glVertexAttrib3fv(index,v){GLctx.vertexAttrib3f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2])}function _emscripten_glVertexAttrib4f(x0,x1,x2,x3,x4){GLctx["vertexAttrib4f"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttrib4fv(index,v){GLctx.vertexAttrib4f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2],HEAPF32[v+12>>2])}function _emscripten_glVertexAttribDivisor(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorANGLE(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorARB(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorEXT(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorNV(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribI4i(x0,x1,x2,x3,x4){GLctx["vertexAttribI4i"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttribI4iv(index,v){GLctx.vertexAttribI4i(index,HEAP32[v>>2],HEAP32[v+4>>2],HEAP32[v+8>>2],HEAP32[v+12>>2])}function _emscripten_glVertexAttribI4ui(x0,x1,x2,x3,x4){GLctx["vertexAttribI4ui"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttribI4uiv(index,v){GLctx.vertexAttribI4ui(index,HEAPU32[v>>2],HEAPU32[v+4>>2],HEAPU32[v+8>>2],HEAPU32[v+12>>2])}function _emscripten_glVertexAttribIPointer(index,size,type,stride,ptr){var cb=GL.currentContext.clientBuffers[index];if(!GL.currArrayBuffer){cb.size=size;cb.type=type;cb.normalized=false;cb.stride=stride;cb.ptr=ptr;cb.clientside=true;cb.vertexAttribPointerAdaptor=function(index,size,type,normalized,stride,ptr){this.vertexAttribIPointer(index,size,type,stride,ptr)};return}cb.clientside=false;GLctx["vertexAttribIPointer"](index,size,type,stride,ptr)}function _emscripten_glVertexAttribPointer(index,size,type,normalized,stride,ptr){var cb=GL.currentContext.clientBuffers[index];if(!GL.currArrayBuffer){cb.size=size;cb.type=type;cb.normalized=normalized;cb.stride=stride;cb.ptr=ptr;cb.clientside=true;cb.vertexAttribPointerAdaptor=function(index,size,type,normalized,stride,ptr){this.vertexAttribPointer(index,size,type,normalized,stride,ptr)};return}cb.clientside=false;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _emscripten_glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}function _emscripten_glWaitSync(sync,flags,timeoutLo,timeoutHi){timeoutLo=timeoutLo>>>0;timeoutHi=timeoutHi>>>0;var timeout=timeoutLo==4294967295&&timeoutHi==4294967295?-1:makeBigInt(timeoutLo,timeoutHi,true);GLctx.waitSync(GL.syncs[sync],flags,timeout)}var IDBStore={indexedDB:function(){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:function(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=function(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=function(){db=req.result;IDBStore.dbs[name]=db;callback(null,db)};req.onerror=function(e){callback(this.error);e.preventDefault()}},getStore:function(dbName,type,callback){IDBStore.getDB(dbName,function(error,db){if(error)return callback(error);var transaction=db.transaction([IDBStore.DB_STORE_NAME],type);transaction.onerror=function(e){callback(this.error||"unknown error");e.preventDefault()};var store=transaction.objectStore(IDBStore.DB_STORE_NAME);callback(null,store)})},getFile:function(dbName,id,callback){IDBStore.getStore(dbName,"readonly",function(err,store){if(err)return callback(err);var req=store.get(id);req.onsuccess=function(event){var result=event.target.result;if(!result){return callback("file "+id+" not found")}else{return callback(null,result)}};req.onerror=function(error){callback(error)}})},setFile:function(dbName,id,data,callback){IDBStore.getStore(dbName,"readwrite",function(err,store){if(err)return callback(err);var req=store.put(data,id);req.onsuccess=function(event){callback()};req.onerror=function(error){callback(error)}})},deleteFile:function(dbName,id,callback){IDBStore.getStore(dbName,"readwrite",function(err,store){if(err)return callback(err);var req=store.delete(id);req.onsuccess=function(event){callback()};req.onerror=function(error){callback(error)}})},existsFile:function(dbName,id,callback){IDBStore.getStore(dbName,"readonly",function(err,store){if(err)return callback(err);var req=store.count(id);req.onsuccess=function(event){callback(null,event.target.result>0)};req.onerror=function(error){callback(error)}})}};function _emscripten_idb_async_delete(db,id,arg,ondelete,onerror){IDBStore.deleteFile(UTF8ToString(db),UTF8ToString(id),function(error){if(error){if(onerror)dynCall_vi(onerror,arg);return}if(ondelete)dynCall_vi(ondelete,arg)})}function _emscripten_idb_async_exists(db,id,arg,oncheck,onerror){IDBStore.existsFile(UTF8ToString(db),UTF8ToString(id),function(error,exists){if(error){if(onerror)dynCall_vi(onerror,arg);return}if(oncheck)dynCall_vii(oncheck,arg,exists)})}function _emscripten_idb_async_load(db,id,arg,onload,onerror){IDBStore.getFile(UTF8ToString(db),UTF8ToString(id),function(error,byteArray){if(error){if(onerror)dynCall_vi(onerror,arg);return}var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer);dynCall_viii(onload,arg,buffer,byteArray.length);_free(buffer)})}function _emscripten_idb_async_store(db,id,ptr,num,arg,onstore,onerror){IDBStore.setFile(UTF8ToString(db),UTF8ToString(id),new Uint8Array(HEAPU8.subarray(ptr,ptr+num)),function(error){if(error){if(onerror)dynCall_vi(onerror,arg);return}if(onstore)dynCall_vi(onstore,arg)})}function _emscripten_is_webgl_context_lost(target){return!GL.contexts[target]||GL.contexts[target].GLctx.isContextLost()}function __reallyNegative(x){return x<0||x===0&&1/x===-Infinity}function __formatString(format,varargs){assert((varargs&3)===0);var textIndex=format;var argIndex=varargs;function prepVararg(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){assert((ptr&7)===4);ptr+=4}}else{assert((ptr&3)===0)}return ptr}function getNextArg(type){var ret;argIndex=prepVararg(argIndex,type);if(type==="double"){ret=HEAPF64[argIndex>>3];argIndex+=8}else if(type=="i64"){ret=[HEAP32[argIndex>>2],HEAP32[argIndex+4>>2]];argIndex+=8}else{assert((argIndex&3)===0);type="i32";ret=HEAP32[argIndex>>2];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=makeBigInt(currArg[0],currArg[1],next==117)}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,1).toString(10)}else if(next==117){argText=unSign(currArg,8*argSize,1).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.lengthexponent&&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].indexOf(".")!=-1&&(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.length>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]=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 __emscripten_traverse_stack(args){if(!args||!args.callee||!args.callee.name){return[null,"",""]}var funstr=args.callee.toString();var funcname=args.callee.name;var str="(";var first=true;for(var i in args){var a=args[i];if(!first){str+=", "}first=false;if(typeof a==="number"||typeof a==="string"){str+=a}else{str+="("+typeof a+")"}}str+=")";var caller=args.callee.caller;args=caller?caller.arguments:[];if(first)str="";return[args,funcname,str]}function _emscripten_get_callstack_js(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 stack_args=null;if(flags&128){stack_args=__emscripten_traverse_stack(arguments);while(stack_args[1].indexOf("_emscripten_")>=0)stack_args=__emscripten_traverse_stack(stack_args[0])}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 jsSymbolName="";var file="";var lineno=0;var column=0;var parts=chromeRe.exec(line);if(parts&&parts.length==5){jsSymbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]}else{parts=newFirefoxRe.exec(line);if(!parts)parts=firefoxRe.exec(line);if(parts&&parts.length>=4){jsSymbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]|0}else{callstack+=line+"\n";continue}}var cSymbolName=flags&32?demangle(jsSymbolName):jsSymbolName;if(!cSymbolName){cSymbolName=jsSymbolName}var haveSourceMap=false;if(flags&8){var orig=emscripten_source_map.originalPositionFor({line:lineno,column:column});haveSourceMap=orig&&orig.source;if(haveSourceMap){if(flags&64){orig.source=orig.source.substring(orig.source.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=" at "+cSymbolName+" ("+orig.source+":"+orig.line+":"+orig.column+")\n"}}if(flags&16||!haveSourceMap){if(flags&64){file=file.substring(file.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=(haveSourceMap?" = "+jsSymbolName:" at "+cSymbolName)+" ("+file+":"+lineno+":"+column+")\n"}if(flags&128&&stack_args[0]){if(stack_args[1]==jsSymbolName&&stack_args[2].length>0){callstack=callstack.replace(/\s+$/,"");callstack+=" with values: "+stack_args[1]+stack_args[2]+"\n"}stack_args=__emscripten_traverse_stack(stack_args[0])}}callstack=callstack.replace(/\s+$/,"");return callstack}function _emscripten_log_js(flags,str){if(flags&24){str=str.replace(/\s+$/,"");str+=(str.length>0?"\n":"")+_emscripten_get_callstack_js(flags)}if(flags&1){if(flags&4){console.error(str)}else if(flags&2){console.warn(str)}else{console.log(str)}}else if(flags&6){err(str)}else{out(str)}}function _emscripten_log(flags,varargs){var format=HEAP32[varargs>>2];varargs+=4;var str="";if(format){var result=__formatString(format,varargs);for(var i=0;i>2]=setjmpId;while((i|0)<(size|0)){if((HEAP32[table+(i<<3)>>2]|0)==0){HEAP32[table+(i<<3)>>2]=setjmpId;HEAP32[table+((i<<3)+4)>>2]=label;HEAP32[table+((i<<3)+8)>>2]=0;setTempRet0(size|0);return table|0}i=i+1|0}size=size*2|0;table=_realloc(table|0,8*(size+1|0)|0)|0;table=_saveSetjmp(env|0,label|0,table|0,size|0)|0;setTempRet0(size|0);return table|0}function _testSetjmp(id,table,size){id=id|0;table=table|0;size=size|0;var i=0,curr=0;while((i|0)<(size|0)){curr=HEAP32[table+(i<<3)>>2]|0;if((curr|0)==0)break;if((curr|0)==(id|0)){return HEAP32[table+((i<<3)+4)>>2]|0}i=i+1|0}return 0}function _longjmp(env,value){_setThrew(env,value||1);throw"longjmp"}function _emscripten_longjmp(env,value){_longjmp(env,value)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function _emscripten_pause_main_loop(){Browser.mainLoop.pause()}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var maxHeapSize=2147483648-PAGE_MULTIPLE;if(requestedSize>maxHeapSize){return false}var minHeapSize=16777216;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,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),PAGE_MULTIPLE));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}function _emscripten_resume_main_loop(){Browser.mainLoop.resume()}function __registerFocusEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.focusEvent)JSEvents.focusEvent=_malloc(256);var focusEventHandlerFunc=function(ev){var e=ev||event;var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(dynCall_iiii(callbackfunc,eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:__findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread);return 0}function __registerKeyEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.keyEvent)JSEvents.keyEvent=_malloc(164);var keyEventHandlerFunc=function(ev){var e=ev||event;var keyEventData=JSEvents.keyEvent;stringToUTF8(e.key?e.key:"",keyEventData+0,32);stringToUTF8(e.code?e.code:"",keyEventData+32,32);HEAP32[keyEventData+64>>2]=e.location;HEAP32[keyEventData+68>>2]=e.ctrlKey;HEAP32[keyEventData+72>>2]=e.shiftKey;HEAP32[keyEventData+76>>2]=e.altKey;HEAP32[keyEventData+80>>2]=e.metaKey;HEAP32[keyEventData+84>>2]=e.repeat;stringToUTF8(e.locale?e.locale:"",keyEventData+88,32);stringToUTF8(e.char?e.char:"",keyEventData+120,32);HEAP32[keyEventData+152>>2]=e.charCode;HEAP32[keyEventData+156>>2]=e.keyCode;HEAP32[keyEventData+160>>2]=e.which;if(dynCall_iiii(callbackfunc,eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:__findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread);return 0}function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread);return 0}function _emscripten_set_main_loop_arg(func,arg,fps,simulateInfiniteLoop){_emscripten_set_main_loop(func,fps,simulateInfiniteLoop,arg)}function __fillMouseEventData(eventStruct,e,target){HEAP32[eventStruct>>2]=e.screenX;HEAP32[eventStruct+4>>2]=e.screenY;HEAP32[eventStruct+8>>2]=e.clientX;HEAP32[eventStruct+12>>2]=e.clientY;HEAP32[eventStruct+16>>2]=e.ctrlKey;HEAP32[eventStruct+20>>2]=e.shiftKey;HEAP32[eventStruct+24>>2]=e.altKey;HEAP32[eventStruct+28>>2]=e.metaKey;HEAP16[eventStruct+32>>1]=e.button;HEAP16[eventStruct+34>>1]=e.buttons;var movementX=e["movementX"]||e.screenX-JSEvents.previousScreenX;var movementY=e["movementY"]||e.screenY-JSEvents.previousScreenY;HEAP32[eventStruct+36>>2]=movementX;HEAP32[eventStruct+40>>2]=movementY;var rect=__specialEventTargets.indexOf(target)<0?__getBoundingClientRect(target):{"left":0,"top":0};HEAP32[eventStruct+44>>2]=e.clientX-rect.left;HEAP32[eventStruct+48>>2]=e.clientY-rect.top;if(e.type!=="wheel"&&e.type!=="mousewheel"){JSEvents.previousScreenX=e.screenX;JSEvents.previousScreenY=e.screenY}}function __registerMouseEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.mouseEvent)JSEvents.mouseEvent=_malloc(64);target=__findEventTarget(target);var mouseEventHandlerFunc=function(ev){var e=ev||event;__fillMouseEventData(JSEvents.mouseEvent,e,target);if(dynCall_iiii(callbackfunc,eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread);return 0}function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread);return 0}function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread);return 0}function __registerUiEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.uiEvent)JSEvents.uiEvent=_malloc(36);target=__findEventTarget(target);var uiEventHandlerFunc=function(ev){var e=ev||event;if(e.target!=target){return}var uiEvent=JSEvents.uiEvent;var b=document.body;HEAP32[uiEvent>>2]=e.detail;HEAP32[uiEvent+4>>2]=b.clientWidth;HEAP32[uiEvent+8>>2]=b.clientHeight;HEAP32[uiEvent+12>>2]=innerWidth;HEAP32[uiEvent+16>>2]=innerHeight;HEAP32[uiEvent+20>>2]=outerWidth;HEAP32[uiEvent+24>>2]=outerHeight;HEAP32[uiEvent+28>>2]=pageXOffset;HEAP32[uiEvent+32>>2]=pageYOffset;if(dynCall_iiii(callbackfunc,eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",targetThread);return 0}function __registerTouchEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.touchEvent)JSEvents.touchEvent=_malloc(1684);target=__findEventTarget(target);var touchEventHandlerFunc=function(ev){var e=ev||event;var touches={};for(var i=0;i>2]=e.ctrlKey;HEAP32[ptr+8>>2]=e.shiftKey;HEAP32[ptr+12>>2]=e.altKey;HEAP32[ptr+16>>2]=e.metaKey;ptr+=20;var targetRect=__getBoundingClientRect(target);var numTouches=0;for(var i in touches){var t=touches[i];HEAP32[ptr>>2]=t.identifier;HEAP32[ptr+4>>2]=t.screenX;HEAP32[ptr+8>>2]=t.screenY;HEAP32[ptr+12>>2]=t.clientX;HEAP32[ptr+16>>2]=t.clientY;HEAP32[ptr+20>>2]=t.pageX;HEAP32[ptr+24>>2]=t.pageY;HEAP32[ptr+28>>2]=t.changed;HEAP32[ptr+32>>2]=t.onTarget;HEAP32[ptr+36>>2]=t.clientX-targetRect.left;HEAP32[ptr+40>>2]=t.clientY-targetRect.top;ptr+=52;if(++numTouches>=32){break}}HEAP32[touchEvent>>2]=numTouches;if(dynCall_iiii(callbackfunc,eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_touchcancel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,25,"touchcancel",targetThread);return 0}function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread);return 0}function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread);return 0}function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread);return 0}function __registerWheelEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.wheelEvent)JSEvents.wheelEvent=_malloc(96);var wheelHandlerFunc=function(ev){var e=ev||event;var wheelEvent=JSEvents.wheelEvent;__fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+64>>3]=e["deltaX"];HEAPF64[wheelEvent+72>>3]=e["deltaY"];HEAPF64[wheelEvent+80>>3]=e["deltaZ"];HEAP32[wheelEvent+88>>2]=e["deltaMode"];if(dynCall_iiii(callbackfunc,eventTypeId,wheelEvent,userData))e.preventDefault()};var mouseWheelHandlerFunc=function(ev){var e=ev||event;__fillMouseEventData(JSEvents.wheelEvent,e,target);HEAPF64[JSEvents.wheelEvent+64>>3]=e["wheelDeltaX"]||0;var wheelDeltaY=-(e["wheelDeltaY"]||e["wheelDelta"]);HEAPF64[JSEvents.wheelEvent+72>>3]=wheelDeltaY;HEAPF64[JSEvents.wheelEvent+80>>3]=0;HEAP32[JSEvents.wheelEvent+88>>2]=0;var shouldCancel=dynCall_iiii(callbackfunc,eventTypeId,JSEvents.wheelEvent,userData);if(shouldCancel){e.preventDefault()}};var eventHandler={target:target,allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:eventTypeString=="wheel"?wheelHandlerFunc:mouseWheelHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target=__findEventTarget(target);if(typeof target.onwheel!=="undefined"){__registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread);return 0}else if(typeof target.onmousewheel!=="undefined"){__registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"mousewheel",targetThread);return 0}else{return-1}}function _emscripten_sleep(){throw"Please compile your program with async support in order to use asynchronous operations like emscripten_sleep"}var __emscripten_webgl_power_preferences=["default","low-power","high-performance"];function __findCanvasEventTarget(target){return __findEventTarget(target)}function _emscripten_webgl_do_create_context(target,attributes){var contextAttributes={};var a=attributes>>2;contextAttributes["alpha"]=!!HEAP32[a+(0>>2)];contextAttributes["depth"]=!!HEAP32[a+(4>>2)];contextAttributes["stencil"]=!!HEAP32[a+(8>>2)];contextAttributes["antialias"]=!!HEAP32[a+(12>>2)];contextAttributes["premultipliedAlpha"]=!!HEAP32[a+(16>>2)];contextAttributes["preserveDrawingBuffer"]=!!HEAP32[a+(20>>2)];var powerPreference=HEAP32[a+(24>>2)];contextAttributes["powerPreference"]=__emscripten_webgl_power_preferences[powerPreference];contextAttributes["failIfMajorPerformanceCaveat"]=!!HEAP32[a+(28>>2)];contextAttributes.majorVersion=HEAP32[a+(32>>2)];contextAttributes.minorVersion=HEAP32[a+(36>>2)];contextAttributes.enableExtensionsByDefault=HEAP32[a+(40>>2)];contextAttributes.explicitSwapControl=HEAP32[a+(44>>2)];contextAttributes.proxyContextToMainThread=HEAP32[a+(48>>2)];contextAttributes.renderViaOffscreenBackBuffer=HEAP32[a+(52>>2)];var canvas=__findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}function _emscripten_webgl_create_context(a0,a1){return _emscripten_webgl_do_create_context(a0,a1)}function _emscripten_webgl_destroy_context_calling_thread(contextHandle){if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}function _emscripten_webgl_destroy_context(a0){return _emscripten_webgl_destroy_context_calling_thread(a0)}function _emscripten_webgl_init_context_attributes(attributes){var a=attributes>>2;for(var i=0;i<56>>2;++i){HEAP32[a+i]=0}HEAP32[a+(0>>2)]=HEAP32[a+(4>>2)]=HEAP32[a+(12>>2)]=HEAP32[a+(16>>2)]=HEAP32[a+(32>>2)]=HEAP32[a+(40>>2)]=1}function _emscripten_webgl_make_context_current(contextHandle){var success=GL.makeContextCurrent(contextHandle);return success?0:-5}Module["_emscripten_webgl_make_context_current"]=_emscripten_webgl_make_context_current;var ENV={};function _emscripten_get_environ(){if(!_emscripten_get_environ.strings){var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8","_":thisProgram};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}_emscripten_get_environ.strings=strings}return _emscripten_get_environ.strings}function _environ_get(__environ,environ_buf){var strings=_emscripten_get_environ();var bufSize=0;strings.forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=_emscripten_get_environ();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _exit(status){exit(status)}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_fdstat_get(fd,pbuf){try{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;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops&&stream.stream_ops.fsync){return-stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _flock(fd,operation){return 0}function _getTempRet0(){return getTempRet0()|0}function _getpagesize(){return 16384}function _getpwnam(){throw"getpwnam: TODO"}function _gettimeofday(ptr){var now=Date.now();HEAP32[ptr>>2]=now/1e3|0;HEAP32[ptr+4>>2]=now%1e3*1e3|0;return 0}function _glActiveTexture(x0){GLctx["activeTexture"](x0)}function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,imageSize,data)}else{GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,HEAPU8,data,imageSize)}return}GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,imageSize,data)}else{GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,HEAPU8,data,imageSize)}return}GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=__heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>__heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}var ERRNO_CODES={EPERM:63,ENOENT:44,ESRCH:71,EINTR:27,EIO:29,ENXIO:60,E2BIG:1,ENOEXEC:45,EBADF:8,ECHILD:12,EAGAIN:6,EWOULDBLOCK:6,ENOMEM:48,EACCES:2,EFAULT:21,ENOTBLK:105,EBUSY:10,EEXIST:20,EXDEV:75,ENODEV:43,ENOTDIR:54,EISDIR:31,EINVAL:28,ENFILE:41,EMFILE:33,ENOTTY:59,ETXTBSY:74,EFBIG:22,ENOSPC:51,ESPIPE:70,EROFS:69,EMLINK:34,EPIPE:64,EDOM:18,ERANGE:68,ENOMSG:49,EIDRM:24,ECHRNG:106,EL2NSYNC:156,EL3HLT:107,EL3RST:108,ELNRNG:109,EUNATCH:110,ENOCSI:111,EL2HLT:112,EDEADLK:16,ENOLCK:46,EBADE:113,EBADR:114,EXFULL:115,ENOANO:104,EBADRQC:103,EBADSLT:102,EDEADLOCK:16,EBFONT:101,ENOSTR:100,ENODATA:116,ETIME:117,ENOSR:118,ENONET:119,ENOPKG:120,EREMOTE:121,ENOLINK:47,EADV:122,ESRMNT:123,ECOMM:124,EPROTO:65,EMULTIHOP:36,EDOTDOT:125,EBADMSG:9,ENOTUNIQ:126,EBADFD:127,EREMCHG:128,ELIBACC:129,ELIBBAD:130,ELIBSCN:131,ELIBMAX:132,ELIBEXEC:133,ENOSYS:52,ENOTEMPTY:55,ENAMETOOLONG:37,ELOOP:32,EOPNOTSUPP:138,EPFNOSUPPORT:139,ECONNRESET:15,ENOBUFS:42,EAFNOSUPPORT:5,EPROTOTYPE:67,ENOTSOCK:57,ENOPROTOOPT:50,ESHUTDOWN:140,ECONNREFUSED:14,EADDRINUSE:3,ECONNABORTED:13,ENETUNREACH:40,ENETDOWN:38,ETIMEDOUT:73,EHOSTDOWN:142,EHOSTUNREACH:23,EINPROGRESS:26,EALREADY:7,EDESTADDRREQ:17,EMSGSIZE:35,EPROTONOSUPPORT:66,ESOCKTNOSUPPORT:137,EADDRNOTAVAIL:4,ENETRESET:39,EISCONN:30,ENOTCONN:53,ETOOMANYREFS:141,EUSERS:136,EDQUOT:19,ESTALE:72,ENOTSUP:138,ENOMEDIUM:148,EILSEQ:25,EOVERFLOW:61,ECANCELED:11,ENOTRECOVERABLE:56,EOWNERDEAD:62,ESTRPIPE:135};function _kill(pid,sig){___setErrNo(ERRNO_CODES.EPERM);return-1}var ___tm_current=8509072;var ___tm_timezone=(stringToUTF8("GMT",8509120,4),8509120);function _tzset(){if(_tzset.called)return;_tzset.called=true;HEAP32[__get_timezone()>>2]=(new Date).getTimezoneOffset()*60;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);HEAP32[__get_daylight()>>2]=Number(winter.getTimezoneOffset()!=summer.getTimezoneOffset());function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=allocate(intArrayFromString(winterName),"i8",ALLOC_NORMAL);var summerNamePtr=allocate(intArrayFromString(summerName),"i8",ALLOC_NORMAL);if(summer.getTimezoneOffset()>2]=winterNamePtr;HEAP32[__get_tzname()+4>>2]=summerNamePtr}else{HEAP32[__get_tzname()>>2]=summerNamePtr;HEAP32[__get_tzname()+4>>2]=winterNamePtr}}function _localtime_r(time,tmPtr){_tzset();var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var start=new Date(date.getFullYear(),0,1);var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);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]=dst;var zonePtr=HEAP32[__get_tzname()+(dst?4:0)>>2];HEAP32[tmPtr+40>>2]=zonePtr;return tmPtr}function _localtime(time){return _localtime_r(time,___tm_current)}function _mktime(tmPtr){_tzset();var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];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]=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]=date.getDay();var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;return date.getTime()/1e3|0}function _usleep(useconds){var msec=useconds/1e3;if((ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&self["performance"]&&self["performance"]["now"]){var start=self["performance"]["now"]();while(self["performance"]["now"]()-start>2];var nanoseconds=HEAP32[rqtp+4>>2];if(nanoseconds<0||nanoseconds>999999999||seconds<0){___setErrNo(28);return-1}if(rmtp!==0){HEAP32[rmtp>>2]=0;HEAP32[rmtp+4>>2]=0}return _usleep(seconds*1e6+nanoseconds/1e3)}function _fpathconf(fildes,name){switch(name){case 0:return 32e3;case 1:case 2:case 3:return 255;case 4:case 5:case 16:case 17:case 18:return 4096;case 6:case 7:case 20:return 1;case 8:return 0;case 9:case 10:case 11:case 12:case 14:case 15:case 19:return-1;case 13:return 64}___setErrNo(28);return-1}function _pathconf(){return _fpathconf.apply(null,arguments)}function _round(d){d=+d;return d>=+0?+Math_floor(d+ +.5):+Math_ceil(d-+.5)}function _setTempRet0($i){setTempRet0($i|0)}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]);return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}FS.staticInit();embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");if(ENVIRONMENT_IS_NODE){_emscripten_get_now=function _emscripten_get_now_actual(){var t=process["hrtime"]();return t[0]*1e3+t[1]/1e6}}else if(typeof dateNow!=="undefined"){_emscripten_get_now=dateNow}else _emscripten_get_now=function(){return performance["now"]()};Module["requestFullscreen"]=function Module_requestFullscreen(lockPointer,resizeCanvas,vrDevice){Browser.requestFullscreen(lockPointer,resizeCanvas,vrDevice)};Module["requestAnimationFrame"]=function Module_requestAnimationFrame(func){Browser.requestAnimationFrame(func)};Module["setCanvasSize"]=function Module_setCanvasSize(width,height,noUpdates){Browser.setCanvasSize(width,height,noUpdates)};Module["pauseMainLoop"]=function Module_pauseMainLoop(){Browser.mainLoop.pause()};Module["resumeMainLoop"]=function Module_resumeMainLoop(){Browser.mainLoop.resume()};Module["getUserMedia"]=function Module_getUserMedia(){Browser.getUserMedia()};Module["createContext"]=function Module_createContext(canvas,useWebGL,setInModule,webGLContextAttributes){return Browser.createContext(canvas,useWebGL,setInModule,webGLContextAttributes)};var GLctx;GL.init();for(var i=0;i<32;i++)__tempFixedLengthArray.push(new Array(i));var ASSERTIONS=false;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 asmLibraryArg={"__assert_fail":___assert_fail,"__cxa_allocate_exception":___cxa_allocate_exception,"__cxa_atexit":___cxa_atexit,"__cxa_thread_atexit":___cxa_thread_atexit,"__cxa_throw":___cxa_throw,"__lock":___lock,"__map_file":___map_file,"__syscall10":___syscall10,"__syscall122":___syscall122,"__syscall15":___syscall15,"__syscall168":___syscall168,"__syscall183":___syscall183,"__syscall192":___syscall192,"__syscall193":___syscall193,"__syscall194":___syscall194,"__syscall195":___syscall195,"__syscall196":___syscall196,"__syscall197":___syscall197,"__syscall199":___syscall199,"__syscall20":___syscall20,"__syscall201":___syscall201,"__syscall220":___syscall220,"__syscall221":___syscall221,"__syscall3":___syscall3,"__syscall320":___syscall320,"__syscall33":___syscall33,"__syscall38":___syscall38,"__syscall39":___syscall39,"__syscall4":___syscall4,"__syscall40":___syscall40,"__syscall5":___syscall5,"__syscall83":___syscall83,"__syscall85":___syscall85,"__syscall9":___syscall9,"__syscall91":___syscall91,"__syscall94":___syscall94,"__unlock":___unlock,"_embind_register_bool":__embind_register_bool,"_embind_register_emval":__embind_register_emval,"_embind_register_float":__embind_register_float,"_embind_register_function":__embind_register_function,"_embind_register_integer":__embind_register_integer,"_embind_register_memory_view":__embind_register_memory_view,"_embind_register_std_string":__embind_register_std_string,"_embind_register_std_wstring":__embind_register_std_wstring,"_embind_register_void":__embind_register_void,"_emval_as":__emval_as,"_emval_call":__emval_call,"_emval_call_method":__emval_call_method,"_emval_call_void_method":__emval_call_void_method,"_emval_decref":__emval_decref,"_emval_equals":__emval_equals,"_emval_get_global":__emval_get_global,"_emval_get_method_caller":__emval_get_method_caller,"_emval_get_module_property":__emval_get_module_property,"_emval_get_property":__emval_get_property,"_emval_incref":__emval_incref,"_emval_is_string":__emval_is_string,"_emval_new":__emval_new,"_emval_new_cstring":__emval_new_cstring,"_emval_new_object":__emval_new_object,"_emval_run_destructors":__emval_run_destructors,"_emval_set_property":__emval_set_property,"_emval_take_value":__emval_take_value,"abort":_abort,"clock_gettime":_clock_gettime,"dlclose":_dlclose,"dlerror":_dlerror,"dlopen":_dlopen,"dlsym":_dlsym,"eglGetProcAddress":_eglGetProcAddress,"emscripten_async_call":_emscripten_async_call,"emscripten_date_now":_emscripten_date_now,"emscripten_force_exit":_emscripten_force_exit,"emscripten_get_element_css_size":_emscripten_get_element_css_size,"emscripten_get_sbrk_ptr":_emscripten_get_sbrk_ptr,"emscripten_glActiveTexture":_emscripten_glActiveTexture,"emscripten_glAttachShader":_emscripten_glAttachShader,"emscripten_glBeginQuery":_emscripten_glBeginQuery,"emscripten_glBeginQueryEXT":_emscripten_glBeginQueryEXT,"emscripten_glBeginTransformFeedback":_emscripten_glBeginTransformFeedback,"emscripten_glBindAttribLocation":_emscripten_glBindAttribLocation,"emscripten_glBindBuffer":_emscripten_glBindBuffer,"emscripten_glBindBufferBase":_emscripten_glBindBufferBase,"emscripten_glBindBufferRange":_emscripten_glBindBufferRange,"emscripten_glBindFramebuffer":_emscripten_glBindFramebuffer,"emscripten_glBindRenderbuffer":_emscripten_glBindRenderbuffer,"emscripten_glBindSampler":_emscripten_glBindSampler,"emscripten_glBindTexture":_emscripten_glBindTexture,"emscripten_glBindTransformFeedback":_emscripten_glBindTransformFeedback,"emscripten_glBindVertexArray":_emscripten_glBindVertexArray,"emscripten_glBindVertexArrayOES":_emscripten_glBindVertexArrayOES,"emscripten_glBlendColor":_emscripten_glBlendColor,"emscripten_glBlendEquation":_emscripten_glBlendEquation,"emscripten_glBlendEquationSeparate":_emscripten_glBlendEquationSeparate,"emscripten_glBlendFunc":_emscripten_glBlendFunc,"emscripten_glBlendFuncSeparate":_emscripten_glBlendFuncSeparate,"emscripten_glBlitFramebuffer":_emscripten_glBlitFramebuffer,"emscripten_glBufferData":_emscripten_glBufferData,"emscripten_glBufferSubData":_emscripten_glBufferSubData,"emscripten_glCheckFramebufferStatus":_emscripten_glCheckFramebufferStatus,"emscripten_glClear":_emscripten_glClear,"emscripten_glClearBufferfi":_emscripten_glClearBufferfi,"emscripten_glClearBufferfv":_emscripten_glClearBufferfv,"emscripten_glClearBufferiv":_emscripten_glClearBufferiv,"emscripten_glClearBufferuiv":_emscripten_glClearBufferuiv,"emscripten_glClearColor":_emscripten_glClearColor,"emscripten_glClearDepthf":_emscripten_glClearDepthf,"emscripten_glClearStencil":_emscripten_glClearStencil,"emscripten_glClientWaitSync":_emscripten_glClientWaitSync,"emscripten_glColorMask":_emscripten_glColorMask,"emscripten_glCompileShader":_emscripten_glCompileShader,"emscripten_glCompressedTexImage2D":_emscripten_glCompressedTexImage2D,"emscripten_glCompressedTexImage3D":_emscripten_glCompressedTexImage3D,"emscripten_glCompressedTexSubImage2D":_emscripten_glCompressedTexSubImage2D,"emscripten_glCompressedTexSubImage3D":_emscripten_glCompressedTexSubImage3D,"emscripten_glCopyBufferSubData":_emscripten_glCopyBufferSubData,"emscripten_glCopyTexImage2D":_emscripten_glCopyTexImage2D,"emscripten_glCopyTexSubImage2D":_emscripten_glCopyTexSubImage2D,"emscripten_glCopyTexSubImage3D":_emscripten_glCopyTexSubImage3D,"emscripten_glCreateProgram":_emscripten_glCreateProgram,"emscripten_glCreateShader":_emscripten_glCreateShader,"emscripten_glCullFace":_emscripten_glCullFace,"emscripten_glDeleteBuffers":_emscripten_glDeleteBuffers,"emscripten_glDeleteFramebuffers":_emscripten_glDeleteFramebuffers,"emscripten_glDeleteProgram":_emscripten_glDeleteProgram,"emscripten_glDeleteQueries":_emscripten_glDeleteQueries,"emscripten_glDeleteQueriesEXT":_emscripten_glDeleteQueriesEXT,"emscripten_glDeleteRenderbuffers":_emscripten_glDeleteRenderbuffers,"emscripten_glDeleteSamplers":_emscripten_glDeleteSamplers,"emscripten_glDeleteShader":_emscripten_glDeleteShader,"emscripten_glDeleteSync":_emscripten_glDeleteSync,"emscripten_glDeleteTextures":_emscripten_glDeleteTextures,"emscripten_glDeleteTransformFeedbacks":_emscripten_glDeleteTransformFeedbacks,"emscripten_glDeleteVertexArrays":_emscripten_glDeleteVertexArrays,"emscripten_glDeleteVertexArraysOES":_emscripten_glDeleteVertexArraysOES,"emscripten_glDepthFunc":_emscripten_glDepthFunc,"emscripten_glDepthMask":_emscripten_glDepthMask,"emscripten_glDepthRangef":_emscripten_glDepthRangef,"emscripten_glDetachShader":_emscripten_glDetachShader,"emscripten_glDisable":_emscripten_glDisable,"emscripten_glDisableVertexAttribArray":_emscripten_glDisableVertexAttribArray,"emscripten_glDrawArrays":_emscripten_glDrawArrays,"emscripten_glDrawArraysInstanced":_emscripten_glDrawArraysInstanced,"emscripten_glDrawArraysInstancedANGLE":_emscripten_glDrawArraysInstancedANGLE,"emscripten_glDrawArraysInstancedARB":_emscripten_glDrawArraysInstancedARB,"emscripten_glDrawArraysInstancedEXT":_emscripten_glDrawArraysInstancedEXT,"emscripten_glDrawArraysInstancedNV":_emscripten_glDrawArraysInstancedNV,"emscripten_glDrawBuffers":_emscripten_glDrawBuffers,"emscripten_glDrawBuffersEXT":_emscripten_glDrawBuffersEXT,"emscripten_glDrawBuffersWEBGL":_emscripten_glDrawBuffersWEBGL,"emscripten_glDrawElements":_emscripten_glDrawElements,"emscripten_glDrawElementsInstanced":_emscripten_glDrawElementsInstanced,"emscripten_glDrawElementsInstancedANGLE":_emscripten_glDrawElementsInstancedANGLE,"emscripten_glDrawElementsInstancedARB":_emscripten_glDrawElementsInstancedARB,"emscripten_glDrawElementsInstancedEXT":_emscripten_glDrawElementsInstancedEXT,"emscripten_glDrawElementsInstancedNV":_emscripten_glDrawElementsInstancedNV,"emscripten_glDrawRangeElements":_emscripten_glDrawRangeElements,"emscripten_glEnable":_emscripten_glEnable,"emscripten_glEnableVertexAttribArray":_emscripten_glEnableVertexAttribArray,"emscripten_glEndQuery":_emscripten_glEndQuery,"emscripten_glEndQueryEXT":_emscripten_glEndQueryEXT,"emscripten_glEndTransformFeedback":_emscripten_glEndTransformFeedback,"emscripten_glFenceSync":_emscripten_glFenceSync,"emscripten_glFinish":_emscripten_glFinish,"emscripten_glFlush":_emscripten_glFlush,"emscripten_glFlushMappedBufferRange":_emscripten_glFlushMappedBufferRange,"emscripten_glFramebufferRenderbuffer":_emscripten_glFramebufferRenderbuffer,"emscripten_glFramebufferTexture2D":_emscripten_glFramebufferTexture2D,"emscripten_glFramebufferTextureLayer":_emscripten_glFramebufferTextureLayer,"emscripten_glFrontFace":_emscripten_glFrontFace,"emscripten_glGenBuffers":_emscripten_glGenBuffers,"emscripten_glGenFramebuffers":_emscripten_glGenFramebuffers,"emscripten_glGenQueries":_emscripten_glGenQueries,"emscripten_glGenQueriesEXT":_emscripten_glGenQueriesEXT,"emscripten_glGenRenderbuffers":_emscripten_glGenRenderbuffers,"emscripten_glGenSamplers":_emscripten_glGenSamplers,"emscripten_glGenTextures":_emscripten_glGenTextures,"emscripten_glGenTransformFeedbacks":_emscripten_glGenTransformFeedbacks,"emscripten_glGenVertexArrays":_emscripten_glGenVertexArrays,"emscripten_glGenVertexArraysOES":_emscripten_glGenVertexArraysOES,"emscripten_glGenerateMipmap":_emscripten_glGenerateMipmap,"emscripten_glGetActiveAttrib":_emscripten_glGetActiveAttrib,"emscripten_glGetActiveUniform":_emscripten_glGetActiveUniform,"emscripten_glGetActiveUniformBlockName":_emscripten_glGetActiveUniformBlockName,"emscripten_glGetActiveUniformBlockiv":_emscripten_glGetActiveUniformBlockiv,"emscripten_glGetActiveUniformsiv":_emscripten_glGetActiveUniformsiv,"emscripten_glGetAttachedShaders":_emscripten_glGetAttachedShaders,"emscripten_glGetAttribLocation":_emscripten_glGetAttribLocation,"emscripten_glGetBooleanv":_emscripten_glGetBooleanv,"emscripten_glGetBufferParameteri64v":_emscripten_glGetBufferParameteri64v,"emscripten_glGetBufferParameteriv":_emscripten_glGetBufferParameteriv,"emscripten_glGetBufferPointerv":_emscripten_glGetBufferPointerv,"emscripten_glGetError":_emscripten_glGetError,"emscripten_glGetFloatv":_emscripten_glGetFloatv,"emscripten_glGetFragDataLocation":_emscripten_glGetFragDataLocation,"emscripten_glGetFramebufferAttachmentParameteriv":_emscripten_glGetFramebufferAttachmentParameteriv,"emscripten_glGetInteger64i_v":_emscripten_glGetInteger64i_v,"emscripten_glGetInteger64v":_emscripten_glGetInteger64v,"emscripten_glGetIntegeri_v":_emscripten_glGetIntegeri_v,"emscripten_glGetIntegerv":_emscripten_glGetIntegerv,"emscripten_glGetInternalformativ":_emscripten_glGetInternalformativ,"emscripten_glGetProgramBinary":_emscripten_glGetProgramBinary,"emscripten_glGetProgramInfoLog":_emscripten_glGetProgramInfoLog,"emscripten_glGetProgramiv":_emscripten_glGetProgramiv,"emscripten_glGetQueryObjecti64vEXT":_emscripten_glGetQueryObjecti64vEXT,"emscripten_glGetQueryObjectivEXT":_emscripten_glGetQueryObjectivEXT,"emscripten_glGetQueryObjectui64vEXT":_emscripten_glGetQueryObjectui64vEXT,"emscripten_glGetQueryObjectuiv":_emscripten_glGetQueryObjectuiv,"emscripten_glGetQueryObjectuivEXT":_emscripten_glGetQueryObjectuivEXT,"emscripten_glGetQueryiv":_emscripten_glGetQueryiv,"emscripten_glGetQueryivEXT":_emscripten_glGetQueryivEXT,"emscripten_glGetRenderbufferParameteriv":_emscripten_glGetRenderbufferParameteriv,"emscripten_glGetSamplerParameterfv":_emscripten_glGetSamplerParameterfv,"emscripten_glGetSamplerParameteriv":_emscripten_glGetSamplerParameteriv,"emscripten_glGetShaderInfoLog":_emscripten_glGetShaderInfoLog,"emscripten_glGetShaderPrecisionFormat":_emscripten_glGetShaderPrecisionFormat,"emscripten_glGetShaderSource":_emscripten_glGetShaderSource,"emscripten_glGetShaderiv":_emscripten_glGetShaderiv,"emscripten_glGetString":_emscripten_glGetString,"emscripten_glGetStringi":_emscripten_glGetStringi,"emscripten_glGetSynciv":_emscripten_glGetSynciv,"emscripten_glGetTexParameterfv":_emscripten_glGetTexParameterfv,"emscripten_glGetTexParameteriv":_emscripten_glGetTexParameteriv,"emscripten_glGetTransformFeedbackVarying":_emscripten_glGetTransformFeedbackVarying,"emscripten_glGetUniformBlockIndex":_emscripten_glGetUniformBlockIndex,"emscripten_glGetUniformIndices":_emscripten_glGetUniformIndices,"emscripten_glGetUniformLocation":_emscripten_glGetUniformLocation,"emscripten_glGetUniformfv":_emscripten_glGetUniformfv,"emscripten_glGetUniformiv":_emscripten_glGetUniformiv,"emscripten_glGetUniformuiv":_emscripten_glGetUniformuiv,"emscripten_glGetVertexAttribIiv":_emscripten_glGetVertexAttribIiv,"emscripten_glGetVertexAttribIuiv":_emscripten_glGetVertexAttribIuiv,"emscripten_glGetVertexAttribPointerv":_emscripten_glGetVertexAttribPointerv,"emscripten_glGetVertexAttribfv":_emscripten_glGetVertexAttribfv,"emscripten_glGetVertexAttribiv":_emscripten_glGetVertexAttribiv,"emscripten_glHint":_emscripten_glHint,"emscripten_glInvalidateFramebuffer":_emscripten_glInvalidateFramebuffer,"emscripten_glInvalidateSubFramebuffer":_emscripten_glInvalidateSubFramebuffer,"emscripten_glIsBuffer":_emscripten_glIsBuffer,"emscripten_glIsEnabled":_emscripten_glIsEnabled,"emscripten_glIsFramebuffer":_emscripten_glIsFramebuffer,"emscripten_glIsProgram":_emscripten_glIsProgram,"emscripten_glIsQuery":_emscripten_glIsQuery,"emscripten_glIsQueryEXT":_emscripten_glIsQueryEXT,"emscripten_glIsRenderbuffer":_emscripten_glIsRenderbuffer,"emscripten_glIsSampler":_emscripten_glIsSampler,"emscripten_glIsShader":_emscripten_glIsShader,"emscripten_glIsSync":_emscripten_glIsSync,"emscripten_glIsTexture":_emscripten_glIsTexture,"emscripten_glIsTransformFeedback":_emscripten_glIsTransformFeedback,"emscripten_glIsVertexArray":_emscripten_glIsVertexArray,"emscripten_glIsVertexArrayOES":_emscripten_glIsVertexArrayOES,"emscripten_glLineWidth":_emscripten_glLineWidth,"emscripten_glLinkProgram":_emscripten_glLinkProgram,"emscripten_glMapBufferRange":_emscripten_glMapBufferRange,"emscripten_glPauseTransformFeedback":_emscripten_glPauseTransformFeedback,"emscripten_glPixelStorei":_emscripten_glPixelStorei,"emscripten_glPolygonOffset":_emscripten_glPolygonOffset,"emscripten_glProgramBinary":_emscripten_glProgramBinary,"emscripten_glProgramParameteri":_emscripten_glProgramParameteri,"emscripten_glQueryCounterEXT":_emscripten_glQueryCounterEXT,"emscripten_glReadBuffer":_emscripten_glReadBuffer,"emscripten_glReadPixels":_emscripten_glReadPixels,"emscripten_glReleaseShaderCompiler":_emscripten_glReleaseShaderCompiler,"emscripten_glRenderbufferStorage":_emscripten_glRenderbufferStorage,"emscripten_glRenderbufferStorageMultisample":_emscripten_glRenderbufferStorageMultisample,"emscripten_glResumeTransformFeedback":_emscripten_glResumeTransformFeedback,"emscripten_glSampleCoverage":_emscripten_glSampleCoverage,"emscripten_glSamplerParameterf":_emscripten_glSamplerParameterf,"emscripten_glSamplerParameterfv":_emscripten_glSamplerParameterfv,"emscripten_glSamplerParameteri":_emscripten_glSamplerParameteri,"emscripten_glSamplerParameteriv":_emscripten_glSamplerParameteriv,"emscripten_glScissor":_emscripten_glScissor,"emscripten_glShaderBinary":_emscripten_glShaderBinary,"emscripten_glShaderSource":_emscripten_glShaderSource,"emscripten_glStencilFunc":_emscripten_glStencilFunc,"emscripten_glStencilFuncSeparate":_emscripten_glStencilFuncSeparate,"emscripten_glStencilMask":_emscripten_glStencilMask,"emscripten_glStencilMaskSeparate":_emscripten_glStencilMaskSeparate,"emscripten_glStencilOp":_emscripten_glStencilOp,"emscripten_glStencilOpSeparate":_emscripten_glStencilOpSeparate,"emscripten_glTexImage2D":_emscripten_glTexImage2D,"emscripten_glTexImage3D":_emscripten_glTexImage3D,"emscripten_glTexParameterf":_emscripten_glTexParameterf,"emscripten_glTexParameterfv":_emscripten_glTexParameterfv,"emscripten_glTexParameteri":_emscripten_glTexParameteri,"emscripten_glTexParameteriv":_emscripten_glTexParameteriv,"emscripten_glTexStorage2D":_emscripten_glTexStorage2D,"emscripten_glTexStorage3D":_emscripten_glTexStorage3D,"emscripten_glTexSubImage2D":_emscripten_glTexSubImage2D,"emscripten_glTexSubImage3D":_emscripten_glTexSubImage3D,"emscripten_glTransformFeedbackVaryings":_emscripten_glTransformFeedbackVaryings,"emscripten_glUniform1f":_emscripten_glUniform1f,"emscripten_glUniform1fv":_emscripten_glUniform1fv,"emscripten_glUniform1i":_emscripten_glUniform1i,"emscripten_glUniform1iv":_emscripten_glUniform1iv,"emscripten_glUniform1ui":_emscripten_glUniform1ui,"emscripten_glUniform1uiv":_emscripten_glUniform1uiv,"emscripten_glUniform2f":_emscripten_glUniform2f,"emscripten_glUniform2fv":_emscripten_glUniform2fv,"emscripten_glUniform2i":_emscripten_glUniform2i,"emscripten_glUniform2iv":_emscripten_glUniform2iv,"emscripten_glUniform2ui":_emscripten_glUniform2ui,"emscripten_glUniform2uiv":_emscripten_glUniform2uiv,"emscripten_glUniform3f":_emscripten_glUniform3f,"emscripten_glUniform3fv":_emscripten_glUniform3fv,"emscripten_glUniform3i":_emscripten_glUniform3i,"emscripten_glUniform3iv":_emscripten_glUniform3iv,"emscripten_glUniform3ui":_emscripten_glUniform3ui,"emscripten_glUniform3uiv":_emscripten_glUniform3uiv,"emscripten_glUniform4f":_emscripten_glUniform4f,"emscripten_glUniform4fv":_emscripten_glUniform4fv,"emscripten_glUniform4i":_emscripten_glUniform4i,"emscripten_glUniform4iv":_emscripten_glUniform4iv,"emscripten_glUniform4ui":_emscripten_glUniform4ui,"emscripten_glUniform4uiv":_emscripten_glUniform4uiv,"emscripten_glUniformBlockBinding":_emscripten_glUniformBlockBinding,"emscripten_glUniformMatrix2fv":_emscripten_glUniformMatrix2fv,"emscripten_glUniformMatrix2x3fv":_emscripten_glUniformMatrix2x3fv,"emscripten_glUniformMatrix2x4fv":_emscripten_glUniformMatrix2x4fv,"emscripten_glUniformMatrix3fv":_emscripten_glUniformMatrix3fv,"emscripten_glUniformMatrix3x2fv":_emscripten_glUniformMatrix3x2fv,"emscripten_glUniformMatrix3x4fv":_emscripten_glUniformMatrix3x4fv,"emscripten_glUniformMatrix4fv":_emscripten_glUniformMatrix4fv,"emscripten_glUniformMatrix4x2fv":_emscripten_glUniformMatrix4x2fv,"emscripten_glUniformMatrix4x3fv":_emscripten_glUniformMatrix4x3fv,"emscripten_glUnmapBuffer":_emscripten_glUnmapBuffer,"emscripten_glUseProgram":_emscripten_glUseProgram,"emscripten_glValidateProgram":_emscripten_glValidateProgram,"emscripten_glVertexAttrib1f":_emscripten_glVertexAttrib1f,"emscripten_glVertexAttrib1fv":_emscripten_glVertexAttrib1fv,"emscripten_glVertexAttrib2f":_emscripten_glVertexAttrib2f,"emscripten_glVertexAttrib2fv":_emscripten_glVertexAttrib2fv,"emscripten_glVertexAttrib3f":_emscripten_glVertexAttrib3f,"emscripten_glVertexAttrib3fv":_emscripten_glVertexAttrib3fv,"emscripten_glVertexAttrib4f":_emscripten_glVertexAttrib4f,"emscripten_glVertexAttrib4fv":_emscripten_glVertexAttrib4fv,"emscripten_glVertexAttribDivisor":_emscripten_glVertexAttribDivisor,"emscripten_glVertexAttribDivisorANGLE":_emscripten_glVertexAttribDivisorANGLE,"emscripten_glVertexAttribDivisorARB":_emscripten_glVertexAttribDivisorARB,"emscripten_glVertexAttribDivisorEXT":_emscripten_glVertexAttribDivisorEXT,"emscripten_glVertexAttribDivisorNV":_emscripten_glVertexAttribDivisorNV,"emscripten_glVertexAttribI4i":_emscripten_glVertexAttribI4i,"emscripten_glVertexAttribI4iv":_emscripten_glVertexAttribI4iv,"emscripten_glVertexAttribI4ui":_emscripten_glVertexAttribI4ui,"emscripten_glVertexAttribI4uiv":_emscripten_glVertexAttribI4uiv,"emscripten_glVertexAttribIPointer":_emscripten_glVertexAttribIPointer,"emscripten_glVertexAttribPointer":_emscripten_glVertexAttribPointer,"emscripten_glViewport":_emscripten_glViewport,"emscripten_glWaitSync":_emscripten_glWaitSync,"emscripten_idb_async_delete":_emscripten_idb_async_delete,"emscripten_idb_async_exists":_emscripten_idb_async_exists,"emscripten_idb_async_load":_emscripten_idb_async_load,"emscripten_idb_async_store":_emscripten_idb_async_store,"emscripten_is_webgl_context_lost":_emscripten_is_webgl_context_lost,"emscripten_log":_emscripten_log,"emscripten_longjmp":_emscripten_longjmp,"emscripten_memcpy_big":_emscripten_memcpy_big,"emscripten_pause_main_loop":_emscripten_pause_main_loop,"emscripten_resize_heap":_emscripten_resize_heap,"emscripten_resume_main_loop":_emscripten_resume_main_loop,"emscripten_set_focus_callback_on_thread":_emscripten_set_focus_callback_on_thread,"emscripten_set_keydown_callback_on_thread":_emscripten_set_keydown_callback_on_thread,"emscripten_set_keyup_callback_on_thread":_emscripten_set_keyup_callback_on_thread,"emscripten_set_main_loop_arg":_emscripten_set_main_loop_arg,"emscripten_set_mousedown_callback_on_thread":_emscripten_set_mousedown_callback_on_thread,"emscripten_set_mousemove_callback_on_thread":_emscripten_set_mousemove_callback_on_thread,"emscripten_set_mouseup_callback_on_thread":_emscripten_set_mouseup_callback_on_thread,"emscripten_set_resize_callback_on_thread":_emscripten_set_resize_callback_on_thread,"emscripten_set_touchcancel_callback_on_thread":_emscripten_set_touchcancel_callback_on_thread,"emscripten_set_touchend_callback_on_thread":_emscripten_set_touchend_callback_on_thread,"emscripten_set_touchmove_callback_on_thread":_emscripten_set_touchmove_callback_on_thread,"emscripten_set_touchstart_callback_on_thread":_emscripten_set_touchstart_callback_on_thread,"emscripten_set_wheel_callback_on_thread":_emscripten_set_wheel_callback_on_thread,"emscripten_sleep":_emscripten_sleep,"emscripten_webgl_create_context":_emscripten_webgl_create_context,"emscripten_webgl_destroy_context":_emscripten_webgl_destroy_context,"emscripten_webgl_init_context_attributes":_emscripten_webgl_init_context_attributes,"emscripten_webgl_make_context_current":_emscripten_webgl_make_context_current,"environ_get":_environ_get,"environ_sizes_get":_environ_sizes_get,"exit":_exit,"fd_close":_fd_close,"fd_fdstat_get":_fd_fdstat_get,"fd_seek":_fd_seek,"fd_sync":_fd_sync,"fd_write":_fd_write,"flock":_flock,"getTempRet0":_getTempRet0,"getpagesize":_getpagesize,"getpwnam":_getpwnam,"gettimeofday":_gettimeofday,"glActiveTexture":_glActiveTexture,"glCompressedTexImage2D":_glCompressedTexImage2D,"glCompressedTexSubImage2D":_glCompressedTexSubImage2D,"glGenerateMipmap":_glGenerateMipmap,"glTexSubImage2D":_glTexSubImage2D,"glViewport":_glViewport,"invoke_fi":invoke_fi,"invoke_ii":invoke_ii,"invoke_iii":invoke_iii,"invoke_iiii":invoke_iiii,"invoke_iiiif":invoke_iiiif,"invoke_iiiii":invoke_iiiii,"invoke_iiiiii":invoke_iiiiii,"invoke_iiiiiii":invoke_iiiiiii,"invoke_iiiiiiif":invoke_iiiiiiif,"invoke_iiiiiiiiii":invoke_iiiiiiiiii,"invoke_iiiiiiiiiii":invoke_iiiiiiiiiii,"invoke_iij":invoke_iij,"invoke_ji":invoke_ji,"invoke_v":invoke_v,"invoke_vi":invoke_vi,"invoke_vidd":invoke_vidd,"invoke_vii":invoke_vii,"invoke_viid":invoke_viid,"invoke_viii":invoke_viii,"invoke_viiif":invoke_viiif,"invoke_viiii":invoke_viiii,"invoke_viiiii":invoke_viiiii,"invoke_viiiiii":invoke_viiiiii,"invoke_viiiiiii":invoke_viiiiiii,"invoke_viiiiiiiii":invoke_viiiiiiiii,"kill":_kill,"localtime":_localtime,"memory":wasmMemory,"mktime":_mktime,"nanosleep":_nanosleep,"pathconf":_pathconf,"round":_round,"saveSetjmp":_saveSetjmp,"setTempRet0":_setTempRet0,"strftime_l":_strftime_l,"table":wasmTable,"testSetjmp":_testSetjmp,"tzset":_tzset};var asm=createWasm();Module["asm"]=asm;var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["__wasm_call_ctors"]).apply(null,arguments)};var _main=Module["_main"]=function(){return(_main=Module["_main"]=Module["asm"]["main"]).apply(null,arguments)};var _strlen=Module["_strlen"]=function(){return(_strlen=Module["_strlen"]=Module["asm"]["strlen"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["free"]).apply(null,arguments)};var _strstr=Module["_strstr"]=function(){return(_strstr=Module["_strstr"]=Module["asm"]["strstr"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["malloc"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["__errno_location"]).apply(null,arguments)};var _realloc=Module["_realloc"]=function(){return(_realloc=Module["_realloc"]=Module["asm"]["realloc"]).apply(null,arguments)};var _fflush=Module["_fflush"]=function(){return(_fflush=Module["_fflush"]=Module["asm"]["fflush"]).apply(null,arguments)};var __get_tzname=Module["__get_tzname"]=function(){return(__get_tzname=Module["__get_tzname"]=Module["asm"]["_get_tzname"]).apply(null,arguments)};var __get_daylight=Module["__get_daylight"]=function(){return(__get_daylight=Module["__get_daylight"]=Module["asm"]["_get_daylight"]).apply(null,arguments)};var __get_timezone=Module["__get_timezone"]=function(){return(__get_timezone=Module["__get_timezone"]=Module["asm"]["_get_timezone"]).apply(null,arguments)};var _setThrew=Module["_setThrew"]=function(){return(_setThrew=Module["_setThrew"]=Module["asm"]["setThrew"]).apply(null,arguments)};var __ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=function(){return(__ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=Module["asm"]["_ZSt18uncaught_exceptionv"]).apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return(___getTypeName=Module["___getTypeName"]=Module["asm"]["__getTypeName"]).apply(null,arguments)};var ___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=function(){return(___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=Module["asm"]["__embind_register_native_and_builtin_types"]).apply(null,arguments)};var _emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=function(){return(_emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=Module["asm"]["emscripten_GetProcAddress"]).apply(null,arguments)};var _memalign=Module["_memalign"]=function(){return(_memalign=Module["_memalign"]=Module["asm"]["memalign"]).apply(null,arguments)};var _emscripten_builtin_free=Module["_emscripten_builtin_free"]=function(){return(_emscripten_builtin_free=Module["_emscripten_builtin_free"]=Module["asm"]["emscripten_builtin_free"]).apply(null,arguments)};var _emscripten_builtin_memalign=Module["_emscripten_builtin_memalign"]=function(){return(_emscripten_builtin_memalign=Module["_emscripten_builtin_memalign"]=Module["asm"]["emscripten_builtin_memalign"]).apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return(dynCall_v=Module["dynCall_v"]=Module["asm"]["dynCall_v"]).apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return(dynCall_vi=Module["dynCall_vi"]=Module["asm"]["dynCall_vi"]).apply(null,arguments)};var dynCall_vii=Module["dynCall_vii"]=function(){return(dynCall_vii=Module["dynCall_vii"]=Module["asm"]["dynCall_vii"]).apply(null,arguments)};var dynCall_viii=Module["dynCall_viii"]=function(){return(dynCall_viii=Module["dynCall_viii"]=Module["asm"]["dynCall_viii"]).apply(null,arguments)};var dynCall_viiii=Module["dynCall_viiii"]=function(){return(dynCall_viiii=Module["dynCall_viiii"]=Module["asm"]["dynCall_viiii"]).apply(null,arguments)};var dynCall_viiiii=Module["dynCall_viiiii"]=function(){return(dynCall_viiiii=Module["dynCall_viiiii"]=Module["asm"]["dynCall_viiiii"]).apply(null,arguments)};var dynCall_viiiiii=Module["dynCall_viiiiii"]=function(){return(dynCall_viiiiii=Module["dynCall_viiiiii"]=Module["asm"]["dynCall_viiiiii"]).apply(null,arguments)};var dynCall_viiiiiii=Module["dynCall_viiiiiii"]=function(){return(dynCall_viiiiiii=Module["dynCall_viiiiiii"]=Module["asm"]["dynCall_viiiiiii"]).apply(null,arguments)};var dynCall_viiiiiiiii=Module["dynCall_viiiiiiiii"]=function(){return(dynCall_viiiiiiiii=Module["dynCall_viiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiii"]).apply(null,arguments)};var dynCall_viiif=Module["dynCall_viiif"]=function(){return(dynCall_viiif=Module["dynCall_viiif"]=Module["asm"]["dynCall_viiif"]).apply(null,arguments)};var dynCall_viid=Module["dynCall_viid"]=function(){return(dynCall_viid=Module["dynCall_viid"]=Module["asm"]["dynCall_viid"]).apply(null,arguments)};var dynCall_vidd=Module["dynCall_vidd"]=function(){return(dynCall_vidd=Module["dynCall_vidd"]=Module["asm"]["dynCall_vidd"]).apply(null,arguments)};var dynCall_ii=Module["dynCall_ii"]=function(){return(dynCall_ii=Module["dynCall_ii"]=Module["asm"]["dynCall_ii"]).apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return(dynCall_iii=Module["dynCall_iii"]=Module["asm"]["dynCall_iii"]).apply(null,arguments)};var dynCall_iiii=Module["dynCall_iiii"]=function(){return(dynCall_iiii=Module["dynCall_iiii"]=Module["asm"]["dynCall_iiii"]).apply(null,arguments)};var dynCall_iiiii=Module["dynCall_iiiii"]=function(){return(dynCall_iiiii=Module["dynCall_iiiii"]=Module["asm"]["dynCall_iiiii"]).apply(null,arguments)};var dynCall_iiiiii=Module["dynCall_iiiiii"]=function(){return(dynCall_iiiiii=Module["dynCall_iiiiii"]=Module["asm"]["dynCall_iiiiii"]).apply(null,arguments)};var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=function(){return(dynCall_iiiiiii=Module["dynCall_iiiiiii"]=Module["asm"]["dynCall_iiiiiii"]).apply(null,arguments)};var dynCall_iiiiiiiiii=Module["dynCall_iiiiiiiiii"]=function(){return(dynCall_iiiiiiiiii=Module["dynCall_iiiiiiiiii"]=Module["asm"]["dynCall_iiiiiiiiii"]).apply(null,arguments)};var dynCall_iiiiiiiiiii=Module["dynCall_iiiiiiiiiii"]=function(){return(dynCall_iiiiiiiiiii=Module["dynCall_iiiiiiiiiii"]=Module["asm"]["dynCall_iiiiiiiiiii"]).apply(null,arguments)};var dynCall_iiiiiiif=Module["dynCall_iiiiiiif"]=function(){return(dynCall_iiiiiiif=Module["dynCall_iiiiiiif"]=Module["asm"]["dynCall_iiiiiiif"]).apply(null,arguments)};var dynCall_iiiif=Module["dynCall_iiiif"]=function(){return(dynCall_iiiif=Module["dynCall_iiiif"]=Module["asm"]["dynCall_iiiif"]).apply(null,arguments)};var dynCall_iij=Module["dynCall_iij"]=function(){return(dynCall_iij=Module["dynCall_iij"]=Module["asm"]["dynCall_iij"]).apply(null,arguments)};var dynCall_ji=Module["dynCall_ji"]=function(){return(dynCall_ji=Module["dynCall_ji"]=Module["asm"]["dynCall_ji"]).apply(null,arguments)};var dynCall_fi=Module["dynCall_fi"]=function(){return(dynCall_fi=Module["dynCall_fi"]=Module["asm"]["dynCall_fi"]).apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return(stackSave=Module["stackSave"]=Module["asm"]["stackSave"]).apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return(stackAlloc=Module["stackAlloc"]=Module["asm"]["stackAlloc"]).apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return(stackRestore=Module["stackRestore"]=Module["asm"]["stackRestore"]).apply(null,arguments)};var __growWasmMemory=Module["__growWasmMemory"]=function(){return(__growWasmMemory=Module["__growWasmMemory"]=Module["asm"]["__growWasmMemory"]).apply(null,arguments)};var dynCall_viiiiiidi=Module["dynCall_viiiiiidi"]=function(){return(dynCall_viiiiiidi=Module["dynCall_viiiiiidi"]=Module["asm"]["dynCall_viiiiiidi"]).apply(null,arguments)};var dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=function(){return(dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=Module["asm"]["dynCall_viiiiiiii"]).apply(null,arguments)};var dynCall_dii=Module["dynCall_dii"]=function(){return(dynCall_dii=Module["dynCall_dii"]=Module["asm"]["dynCall_dii"]).apply(null,arguments)};var dynCall_iid=Module["dynCall_iid"]=function(){return(dynCall_iid=Module["dynCall_iid"]=Module["asm"]["dynCall_iid"]).apply(null,arguments)};var dynCall_viidiii=Module["dynCall_viidiii"]=function(){return(dynCall_viidiii=Module["dynCall_viidiii"]=Module["asm"]["dynCall_viidiii"]).apply(null,arguments)};var dynCall_viidi=Module["dynCall_viidi"]=function(){return(dynCall_viidi=Module["dynCall_viidi"]=Module["asm"]["dynCall_viidi"]).apply(null,arguments)};var dynCall_viiddi=Module["dynCall_viiddi"]=function(){return(dynCall_viiddi=Module["dynCall_viiddi"]=Module["asm"]["dynCall_viiddi"]).apply(null,arguments)};var dynCall_diiii=Module["dynCall_diiii"]=function(){return(dynCall_diiii=Module["dynCall_diiii"]=Module["asm"]["dynCall_diiii"]).apply(null,arguments)};var dynCall_iidi=Module["dynCall_iidi"]=function(){return(dynCall_iidi=Module["dynCall_iidi"]=Module["asm"]["dynCall_iidi"]).apply(null,arguments)};var dynCall_i=Module["dynCall_i"]=function(){return(dynCall_i=Module["dynCall_i"]=Module["asm"]["dynCall_i"]).apply(null,arguments)};var dynCall_vid=Module["dynCall_vid"]=function(){return(dynCall_vid=Module["dynCall_vid"]=Module["asm"]["dynCall_vid"]).apply(null,arguments)};var dynCall_di=Module["dynCall_di"]=function(){return(dynCall_di=Module["dynCall_di"]=Module["asm"]["dynCall_di"]).apply(null,arguments)};var dynCall_iiidi=Module["dynCall_iiidi"]=function(){return(dynCall_iiidi=Module["dynCall_iiidi"]=Module["asm"]["dynCall_iiidi"]).apply(null,arguments)};var dynCall_viddiii=Module["dynCall_viddiii"]=function(){return(dynCall_viddiii=Module["dynCall_viddiii"]=Module["asm"]["dynCall_viddiii"]).apply(null,arguments)};var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=function(){return(dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=Module["asm"]["dynCall_iiiiiiii"]).apply(null,arguments)};var dynCall_jiji=Module["dynCall_jiji"]=function(){return(dynCall_jiji=Module["dynCall_jiji"]=Module["asm"]["dynCall_jiji"]).apply(null,arguments)};var dynCall_viij=Module["dynCall_viij"]=function(){return(dynCall_viij=Module["dynCall_viij"]=Module["asm"]["dynCall_viij"]).apply(null,arguments)};var dynCall_viiiiiiiiiiii=Module["dynCall_viiiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiiii=Module["dynCall_viiiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiiii"]).apply(null,arguments)};var dynCall_jiiii=Module["dynCall_jiiii"]=function(){return(dynCall_jiiii=Module["dynCall_jiiii"]=Module["asm"]["dynCall_jiiii"]).apply(null,arguments)};var dynCall_diiiiiiii=Module["dynCall_diiiiiiii"]=function(){return(dynCall_diiiiiiii=Module["dynCall_diiiiiiii"]=Module["asm"]["dynCall_diiiiiiii"]).apply(null,arguments)};var dynCall_diii=Module["dynCall_diii"]=function(){return(dynCall_diii=Module["dynCall_diii"]=Module["asm"]["dynCall_diii"]).apply(null,arguments)};var dynCall_fii=Module["dynCall_fii"]=function(){return(dynCall_fii=Module["dynCall_fii"]=Module["asm"]["dynCall_fii"]).apply(null,arguments)};var dynCall_viiiid=Module["dynCall_viiiid"]=function(){return(dynCall_viiiid=Module["dynCall_viiiid"]=Module["asm"]["dynCall_viiiid"]).apply(null,arguments)};var dynCall_vij=Module["dynCall_vij"]=function(){return(dynCall_vij=Module["dynCall_vij"]=Module["asm"]["dynCall_vij"]).apply(null,arguments)};var dynCall_viji=Module["dynCall_viji"]=function(){return(dynCall_viji=Module["dynCall_viji"]=Module["asm"]["dynCall_viji"]).apply(null,arguments)};var dynCall_viijii=Module["dynCall_viijii"]=function(){return(dynCall_viijii=Module["dynCall_viijii"]=Module["asm"]["dynCall_viijii"]).apply(null,arguments)};var dynCall_viiji=Module["dynCall_viiji"]=function(){return(dynCall_viiji=Module["dynCall_viiji"]=Module["asm"]["dynCall_viiji"]).apply(null,arguments)};var dynCall_viiiiiiiiii=Module["dynCall_viiiiiiiiii"]=function(){return(dynCall_viiiiiiiiii=Module["dynCall_viiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiii"]).apply(null,arguments)};var dynCall_vddddddi=Module["dynCall_vddddddi"]=function(){return(dynCall_vddddddi=Module["dynCall_vddddddi"]=Module["asm"]["dynCall_vddddddi"]).apply(null,arguments)};var dynCall_vddi=Module["dynCall_vddi"]=function(){return(dynCall_vddi=Module["dynCall_vddi"]=Module["asm"]["dynCall_vddi"]).apply(null,arguments)};var dynCall_iiddddi=Module["dynCall_iiddddi"]=function(){return(dynCall_iiddddi=Module["dynCall_iiddddi"]=Module["asm"]["dynCall_iiddddi"]).apply(null,arguments)};var dynCall_viiiiiiiiiii=Module["dynCall_viiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiii=Module["dynCall_viiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiii"]).apply(null,arguments)};var dynCall_viiiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiiiiii"]).apply(null,arguments)};var dynCall_viiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiii"]=function(){return(dynCall_viiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiii"]=Module["asm"]["dynCall_viiiiiiiiiiiii"]).apply(null,arguments)};var dynCall_viiiiif=Module["dynCall_viiiiif"]=function(){return(dynCall_viiiiif=Module["dynCall_viiiiif"]=Module["asm"]["dynCall_viiiiif"]).apply(null,arguments)};var dynCall_viiid=Module["dynCall_viiid"]=function(){return(dynCall_viiid=Module["dynCall_viiid"]=Module["asm"]["dynCall_viiid"]).apply(null,arguments)};var dynCall_dd=Module["dynCall_dd"]=function(){return(dynCall_dd=Module["dynCall_dd"]=Module["asm"]["dynCall_dd"]).apply(null,arguments)};var dynCall_did=Module["dynCall_did"]=function(){return(dynCall_did=Module["dynCall_did"]=Module["asm"]["dynCall_did"]).apply(null,arguments)};var dynCall_jiij=Module["dynCall_jiij"]=function(){return(dynCall_jiij=Module["dynCall_jiij"]=Module["asm"]["dynCall_jiij"]).apply(null,arguments)};var dynCall_jij=Module["dynCall_jij"]=function(){return(dynCall_jij=Module["dynCall_jij"]=Module["asm"]["dynCall_jij"]).apply(null,arguments)};var dynCall_iidiiii=Module["dynCall_iidiiii"]=function(){return(dynCall_iidiiii=Module["dynCall_iidiiii"]=Module["asm"]["dynCall_iidiiii"]).apply(null,arguments)};var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=function(){return(dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=Module["asm"]["dynCall_iiiiiiiii"]).apply(null,arguments)};var dynCall_iiiiij=Module["dynCall_iiiiij"]=function(){return(dynCall_iiiiij=Module["dynCall_iiiiij"]=Module["asm"]["dynCall_iiiiij"]).apply(null,arguments)};var dynCall_iiiiid=Module["dynCall_iiiiid"]=function(){return(dynCall_iiiiid=Module["dynCall_iiiiid"]=Module["asm"]["dynCall_iiiiid"]).apply(null,arguments)};var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=function(){return(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=Module["asm"]["dynCall_iiiiijj"]).apply(null,arguments)};var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=function(){return(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=Module["asm"]["dynCall_iiiiiijj"]).apply(null,arguments)};var dynCall_vffff=Module["dynCall_vffff"]=function(){return(dynCall_vffff=Module["dynCall_vffff"]=Module["asm"]["dynCall_vffff"]).apply(null,arguments)};var dynCall_vf=Module["dynCall_vf"]=function(){return(dynCall_vf=Module["dynCall_vf"]=Module["asm"]["dynCall_vf"]).apply(null,arguments)};var dynCall_vff=Module["dynCall_vff"]=function(){return(dynCall_vff=Module["dynCall_vff"]=Module["asm"]["dynCall_vff"]).apply(null,arguments)};var dynCall_vfi=Module["dynCall_vfi"]=function(){return(dynCall_vfi=Module["dynCall_vfi"]=Module["asm"]["dynCall_vfi"]).apply(null,arguments)};var dynCall_viif=Module["dynCall_viif"]=function(){return(dynCall_viif=Module["dynCall_viif"]=Module["asm"]["dynCall_viif"]).apply(null,arguments)};var dynCall_vif=Module["dynCall_vif"]=function(){return(dynCall_vif=Module["dynCall_vif"]=Module["asm"]["dynCall_vif"]).apply(null,arguments)};var dynCall_viff=Module["dynCall_viff"]=function(){return(dynCall_viff=Module["dynCall_viff"]=Module["asm"]["dynCall_viff"]).apply(null,arguments)};var dynCall_vifff=Module["dynCall_vifff"]=function(){return(dynCall_vifff=Module["dynCall_vifff"]=Module["asm"]["dynCall_vifff"]).apply(null,arguments)};var dynCall_viffff=Module["dynCall_viffff"]=function(){return(dynCall_viffff=Module["dynCall_viffff"]=Module["asm"]["dynCall_viffff"]).apply(null,arguments)};var dynCall_viifi=Module["dynCall_viifi"]=function(){return(dynCall_viifi=Module["dynCall_viifi"]=Module["asm"]["dynCall_viifi"]).apply(null,arguments)};function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return dynCall_iii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_iiiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{dynCall_viii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return dynCall_ii(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_iiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{dynCall_vii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9){var sp=stackSave();try{return dynCall_iiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{dynCall_vi(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return dynCall_iiiiiii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{dynCall_v(index)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{dynCall_viiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return dynCall_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiif(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return dynCall_iiiiiiif(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiif(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_iiiif(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vidd(index,a1,a2,a3){var sp=stackSave();try{dynCall_vidd(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiif(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viiif(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return dynCall_iiiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9){var sp=stackSave();try{dynCall_viiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viid(index,a1,a2,a3){var sp=stackSave();try{dynCall_viid(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_fi(index,a1){var sp=stackSave();try{return dynCall_fi(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{dynCall_viiiiii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{dynCall_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ji(index,a1){var sp=stackSave();try{return dynCall_ji(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iij(index,a1,a2,a3){var sp=stackSave();try{return dynCall_iij(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}Module["asm"]=asm;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}var calledMain=false;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args){var entryFunction=Module["_main"];args=args||[];var argc=args.length+1;var argv=stackAlloc((argc+1)*4);HEAP32[argv>>2]=allocateUTF8OnStack(thisProgram);for(var i=1;i>2)+i]=allocateUTF8OnStack(args[i-1])}HEAP32[(argv>>2)+argc]=0;try{var ret=entryFunction(argc,argv);exit(ret,true)}catch(e){if(e instanceof ExitStatus){return}else if(e=="unwind"){noExitRuntime=true;return}else{var toLog=e;if(e&&typeof e==="object"&&e.stack){toLog=[e,e.stack]}err("exception thrown: "+toLog);quit_(1,e)}}finally{calledMain=true}}function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&noExitRuntime&&status===0){return}if(noExitRuntime){}else{ABORT=true;EXITSTATUS=status;exitRuntime();if(Module["onExit"])Module["onExit"](status)}quit_(status,new ExitStatus(status))}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(); diff --git a/docs/qcustomplotdemo/qcustomplotdemo.wasm b/docs/qcustomplotdemo/qcustomplotdemo.wasm new file mode 100644 index 0000000..b5e68fb Binary files /dev/null and b/docs/qcustomplotdemo/qcustomplotdemo.wasm differ diff --git a/docs/qcustomplotdemo/qtloader.js b/docs/qcustomplotdemo/qtloader.js new file mode 100644 index 0000000..ef4a6ec --- /dev/null +++ b/docs/qcustomplotdemo/qtloader.js @@ -0,0 +1,577 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// QtLoader provides javascript API for managing Qt application modules. +// +// QtLoader provides API on top of Emscripten which supports common lifecycle +// tasks such as displaying placeholder content while the module downloads, +// handing application exits, and checking for browser wasm support. +// +// There are two usage modes: +// * Managed: QtLoader owns and manages the HTML display elements like +// the loader and canvas. +// * External: The embedding HTML page owns the display elements. QtLoader +// provides event callbacks which the page reacts to. +// +// Managed mode usage: +// +// var config = { +// containerElements : [$("container-id")]; +// } +// var qtLoader = QtLoader(config); +// qtLoader.loadEmscriptenModule("applicationName"); +// +// External mode.usage: +// +// var config = { +// canvasElements : [$("canvas-id")], +// showLoader: function() { +// loader.style.display = 'block' +// canvas.style.display = 'hidden' +// }, +// showCanvas: function() { +// loader.style.display = 'hidden' +// canvas.style.display = 'block' +// return canvas; +// } +// } +// var qtLoader = QtLoader(config); +// qtLoader.loadEmscriptenModule("applicationName"); +// +// Config keys +// +// containerElements : [container-element, ...] +// One or more HTML elements. QtLoader will display loader elements +// on these while loading the applicaton, and replace the loader with a +// canvas on load complete. +// canvasElements : [canvas-element, ...] +// One or more canvas elements. +// showLoader : function(status, containerElement) +// Optional loading element constructor function. Implement to create +// a custom loading screen. This function may be called multiple times, +// while preparing the application binary. "status" is a string +// containing the loading sub-status, and may be either "Downloading", +// or "Compiling". The browser may be using streaming compilation, in +// which case the wasm module is compiled during downloading and the +// there is no separate compile step. +// showCanvas : function(containerElement) +// Optional canvas constructor function. Implement to create custom +// canvas elements. +// showExit : function(crashed, exitCode, containerElement) +// Optional exited element constructor function. +// showError : function(crashed, exitCode, containerElement) +// Optional error element constructor function. +// +// path : +// Prefix path for wasm file, realative to the loading HMTL file. +// restartMode : "DoNotRestart", "RestartOnExit", "RestartOnCrash" +// Controls whether the application should be reloaded on exits. The default is "DoNotRestart" +// restartType : "RestartModule", "ReloadPage" +// restartLimit : +// Restart attempts limit. The default is 10. +// stdoutEnabled : +// stderrEnabled : +// environment : +// key-value environment variable pairs. +// +// QtLoader object API +// +// webAssemblySupported : bool +// webGLSupported : bool +// canLoadQt : bool +// Reports if WebAssembly and WebGL are supported. These are requirements for +// running Qt applications. +// loadEmscriptenModule(applicationName) +// Loads the application from the given emscripten javascript module file and wasm file +// status +// One of "Created", "Loading", "Running", "Exited". +// crashed +// Set to true if there was an unclean exit. +// exitCode +// main()/emscripten_force_exit() return code. Valid on status change to +// "Exited", iff crashed is false. +// exitText +// Abort/exit message. +// addCanvasElement +// Add canvas at run-time. Adds a corresponding QScreen, +// removeCanvasElement +// Remove canvas at run-time. Removes the corresponding QScreen. +// resizeCanvasElement +// Signals to the application that a canvas has been resized. +// setFontDpi +// Sets the logical font dpi for the application. + + +var Module = {} + +function QtLoader(config) +{ + function webAssemblySupported() { + return typeof WebAssembly !== "undefined" + } + + function webGLSupported() { + // We expect that WebGL is supported if WebAssembly is; however + // the GPU may be blacklisted. + try { + var canvas = document.createElement("canvas"); + return !!(window.WebGLRenderingContext && (canvas.getContext("webgl") || canvas.getContext("experimental-webgl"))); + } catch (e) { + return false; + } + } + + function canLoadQt() { + // The current Qt implementation requires WebAssembly (asm.js is not in use), + // and also WebGL (there is no raster fallback). + return webAssemblySupported() && webGLSupported(); + } + + function removeChildren(element) { + while (element.firstChild) element.removeChild(element.firstChild); + } + + function createCanvas() { + var canvas = document.createElement("canvas"); + canvas.className = "QtCanvas"; + canvas.style.height = "100%"; + canvas.style.width = "100%"; + + // Set contentEditable in order to enable clipboard events; hide the resulting focus frame. + canvas.contentEditable = true; + canvas.style.outline = "0px solid transparent"; + canvas.style.caretColor = "transparent"; + canvas.style.cursor = "default"; + + return canvas; + } + + // Set default state handler functions and create canvases if needed + if (config.containerElements !== undefined) { + + config.canvasElements = config.containerElements.map(createCanvas); + + config.showError = config.showError || function(errorText, container) { + removeChildren(container); + var errorTextElement = document.createElement("text"); + errorTextElement.className = "QtError" + errorTextElement.innerHTML = errorText; + return errorTextElement; + } + + config.showLoader = config.showLoader || function(loadingState, container) { + removeChildren(container); + var loadingText = document.createElement("text"); + loadingText.className = "QtLoading" + loadingText.innerHTML = '

    ${loadingState}...

    '; + return loadingText; + }; + + config.showCanvas = config.showCanvas || function(canvas, container) { + removeChildren(container); + } + + config.showExit = config.showExit || function(crashed, exitCode, container) { + if (!crashed) + return undefined; + + removeChildren(container); + var fontSize = 54; + var crashSymbols = ["\u{1F615}", "\u{1F614}", "\u{1F644}", "\u{1F928}", "\u{1F62C}", + "\u{1F915}", "\u{2639}", "\u{1F62E}", "\u{1F61E}", "\u{1F633}"]; + var symbolIndex = Math.floor(Math.random() * crashSymbols.length); + var errorHtml = ` ${crashSymbols[symbolIndex]} ` + var errorElement = document.createElement("text"); + errorElement.className = "QtExit" + errorElement.innerHTML = errorHtml; + return errorElement; + } + } + + config.restartMode = config.restartMode || "DoNotRestart"; + config.restartLimit = config.restartLimit || 10; + + if (config.stdoutEnabled === undefined) config.stdoutEnabled = true; + if (config.stderrEnabled === undefined) config.stderrEnabled = true; + + // Make sure config.path is defined and ends with "/" if needed + if (config.path === undefined) + config.path = ""; + if (config.path.length > 0 && !config.path.endsWith("/")) + config.path = config.path.concat("/"); + + if (config.environment === undefined) + config.environment = {}; + + var publicAPI = {}; + publicAPI.webAssemblySupported = webAssemblySupported(); + publicAPI.webGLSupported = webGLSupported(); + publicAPI.canLoadQt = canLoadQt(); + publicAPI.canLoadApplication = canLoadQt(); + publicAPI.status = undefined; + publicAPI.loadEmscriptenModule = loadEmscriptenModule; + publicAPI.addCanvasElement = addCanvasElement; + publicAPI.removeCanvasElement = removeCanvasElement; + publicAPI.resizeCanvasElement = resizeCanvasElement; + publicAPI.setFontDpi = setFontDpi; + publicAPI.fontDpi = fontDpi; + + restartCount = 0; + + function fetchResource(filePath) { + var fullPath = config.path + filePath; + return fetch(fullPath).then(function(response) { + if (!response.ok) { + self.error = response.status + " " + response.statusText + " " + response.url; + setStatus("Error"); + return Promise.reject(self.error) + } else { + return response; + } + }); + } + + function fetchText(filePath) { + return fetchResource(filePath).then(function(response) { + return response.text(); + }); + } + + function fetchThenCompileWasm(response) { + return response.arrayBuffer().then(function(data) { + self.loaderSubState = "Compiling"; + setStatus("Loading") // trigger loaderSubState udpate + return WebAssembly.compile(data); + }); + } + + function fetchCompileWasm(filePath) { + return fetchResource(filePath).then(function(response) { + if (typeof WebAssembly.compileStreaming !== "undefined") { + self.loaderSubState = "Downloading/Compiling"; + setStatus("Loading"); + return WebAssembly.compileStreaming(response).catch(function(error) { + // compileStreaming may/will fail if the server does not set the correct + // mime type (application/wasm) for the wasm file. Fall back to fetch, + // then compile in this case. + return fetchThenCompileWasm(response); + }); + } else { + // Fall back to fetch, then compile if compileStreaming is not supported + return fetchThenCompileWasm(response); + } + }); + } + + function loadEmscriptenModule(applicationName) { + + // Loading in qtloader.js goes through four steps: + // 1) Check prerequisites + // 2) Download resources + // 3) Configure the emscripten Module object + // 4) Start the emcripten runtime, after which emscripten takes over + + // Check for Wasm & WebGL support; set error and return before downloading resources if missing + if (!webAssemblySupported()) { + self.error = "Error: WebAssembly is not supported" + setStatus("Error"); + return; + } + if (!webGLSupported()) { + self.error = "Error: WebGL is not supported" + setStatus("Error"); + return; + } + + // Continue waiting if loadEmscriptenModule() is called again + if (publicAPI.status == "Loading") + return; + self.loaderSubState = "Downloading"; + setStatus("Loading"); + + // Fetch emscripten generated javascript runtime + var emscriptenModuleSource = undefined + var emscriptenModuleSourcePromise = fetchText(applicationName + ".js").then(function(source) { + emscriptenModuleSource = source + }); + + // Fetch and compile wasm module + var wasmModule = undefined; + var wasmModulePromise = fetchCompileWasm(applicationName + ".wasm").then(function (module) { + wasmModule = module; + }); + + // Wait for all resources ready + Promise.all([emscriptenModuleSourcePromise, wasmModulePromise]).then(function(){ + completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule); + }).catch(function(error) { + self.error = error; + setStatus("Error"); + }); + } + + function completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule) { + + // The wasm binary has been compiled into a module during resource download, + // and is ready to be instantiated. Define the instantiateWasm callback which + // emscripten will call to create the instance. + Module.instantiateWasm = function(imports, successCallback) { + WebAssembly.instantiate(wasmModule, imports).then(function(instance) { + successCallback(instance, wasmModule); + }, function(error) { + self.error = error; + setStatus("Error"); + }); + return {}; + }; + + Module.locateFile = Module.locateFile || function(filename) { + return config.path + filename; + }; + + // Attach status callbacks + Module.setStatus = Module.setStatus || function(text) { + // Currently the only usable status update from this function + // is "Running..." + if (text.startsWith("Running")) + setStatus("Running"); + }; + Module.monitorRunDependencies = Module.monitorRunDependencies || function(left) { + // console.log("monitorRunDependencies " + left) + }; + + // Attach standard out/err callbacks. + Module.print = Module.print || function(text) { + if (config.stdoutEnabled) + console.log(text) + }; + Module.printErr = Module.printErr || function(text) { + // Filter out OpenGL getProcAddress warnings. Qt tries to resolve + // all possible function/extension names at startup which causes + // emscripten to spam the console log with warnings. + if (text.startsWith !== undefined && text.startsWith("bad name in getProcAddress:")) + return; + + if (config.stderrEnabled) + console.log(text) + }; + + // Error handling: set status to "Exited", update crashed and + // exitCode according to exit type. + // Emscripten will typically call printErr with the error text + // as well. Note that emscripten may also throw exceptions from + // async callbacks. These should be handled in window.onerror by user code. + Module.onAbort = Module.onAbort || function(text) { + publicAPI.crashed = true; + publicAPI.exitText = text; + setStatus("Exited"); + }; + Module.quit = Module.quit || function(code, exception) { + if (exception.name == "ExitStatus") { + // Clean exit with code + publicAPI.exitText = undefined + publicAPI.exitCode = code; + } else { + publicAPI.exitText = exception.toString(); + publicAPI.crashed = true; + } + setStatus("Exited"); + }; + + // Set environment variables + Module.preRun = Module.preRun || [] + Module.preRun.push(function() { + for (var [key, value] of Object.entries(config.environment)) { + ENV[key.toUpperCase()] = value; + } + }); + + Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'}); + + Module.qtCanvasElements = config.canvasElements; + + config.restart = function() { + + // Restart by reloading the page. This will wipe all state which means + // reload loops can't be prevented. + if (config.restartType == "ReloadPage") { + location.reload(); + } + + // Restart by readling the emscripten app module. + ++self.restartCount; + if (self.restartCount > config.restartLimit) { + self.error = "Error: This application has crashed too many times and has been disabled. Reload the page to try again." + setStatus("Error"); + return; + } + loadEmscriptenModule(applicationName); + }; + + publicAPI.exitCode = undefined; + publicAPI.exitText = undefined; + publicAPI.crashed = false; + + // Finally evaluate the emscripten application script, which will + // reference the global Module object created above. + self.eval(emscriptenModuleSource); // ES5 indirect global scope eval + } + + function setErrorContent() { + if (config.containerElements === undefined) { + if (config.showError !== undefined) + config.showError(self.error); + return; + } + + for (container of config.containerElements) { + var errorElement = config.showError(self.error, container); + container.appendChild(errorElement); + } + } + + function setLoaderContent() { + if (config.containerElements === undefined) { + if (config.showLoader !== undefined) + config.showLoader(self.loaderSubState); + return; + } + + for (container of config.containerElements) { + var loaderElement = config.showLoader(self.loaderSubState, container); + container.appendChild(loaderElement); + } + } + + function setCanvasContent() { + if (config.containerElements === undefined) { + if (config.showCanvas !== undefined) + config.showCanvas(); + return; + } + + for (var i = 0; i < config.containerElements.length; ++i) { + var container = config.containerElements[i]; + var canvas = config.canvasElements[i]; + config.showCanvas(canvas, container); + container.appendChild(canvas); + } + } + + function setExitContent() { + + // publicAPI.crashed = true; + + if (publicAPI.status != "Exited") + return; + + if (config.containerElements === undefined) { + if (config.showExit !== undefined) + config.showExit(publicAPI.crashed, publicAPI.exitCode); + return; + } + + if (!publicAPI.crashed) + return; + + for (container of config.containerElements) { + var loaderElement = config.showExit(publicAPI.crashed, publicAPI.exitCode, container); + if (loaderElement !== undefined) + container.appendChild(loaderElement); + } + } + + var committedStatus = undefined; + function handleStatusChange() { + if (publicAPI.status != "Loading" && committedStatus == publicAPI.status) + return; + committedStatus = publicAPI.status; + + if (publicAPI.status == "Error") { + setErrorContent(); + } else if (publicAPI.status == "Loading") { + setLoaderContent(); + } else if (publicAPI.status == "Running") { + setCanvasContent(); + } else if (publicAPI.status == "Exited") { + if (config.restartMode == "RestartOnExit" || + config.restartMode == "RestartOnCrash" && publicAPI.crashed) { + committedStatus = undefined; + config.restart(); + } else { + setExitContent(); + } + } + + // Send status change notification + if (config.statusChanged) + config.statusChanged(publicAPI.status); + } + + function setStatus(status) { + if (status != "Loading" && publicAPI.status == status) + return; + publicAPI.status = status; + + window.setTimeout(function() { handleStatusChange(); }, 0); + } + + function addCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtAddCanvasElement(element); + else + console.log("Error: addCanvasElement can only be called in the Running state"); + } + + function removeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtRemoveCanvasElement(element); + else + console.log("Error: removeCanvasElement can only be called in the Running state"); + } + + function resizeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtResizeCanvasElement(element); + } + + function setFontDpi(dpi) { + Module.qtFontDpi = dpi; + if (publicAPI.status == "Running") + Module.qtSetFontDpi(dpi); + } + + function fontDpi() { + return Module.qtFontDpi; + } + + setStatus("Created"); + + return publicAPI; +} diff --git a/docs/qcustomplotdemo/qtlogo.svg b/docs/qcustomplotdemo/qtlogo.svg new file mode 100644 index 0000000..ad7c777 --- /dev/null +++ b/docs/qcustomplotdemo/qtlogo.svg @@ -0,0 +1,40 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/docs/qtloader.js b/docs/qtloader.js new file mode 100644 index 0000000..ef4a6ec --- /dev/null +++ b/docs/qtloader.js @@ -0,0 +1,577 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// QtLoader provides javascript API for managing Qt application modules. +// +// QtLoader provides API on top of Emscripten which supports common lifecycle +// tasks such as displaying placeholder content while the module downloads, +// handing application exits, and checking for browser wasm support. +// +// There are two usage modes: +// * Managed: QtLoader owns and manages the HTML display elements like +// the loader and canvas. +// * External: The embedding HTML page owns the display elements. QtLoader +// provides event callbacks which the page reacts to. +// +// Managed mode usage: +// +// var config = { +// containerElements : [$("container-id")]; +// } +// var qtLoader = QtLoader(config); +// qtLoader.loadEmscriptenModule("applicationName"); +// +// External mode.usage: +// +// var config = { +// canvasElements : [$("canvas-id")], +// showLoader: function() { +// loader.style.display = 'block' +// canvas.style.display = 'hidden' +// }, +// showCanvas: function() { +// loader.style.display = 'hidden' +// canvas.style.display = 'block' +// return canvas; +// } +// } +// var qtLoader = QtLoader(config); +// qtLoader.loadEmscriptenModule("applicationName"); +// +// Config keys +// +// containerElements : [container-element, ...] +// One or more HTML elements. QtLoader will display loader elements +// on these while loading the applicaton, and replace the loader with a +// canvas on load complete. +// canvasElements : [canvas-element, ...] +// One or more canvas elements. +// showLoader : function(status, containerElement) +// Optional loading element constructor function. Implement to create +// a custom loading screen. This function may be called multiple times, +// while preparing the application binary. "status" is a string +// containing the loading sub-status, and may be either "Downloading", +// or "Compiling". The browser may be using streaming compilation, in +// which case the wasm module is compiled during downloading and the +// there is no separate compile step. +// showCanvas : function(containerElement) +// Optional canvas constructor function. Implement to create custom +// canvas elements. +// showExit : function(crashed, exitCode, containerElement) +// Optional exited element constructor function. +// showError : function(crashed, exitCode, containerElement) +// Optional error element constructor function. +// +// path : +// Prefix path for wasm file, realative to the loading HMTL file. +// restartMode : "DoNotRestart", "RestartOnExit", "RestartOnCrash" +// Controls whether the application should be reloaded on exits. The default is "DoNotRestart" +// restartType : "RestartModule", "ReloadPage" +// restartLimit : +// Restart attempts limit. The default is 10. +// stdoutEnabled : +// stderrEnabled : +// environment : +// key-value environment variable pairs. +// +// QtLoader object API +// +// webAssemblySupported : bool +// webGLSupported : bool +// canLoadQt : bool +// Reports if WebAssembly and WebGL are supported. These are requirements for +// running Qt applications. +// loadEmscriptenModule(applicationName) +// Loads the application from the given emscripten javascript module file and wasm file +// status +// One of "Created", "Loading", "Running", "Exited". +// crashed +// Set to true if there was an unclean exit. +// exitCode +// main()/emscripten_force_exit() return code. Valid on status change to +// "Exited", iff crashed is false. +// exitText +// Abort/exit message. +// addCanvasElement +// Add canvas at run-time. Adds a corresponding QScreen, +// removeCanvasElement +// Remove canvas at run-time. Removes the corresponding QScreen. +// resizeCanvasElement +// Signals to the application that a canvas has been resized. +// setFontDpi +// Sets the logical font dpi for the application. + + +var Module = {} + +function QtLoader(config) +{ + function webAssemblySupported() { + return typeof WebAssembly !== "undefined" + } + + function webGLSupported() { + // We expect that WebGL is supported if WebAssembly is; however + // the GPU may be blacklisted. + try { + var canvas = document.createElement("canvas"); + return !!(window.WebGLRenderingContext && (canvas.getContext("webgl") || canvas.getContext("experimental-webgl"))); + } catch (e) { + return false; + } + } + + function canLoadQt() { + // The current Qt implementation requires WebAssembly (asm.js is not in use), + // and also WebGL (there is no raster fallback). + return webAssemblySupported() && webGLSupported(); + } + + function removeChildren(element) { + while (element.firstChild) element.removeChild(element.firstChild); + } + + function createCanvas() { + var canvas = document.createElement("canvas"); + canvas.className = "QtCanvas"; + canvas.style.height = "100%"; + canvas.style.width = "100%"; + + // Set contentEditable in order to enable clipboard events; hide the resulting focus frame. + canvas.contentEditable = true; + canvas.style.outline = "0px solid transparent"; + canvas.style.caretColor = "transparent"; + canvas.style.cursor = "default"; + + return canvas; + } + + // Set default state handler functions and create canvases if needed + if (config.containerElements !== undefined) { + + config.canvasElements = config.containerElements.map(createCanvas); + + config.showError = config.showError || function(errorText, container) { + removeChildren(container); + var errorTextElement = document.createElement("text"); + errorTextElement.className = "QtError" + errorTextElement.innerHTML = errorText; + return errorTextElement; + } + + config.showLoader = config.showLoader || function(loadingState, container) { + removeChildren(container); + var loadingText = document.createElement("text"); + loadingText.className = "QtLoading" + loadingText.innerHTML = '

    ${loadingState}...

    '; + return loadingText; + }; + + config.showCanvas = config.showCanvas || function(canvas, container) { + removeChildren(container); + } + + config.showExit = config.showExit || function(crashed, exitCode, container) { + if (!crashed) + return undefined; + + removeChildren(container); + var fontSize = 54; + var crashSymbols = ["\u{1F615}", "\u{1F614}", "\u{1F644}", "\u{1F928}", "\u{1F62C}", + "\u{1F915}", "\u{2639}", "\u{1F62E}", "\u{1F61E}", "\u{1F633}"]; + var symbolIndex = Math.floor(Math.random() * crashSymbols.length); + var errorHtml = ` ${crashSymbols[symbolIndex]} ` + var errorElement = document.createElement("text"); + errorElement.className = "QtExit" + errorElement.innerHTML = errorHtml; + return errorElement; + } + } + + config.restartMode = config.restartMode || "DoNotRestart"; + config.restartLimit = config.restartLimit || 10; + + if (config.stdoutEnabled === undefined) config.stdoutEnabled = true; + if (config.stderrEnabled === undefined) config.stderrEnabled = true; + + // Make sure config.path is defined and ends with "/" if needed + if (config.path === undefined) + config.path = ""; + if (config.path.length > 0 && !config.path.endsWith("/")) + config.path = config.path.concat("/"); + + if (config.environment === undefined) + config.environment = {}; + + var publicAPI = {}; + publicAPI.webAssemblySupported = webAssemblySupported(); + publicAPI.webGLSupported = webGLSupported(); + publicAPI.canLoadQt = canLoadQt(); + publicAPI.canLoadApplication = canLoadQt(); + publicAPI.status = undefined; + publicAPI.loadEmscriptenModule = loadEmscriptenModule; + publicAPI.addCanvasElement = addCanvasElement; + publicAPI.removeCanvasElement = removeCanvasElement; + publicAPI.resizeCanvasElement = resizeCanvasElement; + publicAPI.setFontDpi = setFontDpi; + publicAPI.fontDpi = fontDpi; + + restartCount = 0; + + function fetchResource(filePath) { + var fullPath = config.path + filePath; + return fetch(fullPath).then(function(response) { + if (!response.ok) { + self.error = response.status + " " + response.statusText + " " + response.url; + setStatus("Error"); + return Promise.reject(self.error) + } else { + return response; + } + }); + } + + function fetchText(filePath) { + return fetchResource(filePath).then(function(response) { + return response.text(); + }); + } + + function fetchThenCompileWasm(response) { + return response.arrayBuffer().then(function(data) { + self.loaderSubState = "Compiling"; + setStatus("Loading") // trigger loaderSubState udpate + return WebAssembly.compile(data); + }); + } + + function fetchCompileWasm(filePath) { + return fetchResource(filePath).then(function(response) { + if (typeof WebAssembly.compileStreaming !== "undefined") { + self.loaderSubState = "Downloading/Compiling"; + setStatus("Loading"); + return WebAssembly.compileStreaming(response).catch(function(error) { + // compileStreaming may/will fail if the server does not set the correct + // mime type (application/wasm) for the wasm file. Fall back to fetch, + // then compile in this case. + return fetchThenCompileWasm(response); + }); + } else { + // Fall back to fetch, then compile if compileStreaming is not supported + return fetchThenCompileWasm(response); + } + }); + } + + function loadEmscriptenModule(applicationName) { + + // Loading in qtloader.js goes through four steps: + // 1) Check prerequisites + // 2) Download resources + // 3) Configure the emscripten Module object + // 4) Start the emcripten runtime, after which emscripten takes over + + // Check for Wasm & WebGL support; set error and return before downloading resources if missing + if (!webAssemblySupported()) { + self.error = "Error: WebAssembly is not supported" + setStatus("Error"); + return; + } + if (!webGLSupported()) { + self.error = "Error: WebGL is not supported" + setStatus("Error"); + return; + } + + // Continue waiting if loadEmscriptenModule() is called again + if (publicAPI.status == "Loading") + return; + self.loaderSubState = "Downloading"; + setStatus("Loading"); + + // Fetch emscripten generated javascript runtime + var emscriptenModuleSource = undefined + var emscriptenModuleSourcePromise = fetchText(applicationName + ".js").then(function(source) { + emscriptenModuleSource = source + }); + + // Fetch and compile wasm module + var wasmModule = undefined; + var wasmModulePromise = fetchCompileWasm(applicationName + ".wasm").then(function (module) { + wasmModule = module; + }); + + // Wait for all resources ready + Promise.all([emscriptenModuleSourcePromise, wasmModulePromise]).then(function(){ + completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule); + }).catch(function(error) { + self.error = error; + setStatus("Error"); + }); + } + + function completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule) { + + // The wasm binary has been compiled into a module during resource download, + // and is ready to be instantiated. Define the instantiateWasm callback which + // emscripten will call to create the instance. + Module.instantiateWasm = function(imports, successCallback) { + WebAssembly.instantiate(wasmModule, imports).then(function(instance) { + successCallback(instance, wasmModule); + }, function(error) { + self.error = error; + setStatus("Error"); + }); + return {}; + }; + + Module.locateFile = Module.locateFile || function(filename) { + return config.path + filename; + }; + + // Attach status callbacks + Module.setStatus = Module.setStatus || function(text) { + // Currently the only usable status update from this function + // is "Running..." + if (text.startsWith("Running")) + setStatus("Running"); + }; + Module.monitorRunDependencies = Module.monitorRunDependencies || function(left) { + // console.log("monitorRunDependencies " + left) + }; + + // Attach standard out/err callbacks. + Module.print = Module.print || function(text) { + if (config.stdoutEnabled) + console.log(text) + }; + Module.printErr = Module.printErr || function(text) { + // Filter out OpenGL getProcAddress warnings. Qt tries to resolve + // all possible function/extension names at startup which causes + // emscripten to spam the console log with warnings. + if (text.startsWith !== undefined && text.startsWith("bad name in getProcAddress:")) + return; + + if (config.stderrEnabled) + console.log(text) + }; + + // Error handling: set status to "Exited", update crashed and + // exitCode according to exit type. + // Emscripten will typically call printErr with the error text + // as well. Note that emscripten may also throw exceptions from + // async callbacks. These should be handled in window.onerror by user code. + Module.onAbort = Module.onAbort || function(text) { + publicAPI.crashed = true; + publicAPI.exitText = text; + setStatus("Exited"); + }; + Module.quit = Module.quit || function(code, exception) { + if (exception.name == "ExitStatus") { + // Clean exit with code + publicAPI.exitText = undefined + publicAPI.exitCode = code; + } else { + publicAPI.exitText = exception.toString(); + publicAPI.crashed = true; + } + setStatus("Exited"); + }; + + // Set environment variables + Module.preRun = Module.preRun || [] + Module.preRun.push(function() { + for (var [key, value] of Object.entries(config.environment)) { + ENV[key.toUpperCase()] = value; + } + }); + + Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'}); + + Module.qtCanvasElements = config.canvasElements; + + config.restart = function() { + + // Restart by reloading the page. This will wipe all state which means + // reload loops can't be prevented. + if (config.restartType == "ReloadPage") { + location.reload(); + } + + // Restart by readling the emscripten app module. + ++self.restartCount; + if (self.restartCount > config.restartLimit) { + self.error = "Error: This application has crashed too many times and has been disabled. Reload the page to try again." + setStatus("Error"); + return; + } + loadEmscriptenModule(applicationName); + }; + + publicAPI.exitCode = undefined; + publicAPI.exitText = undefined; + publicAPI.crashed = false; + + // Finally evaluate the emscripten application script, which will + // reference the global Module object created above. + self.eval(emscriptenModuleSource); // ES5 indirect global scope eval + } + + function setErrorContent() { + if (config.containerElements === undefined) { + if (config.showError !== undefined) + config.showError(self.error); + return; + } + + for (container of config.containerElements) { + var errorElement = config.showError(self.error, container); + container.appendChild(errorElement); + } + } + + function setLoaderContent() { + if (config.containerElements === undefined) { + if (config.showLoader !== undefined) + config.showLoader(self.loaderSubState); + return; + } + + for (container of config.containerElements) { + var loaderElement = config.showLoader(self.loaderSubState, container); + container.appendChild(loaderElement); + } + } + + function setCanvasContent() { + if (config.containerElements === undefined) { + if (config.showCanvas !== undefined) + config.showCanvas(); + return; + } + + for (var i = 0; i < config.containerElements.length; ++i) { + var container = config.containerElements[i]; + var canvas = config.canvasElements[i]; + config.showCanvas(canvas, container); + container.appendChild(canvas); + } + } + + function setExitContent() { + + // publicAPI.crashed = true; + + if (publicAPI.status != "Exited") + return; + + if (config.containerElements === undefined) { + if (config.showExit !== undefined) + config.showExit(publicAPI.crashed, publicAPI.exitCode); + return; + } + + if (!publicAPI.crashed) + return; + + for (container of config.containerElements) { + var loaderElement = config.showExit(publicAPI.crashed, publicAPI.exitCode, container); + if (loaderElement !== undefined) + container.appendChild(loaderElement); + } + } + + var committedStatus = undefined; + function handleStatusChange() { + if (publicAPI.status != "Loading" && committedStatus == publicAPI.status) + return; + committedStatus = publicAPI.status; + + if (publicAPI.status == "Error") { + setErrorContent(); + } else if (publicAPI.status == "Loading") { + setLoaderContent(); + } else if (publicAPI.status == "Running") { + setCanvasContent(); + } else if (publicAPI.status == "Exited") { + if (config.restartMode == "RestartOnExit" || + config.restartMode == "RestartOnCrash" && publicAPI.crashed) { + committedStatus = undefined; + config.restart(); + } else { + setExitContent(); + } + } + + // Send status change notification + if (config.statusChanged) + config.statusChanged(publicAPI.status); + } + + function setStatus(status) { + if (status != "Loading" && publicAPI.status == status) + return; + publicAPI.status = status; + + window.setTimeout(function() { handleStatusChange(); }, 0); + } + + function addCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtAddCanvasElement(element); + else + console.log("Error: addCanvasElement can only be called in the Running state"); + } + + function removeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtRemoveCanvasElement(element); + else + console.log("Error: removeCanvasElement can only be called in the Running state"); + } + + function resizeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtResizeCanvasElement(element); + } + + function setFontDpi(dpi) { + Module.qtFontDpi = dpi; + if (publicAPI.status == "Running") + Module.qtSetFontDpi(dpi); + } + + function fontDpi() { + return Module.qtFontDpi; + } + + setStatus("Created"); + + return publicAPI; +} diff --git a/docs/qtlogo.svg b/docs/qtlogo.svg new file mode 100644 index 0000000..ad7c777 --- /dev/null +++ b/docs/qtlogo.svg @@ -0,0 +1,40 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/docs/video_system.html b/docs/video_system.html new file mode 100644 index 0000000..363adfb --- /dev/null +++ b/docs/video_system.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/video_system/index.html b/docs/video_system/index.html new file mode 100644 index 0000000..2dcaa48 --- /dev/null +++ b/docs/video_system/index.html @@ -0,0 +1,750 @@ + + + + + +视频监控系统开发及使用手册 + +

    +
  • 0 前言说明

    0.1 系统说明

    1. 本视频监控系统做的是通用的系统,主要偏重整体框架和UI交互等。

    2. 主要功能包括摄像机管理,实时视频显示,视频轮询、视频存储、设备地图显示,各种画面切换,各种悬停子模块、onvif搜索设备和云台控制及预置位,通用的NVR视频流播放(比如海康的NVR支持直接取流回放),录像计划、用户管理等功能。

    3. 如果是依赖SDK去实现的功能(雨刷、去雾等)都没有做,那个破坏了兼容性,无法通用其他摄像机设备以及其他操作系统。

    4. 每个厂家SDK和定制的功能都不一样,如果有这方面的需要都是买过去自己加上SDK的功能和自己定制需要的功能。

    5. 整个项目源代码行数大概30W行(项目代码本身除去第三方库以后约7W行,就是自己写的部分),其中代码13.5W行(占比45%),注释12.7W行(占比42%),空行3.5W行。分层设计注释详细。

    6. 本程序会一直持续迭代更新,包括项目源码、整体框架、使用说明等,一次购买终生售后。

    0.2 特别说明

    1. 程序本身是个客户端(直接从摄像机或者NVR等设备取rtsp视频流)并不是服务器程序。

    2. 摄像机管理没有限制摄像机的数量,理论上10000路肯定没有问题,就是个数据库记录。

    3. 实时显示具体能支持多少路,和具体的电脑配置有关(亲测1.8G主频8G内存I5子码流64路,总之比海康大华客户端要更优秀)。

    4. 程序实时显示界面最大可以到64路,每个通道都是打开的时候才会去建立连接取视频流,而不是一开始就建立了连接。

    5. 系统采用onvif协议+rtsp视频流机制,并不限定支持哪家的摄像机,只要符合这两种协议的都支持,市面上99%的网络摄像机都支持这两种基础协议,包括但不限于海康、大华、宇视、天地伟业、华为等各种安防厂家的摄像机。

    6. 本系统没有内置人脸识别等任何相关算法,提供的是相关的接口,比如自己的算法识别到人脸区域后,将区域坐标传入视频控件自动绘制。

    7. 系统采用纯QtWidget(非qml)编写,解码采用ffmpeg,搜索采用onvif协议,视频播放采用rtsp协议,所有源码开放,没有封装的库。

    8. 同时集成了数据库、多线程、串口通信、网络通信、音视频解码/同步/存储、网页地图、界面美化、UI布局等众多知识点。

    9. 未经本人许可不可将本项目源码扩散,如有发现本人将追究法律责任,谢谢配合。

    0.3 相关站点

    1. 国内站点:https://gitee.com/feiyangqingyun

    2. 国际站点:https://github.com/feiyangqingyun

    3. 个人主页:https://blog.csdn.net/feiyangqingyun

    4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun

    5. 产品主页:https://blog.csdn.net/feiyangqingyun/article/details/97565652

    6. 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/video_system/

    7. 体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_system.zip。

    8. 文章导航:https://qtchina.blog.csdn.net/article/details/121327495

    0.4 功能特点

    0.4.1 软件模块

    1. 视频监控模块,各种停靠小窗体子模块,包括设备列表、图文警情、窗口信息、云台控制、预置位、巡航设置、设备控制、悬浮地图、网页浏览等。

    2. 视频回放模块,包括本地回放、远程回放、设备播放、图片回放、视频上传等。

    3. 电子地图模块,包括图片地图、在线地图、离线地图、路径规划等。

    4. 日志查询模块,包括本地日志、设备日志等。

    5. 系统设置模块,包括系统设置(基本设置、视频参数、数据库设置、地图配置、串口配置等)、录像机管理、摄像机管理、轮询配置、录像计划、用户管理等。

    0.4.2 基础功能

    1. 支持各种视频流(rtsp、rtmp、http等)、视频文件(mp4、rmvb、avi等)、本地USB摄像机播放。

    2. 支持多画面切换,包括1、4、6、8、9、13、16、25、36、64画面切换。

    3. 支持全屏切换,多种切换方式包括鼠标右键菜单、工具栏按钮、快捷键(alt+enter全屏,esc退出全屏)。

    4. 支持视频轮询,包括1、4、9、16画面轮询,可设置轮询分组(轮询预案)、轮询间隔、码流类型等。

    5. 支持onvif协议,包括设备搜索、云台控制、预置位、设备控制(图片参数、校对时间、系统重启,抓拍图片等)。

    6. 支持权限管理,不同的用户可以对应不同的模块权限,比如删除日志、关闭系统等。

    7. 数据库支持多种,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金仓等。

    8. 本地USB摄像机支持设置分辨率、帧率等参数。

    9. 所有停靠模块都自动生成对应的菜单用来控制显示和隐藏,在标题栏右键可以弹出。

    10. 支持显示所有模块、隐藏所有模块、复位普通布局、复位全屏布局。

    11. 双击设备弹出实时预览视频,支持图片地图、在线地图、离线地图等。

    12. 摄像机节点拖曳到对应窗体播放视频,同时支持拖曳本地文件直接播放。

    13. 删除视频支持鼠标右键删除、悬浮条关闭删除、拖曳到视频监控面板外删除等多种方式。

    14. 图片地图上设备按钮可自由拖动,自动保存位置信息。百度地图上可以鼠标单击获取经纬度信息,用来更新设备位置。

    15. 视频监控面板窗体中任意通道支持拖曳交换,瞬间响应。

    16. 封装了百度地图,视图切换,运动轨迹,设备点位,鼠标按下获取经纬度等。

    17. 双击节点、拖曳节点、拖曳窗体交换位置等操作,均自动更新保存最后的播放地址,下次软件打开自动应用。

    18. 右下角音量条控件,失去焦点自动隐藏,音量条带静音图标,自动记忆最后的音量及静音状态。

    19. 支持视频截图,可指定单个或者对所有通道截图,底部小工具栏也有截图按钮,每个视频控件悬浮条也有抓拍按钮。

    20. 支持超时自动隐藏鼠标指针、自动全屏机制。

    21. 支持onvif云台控制,可上下左右移动云台摄像机,包括复位和焦距调整等。

    22. 支持onvif预置位,可以添加、删除、修改预置位,可以调用起始位。

    23. 支持OSD增删改查,可以通过onvif协议添加及修改OSD信息。

    24. 支持onvif图像参数设置,包括明亮度、对比度、饱和度、尖锐度等。

    25. 支持onvif其他操作,包括抓图、网络设置、校时、重启、事件订阅等。

    26. 支持任意onvif摄像机,包括但不限于海康、大华、宇视、天地伟业、华为等。

    27. 可保存视频,可通过录像计划存储,也可在悬浮条手动切换开始录像和停止录像。

    28. 可设置视频流通信方式tcp或udp,可设置视频解码是速度优先、质量优先、均衡处理、最快速度等。

    29. 可设置软件中文名称、英文名称、LOGO图标等。

    30. 存储的视频文件支持导出到指定目录,支持批量上传到服务器。

    31. 完善的录像计划设置,支持每个通道7 * 24小时每半小时设置是否存储录像。

    32. 音视频同步显示以及音视频同步存储到MP4文件。

    0.4.3 特色功能

    1. 主界面采用停靠窗体模式,各种组件以小模块的形式加入,可自定义任意模块加入。

    2. 停靠模块可拖动任意位置嵌入和悬浮,支持最大化全屏,支持多屏幕。

    3. 双重布局文件存储机制,正常模式、全屏模式都对应不同的布局方案,自动切换和保存,比如全屏模式可以突出几个模块透明显示在指定位置,更具科幻感现代化。

    4. 原创onvif协议机制,采用底层协议解析(udp广播搜索+http请求执行命令)更轻量易懂易学习拓展,不依赖任何第三方组件比如gsoap。

    5. 原创数据导入、导出、打印机制,跨平台不依赖任何组件,瞬间导出数据。

    6. 内置多个原创组件,宇宙超值超级牛逼,包括数据导入导出组件(导出到xls、pdf、打印)、数据库组件(数据库管理线程、自动清理数据线程、万能分页、数据请求等)、地图组件、视频监控组件、文件多线程收发组件、onvif通信组件、通用浏览器内核组件等。

    7. 自定义信息框+错误框+询问框+右下角提示框(包含多种格式)等。

    8. 精美换肤,高达20套皮肤样式随意更换,所有样式全部统一,包括菜单等。

    9. 选中通道对应设备树节点高亮,选中通道节点对应视频控件高亮,方便查看当前通道信息。

    10. 视频控件悬浮条可以自行增加多个按钮,监控界面底部小工具栏也可自行增加按钮。

    11. 双击摄像机节点自动播放视频,双击节点自动依次添加视频,会自动跳到下一个,双击父节点自动添加该节点下的所有视频。可选主码流、子码流。

    12. 录像机管理、摄像机管理,可添加删除修改导入导出打印信息,立即应用新的设备信息生成树状列表,不需重启。

    13. 可选多种内核自由切换,ffmpeg、vlc、mpv等,均可在pro中设置。推荐用ffmpeg,跨平台最多,默认提供好了linux和mac平台上编译好的库。

    14. 支持硬解码,可设置硬解码类型(qsv、dxva2、d3d11va等)。

    15. 默认采用opengl绘制视频,超低的CPU资源占用,支持yuyv和nv12两种格式绘制,性能爆表。

    16. 标签和图形信息支持三种绘制方式,绘制到遮罩层、绘制到图片、源头绘制(对应信息可以存储到文件)。

    17. 包括但不限于视频监控内核组件的所有功能,可参阅说明书中功能介绍 视频监控内核

    18. 高度可定制化,用户可以很方便的在此基础上衍生自己的功能,比如增加自定义模块,增加运行模式、机器人监控、无人机监控、挖掘机监控等。

    19. 支持xp、win7、win10、win11、linux、mac、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。

    20. 注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。

    0.5 目录说明

    1. 本源码项目文件中对编译生成的临时文件和可执行文件做了重定向,可执行文件并不在build开头的目录下,而是在源码同级目录的bin目录下。

    2. config目录放的是软件的配置文件、地图模块需要的图片资源等。

    3. db目录一般有三个文件,key.db是秘钥文件、video_system.db是对应sqlite的数据库文件、video_system.sql是对应数据库脚本(可以在系统设置中数据库管理部分执行脚本用来切换到mysql等其他数据库)。

    4. logo目录存放的各种左上角软件LOGO图片,可以在系统设置中下拉选择。

    5. map目录存放的图片地图模块所用的地图图片文件,可以手动拷贝到此。

    6. sound目录存放的本系统所用的声音文件。

    7. layout目录存放的不同工作模式不同界面对应的布局方案配置文件。

    0.6 编译说明

    0.6.1 特别提示

    1. 本系统没有说基于哪个Qt版本,由于系统中电子地图模块用到了浏览器模块,所以理论上要求你电脑的Qt版本也有浏览器模块才行

    2. 如果没有则电子地图模块不可用,但是其余功能全部可用没有任何影响。

    3. 本人亲测Qt4.7到Qt6.7之间的所有版本(理论上支持后续所有版本),亲测msvc、mingw、gcc、clang、armgcc各种编译器,亲测xp、win7、win10、linux、mac、树莓派、香橙派、全志H3、cotex-A9、imx6等。

    4. 2021-1-6开始集成了miniblink浏览器内核,意味着mingw版本的qt5.6以上版本也全部支持,这样就所有系统都有浏览器模块不需要担心没有电子地图的问题。Qt6.4.1到Qt6.5.1之间的版本,miniblink浏览器控件会和openglwidget冲突导致白屏,建议避开这几个版本。

    5. 部分构建套件可能不支持预编译头,预编译头仅仅是为了加快编译速度,和程序本身无关。比如在win+Qt5.5 5.6就发现不支持,也可能是支持的不够全面,如果编译发生错误可以试着打开pro文件注释掉PRECOMPILED_HEADER = head.h 这行。

    6. Qt6.2的mingw版本的multimedia模块不可用,msvc版本的正常。

    7. 开启视频存储后默认存储的MP4格式的文件,如果想要调整体积大小,可以找到core/core_videoffmpeg/ffmpegsave.cpp videoCodecCtx->bit_rate = FFmpegHelper::getBitRate(videoWidth, videoHeight); 将这个码率调小即可,比如 videoCodecCtx->bit_rate = FFmpegHelper::getBitRate(videoWidth, videoHeight)/2; 可以将体积减少一半,相应的画质也会差一些。

    8. 推荐用64位的Qt搭配64位的ffmpeg,目前绝大部分系统都是64位的,能获得最大性能提升,本人亲自对比测试32位和64位,64位无论资源占用和操作响应等体验都更优。尤其是开启硬解码后,如果64个通道都需要硬解码,32位的测试下来貌似资源不够用。

    9. 如果更改appconfig.cpp中的值发现没有变化,那是因为里面的值是用来默认生成配置文件的值,如果配置文件已经存在,则对应变量是从配置文件读取的值,如果想要更改后的默认值生效,需要删除配置文件(config/video_system.ini)重新打开程序即可。

    10. 内核ffmpeg画框画文字水印等采用的滤镜实现,默认硬解码的数据是NV12不支持滤镜,意味着画框等无效,绘制文字有效,如果一定要在硬解码的帧数据画框,可以使用包含各种形状比如正方形/三角形/矩形的图形字体,指定图形字体的值来绘制。

    0.6.2 注意事项

    1. 可执行文件在源码同级目录的bin目录下。

    2. 编译完成后记得将源码下的file目录下(切记是file目录下而不是file目录)的所有文件复制到可执行文件同一目录。

    3. 如果开启了视频监控(默认开启),则记得将对应的动态库文件复制到可执行文件同一目录。比如采用ffmpeg内核(默认就是ffmpeg)的话,则将下载到的dll_ffmpeg4下的所有文件复制到可执行文件同一目录。

    4. 各个操作系统对应的ffmpeg编译好的动态库以及miniblink的动态库下载地址。 +https://pan.baidu.com/s/13LDRu6mXC6gaADtrGprNVA  提取码: ujm7。

    5. 如果是64位的qt则对应的dll是拷贝dll_ffmpeg4_64目录下的,64位的linux对应的是linuxlib64.tar.gz。

    6. 本系统支持ffmpeg2/3/4/5/6所有版本,默认是ffmpeg4,如果要支持XP需要用ffmpeg2/3。如果是在linux/mac系统上编译记得查看core_videoffmpeg/下面的 linux系统和mac系统上库的用法.txt/编译阶段linux系统ffmpeg库放置位置.jpg/运行阶段linux系统ffmpeg库放置位置.jpg。

    7. 如果编译运行提示miniblink文件不存在请先拷贝,则说明你当前用的Qt版本没有浏览器模块,要么没安装,要么不支持,你也不用担心啥,此时自动切换用的miniblink浏览器内核,你还需要将ffmpeg库下载的网盘的地方找到dll_miniblink.zip下载解压到可执行文件同一目录即可。

    8. 系统中所有的图标,都采用的图形字体,对照表在doc目录下的FontAwesome.png、FontAliBaBa.png,对应图形字体类IconHelper中加载的图形字体,后期如果还有增加的其他图形字体也是放在这里,一个类支持多种图形字体,通过不同的值范围自动设置。

    9. 如果发现地图打不开或者提示秘钥文件丢失,请先确认file目录下的所有文件有没有拷贝过去。

    10. 如果是用vs+qt可能报错 error LNK2026,解决办法详细见本文档中13其他说明/13.5环境使用qt+vs。

    11. 默认用户名admin 密码admin。

    12. 系统配置参数在加载的时候会对节点值进行过滤判断,如果为空会自动用初始值生成新的配置文件,如果不想要显示版权所有公司,可以填xxx而不是删掉整个值。

    13. 如果是用vlc推流的rtsp地址,比如 rtsp://:8554/aabb,由于vlc推流默认写死的采用的udp协议,所以监控系统也必须在系统设置中通信方式选择udp才行(默认tcp)。

    0.6.3 离线地图

    1. 离线地图可以用网上的瓦片地图下载器下载百度的离线地图放到对应目录即可。

    2. 也可以直接下载网盘中已经下载好的上海市的离线地图。

    3. 下载地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名称:bin_map_tiles.tar.xz

    使用说明

    1. 将压缩包下的两个文件夹复制到对应可执行文件下的config文件夹下,和map.js文件同一级目录。

    2. tiles文件夹是街道图,tiles_hybrid文件夹是卫星图,tiles_self是路网图,路网图和卫星图合并就是混合图。

    3. 默认提供的是上海市徐汇区的瓦片地图,如果自己用万能地图下载器下载的百度地图的瓦片文件,也可以对应替换就行。

    4. 要注意的是格式,默认是jpg,如果下载的瓦片地图格式是png则需要打开config文件夹下的map_load.js文件,将.jpg改成.png保存即可。

    0.7 地址格式

    0.7.0 特别提示

    1. 由于编解码涉及到很多参数,一般都按照默认参数进行处理。

    2. 部分用户有时候希望通过填入的播放地址就带上这些信息,比如通信协议、桌面采集的分辨率、编码保存是否转码、转码是否缩放原图等。

    3. 各种参数设置有个优先级,优先取地址中带的,没有带则取结构体中的,还没有则取默认值。

    4. 有些值会根据具体情况自动调整,比如本地设备采集没有硬解码,udp开头的视频流强制用udp协议,有些不支持硬解的格式自动将硬解码=none。

    5. 对于需要在地址中指定参数,对应占位符不填的需要占位符留空,不可以跳过。

    6. 占位符中填了对应参数的必须严格按照指定的格式要求,不按照则很可能导致解析失败。

    7. 参数用英文竖杠 | 隔开。

    0.7.1 通用格式

    1. 格式要求: url|transport|encodeType|videoFormat|encodeVideoFps|encodeVideoRatio|encodeVideoScale。

    2. url表示媒体地址,比如 f:/1.mp3 d:/1.mp4 rtsp://192.168.0.100 等。

    3. transport表示通信协议,可选 tcp/udp,一般用于rtsp视频流,很多时候在linux系统中必须指定tcp,rtsp摄像头才能正常采集。

    4. encodeType表示编码策略,0-自动识别处理(非264/265/aac则转码),1-文件强制转码,2-所有全部转码,在调用录像函数的时候才会用到。

    5. videoFormat表示视频编码格式,0-自动处理(源头是264就264/265就265),1-强制用264编码,2-强制用265编码。

    6. encodeVideoFps表示编码帧率,默认取源头流的帧率,如果指定了则取指定的。

    7. encodeVideoRatio表示视频压缩比率,对应bit_rate的值,在不改变分辨率的情况下,通过调整这个参数来控制保存文件体积的大小。范围值0-1。

    8. encodeVideoScale表示视频缩放值,字符串类型,如果值float值,则相当于在原有分辨率按照这个值等比例缩放,比如encodeVideoScale=0.5,视频源分辨率是1920x720,则编码保存按照960x360这个分辨率保存。如果是640x480,则按照指定的这个分辨率强制缩放,可能会变形。

    0.7.2 本地摄像头

    1. 格式要求:url|bufferSize|frameRate。

    2. url表示媒体地址,采集摄像头统一约定 video=开头。

    3. bufferSize表示分辨率,可填1280x720这种,不填默认640x480。

    4. frameRate表示帧率,不填默认25。

    5. win系统如何查看设备名见本文档中 打开本地摄像头

    6. linux系统查看设备名直接执行命令 ls /dev/video * 即可,一般对应的设备名是 /dev/video0。

    7. 下面假定本地摄像头的设备名为 USB2.0 PC CAMERA。

    8. 写法1:video=USB2.0 PC CAMERA,这种写法默认按照640x480分辨率打开摄像头。

    9. 写法2:video=USB2.0 PC CAMERA|1280x720|30,这种写法按照指定的分辨率1280x720以及采集帧率30来打开摄像头。

    10. 写法3:video=/dev/video0,这种是对应linux系统,程序内部会自动过滤和调整填入的地址。

    11. 如果指定了分辨率和帧率则需要硬件支持才行,比如摄像头的最大分辨率是640x480,而指定了1280x720则会打开失败。

    0.7.3 本地桌面

    1. 格式要求:url|bufferSize|frameRate|offsetX|offsetY|screenIndex|encodeVideoScale。

    2. url表示媒体地址,采集桌面统一约定 desktop=开头。

    3. bufferSize表示采集分辨率,不填则默认取屏幕分辨率。

    4. frameRate表示采集帧率,基本上在2-30之间,不填的话默认ffmpeg会设定一个值,有时候是30。

    5. offsetX/offsetY表示偏移值XY坐标,从屏幕的左上角(0,0)开始。

    6. screenIndex表示屏幕索引,不填的话则默认取当前鼠标所在屏幕。在多个屏幕的时候可通过此参数指定屏幕索引。

    7. encodeVideoScale表示缩放,1表示原始比例(默认值1),0.2则表示按照原始分辨率等比例0.2倍缩放,也可以填400x300表示强制按照这个分辨率缩放。这个在高分辨率的时候特别有用,比如采集的桌面分辨率很大,但是传输的时候受限于带宽,需要等比例压缩一下再传输,此时可以填0.5/0.2之类的值。

    8. 写法1:desktop=desktop,当前屏幕全屏采集。

    9. 写法2:desktop=desktop||15|0|0|1,屏幕2全屏采集,帧率15。

    10. 写法3:desktop=desktop|800x600|10|50|100,鼠标所在当前屏幕采集,采集区域rect(50,100,800,600),帧率10。

    11. 写法4:desktop=desktop|10x10,约定10x10分辨率表示所有屏幕合并到一个屏幕采集,比如两个屏幕的时候,当做一个屏幕整体采集。当合并屏幕采集的时候,XY偏移值参数无效。

    12. 写法5:desktop=desktop|800x600|25|1500|300|255,约定屏幕索引255则取用户自定义的区域,该字符串表示采集区域是(1500, 300, 800, 600),自由区域,可以任意指定,比如两个屏幕中间区域。前提只要保证该区域在两个屏幕区域中,如果超过了的话可能采集失败,这要求用户需要对采集区域精准定位。

    13. 经过大量测试发现,如果打包发布的Qt程序带了qt.conf文件并且里面指定了 WindowsArguments = dpiawareness=0 ,在电脑分辨率设置了缩放比不为100%的时候,计算出来的桌面区域未必正确,建议如果此种情况下一定要采集正确的桌面,去掉qt.conf文件中的对应内容或者删除qt.conf文件即可。

    0.7.4 电视频道

    1. 中央综合:http://39.135.138.60:18890/PLTV/88888910/224/3221225618/index.m3u8

    2. 中央新闻:http://39.135.138.60:18890/PLTV/88888910/224/3221225638/index.m3u8

    3. 中央音乐:http://39.135.138.60:18890/PLTV/88888910/224/3221225641/index.m3u8

    4. 中央电视:http://39.135.138.60:18890/PLTV/88888910/224/3221225635/index.m3u8

    5. 中央记录:http://39.135.138.60:18890/PLTV/88888910/224/3221225646/index.m3u8

    6. 中央少儿:http://39.135.138.60:18890/PLTV/88888910/224/3221225639/index.m3u8

    7. 湖南卫视:http://39.135.138.60:18890/PLTV/88888910/224/3221225745/index.m3u8

    8. 深圳卫视:http://39.135.138.60:18890/PLTV/88888910/224/3221225741/index.m3u8

    9. 上海纪实:http://39.135.138.60:18890/PLTV/88888910/224/3221225654/index.m3u8

    10. 天津卫视:http://39.135.138.60:18890/PLTV/88888910/224/3221225739/index.m3u8

    0.7.5 视频文件

    万能办法,用谷歌或者谷歌内核的浏览器,打开时光网 http://www.mtime.com/ ,随便打开个视频,这里一般是预告片,按F12切换到审查元素,顶部切换到网络,选中媒体,刷新网页,按照尺寸排列,最大的那个MP4文件就是,鼠标右键复制地址,这个地址就是完整的网络地址。

    1. http://vfx.mtime.cn/Video/2021/11/16/mp4/211116131456748178.mp4

    2. http://vfx.mtime.cn/Video/2023/03/09/mp4/230309152143524121.mp4

    3. http://vfx.mtime.cn/Video/2023/03/07/mp4/230307085324679124.mp4

    4. http://vfx.mtime.cn/Video/2022/07/18/mp4/220718132929585151.mp4

    5. http://vfx.mtime.cn/Video/2022/12/17/mp4/221217153424902164.mp4

    6. http://vfx.mtime.cn/Video/2022/07/04/mp4/220704110656040153.mp4

    7. http://vfx.mtime.cn/Video/2021/02/08/mp4/210208150307073134.mp4

    8. http://vfx.mtime.cn/Video/2021/05/11/mp4/210511114524329144.mp4

    9. http://vfx.mtime.cn/Video/2021/04/20/mp4/210420113022586184.mp4

    10. http://vfx.mtime.cn/Video/2021/03/13/mp4/210313111010421158.mp4

    11. http://vfx.mtime.cn/Video/2020/01/15/mp4/200115125943120574.mp4

    百度视频

    1. https://vd2.bdstatic.com/mda-nhpqy7k8xamgiqw3/720p/h264/1661362621500413748/mda-nhpqy7k8xamgiqw3.mp4

    2. https://vd2.bdstatic.com/mda-nhp9zvu4tiinsp7z/576p/h264/1661324637707658476/mda-nhp9zvu4tiinsp7z.mp4

    3. https://vd4.bdstatic.com/mda-nhp77xn7fx3e0jgb/576p/h264/1661317610850513689/mda-nhp77xn7fx3e0jgb.mp4

    4. https://vd2.bdstatic.com/mda-nhp72n8xvbtdcmcq/576p/h264/1661317214259599500/mda-nhp72n8xvbtdcmcq.mp4

    5. https://vd2.bdstatic.com/mda-nhp6z0in87tvw77v/576p/h264/1661316943890074768/mda-nhp6z0in87tvw77v.mp4

    6. http://vd3.bdstatic.com/mda-jennyc5ci1ugrxzi/mda-jennyc5ci1ugrxzi.mp4

    7. http://vd2.bdstatic.com/mda-mhhf5mr00yyhpfjs/1080p/cae_h264/1629284581057661229/mda-mhhf5mr00yyhpfjs.mp4

    8. http://vd2.bdstatic.com/mda-mhig1c3sw223mx8p/1080p/cae_h264/1629380139191731149/mda-mhig1c3sw223mx8p.mp4

    9. http://vd3.bdstatic.com/mda-mekfm7wu6f4rtt99/1080p/cae_h264/1621595318412084671/mda-mekfm7wu6f4rtt99.mp4

    10. http://vd2.bdstatic.com/mda-mesdm11tdp69a9ye/1080p/cae_h264/1622115758783335310/mda-mesdm11tdp69a9ye.mp4

    时间很短的视频文件

    1. https://highlight-video.cdn.bcebos.com/video/6s/95ae2066-ee02-11ed-9f01-6c92bf5ceb6f.mp4

    2. https://highlight-video.cdn.bcebos.com/video/6s/1a74a352-d1fb-11ed-829b-6c92bf468c1f.mp4

    3. https://highlight-video.cdn.bcebos.com/video/6s/e0d35168-edf5-11ed-8709-6c92bf3b0281.mp4

    4. https://highlight-video.cdn.bcebos.com/video/6s/0757f6ec-ee03-11ed-85d3-6c92bf3b0af4.mp4

    5. https://highlight-video.cdn.bcebos.com/video/6s/6ffb9cbe-ee01-11ed-916c-6c92bfb45e04.mp4

    0.7.6 网友提供

    下面的地址几乎都失效

    1. rtmp://live.yihtc.com:10935/hls/stream_3

    2. rtmp://live.yihtc.com:10935/hls/stream_13

    3. rtmp://218.3.205.46/live/ggpd_sd

    4. rtmp://hls.hsrtv.cn/hls/hstv2

    5. rtmp://hls.hsrtv.cn/hls/hstv1

    6. rtmp://222.173.22.119:1935/live/jnyd_sd

    7. rtmp://222.173.22.119:1935/live/xwhd_hd

    8. rtmp://livetv.dhtv.cn:1935/live/peoples

    9. rtmp://livetv.dhtv.cn:1935/live/citylife

    10. rtmp://livetv.dhtv.cn:1935/live/financial

    11. rtmp://livetv.dhtv.cn:1935/live/news

    0.7.7 监控设备

    下面列出的是一些常用厂家的格式,不同厂家格式不一样,具体什么格式请咨询厂家索要对应的视频流格式,或者设备支持onvif的话,通过onvif工具搜索可以拿到视频流格式。

    0.7.7.1 海康
    • 实时预览格式:rtsp://admin:12345@192.168.1.128:554/Streaming/Channels/101?transportmode=unicast

    • 视频回放格式:rtsp://admin:12345@192.168.1.128:554/Streaming/tracks/101?starttime=20120802t063812z&endtime=20120802t064816z

    • 流媒体视频流:rtsp://172.6.24.15:554/Devicehc8://172.6.22.106:8000:0:0?username=admin&password=12345

    • 日期时间格式:ISO 8601 表示Zulu(GMT) 时间 YYYYMMDD”T”HHmmSS.fraction”Z”,

    • 单播多播说明:unicast表示单播,multicast表示多播,默认单播,可以省略。

    • 通道码流说明:101,1是通道号,01是通道的码流编号,也可以是02、03,第2通道主码流=201,第16通道子码流=1602,依次类推。

    0.7.7.2 大华
    • 实时预览格式:rtsp://192.168.1.128:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif

    • 视频回放格式:rtsp://admin:12345@192.168.1.128:554/cam/playback?channel=1&subtype=0&starttime=2021_03_18_11_36_01&endtime=2021_03_18_12_05_01

    • 格式内容说明:channel表示通道,subtype表示码流编号,日期时间字符串非常明确。

    0.7.7.3 常规
    • 实时预览格式:rtsp://admin:12345@192.168.1.128:554/live?channel=1&stream=1

    • 视频回放格式:rtsp://admin:12345@192.168.1.128:554/file?channel=1&start=1494485280&stop=1494485480

    • 其他通用格式:rtsp://admin:12345@192.168.1.128:554/0 0-主码流 1-子码流

    • 日期时间说明:先转换时间戳,1970年到该时间经过的秒数。

    0.7.8 指定协议

    • 由于视频流源头限制,可能有些源头只支持tcp/udp协议的一种,就需要手动指定。

    • 指定tcp协议打开视频流:rtsp://admin:12345@192.168.1.128/1|tcp

    • 指定udp协议打开视频流:rtmp://livetv.dhtv.cn:1935/live/financial|udp

    0.8 版本说明

    0.8.1 精益求精

    后期规划

    1. 摄像机信息表的用户信息字段用起来,视频流地址不带用户信息,主动加入用户信息构建最终地址应用。

    2. 用户密码密文存储,防止泄露。

    3. 重新编码保存模式下,不支持crop裁剪滤镜。

    V20231205

    1. 增加通用地址格式规范,url|transport|encodeType|videoFormat|encodeVideoRatio|encodeVideoScale,可以直接在播放地址中指定通信协议、是否编码保存、编码帧率等信息,具体可以参见说明书中的地址格式说明。

    2. 对大华的NVR增加自适应计算配置文件个数,有些是2个有些是3个,需要自适应,计算后按照对应的规则添加NVR的通道。

    3. 鼠标拾取限定鼠标左键操作。

    4. 悬浮条增加判断,如果处于电子放大期间则鼠标移开不自动隐藏,方便标记当前哪些通道处于电子放大期间。

    5. 鼠标画矩形增加坐标换算,鼠标可能是从左上角到右下角,也可能是从右侧到左侧,而QRect只支持左上角右下角参数,需要自动换算,用户有可能是从右下角到左上角,这些特殊情况也要支持。

    V20231125

    1. 视频监控布局类videobox新增了指定行数列数接口,新增了指定行列数的默认布局,比如1_2x4表示通道1开始按照2行4列排列,方便垂直屏幕展示比如手机上或者竖屏。

    2. 优化本地摄像头和桌面采集的暂停策略,和文件一样,暂停期间不需要去实时采集。而视频流这种暂停期间必须实时采集不解码。

    3. 修复http地址中带空格的地址无法正常播放的BUG,需要用QUrl().toEncoded转码。

    4. 鼠标按下发送对应源图像坐标信号增加事件类型参数,鼠标按下、鼠标松开、鼠标移动三种都能够发出信号,以便外部用于动态绘制矩形区域,相当于拿到对应的矩形区域在下发处理。

    5. 内核增加电子放大功能,鼠标按下拾取区域,作为crop滤镜,实现电子放大。移除该滤镜可以恢复。

    6. 屏幕采集增加自定义区域采集规则,约定屏幕索引255则取用户填入的自定义区域进行采集。

    7. 组件onvif增加错误数据返回信号,可以查看具体错误数据信息,方便分析问题,比如是否是用户信息不对导致的。

    8. 悬浮条增加电子放大按钮,直接开启电子放大和结束电子放大,电子放大期间,在视频画面上选择区域后自动对该区域放大。

    V20231105

    1. 内核ffmpeg中保存类型SaveVideoType_H264改成了SaveVideoType_Stream,表示裸流类型,可以是264/265。

    2. 保存裸流情况下增加区分264/265拓展名。

    3. 内核ffmpeg/qtav/easyplayer/海康sdk等增加逐帧播放功能。

    4. 内核ffmpeg增加缓存大小的参数传入,对应buffer_size参数,可以通过参数配置。有些极大帧率或者分辨率的设备需要这个参数设置才能正常运行,否则很可能缓存不够导致花屏。

    5. 修正onvif组件在设备没有回传时区TimeZone节点信息的时候无法正确设置时间的BUG,改成默认用东八区去计算。

    V20231010

    1. 修复部分视频文件在循环播放的时候失效的BUG,经查阅这种文件一般前面会缺失一些数据帧,导致播放定位失败,改成通过videofirstpts时间判断。

    2. 修复在win10及以上系统中CPU使用率采集和任务管理器不一致的BUG,改成了命令行typeperf获取。

    3. 修复了ffmpeg内核opengl绘制yuv数据在部分很老的硬件上绿屏的BUG,将 GL_RED 全部换成了 GL_LUMINANCE 以便支持旧版本的opengl。比如部分配置低的手机。

    4. 修复linux系统上采集本地摄像头无法设置分辨率的BUG。

    5. 本地文件回放增加拖曳播放,方便用于测试从NVR下载的视频文件。

    6. 内核ffmpeg增加自动获取本地音视频设备文件名的接口。

    V20230915

    1. 彻底解决应用滤镜后可能出现崩溃的BUG,比如在频繁大量切换新的滤镜过程中,刚好界面这边在绘制画面数据,导致数据冲突引发的BUG,之前绘制模式和硬解码模式不崩溃是因为,绘制模式用的是painter绘制图片,没有用opengl绘制,硬解码是因为取出来的帧数据就是中转过的,不会出现数据冲突的情况。所以在没有硬解码情况下的opengl绘制模式,增加了一个avframe用于中转数据,同时在新切换滤镜后的延迟1-2帧(时间大概0.03s)应用新的滤镜,这样就再也不会出现opengl绘制数据冲突崩溃情况。也考虑过传递给opengl绘制的数据拷贝一份,肯定可以终极解决问题,但是每次帧数据都拷贝一份那就增加了不少CPU,不可取。

    2. 将录播监控类型去掉,配置参数新增了AudioLevel用于开启音频振幅,开启后,主界面每个通道右侧会显示对应的音频振幅,分左右通道。

    3. 桌面采集改成永远不共享解码策略。

    4. 新增摄像机和录像机默认名称配置参数。

    5. 双击NVR父节点打开该节点下面的所有摄像机,增加延时,防止不延时情况下在部分电脑上可能崩溃的BUG。

    V20230906

    1. 修复本地桌面地址默认分辨率问题,当没有指定分辨率的时候取当前鼠标所在的屏幕区域作为分辨率。支持多屏幕,包括虚拟机中分辨率奇数问题,自动取偶数。

    2. 重新调整桌面录屏的XY坐标策略,设置值永远是正数值,根据当前屏幕所在位置进行偏移(左上角X=0 Y=0),多屏幕情况下坐标可能是负数,而且屏幕可以是横向还可能是竖向,自动程序计算,这样用户只需要填入从当前屏幕左上角开始偏移多少就行,而不需要去计算具体的值。同时纠正超过屏幕区域的采集分辨率,以设定的偏移值开始到右下角结束进行裁剪。

    3. 桌面采集增加手动支持屏幕索引参数,在XY坐标偏移值后面,不指定则以鼠标所在当前屏幕为准,指定则以指定的索引为准,屏幕索引大于屏幕数量则以鼠标所在当前屏幕为准。这样相当于可以对每个屏幕分开采集,每个屏幕都是在一个独立的通道显示。

    4. 测试发现在linux系统上如果使用ffmpeg静态库,会报错提示avfilter不成功,需要调整库链接顺序才行,之前是 -lavformat -lavcodec -lavfilter -lswscale -lavutil -lswresample,统一改成 -lavformat -lavfilter -lavcodec -lswresample -lswscale -lavutil ,通过查阅ffmpeg的示例代码的链接顺序得知。

    5. 测试发现在ubuntu18/20/22等系统上编译程序设置rpath失败,导致编译后的程序只能编译运行,不能双击运行。查阅资料原来是新版的系统修改了对应的rpath设置机制,https://blog.csdn.net/random_repick/article/details/122980119 ,需要在编译参数加上 -disable-new-dtags 参数即可。之前是 QMAKE_LFLAGS += "-Wl,-rpath,'$$ORIGIN/lib'" ,改成 QMAKE_LFLAGS += "-Wl,-rpath,'$$ORIGIN/lib',-disable-new-dtags" 。

    6. 滤镜osd增加了背景颜色参数,支持透明度。

    7. 修正linux系统桌面采集对应偏移值没起作用的BUG,需要通过设备名传入,比如 :0.0+0,0 后面的 0,0 才是表示偏移值。

    V20230818

    1. 所有密码框全部提升为自定义文本框控件,全局样式加入密码按钮,单击显示密码,再次单击密文显示。登录窗体、登出窗体、数据库管理等界面。

    2. 数据库组件增加access数据库的支持。

    3. 通过远程设备回放rtsp视频流,增加进度条显示,可以切换进度条,一般海康大华等厂家的NVR支持rtsp视频流回放,而且带了时长,可以切换回放的进度,但是不能倍速。

    4. 将带柱状声音条的视频面板重命名为 frmvideowidgetvolume,带播放进度条和时长的视频面板命名为 frmvideowidgetslider,视频预览窗体重命名为 frmvideowidgetpreview,因为这三者属于独立的视频控件窗体,在多处独立使用。

    5. 远程回放rtsp视频流增加同步播放进度,勾选后,切换某个通道进度,其他几个通道自动切换到对应播放进度,这样可以查看回放通道同一时刻的监控画面。

    6. 更新地图秘钥,之前的秘钥文件由于使用者太多,会出现未授权地图字样。

    7. 修复onvif报警事件触发的报警录像存储文件前缀标识不正确的BUG,当通道显示的主码流而系统设置默认打开子码流的情况下会发生。

    8. 日志记录中备注字段用于存储报警图片文件或者报警视频文件的文件名称,报警视频优先级大于报警图片。双击预览报警图片或者报警视频。

    9. 修复报警日志中弹出预览失败的情况,当文件被删除后要先判断文件是否存在。

    10. 回放界面增加了播放按钮,可以暂停和继续播放当前回放的视频。

    11. 将报警视频预览单独一个函数,带播放进度条,回放报警时候的时候,可以暂停和继续播放。

    12. 日志记录增加按照通道查询。报警日志存入的时候都统一换成两位字符串作为通道存入,比如 01/02/03/16,统一长度对齐。

    13. 修复实时视频流查看的时候,没有时长的BUG,不要去获取时长,是个很大的负数。只有回放的视频流才有时长。

    V20230802

    1. 轮询管理中添加轮询通道的时候,对应分组以右侧选中的分组为准,选中的哪个分组则对应添加的时候就添加到对应轮询分组中。

    2. 轮询管理中左侧表格增加右键菜单(全部选中、反向选中、全部不选),执行对应的操作。

    3. 增加自定义密码文本框,可设置双击显示明文/失去焦点自动恢复,以及右侧显示密码按钮,单击切换明文密文显示。

    4. 修复ffmpeg内核录像阶段硬解码模式下各种滤镜信息没有保存到文件的BUG。

    5. 修复ffmpeg内核录像阶段硬解码模式下保存的视频文件,播放期间渐渐变模糊的BUG。

    6. core_qui组件更名为core_qthelper,里面的类名也全部重新更换,比如quihelper改成了qthelper,表达更精确。

    7. 内核ffmpeg增加视频流地址末尾加通信协议(tcp/udp),有些视频流必须用tcp或udp协议才能加载成功,可以手动指定,已经有全局的视频配置参数,地址中带的协议优先级最高,没有带则采用全局配置的。

    8. 彻底解决时区时间不对导致部分摄像头设备不能onvif交互的问题,如果本地时区设置的和设备设置的时区不一致,需要转换后再统一用标准时间去下发onvif指令,之前写死的东八区8小时,应该根据系统环境去获取,而且还要区分夏令时(时区-1),还要区分半小时制的时区(5.30时区),一套组合拳打下来,彻底解决问题。嵌入式板子很多不是东八区或者linux系统也可能是其他时区。这个细节市面上99%的onvif协议监控软件都没有考虑(一运行就崩溃或者无法正常加载onvif设备),必须要求运行软件的环境和设备所在环境的时区时间一致。

    V20230718

    1. 各种内核都增加音视频轨道参数,可以读取和设置,在节目流ts文件非常有用,可以手动指定音视频轨道。

    2. 通信协议增加none选项,有些rtsp视频流不支持设置tcp/udp通信参数。

    3. 内核ffmpeg增加设置旋转角度功能,比如现场传过来的原视频是倒的,可以主动设置旋转角度旋转成正的,而且保存视频文件也可以一起应用这个设置。

    4. 修复大分辨率视频采用GPU绘制模式开启大量滤镜下可能崩溃的BUG。频繁更新滤镜,会和opengl绘制冲突,如果是painter绘制,不影响。如果采用硬解码,也没有这个问题。

    5. 重写云台仪表盘控件,在现有换肤下更精美,新增了边距和渐变边框等属性,修复了鼠标按下时候可能崩溃的BUG。

    6. 新增配置参数控制是否通道名字用摄像头的名字,默认通道01/通道02字样。

    7. 配置参数增加公司网址/公司电话,可以自定义,在弹出关于对话框中显示。

    8. 修复当设备树状列表不开启码流子节点的时候,左侧通道选中,设备列表选中节点不正确的BUG。

    9. 将标签信息停靠窗体改成按钮弹出来,不放在主界面悬停窗体组合中。

    10. 新增网络信息配置窗体,用于查询和修改设备的网络信息比如IP地址子网掩码等。

    V20230705

    1. 增加265裸流文件的正常解析。

    2. 去掉串口模块的依赖,备用,有些msvc套件编译这个模块会报错。

    3. 增加两个开关,顶部标题右键菜单和悬停模块右键菜单,可以在系统设置中勾选开启。

    4. 增加了2/3分屏显示。可选择是否启用,默认关闭。

    5. 修复当单独使用解码线程类(没有视频显示窗体)的时候,无法正常关闭的BUG。因为之前不存在单独使用解码线程类。

    6. 内核ffmpeg保存视频增加指定分辨率和缩放比,这样可以大大减少文件体积,比如显示采用1920x1080分辨率,保存采用640x480,还可以指定等比例缩放比,比如0.5缩放比则是等比例减少一半,保持宽高等比例。

    7. 内核ffmpeg保存视频增加仅仅发送数据包标志位,这样可以在保存的时候进行多路推流和保存到其他文件。也就是打开一个视频地址可以保存到多个不同的文件或者推流到多路。

    8. 视频监控增加打开失败信号,参数对应错误枚举值,可以对应查看枚举值定义找出具体错误原因。

    9. 内核ffmpeg视频保存类在推流模式下增加自动重连机制,流媒体服务器中断恢复后自动重连继续推流。

    10. 内核ffmpeg视频保存类增加保存开始/保存结束/保存失败信号,方便推流的时候根据信号做出反应。

    11. 修复多屏幕在上下屏情况下右下角弹出框位置不正确的BUG,此问题N多知名软件也存在,可能上下屏的用户情况比较少。

    12. 增加了云台移动类型下拉框,默认隐藏,可以配置文件VisiblePtzStep打开,可选绝对移动/相对移动/连续移动,默认连续移动,所有厂家都会实现连续移动,大部分厂家未实现其他两种移动。

    V20230611

    1. 增强解码的健壮性,比如在ffmpeg中未找到对应的解码器,取消对应视音频的处理,比如没找到G.722.1的音频解码器(AV_CODEC_ID_NONE),则不处理音频数据,直接保留处理视频数据即可。之前是直接打开失败不做任何处理。

    2. 内核ffmpeg增加了清空缓存接口,在切换播放进度前执行。测试发现有极少数文件切换进度后存在缓存数据导致画面发抖1-2s。

    3. 滤镜初始化增加锁,防止大量通道启用大量滤镜,界面切换和尺寸发生变化的时候导致的可能崩溃的BUG。

    4. 设备播放模块增加自动自增通道号功能,一般从NVR打开1路以后接下来就是打开第二路,递增即可。

    5. 修复带旋转角度的视频在绘制模式以及抓图下画面不正确的BUG。

    6. onvif组件修复当rtsp端口不是554的时候的地址获取错误的BUG,统一调整即支持外网映射交互整个onvif组件,也支持内网包括修改过端口的。

    7. 将filehttp改成fileweb类型,因为rtsp视频流也有时长的时候,有些回放视频流是rtsp格式带了时长,可以任意切换播放位置。

    8. 增加删除和修改摄像机信息后,视频通道对应更新状态,比如删除了某个设备,该设备如果处于播放阶段则停止播放。

    V20230605

    1. 内核ffmpeg保存视频类增加超时判断。

    2. 内核ffmpeg所有类打印错误信息参数增加带上错误码和错误详情,方便分析问题。

    3. 内核ffmpeg改进硬解码格式的合法性检查。

    4. 修复默认传入静音状态除了ffmpeg内核外其他内核没有生效的BUG。

    5. 标签文字水印增加了图形字体的支持,极大的丰富了文字水印的内容,可以将各种图形图案以文字的形式绘制到原图中。文本绘制的性能比图片高很多,可以将方框等各种图形转换成图形字体再以水印加到原图中。

    6. 内核ffmpeg增加硬解码失败自动转软解码策略。

    7. 内核ffmpeg增加图片滤镜功能,和之前各种文字水印和其他滤镜一起(文字水印和图片水印叠加功能折腾很久)。

    8. 重写保存视频线程,支持音视频同步合并保存到MP4文件,保存线程可选是否强制编码还是源数据保存。强制编码会增加CPU占用,但是有些情况必须强制编码,比如非264格式需要推流,重新改变保存文件体积大小,将OSD标签和图形信息存入文件或推流等。

    9. 内核ffmpeg保存视频支持不编码(源头是h264/h265+aac)、部分编码(参数指定视频或者音频编码)、完全编码(所有格式不符合则强制编码)等三种组合。

    10. 修复如果文件名称为rtmp/rtsp/http开头的时候地址类型解析不正确的BUG,要用rtmp://这种开头判断。

    11. 内核ffmpeg增加编码策略选项,可选自动(非264/265/aac则转码)、仅限文件(文件类型则转码)、所有转码,默认选择自动处理,可以大大节约CPU资源占用。

    12. 改进策略当选择最快速度播放的时候,文件类型的也全力解码数据并显示,不做任何的同步和延时。这样可以测试本机最大的解码能力。

    V20230522

    1. 组件onvif增加时间差值计算,有些设备在发送鉴权数据的时候需要以设备的时间为准,而不是以onvif客户端为准,很多设备可能时间在1970年或者2000年,意味着发送鉴权的时候对应时间要1970年或者2000年,不然会鉴权失败,所以在首次鉴权的时候需要获取设备的时间(主动设置时间后也需要获取一次),计算时间差值,下发鉴权的时候主动加上这个差值。

    2. 内核ffmpeg增加对指定窗口标题的窗口进行录屏,目前测试下来只支持英文的标题。

    3. 修复短时长(5s)视频文件播放在关闭的时候可能崩溃的BUG。

    4. 保存视频文件增加首帧必须关键帧的过滤,保证保存的视频文件在任何地方打开都不会绿屏。这个过滤机制会导致保存的视频文件缺少开始部分的帧,比如摄像头设置的I帧(关键帧)间隔是50则最大可能接近2s的帧丢失,这个丢失无法避免,因为开头部分的非关键帧无法正确计算得到完整的图片。

    5. 修复了开启了录像计划下,双击打开父节点视频后,录像计划线程停止后未开启的BUG。

    6. 视频回放查询功能增加过滤正在写入的文件,不要放入到文件列表。

    7. 修复部分265编码的视频流保存的时候时长不正确的BUG,因为视频流有平均帧率和基本帧率,保存的时候取基本帧率。

    8. 配置参数增加opengl类型选择,可选AA_UseOpenGLES防止有些电脑显卡驱动版本不够或者硬件显卡不支持的情况,启用AA_UseOpenGLES以后也可以正常使用opengl用来绘制视频数据。

    9. 增加用户没有填经纬度时自动以地图中心坐标为准的处理,防止没有经纬度坐标导致地图加载失败。

    10. 增加低分辨率下默认隐藏OSD标签管理悬停模块,该模块对界面高度有要求导致把整个界面撑起来而看不到底部。

    V20230510

    1. 增加文字水印单独示例,专门演示如何添加日期时间标签,文字标签,指定标签更新内容,以及显示实时码率文字水印。

    2. 内核ffmpeg增加实时码率计算,发出结果信号。

    3. 增加了OSD标签格式日期时间带毫秒枚举值。

    4. 增加统计实时码率开关,开启后,在人工智能开关开启状态下,会将实时码率信息以文字水印OSD的方式贴到视频上。

    5. 文字水印演示字体大小改成了以视频宽度比例为准,以便保证字体足够大能够看清。

    6. 内核ffmpeg增加保存视频压缩比率参数,可根据网络带宽需求调整清晰度,包括保存的视频文件大小和推流占用带宽。

    7. 增加保存视频压缩比率参数,可控保存后视频文件体积大小(只针对需要重新编码的场景)。

    8. 增加多镜头多通道摄像机的支持,有些摄像机带了多个镜头,每个镜头对应一个通道。

    9. 内核ffmpeg增加只推流的情况下手动切换实时预览(需要解码才能预览/推流不需要解码也可以推流/以便最小占用CPU)。

    V20230416

    1. 新增桌面录屏的支持,包括ffmpeg、vlc、qtav、easyplayer等内核。

    2. 桌面录屏可指定录屏区域位置。

    3. 完善easyplayer内核对各种视频流的支持。

    4. 重新优化视频类型的判断,http开头的地址可能是文件也可能是视频流,以最终时长作为判断依据。

    5. 增加了H264裸流视频文件倍速播放。

    6. 内核ffmpeg增加发送packet帧信号,一般用于推流的同时保存视频文件需要。

    7. 模块onvif增加osd相关处理,可以获取所有osd,并执行添加、删除、修改操作。

    8. 增加OSD管理悬停模块,可以增删改查OSD相关信息。

    V20230323

    1. onvif模块增加获取mac地址。

    2. 所有监控内核增加矫正视频类型,比如http开头的有文件长度的则强制设置为filehttp类型,方便后期其他判断处理。

    3. 新增主动设置文件时长和播放进度的函数,以便事件回调那边主动设置。

    4. 修复ffmpeg内核部分视频文件当分辨率不是常规分辨率时(比如分辨率426x240)回调取出图片不正确的BUG,转换需要做字节对齐设置,现在约定统一用4字节对齐,这样兼容了所有可能的分辨率。

    5. 修复ffmpeg内核在高倍速比如5倍速播放情况下,如果解码来不及导致播放进度计算不正确的BUG。

    6. 增加对http开头的地址对应视频类型的判断,有些是视频文件(有时长并且可以切换播放进度),有些是实时视频,尽管地址格式都是 http://xxxxxx/xx.m3u8 这种。

    V20230201

    1. 新增天气预报模块开关。

    2. 海康内核增加手动指定端口解析。

    3. 更新onvif相关处理,支持内网摄像头通过路由器端口映射公开到外网,以外网的IP地址形式访问。

    4. 设备搜索模块在单播的时候增加厂家为空则先获取设备信息获取到制造商名称并自动填入。

    5. 内核vlc增加图片和文字水印功能,从源头处理。

    6. 内核mpv增加文字水印功能。

    7. 内核ffmpeg增加网络访问视频文件头部消息user_agent=Mozilla,有些视频网站根据这个头部消息过滤不让ffmpeg访问。

    8. onvif单播搜索增加指定地址不存在的过滤。

    9. 增加对显卡禁用环境的识别,自动切换采用Qt::AA_UseOpenGLES,否则在禁用显卡环境中无法正常使用opengl。

    10. 增加当处于OpenGLES绘制下自动将硬解码改成none,防止无法正常显示视频画面。

    11. onvif组件搜索功能增加错误提示,比如绑定组播失败、单播地址不通等提示。

    12. 无人机移动演示模块增加过滤,还没有初始化好就不触发js交互。

    13. 增加对虚拟机环境的识别,自动切换采用Qt::AA_UseOpenGLES,否则在虚拟机中硬解码下无法使用AA_UseDesktopOpenGL。

    14. 录像计划批量按钮增加先清空再批量,否则通道数不一致。

    15. 本地回放等界面增加全选、全不选按钮,用于对查询出来的视频文件全部选中和不选中。

    16. 打包文件增加了wenquanyi.ttf字体文件,由于ffmpeg用到了滤镜,为了支持中文正确显示,依赖指定的中文字体文件,放到可执行文件同一目录即可。

    V20230108

    1. 内核ffmpeg实现了各种OSD标签和图形直接绘制到帧上,保存也带了对应的标签信息,之前是绘制在遮罩层上。

    2. 内核ffmpeg带旋转角度的视频旋转采用滤镜实现,之前是通过算法转换。

    3. 修复图文警情在清空后重新添加警情的时候最底部一个item可能高度不对的BUG。

    4. 批量添加NVR通道改进编号和摄像头名称策略,编号为NVR地址的后两个网段的值加上3位通道字符串,名称为通道001/通道002依次下去。这样符合现场跨网段的场景,一般现场有N多摄像机和NVR,很多都是跨网段的场景。

    5. 地图上设备单击弹出视频预览增加过滤,限制双击只允许单击。

    6. 增加配置参数控制设备树是否显示主码流子码流节点。

    7. 增加配置参数双击打开分组最大数量,0-最大通道数量 1-当前通道数量 2-自动调整数量。

    8. 增加配置参数记录最后展开的设备节点,下次打开自动应用。

    V20221212

    1. 改进实时监测设备在线情况逻辑,之前是一次性所有的处理,改成了排队处理,每次间隔0.1s,同时处理完一个来回后休息5s,这样在设备数据很多的时候尤其有效。

    2. 视频参数设置中新增离线检测开关和报警视频存储时间下拉框选择。

    3. 设备播放模块增加添加完一个通道后自动切换到下一个通道。

    4. 将批量添加单独做成窗体,通用于轮询管理和摄像机管理,可以很方便的批量添加摄像机,录像机通道递增等各种智能规则。

    5. 打开弹窗视频增加在线判断,没有开启在线检测则先检测再判断是否需要弹窗。

    6. 纠正图片参数调节中饱和度和对比度界面上名称标识写反了的BUG。

    V20221207

    1. 报警事件抓图后添加到图文警情,改成线程排队处理,之前在主线程处理,如果有多个同时,很可能卡主界面,而且还要等待抓图的文件生成才能正确显示图片。

    2. 新增警情字典表config/event.txt,格式 1,IsMotion,移动报警,移动结束 ,分别表示 事件等级/唯一标识/报警字样/解除字样 ,这样大大增强灵活性,每个不同厂家的设备可能有不同的关键字表示不同的警情,用户只需要在字典表中编辑好即可。

    3. 内核vlc彻底解决回调模式下视频流需要手动指定的问题,改成了在播放后拿到分辨率后去设置回调数据,完美解决。

    4. 修复内核vlc中打开视频流后多次触发读取媒体信息的BUG,包括中途视频流发生变化也会多次触发。

    5. 修复悬停模块透明度值应用不及时的BUG。

    6. 图文警情双击显示原图增加自适应图片大小策略,并限定最大分辨率。

    7. 增加了左右通道音频振幅分别计算,之前混在一起计算。单通道的则左右一样。

    8. 视频预览窗体增加自适应视频大小策略,并限定最大分辨率。

    9. 新增将选择的软件图标作为全局的左上角图标,选择后立即应用。

    10. 修复在共享解码线程中再次打开弹出的视频窗体声音大小和静音状态不一致的BUG,改成了和原共享解码线程一致。

    11. 弹出窗体自适应最大尺寸,如果视频尺寸超过了最大尺寸则等比例缩放到合适尺寸。

    12. 报警事件抓图按照日期文件夹存放,之前存放在image_alarm目录下挤在一起,多了就很难看。

    13. 新增每个视频控件都有共享解码属性,每个控件都可以控制是否需要共享解码,之前是统一全局的属性,有时候需要单独弹出的报警视频独立处理以及存储录像,此时就需要指定该控件不共享解码,极大的增加了自由度。

    14. 修复清空录像机信息后,设备列表无法正常加载的BUG,改成了自动生成一个默认的分组。

    15. 新增半透明轮询分组提示标签窗体,在轮询启动后显示停止轮询后隐藏,可以拖动到合适位置,自动记忆最后的位置。方便在全屏轮询阶段告知用户当前轮询到哪里。

    16. 增加开关量报警弹出报警视频,并录像存储,可在视频回放中查询对应的报警视频并回放。

    17. 报警视频弹窗窗体标题栏,如果指定了存储报警录像,则显示关闭倒计时字样。

    18. 修复在打开了未连接的视频通道,通道处于不断重连中,单击轮询崩溃的BUG。

    19. onvif组件增加唯一标识,打印信息更清晰,带上唯一标识和设备IP地址。

    V20221125

    1. onvif搜索增加超时时间参数,经过大量的现场应用反馈,少部分厂家的设备,在极端的网络环境中,返回的数据要慢,需要把之前写死在代码中的超时时间放出来作为参数设置可调节。

    2. 视频参数增加悬浮工具栏位置参数,可以设置视频控件的悬浮条位置在顶部、底部、左侧、右侧四个位置。

    3. 解决Qt6.4及以后版本比如Qt6.5上minibink和opengl冲突导致opengl黑屏的bug,此问题找了很久发现原来是和miniblink冲突了,改成了异步加载miniblink浏览器控件即可,代码 QMetaObject::invokeMethod(this, "initWebView", Qt::QueuedConnection);

    4. 对不启用任何解码内核增加过滤,没有指定内核则不用启动解码线程。

    5. 测试发现Qt6.4.1版本音频播放有问题,会打印 qt.multimedia.audiooutput: Failed to setup resampler ,确认过是官方新增的bug(https://forum.qt.io/topic/140523/qt-6-x-error-message-qt-multimedia-audiooutput-failed-to-setup-resampler/5),用最新的6.5版本即可,总之不要用6.4.1。

    6. 使用示例增加音频频谱示例。

    7. 使用示例增加拖曳播放示例。

    8. 系统设置增加音频振幅开关,开启后视频右侧都会显示左右通道额音量条。

    9. 初始化结构体参数增加过滤机制,地址为空的不处理。

    10. 新增了视频通道拖动配置参数,可控是否允许拖动交换通道,防止误操作。

    11. 增加根据视频控件的高度自动调整音量条格子数量,比如4通道60个格子,64通道20个格子,保证音量条自适应。

    12. 音量条的圆角角度、格子高度、边距、间距等参数可自由设置。

    13. 静音状态约定只是声音不发送给音频输出设备播放,音频数据正常解析,包括音频频谱正常显示。

    14. 增加根据视频控件的宽度自动调整音量条的宽度,比如4通道的时候音量条可以宽一些,64通道音量条可以窄一些。以便留出更多的空间给视频显示而不会显得很拥挤。

    15. 增加根据视频控件的宽度自动设置悬浮条提示信息是否需要显示,宽度不够则不显示,比如悬浮条设定显示在左侧右侧由于宽度不够也不显示提示文字信息。

    16. 增加报警事件抓图显示在图文警情中。

    17. 增加udp://开头的视频流强制采用udp协议解析。

    18. 修复重连后默认的音量大小以及静音状态不正确的BUG。

    V20221121

    1. 新增图形字体文件可编辑,可以根据需要添加自己的图标到iconfont.ttf字体文件,需要借助fontcreator工具。

    2. 新增部分图标,把底部通道1-通道64的图标换成了数字模样的,整齐统一容易拓展。

    3. 修复ffmpeg内核声音播放的时候遇到标题栏或者UI按下卡住停顿0.5s的BUG,改成了线程中播放音频,无论UI如何卡丝毫不影响。

    4. 视频回放增加手动停止按钮以及静音切换按钮。

    5. 增加ffmpeg内核声音解码过滤,部分摄像机的音频流如果是48000采样会导致转换失败,增加过滤处理。

    6. 修复应用最后的音量大小和静音状态时候在ffmpeg内核下有时候不成功的BUG。

    7. 实时检测摄像机是否在线,增加其他端口的识别,默认554端口,也可能有其他端口。

    8. 改进默认音量大小和静音状态设置逻辑,如果采用QAudioOutput播放音频则初始化的时候传入对应参数,如果是内核自带声音静音接口的则在打开成功以后主动去设置默认的音量大小和静音状态。

    9. 本地回放增加停止播放和静音切换图标按钮,并优化对应的处理逻辑。

    10. 修复qmedia内核静音切换对应标志位没有改变的BUG。

    11. 对视频监控控件新增获取是否暂停状态、音量大小、静音状态等函数。

    12. 本地回放新增当用户按下播放按钮右侧又选择了对应的文件则自动触发双击播放。

    13. 修复本地回放中停止播放后当还不是末尾一个视频文件时还会自动播放下一个的BUG,因为有自动播放机制,需要增加标志位判断,只要按下过停止按钮则无需自动播放。

    14. 修复ffmpeg内核在快速拖动进度条期间切换播放进度后小概率出现播放暂停的BUG。之前复用的暂停标志位,由于很多地方用到并且可能修改了暂停标志位导致恰时间点的不正确,新增了切换进度标志位,专用于切换进度判断,完美解决。

    15. 增加onvif指令过滤重复机制,当队列中有相同的onvif地址和指令的时候,不需要加入队列。

    16. 内核ffmpeg增加了实时码率的计算,统计的一个周期内(帧率25就统计25个包)所有视频数据包的总大小。

    17. 重新更新全部说明书,包括截图和文字说明。

    V20221116

    1. 每个视频控件都可以手动开启和停止录像,开启的时候传入文件名即可。

    2. 修正视频控件边框大小计算当尺寸为奇数的时候不准确的情况,增加了偏移1个像素处理非常完美。

    3. 修复ffmpeg内核打开视频流中途分辨率变化后计算不正确的BUG,中途分辨率调整后策略改成重新打开。

    4. 修复ffmpeg内核在暂停阶段切换播放进度后会继续播放的BUG,应该是要继续处于暂停播放。

    5. 解码线程基类、保存线程基类都增加全局静态变量控制是否打印消息,由于解码线程等类中要打印的信息特别多,可以在需要的时候开启,几乎每一个重要的步骤或者可能出错的地方都会有对应打印信息,方便跟踪查找问题。有时候想关注其他地方的打印信息,为了避免给解码线程的打印信息冲掉,尤其是通道数量多的时候,信息类似涌过来,此时可以关闭解码线程的打印信息,专注于其他打印信息。

    6. 视频配置参数这块很多参数的设置改成了立即应用,比如边框大小、图片显示策略等,不能立即应用的也可以通过主界面中的停靠窗体设备控制单击刷新通道来应用。

    7. 录像计划改成了立即应用,添加、删除、修改后都会立即更新录像计划到视频管理线程类。

    8. 视频回放中的日期选择范围,改成了精确到分,无需精确到秒。

    9. 视频回放增加了倍速选项,可选0.5/1.0/2.0/4.0/8.0等倍速。设置完立即应用,下一个自动播放的也会立即应用该倍速。

    10. 视频管理线程类对切换保存文件的时间的精准度做了调整,比如30分钟一个文件,文件的时间是12:00:00到12:29:59,12:30:00到12:59:59,整半点开始,59秒结束。

    11. 目前的视频存储策略是中间存储的保证是30分钟的一个文件,头部和尾部,因为开启录像或者结束录像的时间未必是整半点,所以可能产生的录像文件的时间不一定的30分钟一个。

    12. 经过详细测试对比,如果是视频流,开启了变码流则视频大小未必一样,如果是定码流则几乎一样,变码流则文件大小相差比较大,视频中动静变化比较大或者颜色比较多的文件体积更大。

    13. 同样分辨率的视频流,用H265编码生成的视频文件体积比H264小很多(同一个摄像头同样主码流分辨率切换到H265存储体积大概是普通H264的40%,还有其他H264H/H264B之类的没有具体对比测试),本系统中的策略是源头是H264的就采用H264编码,源头是H265的就用H265编码存储。这样可以不用转码大大减轻CPU运算压力。

    14. 录像文件存储以本地时间为准,如果设备的时间和本地时间不一致,可能会看到摄像头视频文件上显示的时间和要求的时间不一致,在开启了onvif校时的情况下,大概会有3s左右的偏差,也就是说录像文件上显示的时间可能是走到10:30:03才结束,如果时间完全一致则应该是10:29:59。

    15. 增加目标秒数核对以便尽量保持录像时间以59秒结束,可以自行更改该目标秒数值保持一致。

    16. 所有下拉框中的通道字符串为了整齐统一改成了两位字符串比如 通道01、通道05、通道16,除了主界面通道文字是 通道1、通道5、通道16字样,其余全部两位。

    V20221111

    1. 新增录像计划,增加录像任务计划控件,支持星期一到星期日每天24小时勾选是否录像,精确到30分钟间隔。

    2. 任务策略表格支持直接右键菜单全部选中、反向选中、清空选中操作。

    3. 新增录像计划表RecordInfo,对应字段RecordCh表示通道0-64,RecordWeek1-RecordWeek7表示星期一到星期日的录像计划字符串表示,通过占位符表示该30分钟时间内是否录像,每天有48个小格式。

    4. 通道唯一标识统一ch01到ch64字样,录像文件以及截图都按照这个作为文件的前缀,方便查找。

    5. 调整了一个设备多路通道(比如NVR或者部分相机)搜索的结果组合的策略,以便配置成多个不同的通道。大部分厂家的规则是每个通道一路主码流一路子码流,依次顺序存放。

    6. 录像计划新增批量一键添加64通道7 * 24小时录像,绝大部分时候都是这个情况所以可以一键添加,添加好以后有特殊的可以自行调整。

    7. 演示示例demo新增了配置参数保存对应选择的视频地址。

    8. 视频参数设置做了重大调整,按照新的解码内核来设计,更合理更贴切,把一些不需要的删除了。

    V20220918

    构思和编码及测试花了一年时间,将所有视频监控内核重新架构重写,抽象视频解码线程类和视频窗体展示类,着重解决了视频解码线程复用。具体可参见文档中的内核模块说明。

    视频复用技术难点

    • 通道1打开视频流A,通道2也打开视频流A,通道3也打开视频流A,此时通道1负责打开视频流A,其他两个通道公用通道1的视频流数据。

    • 通道1关闭视频流A(仅仅是关闭映射,不能关闭视频流),通道2关闭视频流A(仅仅是关闭映射,不能关闭视频流),通道3关闭视频流A(关闭映射+关闭视频流)。

    • 首次打开视频流地址的通道负责打开视频流。

    • 末次关闭视频流地址的通道负责关闭视频流。

    主要改进功能点

    1. 共享解码线程,相同地址的已经打开过的,直接复用,大大减轻网络流量和推流设备的压力。

    2. 动态内核挂载,解码和展示分离,通过基类的公共接口设计,视频控件可以任意动态挂载任意的解码内核,在打开的时候指定即可,内部会根据指定的内核自动实例化对应解码线程解码。

    3. 悬浮工具栏控件,各种颜色设置,包括透明度,位置可以上下左右,内容可以自定义。单击事件发信号,常用的录像、抓图、静音、关闭等按钮内置了实现,其余自定义按钮可以自行拿到信号做处理。空白处显示对应通道的分辨率、录像状态等信息,提供接口设置对应提示信息。

    4. 自定义标签OSD,任意多个,有多种类型和属性参数。

    5. 自定义图形,任意多个,直接绘制到原图上,有多种类型和属性参数。

    6. 视频控件基类,参数极其丰富,包括边框大小、边框颜色、焦点颜色、背景颜色、文字颜色、填充颜色、背景文字、背景图片、是否拷贝图片、缩放显示模式、视频显示模式等。

    7. 解码线程基类,参数极其丰富,包括解析内核、视频地址、缓存分辨率、解码策略、硬件加速、通信协议、缓存时间、循环播放、读取超时时间、连接超时时间等。

    8. 除了常规的视频文件、网络文件、视频流,还支持本地摄像头、旋转了90度的手机视频文件、非H264的文件自动转码显示。

    9. 对ffmpeg内核做了极度优化,支持音频视频文件保存,之前只支持rtsp视频流,而且生成的文件不标准没有文件属性分辨率信息等。

    10. 统一的打印格式,完整的信号通知,友好的接口设计。

    0.8.2 破茧成蝶

    V20220625

    1. 在之前支持NVR所有通道批量添加基础上,增加自动添加NVR信息到表,这样每个NVR都会自动添加,如果有手动添加好的则取添加好的,以IP地址为准。

    2. 修复设备在线状态处理,在同一个NVR下IP地址相同的不同通道视频,不会处理在线状态的BUG。

    3. 修复在postgresql数据库和oracle数据库下,QSqlTableModel对应setTable设置表名严格区分大小写的BUG。

    4. 测试发现有些很老的设备支持的是onvif1.0,云台地址需要用getCapabilities才能拿到,改进这个处理,兼容任意版本。

    V20220612

    1. 修复qss中分组框QGroupBox标题位移的BUG,在linux系统表现不统一。

    2. 改进同样的内容导出到pdf和打印显示效果不一致的情况,统一设置分辨率为96。

    3. 摄像机管理增加多选删除,删除的时候除了删除摄像机表中对应记录,也同时删除轮询信息表中的记录。

    4. 初始化数据库按钮增加弹框确认,由于这个操作安全级别非常高,增加弹框确认很有必要。

    5. 所有QTableView+QSqlTableModel对应的保存按钮代码增加主动设置焦点,避免mac系统中当单元格处于编辑状态,再去单击保存按钮,数据依然是之前的数据的BUG。

    6. 样式表全局颜色增加悬停背景颜色QUIConfig::HoverBgColor和选中背景颜色QUIConfig::SelectBgColor用于自定义委托。

    7. 对于加深的样式,重新设置单元格等item选中和悬停颜色 默认悬停-DarkColorEnd 选中-NormalColorEnd,加深颜色设置为相反。

    8. 增加全局参数控制是悬停颜色覆盖选中颜色还是选中颜色优先,默认选中颜色优先,这样选中的item鼠标移上去不会改变掉颜色。

    9. 增加过滤同名的NVR,之前会重复加载,现在限定同名的只加载一个,要求整个系统中NVR的名字必须唯一。

    10. 轮询管理中增加摄像机表的过滤条件,启用了的才显示在表格中。

    11. 增加播放记录开关,用于软件启动后,是否从播放记录url.txt读取历史记录进行播放。

    12. 增加播放记录url.txt过滤机制,只有摄像机表中存在且启用过的才可以播放。也可以改成只对rtsp开头的进行过滤。

    13. 增加选择列表通道的时候自动选中视频通道,高亮显示,这样很明确知道选择的哪个,同理,选中视频通道也高亮选中列表通道。相当于通道选中和列表选中联动。

    14. 增加设备列表在线离线不同图标显示,目前只对rtsp地址开头的进行实时监测上线离线状态,其他全部永远当做在线。离线图标颜色取系统设置中的报警图标颜色。

    15. 增加设备在线状态字段列表,实时监测设备状态期间先判断状态是否发生变化,只有发生变化了才需要去调用对应函数处理,大大减少无效的多余的处理。

    16. 修复设备列表双击空白处崩溃的BUG,需要过滤空节点item。

    17. 增加表格策略,单选按下编辑、多选双击编辑,有些用户需要多选摄像机列表删除。

    V20220515

    1. 将用户退出中的退出系统权限验证去掉,理论上对退出系统这个限制没啥意义,还可以通过任务管理器强制关闭进程。

    2. 将退出系统的权限名称改成调整布局,没有调整布局权限则不能调整拖动停靠窗体位置等。

    3. 视频面板窗体对象指针放到了全局静态变量,这样很多地方可以直接使用,比如声音控制、布局调整、视频轮询等。这样就不用繁琐的信号槽切换,可以省略很多不必要的代码,性能更高。

    4. 修复静音状态下调整音量可能不正确的BUG,静音状态下只改变音量值变量而不是正常改变音量。

    5. 实现右下角音量面板静音切换、音量值调整,全局视频控件应用。

    6. 改进默认地图算法,取第一个有背景地图的设备的图片作为默认图片,可能默认图片不存在则取图片列表中的第一张。

    7. 修复ffmpeg内核回调模式自动重连崩溃的BUG,此时图片不存在应该置为空。

    8. 增加识别秘钥有限制后限定标题栏带试用字样。

    9. 重写通用的视频地址类videourl,将通道改成0开始,分隔符改成英文逗号,视频地址集合通过指定枚举值选择不同类型添加。

    10. 增加自动插入临时消息到数据库用户操作记录,增加参数控制是否需要显示临时消息的时候插入。

    V20220413

    1. 修复视频控件设置自定义背景颜色的时候,没有考虑边框的范围问题。

    2. 选项卡样式去掉悬停样式,经过观察对比Qt自带的样式都是没有悬停样式,直接是选中样式。

    3. 修复自定义委托复选框不居中的问题,之前计算不准确会有细微偏差。

    4. 自定义委托增加悬停颜色。

    5. 重写自定义委托禁用列,支持文字颜色、背景颜色、字体等特性。

    6. 修复用户登录、用户退出界面标题栏字体被放大的BUG,因为样式冲突了。

    7. 将NvrInfo和IpcInfo中的地址字段改名为mark备注字段,涵盖内容更广。

    8. 地图模块默认卫星图增加了叠加层,更符合实际需求,对应地图综合应用示例做了极大升级改善,比如下载离线地图改成了最新的地址,可以下载到和在线地图一样的瓦片图片文件,离线地图下载改成了多线程,速度提升10倍以上。

    9. 自定义委托增加quistyle标记,有该标记则自动代码内部引用换肤全局颜色变量,这样删除了大量的设置自定义委托背景颜色的代码。

    10. 修复Qt6中msvc编译器下,强制指定miniblink浏览器内核的时候编译通不过的BUG,其实这个操作有点吃饱了撑着,因为msvc下有webengine浏览器内核。但是就是因为有极个别人有这个需求,客户就是上帝。

    11. 增加用户管理权限。

    12. 将用户权限和用户信息相关类合并到通用的类userhelper中,做成通用的权限组件。

    13. 修复Qt6中自定义复选框委托,在设置了全局样式的情况下,会不断切换选中的BUG。

    14. 效果图重新截图,用最新的运行界面。

    15. 组件示例增加4通道视频同时播放,进度条控制。

    V20220106

    1. 彻底修复全屏模式+webengine同时存在的情况下鼠标右键菜单无法弹出以及视频可能黑屏的BUG,这是Qt的BUG。

    2. 同时测试多屏幕下正常状态和全屏状态的情况,多屏幕不同分辨率。

    3. 增加其他设置界面,将串口设置、网络设置等移动到其他设置。随着功能越来越多,也很有必要单独拆分设置。

    4. 修复打印预览看不到文字的BUG,原来是设置了QGraphicsView的前景色导致的,把前景色和背景色设置成一样的了,其实是有文字的,鬼想得到QPrintPreviewDialog里面的预览原来用的是QGraphicsView绘制的。

    5. 修复qchart图表控件鼠标按下松开后会跟随窗体移动的BUG,因为qchart鼠标按下是UngrabMouse事件而不是MouseButtonRelease。

    6. 修复表格行按下后自定义委托颜色在部分样式方案下设置不正确的BUG。

    7. 增加视频弹窗按钮,封装的统一的视频弹窗静态函数,直接传入url地址即可。

    8. 修复鼠标按下视频预览底部工具栏也能拖曳视频的BUG。

    9. 海康内核解析增加对通道的解析,比如可能是一个摄像机有多个通道,或者NVR多个通道。同时完善主码流子码流的解析,可以解析多个码流,之前只能解析主码流子码流两个。

    10. 海康内核句柄模式下增加等比例缩放自适应。

    11. onvif模块修复部分厂家摄像机比如天地伟业,搜索返回的媒体地址等一系列请求地址,没有加onvif节点的BUG。

    V20211220

    1. 重新梳理整个onvif模块,调整对应的结构,删除多余的变量和设置等,对应云台控制等操作需要指定profile,通过参数传入。

    2. 对应图片参数操作需要指定videosource,通过参数传入。

    3. 去除数据库字段mediaurl、ptzurl,因为这两个数据每次都是更新重新获取的,通过getServices获取,这两个字段改成了videosource、profiletoken,用来从数据库读取出来,每次使用的时候自动下发。

    4. 预置位表格中的按钮样式调整,去掉圆角,增加边距,效果更完美。

    5. 新增nvr多个通道onvif支持,改动onvif模块代码和数据库结构。

    • 搜索设备后判断是否多个videosource,多个表示有多个视频源,一般是NVR,也有部分IPC自带多个视频源。

    • 有多个则根据不同厂家不同规则,找出对应的每个通道的videosource、profiletoken、rtspmain、rtspsub用分隔符 | 插入到临时表格中。

    • 摄像机管理界面接收到添加设备的时候,在addDevice槽函数中,判断发过来的数据,带了 | 要分别取出来作为通道添加到数据库中。

    1. 重新定义搜索的摄像机设备命名规则,按照摄像机#ip地址末尾数字的方式。

    2. 如果是NVR过来的摄像机,增加自动查找NVR的名称插入数据库。

    3. 获取预置位增加立即清空所有行,之前是先清空内容再根据读取到的预置位个数设置行数。

    4. 增加双击打开NVR(也叫分组)对应策略 0-最后空白通道 1-从头清空通道。

    5. 增加双击打开IPC(也叫设备)对应策略 0-最后空白通道 1-最后按下通道。

    6. 改进在分辨率不同缩放比例保持一致的UI体验,不受缩放比例的影响。

    7. 修正异或加密,增加对@String开头的密文进行过滤,防止高版本产生的配置文件到低版本的Qt程序不能正确解析的BUG。

    8. 如果打开视频流出错提示 Server returned 5XX Server Error reply 表示摄像机的码流满了,可能多个地方在拉取码流导致摄像机输出的视频流被占满,已经没有更多资源。

    V20211205

    1. 地图内核增加了海量点接口。

    2. 路径规划模块彻底重写,支持重新绘制、沿线移动等模式,数据表格显示。

    3. 设备轨迹模块改成从gps点集合文本文件加载进行循环动态模拟移动,默认飞机图标,以便转动角度。

    4. 设备播放增加保存视频开关配置参数,可以直接在界面上开启,开启后,通过rtsp从nvr取流比如回放视频,可以将回放的视频保存MP4文件到本地。

    5. 修正Qt6通过属性设置标签labtip不能居中对齐的BUG。

    6. 封装通用的设置一堆按钮比如添加、删除、保存、导入、导出等按钮图形字体的函数,直接传入父面板即可,自动查找对应的objname设置图标,省去一堆重复代码。

    7. 新增飞行轨迹模块frmDeviceGps2,之前的frmDeviceGps作为通过外部函数调用移动。

    8. 样式统一整理规范,分类6大类:black、dark、flat、light、normal、other。

    V20211111

    1. ONVIF组件增加图片参数范围获取,之前默认0-255,有些设备是0-100 0-128之类的,获取后设置到滑动条范围。

    2. ONVIF组件增加网络参数设置,比如IP地址,子网掩码、网关地址、DNS设置等。

    3. ONVIF组件将结构体定义统一移到一个头文件onvifstruct.h,方便后期拓展管理。

    4. 预置位模块,调用、添加(调用)、删除三种功能,改成了以三个按钮的形式加到每个预置位信息的后面直接单击使用。之前是先选中预置位所在行,然后单击下面的按钮。

    5. 通道轮询全部移动单独的悬停的模块。

    6. 视频面板窗体指针改成了全局变量,多处需要引用。

    7. 修复1通道轮询后,再次启动程序无法正确加载通道面板布局的BUG。

    8. 修复底部通道切换,部分样式效果悬停时候颜色不正确的BUG。改成了取报警图标颜色和已处理颜色。

    9. 路径规划模块增加模拟轨迹设备自动旋转角度移动。

    10. 路径规划模块模拟轨迹增加移动间隔下拉框选择。

    11. 修复Qt4对应webkit模块不支持返回数组的问题,改成字符串拼接用 ; 符隔开。

    12. 修复Qt4对应webkit模块不支持路径规划的BUG,因为开启了实时路况属性。

    13. 路径规划增加绘制实时轨迹线条,不同颜色显示。

    V20211101

    1. 修正开启轮询后关闭所有视频通道不弹出提示信息。

    2. 所有信息框增加阴影边框区分突出显示,并跟随系统换肤自动更新边框阴影。

    3. 修正视频轮询分隔符,将|改成;因为如果是竖杠遇到带有参数的url则会出错。

    4. 将设备图片统一存放到config/device目录,之前在config目录下,随着越来越多非常凌乱。

    5. 修复之前通过信号执行通道切换,对应文字显示反了的BUG(通道1交换到通道2,新的通道2应该显示之前通道1的文本)。

    6. 将鼠标按下两个通道交换的处理代码,复用信号槽切换通道的函数。

    7. 将视频监控布局切换部分单独提取类VideoBox,专门负责管理各种通道布局切换,复用代码并且方便后期拓展,这部分代码和具体的处理无关,一直以来就想要单独提取出来进行管理,后期可以方便的增加其他异形布局以及255通道布局等,很多项目都用到了这个切换逻辑。

    8. 同时增加了布局切换子菜单比如13画面子菜单切换到52_64通道。

    9. 修复Qt6中视频控件悬浮条无法显示的BUG,因为Qt6将void enterEvent(QEvent *);改成了void enterEvent(QEnterEvent *);也不打个招呼。这种改变编译也不会提示的。

    10. 数据库组件修正sqlserver数据库必须设置数据源的不足,改成了dsn字符串形式,不需要新建数据源也能直接通信。

    11. 数据库组件修正mysql数据库必须存在默认数据库mysql的不足,改成了不需要默认数据库也能正常通信。

    12. 数据库组件修正没有默认数据库也能在建立连接后新建数据库操作。

    13. 数据库脚本执行将DROP DATABASE IF EXIST改成了DROP DATABASE ,这样无论什么时候都能先删除原来的数据库然后再新建数据库CREATE DATABASE。有些数据库不支持IF EXIST。

    V20211005

    1. 修正ffmpeg内核,在播放地址不存在的情况下,打开容易卡主引起崩溃的BUG,在打开回调函数中增加对线程停止标志位的判断,一旦在打开的回调中识别到需要停止线程则立即返回结束。

    2. 增加临时信息中间弹出框提示信息,比如一次性关闭所有通道的时候,界面会卡主的期间提示。

    3. 增加忙碌鼠标图标切换显示,忙完以后自动恢复鼠标样式。

    4. 修正ffmpeg内核,开始时间记录可能出现问题的BUG,会导致部分特殊MP4文件打不开。

    5. 应用程序关闭,增加全局退出信号关联到视频通道管理类,先关闭所有视频通道再彻底退出应用程序。不这样处理的话,发现vlc内核在开启了视频存储的时候,会关不掉程序。

    6. 修复在没有声音播放的情况下主动调用停止播放造成崩溃的BUG。

    7. 修复在linux系统上QUIWidget弹出的无边框窗体带系统标题栏的BUG。

    8. 修复ffmpeg内核关闭视频后opengl窗体来不及隐藏的BUG。

    9. 修复重复立即刷新打开所有通道,前一次还没执行后一次又来了的BUG,改成了定时器处理,在立即执行前将上一次还没来得及执行的先停止。

    10. 增加about关于对话框窗体,显示版本号、版权所有、网址、电话等信息。

    11. 所有弹出窗体都跟随软件主窗体默认居中,这个特性非常棒。

    12. 所有皮肤增加右键菜单选中图标样式、右键菜单二级子菜单右侧小三角箭头图标样式,单选框、复选框、禁用状态图标全部更新,从图形字体绘制,极其统一舒服。

    13. 着重对日志类savelog增加了最大行数、最大文件大小等参数设置,可以设置按照行数或者大小来自动分割日志文件。

    14. 日志类增加了可过滤不同的消息类型,不同消息类型增加消息头。

    15. 经过大量对比测试发现,使用miniblink浏览器内核,容易卡,说不定什么时候就失效了,问题集中在32位,64位的目前没有发现这个现象,webengine暂时没有这个现象,但是加载打开摄像机的网页配置,还是miniblink更优秀。

    16. 中文标题栏支持换行,既可以副标题写在英文标题上,也可以同等大小字体写在中文标题上。

    V20210922

    1. 视频控件边框增加0像素选项,这样看起来没有边框,有些场景需要无缝拼接。

    2. 修复当采用NVR通道作为摄像机视频流显示的时候,ONVIF处理索引越界崩溃的情况,因为一台NVR同一个IP地址对应多个摄像机。

    3. 所有样式17套皮肤更新边框颜色。

    4. 系统信息增加对应的编译器名字、位数、版本等。

    5. 演示demo增加视频叠加演示功能,比如在主视频的左上角、右上角、左下角、右下角在增加一个视频缩略图显示。

    6. 新增天气预报模块,可设置城市、采集间隔、展示样式等。

    7. 增加了vlc内核下本地摄像头格式自动纠正,如果采用ffmpeg的格式video=USB2.0 PC CAMERA|1920x1080自动纠正。

    8. 纠正vlc内核下本地摄像头不自动拉伸的BUG。

    9. 修正vlc内核动态保存视频文件,文件命名不符合规范,重新按照设定的重命名。

    10. 修复vlc内核中本地摄像头会当做rtsp视频流的BUG。

    11. 天气预报模块新增城市显示,新增双击弹出天气预报设置,含打印信息。

    12. 系统信息,增加秘钥文件的内容,比如允许的设备数量、到期日期等。

    13. 修复配置文件一旦新增加节点,之前节点全部初始值运行的BUG,应该是存在的节点则读取节点值,不存在的节点以初始值运行。

    V20210705

    1. 改进窗体居中显示算法,可设置参照窗体,默认基于当前屏幕中心,可设置参照主窗体则基于参照窗体,在大分辨率屏幕效果非常好,不然主窗体很小,弹个窗找不到还在很远的地方,还以为没有弹呢。

    2. 将登陆窗体、登出窗体、用户管理等公用界面,做成了通用库core_form。

    3. 修复MAC系统上无边框窗体无法最小化的BUG。

    4. 增加超级管理员密码A具有所有权限的机制,避免管理员误将系统设置权限取消后无法再次进去系统设置的问题。

    5. 图片参数增加锐度,图片参数设置滑块调节松开立即设置。

    6. 修复当没有启用图片地图的时候对应界面隐藏的时候保存设备坐标位置报错BUG,因为没有启用的情况下没有设置对应的对象指针。

    V20210603

    1. 将onvif搜索的用户密码,设备播放界面的设备密码等配置参数全部改成了密文存储。

    2. 大量修改代码,全部支持Qt4-Qt6所有版本。

    3. 调整onvif代码执行机制,改成了异步执行。

    4. 云台协议增加了连续移动。

    5. 增加了预置位相关处理,包括获取预置位、调用预置位、添加预置位、删除预置位。

    6. 自动巡航按照预置位集合进行,采用定时器去调用预置位队列。

    7. 增加图文警情行数、窗口信息行数配置,0行表示自动处理。

    8. 做了大量的代码改进,比如onvif内核换成了QDom对象处理,之前是采用的QXmlQuery查询,由于XmlPatterns这个模块逐渐废弃了,而且在Qt6中不再有,所以彻底移除了XmlPatterns相关的代码,改用其他处理方式实现。

    9. 增加了预置位和自动巡航处理,其中包括获取预置位集合、调用预置位、添加预置位、删除预置位、设置起始位、调用起始位等。

    10. ONVIF内核几乎全部重写,将数据改成了结构体,比如设备信息、预置位信息、事件信息等,可以存储更多的数据,拓展也非常灵活。

    11. onvif处理部分增加了对非onvif设备的过滤,通过判断是否存在onvif地址。这样可以大大加快处理速度,打开视频的时候去实例化onvif通信,关闭视频的时候删除对应的onvif类,这样可以动态响应。

    12. 所有onvif指令改成了线程处理,处理完成一个立马处理下一个,排队处理。

    V20210425

    1. 配置文件密码改成密文存储。

    2. 增加了无敌的牛逼的万能的完美入微级自动分页导航控件。

    3. 日志记录表增加索引,速度提升100倍以上。

    4. 新增多个设备轨迹 不同颜色+传入经纬度 单独示例。

    5. 对地图核心类所有覆盖物都增加颜色+粗细+透明度的参数,可动态传入对应值。

    6. 系统设置增加用户管理模块,可分别设置对应的权限。

    7. 万能权限管理算法,通过设置不同需要授权的模块名称,对应切换的按钮自动计算。

    8. 增加了appkey秘钥类,用于校验秘钥是否正确,运行时间等。

    V20210403

    1. 增加全局变量AppData::LastLiveTime,记住程序最后的活动时间-包括键盘+鼠标活动,用于两个判断,一个是超过多久没有操作全屏下隐藏鼠标光标,一个是超过多久没有操作如果没有全屏则自动全屏。

    2. 增加App::TimeAutoFull配置参数用来判断比较超时自动全屏。

    3. 重命名为TimeHideCursor表示程序多久未操作自动隐藏光标,TimeAutoFull程序多久未操作自动全屏界面,下拉框选项值增加0,表示不启用此功能。

    4. 增加信息列表模块frmMsgList,用于图文列表显示信息,对应兄弟类frmMsgTable用于表格显示消息。

    5. 大改版,将中间部分全部改成了QMainWindow,子模块全部采用停靠窗体,可以悬浮半透明,自动记忆每个模块的最后的位置,启动后自动应用。

    6. 移除大改版后的所有不需要用的变量和配置参数,重新调整配置参数。

    7. 增加透明度参数用于停靠窗体独立出来后的透明度。

    8. 将摄像机控制部分比如云台+控制+预置位+巡航,单独分类到ipc模块,方便管理。

    9. 限定操作员不能移动停靠窗体等,需要管理员设计好。

    10. 修复系统设置中工作模式等切换造成的自动重启会弹出退出和登录两个窗体的BUG。

    11. 修复自动登录用户计算不正确的BUG,要以最后登录的用户为准。

    V20210322

    1. 本地摄像头增加参数帧率,第二个参数是分辨率,第三个参数为帧率,不设置则采用默认的帧率,video=USB2.0 PC CAMERA|1920x1080|25。

    2. 增加独立的demo模块,专门用于测试监控系统中用到的组件和控件,演示如何使用,比如视频图片界面演示从文件夹读取图片绘制到窗体,视频窗体演示系统的核心组件视频控件的设置参数如何使用等。

    3. 增加了对其他数据库的支持,比如posgres、oracle、odbc、kingbase等数据库,理论上只要支持odbc数据源方式的都支持。

    4. 增加IndexStart启动窗体索引配置参数,0-主程序 1-演示示例。

    V20210305

    1. 修复数据库有时候没加载到的BUG。

    2. 新增配置参数控制画面切换的菜单和快捷图标是否显示。

    3. ffmpeg内核增加了可动态保存机制,点击开始保存按钮启动保存,单击结束则生成视频文件,如此往复。

    4. 海康内核判断主码流子码流改成了 /101? 和 /main/ 同时判断。

    5. 新增多屏幕的支持,自动在对应屏幕最大化全屏,对话框位置,右下角提示框等。

    6. 再次分类存放代码文件,分成core ui class三大类。

    7. 系统配置更改视频控件参数,统一一个函数设置,initCommonVideoWidget函数中做了过滤,必须关闭状态的视频控件设置才起作用。

    8. 设备播放模块增加大华NVR的远程回放地址,其他地址计算算法调整。

    9. 新增界面模块功能启用配置参数。

    10. 新增主界面顶部导航模块中间界面,用于不同的运行模式加载不同的模块。

    0.8.3 快速迭代

    V20201212

    1. 增加USB摄像机分辨率设置,直接url带掉。

    2. 所有地图内核公用一个,复用代码。

    3. 增加地图默认级别和中心点坐标设置参数。

    4. 主界面四个模块独立出来,做成了可配置,这样后期可以任意位置放置自定义模块。

    5. 四个模块标题栏自定义。

    6. vlc内核和mpv内核的离线判断,当句柄模式下,统一为getLastTime,当调用该函数的时候自动查询播放状态,如果正在播放则自动更新时间为当前时间。

    7. 将各种在代码中define定义不同内核的代码全部优化,统一为一个类,很大减少代码量,统一为CommonVideoWidget和CommonVideoManage类。

    V20201108

    1. 轮询点模块增加批量生成功能。

    2. 录像机、摄像机、轮询点,增加导入导出功能。

    3. ffmpeg内核增加读取帧回调,超时识别,可以快速识别掉线。

    20200828

    1. 增加了云台控制过滤,没有打开的视频禁用云台。

    2. linux上全屏BUG修复,采用showfullscreen。

    3. 增加轮询点管理模块。

    4. 修正轮询的可能崩溃的BUG。

    V20200730

    1. 系统设置增加了视频上传模块,用来将本地的视频文件传输到服务器,多线程并发。

    2. 视频监控内核新增MPV内核,修正了其他内核的部分函数和处理。

    3. 海康内核进行大改动,同时支持视频流和本地MP4文件播放,自动分析切换。

    4. 海康内核增加回调处理,可以拿到每一张图片。

    5. 海康内核进行了linux上的实验,可以正常播放。

    6. ffmpeg内核增加保存到MP4。

    7. 本地文件回放vlc部分增加进度切换等。

    8. 悬浮条关闭按钮增加实际处理,之前只是打印消息。

    9. 改进了vlc和mpv的事件回调机制,使其同时支持qt4+qt5。

    V20200620

    1. 增加了opengl显示实时视频,CPU占用极低。

    2. 增加了地图上设备点位置的调整。

    3. 设备点双击弹出实时视频预览。

    4. 增加GPS运动轨迹显示。

    5. ffmpeg解码类增加了音频播放,采用的QAudioOutput。

    V20191105

    1. 增加云台控制功能,可以上下左右等八个方位控制云台,默认采用相对移动,云台中间按下表示复位。

    2. 系统设置增加码流类型选择,默认子码流,切换完自动应用。

    3. 云台控制增加速度功能,值越大,速度越快。

    4. 增加焦距控制,可放大缩小,速度也可控制。

    1 用户登录退出

    1.1 用户登录

    +

    系统启动后,首先会弹出用户登录界面,从用户姓名的下拉框选择用户名,然后输入密码(默认用户名密码都是admin),单击登录按钮,密码正确则会进入到系统主界面,错误会弹出提示,错误超过三次自动关闭,需要重新打开软件。

    在登录界面可以勾选是否记住密码,是否自动登录,如果勾选了记住密码,则下次启用软件会自动填入最后用户的密码,勾选了自动登录(以最后的用户信息作为当前登录用户)则启动后直接进入主界面。如果开启了自动登录,不会弹出登录界面,可以在系统设置中关闭自动登录和记住密码。

    1.2 用户退出

    在主界面单击右上角的关闭按钮,会弹出用户退出界面,需要输入密码验证防止误关闭,会自动填入登录的用户名,密码输入正确才会退出软件。用户登录和退出都内置了超级密码a防止管理员忘记密码。

    2 主界面操作

    +

    主界面由顶部主菜单导航、左侧右侧停靠窗体(设备列表、窗口信息、图文警情、悬浮地图、云台控制、设备控制、预置巡航、视频轮询等)、中间视频监控主画面组成,其中左右两侧的停靠窗体可以拉伸宽度,上下停靠窗体之间也可以拉伸高度,每个停靠窗体都可以关闭和悬浮。自动保存布局文件,下次启动自动应用。

    新增说明

    • 2021-5-8,主界面改成了停靠窗体模式。

    • 拓展性更强,可以任意组合多种子模块。

    • 模块可停靠悬浮。

    • 在普通模式和全屏模式都有独立的布局文件。

    • 不同的工作模式都可对应不同的布局文件。

    2.1 模块显示

    +

    左侧和右侧的面板,可以通过单击面板右上角的关闭按钮来隐藏,当隐藏一个面板以后,剩余的面板会自动填充布局,如果需要重新显示面板,则在标题栏鼠标右键就可以对小面板进行显示和隐藏,右上角的时间和CPU显示面板可以在系统设置中控制显示隐藏。系统会自动记住最后的布局比如显示的面板和宽高占比,下次启动后自动应用。

    特别说明

    1. 在停靠窗体的标题栏鼠标右键也会弹出子窗体的开启菜单,复选框勾选表示显示,悬浮的窗体没有这个特性,一定要是嵌入在主界面中的子窗体标题栏才有。

    2. 如果是全屏模式,由于没有了标题栏,想要关闭模块的话,需要将其拖动到边缘嵌入主窗体,然后在标题栏鼠标右键菜单中关闭即可。

    2.2 模块拖动

    面板和面板之间有个分隔条,鼠标移到对应分隔条的地方,会变成可拉动的鼠标指针,此时可以上下左右拉动调整宽高,调整好以后会自动保存宽高比例,下次启动后自动应用最后的配置来显示。

    2.3 视频播放

    视频播放支持多种方式:

    1. 双击子节点播放单个摄像机,在当前选中通道处播放。

    2. 双击父节点播放整个录像机的摄像机,依次排列。

    3. 按住子节点拖曳到对应通道,播放摄像机。

    4. 本地文件直接拖曳到通道,自动播放本地文件。

    5. 启动后自动播放最后通道的视频信息。

    6. 代码接口提供指定通道播放url。

    7. 代码接口提供指定两个通道交换,比如报警的时候将某个通道移到最前面显示。

    2.4 视频截图

    +

    视频截图支持多种方式:

    1. 监控通道鼠标右键,弹出菜单选择截图当前视频/截图所有视频。

    2. 视频面板底部工具栏截图按钮。

    3. 每个通道悬浮工具条截图按钮。

    4. 截图默认保存在可执行文件所在目录下的image_normal目录,文件名格式ch01_2022-11-24-13-41-24-000.jpg。

    5. 底部工具栏截图按钮触发截图后会弹出提示抓拍文件后的保存位置。

    2.5 删除视频

    +

    有多种方法可以删除视频:

    1. 鼠标右键删除当前视频。

    2. 鼠标右键删除所有视频。

    3. 按住通道画面移出视频监控画面。

    4. 悬浮条关闭按钮。

    2.6 画面切换

    系统支持多画面切换,全屏切换等,包括1+4+6+8+9+13+16+25+36+64画面切换,如果还需要增加更多的画面比如81+100等,可以直接在源码中稍微修改即可。

    1. 鼠标右键画面切换。

    2. 底部左侧画面切换缩略图。

    3. 快捷键alt+enter全屏。

    4. 快捷键esc退出全屏。

    64画面效果图 + +

    2.7 声音调节

    +

    在主界面画面栏右下角,按下声音图标自动弹出声音调节面板,失去焦点自动隐藏,拉动声音滚动条来调节声音大小,还有静音切换。右下角的声音和静音切换是针对所有通道的,单个通道可以在每个通道的悬浮条工具栏中单击静音切换按钮。

    2.8 视频轮询

    功能说明

    1. 开启是否一运行自动轮询。

    2. 可设置轮询间隔,比如5s、10s、30s、60s等。

    3. 可设置轮询画面类型,比如1画面、4画面、9画面、16画面。

    4. 可选择切换不同的轮询方案。

    5. 开始轮询和停止轮询。

    6. 暂停轮询和继续轮询。

    2.9 通道交换

    通道交换功能很常用,一般用户喜欢调整自己想要的通道显示到前面或者占据画面的更大部分,比如6画面8画面的时候,左侧有一个画面占据很大的位置,一般这个用来显示重要性最高的实时视频,如果需要通道交换,则按住通道拖动到另外一个通道上面松开鼠标即可,会立即应用,瞬间切换,这里切记不要移出视频画面外,移出去表示删除。

    本系统也封装了代码中动态控制切换和动态交换,具体代码在DeviceThreadUI类中,具体全局函数在AppEvent类中。

    2.10 云台控制

    如果需要控制云台移动,先要选择对应的通道,边缘会高亮,进行云台控制的前提是该摄像机要是支持云台的摄像机,很多人以为啥摄像机都可以移动,这是错误的,如果摄像机不支持云台,这个功能就别玩了,玩不起,经常遇到一些人说怎么云台不能用了,一检查尼玛原来摄像机根本没有云台。

    本系统云台控制走的是onvif协议,没有使用私有协议,上百家厂家的摄像机,走私有协议会玩死人的,所以统一采用onvif通用协议,需要提前在系统设置中的摄像机管理,搜索摄像机,输入正确的onvif用户信息后一键获取到云台地址。

    2.11 设备控制

    设备控制部分,目前可以获取和设置图片参数、手动校时、重启设备等,上面那一堆复选框对应功能需要用厂家sdk去实现,后期可能会增加一些onvif能够处理的功能。和云台控制操作一样,操作前也是需要选中某个通道,然后才是对选中的通道进行设备控制,比如图片参数中的明亮度、对比度、饱和度。

    2.12 报警订阅

    +

    本系统默认支持海康、大华、宇视、华为、天地伟业等厂家的摄像机的报警事件订阅,可以在系统设置中的视频参数设置中开启事件订阅开关,如果摄像机已经开启了报警事件的话(一般摄像机的网页配置界面进去有移动侦测、遮挡报警、人脸识别、报警输入等各种),默认一般是关闭的,比如摄像机后面的开关量输入报警接口,需要web页面进去设置开启。

    报警订阅走的是onvif协议,具体事件内容和含义可以在config/event.txt事件字典表中修改,由于onvif事件有多种,而且不同厂家对应关键字对应的事件含义可能不一样,不同厂家的设备可能含义有点出入,所有可以通过事件字典表自行更改,对应内容含义 事件等级/唯一标识/报警字样/解除字样,默认程序按照这个表中的进行过滤,不在表中的可以正常收到但是不会处理。

    常用几种事件字典:

    • 1,IsMotion,有人在移动,移动结束

    • 1,IsInside,有人在闯入,入侵结束

    • 1,LogicalState,开关量报警,报警结束

    • 1,State,开关量联动,联动结束

    2.13 悬浮工具

    悬浮条功能介绍:

    1. 内置悬浮条控件,悬浮条位置支持顶部、底部、左侧、右侧。

    2. 悬浮条控件参数包括边距、间距、背景透明度、背景颜色、文本颜色、按下颜色、位置、按钮图标代码集合、按钮名称标识集合、按钮提示信息集合。

    3. 悬浮条控件一排工具按钮可自定义,通过结构体参数设置,图标可选图形字体还是自定义图片。

    4. 悬浮条按钮内部实现了录像切换、抓拍截图、静音切换、关闭视频等功能,也可以自行在源码中增加自己对应的功能。

    5. 悬浮条按钮对应实现了功能的按钮,有对应图标切换处理,比如录像按钮按下后会切换到正在录像中的图标,声音按钮切换后变成静音图标,再次切换还原。

    6. 悬浮条按钮单击后都用名称唯一标识作为信号发出,可以自行关联响应处理。

    7. 悬浮条空白区域可以显示提示信息,默认显示当前视频分辨率大小,可以增加帧率、码流大小等信息。

    2.14 标签叠加

    可动态添加任意多个osd标签信息,标签信息包括名字、是否可见、字号大小、文本文字、文本颜色、标签图片、标签坐标、标签格式(文本、日期、时间、日期时间、图片)、标签位置(左上角、左下角、右上角、右下角、居中、自定义坐标)。

    具体结构体参数和使用方法如下:

    2.15 图形绘制

    可动态添加任意多个图形信息,这个非常有用,比如人工智能算法解析后的图形区域信息直接发给视频控件即可。图形信息支持任意形状,直接绘制在原始图片上,采用绝对坐标。

    具体结构体参数和使用方法如下:

    2.16 预置巡航

    操作步骤:

    1. 左侧选中通道,前提是该通道的设备支持预置位,一般是球机才有预置位。

    2. 单击获取预置位,所有预置位信息会表格形式显示,每个预置位有唯一编号和名称,名称可以修改,编号改不了。

    3. 预置位表格中三个按钮依次为执行、更新、删除。

    4. 单击执行按钮(三角形状),会调用对应的预置位,设备会切换到对应预置位对应的位置。

    5. 单击更新按钮(加号形状),将当前设备停留的位置作为新的位置更新对应预置位。

    6. 单击删除按钮(删除形状),将当前选中的预置位信息删除,有部分设备仅仅是删除位置信息,预置位还会在,具体要看设备的支持。

    7. 输入预置位名称,调整画面到要新加的预置位置,单击添加预置位按钮,会新增加一个预置位。

    8. 调用起始位,一般是球机的默认开机后的位置,原始位置,单击调用起始位按钮后,会自动切换过去。

    9. 设置起始位,将当前位置设置为起始位置。

    2.17 标签信息

    操作步骤:

    1. 左侧选中通道,前提是该通道的设备支持OSD的onvif协议设置,一般大厂的都会支持。

    2. 单击获取OSD,所有OSD的唯一标识自动列在列表框中。

    3. 选中一个OSD,会自动获取该OSD的详细信息然后填入在下面,比如坐标位置、字体大小、标签类型等。

    4. 单击添加OSD,会将填写好的对应唯一标识的OSD添加到设备中,一般摄像头会限制OSD的数量,如果已经存在了很多OSD,有可能添加会失败,很多设备会限制最大支持4个OSD。

    5. 添加OSD的时候未必是按照填写的唯一标识来添加,设备一般按照自己的命名规则,所以该字段默认即可,比如海康的OSD标识都是OsdToken_开头。

    6. 修改OSD,一般支持的修改字段是坐标位置和文字内容,当然这两个也基本上是最常用的需要修改的字段,一般设备不支持将日期时间类型的OSD修改成文字文本类型的OSD,可以选择删除再添加的方式来实现。

    7. 很多设备会限制只支持1个日期时间的OSD和多个文字文本的OSD,所以如果你添加多个日期时间OSD的时候,可能会失败。

    8. 单击删除OSD会将当前选中的OSD删除,删除后会重新读取所有OSD信息。

    9. 在左侧通道上按下鼠标,会自动将鼠标按下处的位置对应的真实像素坐标发送到坐标位置文本框中,以便添加和修改OSD。

    3 视频回放

    视频回放中有多个子模块,分别是不同的含义:

    1. 本地回放:回放存储在本地电脑的视频文件。

    2. 远程回放:通过sdk方式回放NVR上的存储录像(暂未实现,每个厂家不一样)。

    3. 设备播放:通用的rtsp取流形式的播放实时视频和回放录像文件,支持海康大华等厂家的NVR回放。

    4. 图片回放:查找对应文件夹下的所有通道图片,按照设定的间隔回复,类似视频效果,一般用在存储一堆图片序列的应用场景中。

    5. 视频上传:将查询的本地存储的视频文件上传到云端服务器。类似于将视频文件存储到服务器上,需要手动填写服务器地址和端口。

    3.1 本地回放

    3.1.1 视频查询

    基本步骤:

    1. 选择设备通道(可以所有通道后者某个通道)。

    2. 选择视频类型(存储视频/报警视频),目前只有存储视频。

    3. 选择时间范围,考虑都范围大文件数量过多,默认限定查询60天内范围的视频。

    4. 单击查询按钮,符合条件的视频文件都会列出来,双击可以播放。

    5. 每个文件前面都有复选框,可以勾选用于下载和删除。

    6. 单击下载按钮,会将当前选中的文件拷贝到选择的目录。

    7. 单击删除按钮,会将当前选中的文件删除。

    8. 单击清空按钮,会将所有查询出来的文件全部删除。

    9. 播放过程中实时显示播放进度,可以单击或者拖动进度条切换进度。

    10. 默认播放完成一个会自动播放下一个,如果有下一个的话。

    11. 进度条左侧显示当前播放时长和文件总时长。

    12. 进度条右侧有三个按钮,分别是播放/暂停按钮、停止按钮、静音切换按钮。

    13. 右上角可以选择播放速度,播放过程中也会立即应用,可选0.5倍速、1.0倍速、2.0倍速、4.0倍速、8.0倍速等。

    3.1.2 存储规则

    1. 默认存储主目录 video_normal。

    2. 主目录下按照日期目录存放(2025-10-01/2025-10-31)。

    3. 日期目录下是单个视频文件(ch01_2021-04-07-14-08-11.mp4/ch02_2021-04-07-14-08-11.mp4)。

    4. 拓展功能可以存储对应的数据文件比如经纬度数据和视频文件一个目录(名称一样并且拓展名可以是txt)。

    3.2 远程回放

    远程回放模块是用来通过sdk的形式回放远程NVR设备上的录像文件,这个暂未实现,本系统主要是为了兼容性和通用性,通过具体sdk形式调用的处理都没有做,破坏了移植性,到了其他平台就没法使用了。

    3.3 设备播放

    设备播放模块主要是通过rtsp视频流的形式来拉取实时视频和回放视频,现在越来越多的NVR支持直接通过取流的形式来拉取实时视频流和回放视频,这样使用起来很方便,当然在拉取视频流的时候要传入用户信息,防止非法获取,现在越来越多的应用场景需要通过NVR来调取回放视频,传统的SDK的方式非常累厂家太多,而国标的形式太繁琐复杂,于是rtsp形式的最简单的方式应运而生,目前支持的厂家也越来越多,每个厂家格式的规则不一样,可以自行咨询厂家的规则,本程序默认实现了海康、大华的规则。

    基本步骤:

    1. 选择设备厂家,不同厂家rtsp视频流格式不一样,内置支持了海康、大华、通用的。

    2. 选择视频类型,支持实时视频和回放视频两种,回放视频还要选择时间范围。

    3. 填写用户名称、用户密码,最后组成rtsp视频流字符串一起。

    4. 填写或者下拉选择设备地址,填写IP地址,默认会把录像机管理中添加的设备地址填充到下拉框。

    5. 选择设备通道,一个设备比如NVR可能有多个通道,摄像机一般只有1个通道。

    6. 选择码流类型,可以选择主码流、子码流、三码流。

    7. 选择时间范围,实时视频不用选,回放视频才需要。

    8. 左侧选中某个通道,单击播放按钮,会将对应参数组成的rtsp视频流地址打开。

    9. 单击删除按钮,相当于关闭选中的通道。

    10. 可以单击暂停和继续两个按钮用来控制暂停播放和继续播放。由于是视频流是实时的,所以暂停期间会正常接收数据,但是并不会解码,所以当你再次播放时已经是最新的当前时间的视频数据。

    3.4 图片回放

    3.4.1 图片查询

    选择设备通道和时间范围,单击查询按钮,会将查询到的图片序列按照日期的形式作为一行添加到列表结果中,双击可以自动播放,可以调节播放速度。

    3.4.2 存储规则

    1. 默认存储主目录 image_normal

    2. 主目录下按照日期目录存放(2025-10-01/2025-10-31)

    3. 日期目录下是单个图片文件(ch01_2021-04-07-14-08-11-222.jpg/ch02_2021-04-07-14-08-11-333.jpg)

    4. 拓展功能可以存储对应的数据文件比如警情文字和图片文件一个目录(名称一样并且拓展名可以是txt)

    3.4.3 导出报告

    图文混排,可以自定义信息,封装好的类,传入图片队列,图片自适应等比例缩放显示,超过自动分页。

    3.5 视频上传

    +

    视频上传功能主要用来将本地存储的视频文件(也可以是其他文件),通过网络传输(默认TCP)上传到其他地方比如服务器,服务器上要运行接收文件的程序,这样就相当于远程备份视频文件的功能,视频文件可以勾选需要上传哪一些。

    3.5.1 本地设置

    本地只需要在视频监控系统客户端上切换到视频上传页面,然后选择要查询的日期范围,单击查询,会将视频文件查询出来显示在左边的表格中,可以勾选要上传的视频文件,右侧填写好服务器的IP和端口(默认6000),单击上传按钮,会多线程的形式上传文件。

    3.5.2 远程设置

    远程需要放置文件传输工具,该工具完整源码如果购买了视频监控系统,可以赠送,该工具同时具备了发送端和接收端的功能,配套视频监控系统使用的是接收端,视频监控系统作为发送端,填好监听端口后,单击监听按钮,一旦有连接文件上传,会自动显示对应的接收进度,文件名称以上传的文件名为准。

    3.5.3 文件加密

    默认文件传输过程采用了加密机制,意味着传输的数据是加密后的数据,接收到以后根据设置的秘钥进行解密重新生成文件,防止文件传输过程中被拦截,可自定义加密规则。

    3.5.4 功能特点

    1. 多线程收发文件,支持加密传输。

    2. 接收端支持监听端口接收文件和主动连接服务器接收文件两种方式。

    3. 按照 文件开始符+文件大小+文件内容+文件结束符 逐个分包接收。

    4. 可对接收的加密过的文件包进行解密输出。

    5. 如果采用连接服务器方式接收文件可指定请求文件。

    6. 接收端请求文件的形式可以作为通用的程序升级方案。

    7. 进度条实时更新收发文件的进度。

    8. 发送端可设置每个包最很大小即切片分包数量。

    9. 发送端可对文件的每个包进行加密传输。

    10. 发送端支持对包进行合并发送。

    11. 可指定目录对客户端发来的请求文件进行搜索。

    12. 每个功能独立的一个类,接口清晰友好,使用方便。

    13. 支持任意Qt版本、任意系统、任意编译器。

    4 电子地图

    电子地图有多个子模块,分别不同的功能,在每个模块上,双击对应的摄像机,都可以弹出实时视频预览画面,支持多个画面同时打开,每个摄像机都一个画面窗体。

    1. 图片地图:摄像机分布在平面图上。

    2. 离线地图:默认采用百度离线瓦片地图,本地使用。

    3. 在线地图:默认采用百度地图,需要联网使用。

    4. 路径规划:指定起始点和终点经纬度坐标,查询最优路径并绘制路线,提取路线坐标集合,动态模拟轨迹,比如机器人和飞机轨迹。

    4.1 双击预览

    4.2 图片地图

    1. 图片地图的功能是为了方便直接提供图片文件,然后摄像机点位可直接拖动,更精确定位的场景,图片可以提供鸟瞰图这种,看起来更直观大气,有3D的感觉。

    2. 图片文件存放在可执行文件下的map文件夹下,如果需要增加或者删除,可以直接文件操作即可,比如复制新的图片文件到这个目录下即可。

    3. 具体摄像机对应哪张图片,可以在摄像机管理中设置,对应字段为地图,直接下拉选择对应的地图即可,默认选择无,就是该摄像机不属于任何地图。

    4.3 离线地图

    功能和在线地图完全一致,唯一区别就是地图是离线的,不需要联网。离线的地图需要自己准备好,可以网上通过瓦片地图下载器来下载需要的地方的离线地图,一般离线地图比较大,他是一张张图片,所以建议离线地图只下载自己需要的即可,比如某个县的地图,而不是所有的,所有的起码有几十GB。

    使用说明

    1. 默认系统提供的是上海市的地图。

    2. 下载地址在下面文章中,会自动更新地址。 +https://blog.csdn.net/feiyangqingyun/article/details/104005917

    3. 请下载同目录下的bin_map_tiles.zip压缩包,解压到config目录下,最后config文件夹下会多出来tiles tiles_hybrid两个文件夹。

    4.4 在线地图

    在摄像机管理的界面,可以添加经纬度信息,这样就可以在地图上显示对应的摄像机点位信息,如果发现位置不对,可以在右侧先选择摄像机设备,然后鼠标单击新的位置,右侧目标经度、目标纬度信息会自动更新,然后再单击更新经纬度值则会更新当前下拉选择的设备的经纬度信息,也可以在摄像机管理界面手动填入进行修改。

    在右侧还有模拟运动轨迹、开始显示轨迹两个按钮,有可能后期还会增加其他功能,是为了演示如何在地图上实现地图的相关功能,开始显示轨迹采用的定时器来生成轨迹点数据,动态模拟运动轨迹,可以单击显示设备位置按钮还原最初的设备点位图。

    功能特点

    1. 同时支持在线地图和离线地图两种模式。

    2. 同时支持webkit内核、webengine内核、IE内核。

    3. 支持设置多个标注点,信息包括名称、地址、经纬度。

    4. 可设置地图是否可单击、拖动、鼠标滚轮缩放。

    5. 可设置协议版本、秘钥、主题样式、中心坐标、中心城市、地理编码位置等。

    6. 可设置地图缩放比例和级别,缩略图、比例尺、路况信息等控件的可见。

    7. 支持地图交互,比如鼠标按下获取对应位置的经纬度。

    8. 支持查询路线,可设置起点位置、终点位置、路线模式、路线方式、路线方案(最少时间、最少换乘、最少步行、不乘地铁、最短距离、避开高速)。

    9. 可显示点线面工具,可直接在地图上划线、点、矩形、圆形等。

    10. 可设置行政区划,指定某个城市区域绘制图层,在线地图自动输出行政区划边界点集合到js文件给离线地图使用。

    11. 可静态或者动态添加多个覆盖物。支持点、折线、多边形、矩形、圆形、弧线、点聚合等。

    12. 函数接口友好和统一,使用简单方便,就一个类。

    13. 支持js动态交互添加点、删除点、清空点、重置点,不需要刷新页面。

    14. 支持任意Qt版本、任意系统、任意编译器。

    4.5 路径规划

    基本步骤

    1. 输入起点坐标和终点坐标,也可以勾选地图选点,开启后直接在左侧的地图界面鼠标按下自动识别对应的经纬度坐标填入,单选框勾选的起点则填入起点坐标输入框中,勾选的终点就填入终点坐标输入框中。

    2. 选择路线方式,可选公交、驾车、步行、骑行等方式,默认选择步行。

    3. 选择路线方案,可选最少时间、最短距离、避开高速等。

    4. 输入关键点数,一般查询返回的路径的经纬度坐标点数非常密集,可能非常多,我们需要根据输入的关键点数来过滤,比如输入30,表示从所有经纬度数据中平均提取出来30个数据就行。点数合计,查询路线后自动返回所有经纬度坐标的数据个数。

    5. 单击查询路线,自动返回对应路径的所有经纬度坐标。

    6. 单击帅选数据,按照填入的关键点数进行数据帅选,在下方可以看到原始数据和最终数据,选中某个数据,自动在左侧生成点预览对应的位置。

    7. 单击模拟轨迹,会启动定时器,从第一个数据点开始,自动移动设备比如机器人、飞行器等,查看整个轨迹点路径是否正确。

    5 日志查询

    5.1 本地日志

    本地日志存放的是本系统的操作日志,比如用户登录退出、记录删除、设备报警等操作,都会有对应的记录存放的数据库,可以在这里选择时间段和日志类型进行查询。查询后的日志记录可以翻页查看,还可以直接支持指定页码跳转,(此翻页组件超级牛逼,外观和功能分离,自动计算页码切换导航,具体可参见对应类的头文件功能描述),每页显示多少条记录在系统设置中可以设置。

    5.1.1 查询记录

    1. 可以按照多条件进行查询记录。

    2. 可以选择设备通道。

    3. 可以选择日志的类型:用户操作、运行日志、设备日志、报警日志。

    4. 可以选择时间范围。

    5. 在查询记录的时候,如果勾选了前面的复选框则表示启用该选择条件进行查询。

    6. 没有勾选,就算后面选择了类型等,也是按照where 1=1 条件查询的。

    7. 查询后的记录会自动分页显示,而不是一次性显示。

    8. 可以单击底部的翻页按钮进行翻页查看记录。

    9. 可以快速切换到第一页、末一页、上一页、下一页、显示的页码切换、指定的页码切换。

    5.1.2 打印记录

    单击打印按钮,会将当前查询的记录打印出来,自动分页。打印前会弹出打印预览对话框,可以最后在这里调整边距、纸张等设置参数。

    5.1.3 导出记录到xls

    单击XLS按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    5.1.4 导出记录到pdf

    5.1.5 删除记录

    单击删除按钮,会弹出时间范围选择对话框,选择要删除的记录的开始时间和结束时间,单击确定,会将该时间段内的记录全部删除,结束时间必须大于开始时间。

    5.1.6 清空记录

    单击清空按钮会先弹出询问框提示是否需要清空数据,单击确定则自动清空所有的记录,清空后不能恢复。

    5.2 设备日志

    设备日志是指直接通过sdk协议,远程从NVR设备上拉取日志记录到本地显示,其余功能和本地日志一致,此功能未实现。

    6 系统设置

    6.1 基本设置

    6.1.1 常规设置

    基本设置中有部分参数的切换会自动重启应用。

    参数说明

    1. 开机运行:开启以后自动随着系统启动运行,默认开启。

    2. 自动登录:开启以后会自动以最后登录的用户信息登录到系统,默认关闭。

    3. 记住密码:开启以后会自动填入最后登录的用户信息到登录窗体,默认关闭。

    4. 中文标题:软件左上角标题栏的中文标题,改动立即应用。

    5. 英文标题:软件左上角标题栏的英文标题,改动立即应用。

    6. 版权所有:当前软件版权所有的公司,目前没有显示在哪里,备用。

    7. 调试日志:开启后会将打印日志输出到日志文件,默认关闭,日志文件存放在可执行文件夹下的log目录下。

    8. 运行时间:开启后会实时记录系统的运行时间,记录当前软件启动后运行了多久,运行时间文件存放在可执行文件夹下的log目录下。

    9. 工作模式:默认视频监控,可选机器人监控、无人机监控等。

    10. 导航样式:用于选择顶部导航栏和左侧导航栏的样式,上侧+左侧表示顶部导航栏上侧样式(图标在上面,文字在下面),左侧导航栏左侧样式(图标在左侧,文字在右侧)。

    11. 界面样式:系统自带17套皮肤,可以在这里自动换肤,默认视频黑。

    12. 软件图标:自动从logo文件夹读取,可以自行选择对应的logo文件。

    13. 全屏模式:开启以后,最大化显示自动全屏显示而不是最大化显示,默认关闭。

    14. 弹框时间:右下角弹出提示信息自动关闭时间,0秒表示常驻不关闭。

    15. 报警声音:0表示不启用,其余表示报警后播放的声音次数。

    16. 鼠标隐藏:主界面多久鼠标没有操作过会自动隐藏鼠标指针,一般在全屏轮询的时候需要设置,效果会更好。

    17. 自动全屏:经过多久以后鼠标没有操作过自动全屏,0表示不启用。

    18. 播放记录:如果开启在软件打开后会自动读取上一次的播放记录并自动打开,不需要可以关闭。

    19. 图文警情:图文警情模块消息行数,0表示自动计算填满,不产生滚动条。

    20. 窗口消息:窗口消息模块消息行数,0表示自动计算填满,不产生滚动条。

    21. 透明度值:停靠窗体的透明度值,可调节,动态应用。

    6.1.2 视频参数

    参数说明

    1. 共享解码:开启后相同地址的通道会复用之前已经打开的通道,这样可以大大节省网络流量和解码压力。

    2. 播放音频:开启以后可以播放声音,有时候不需要声音的时候可以关闭,节省资源。

    3. 保存视频:录像计划的总开关,开启以后自动存储录像文件,目录在可执行文件目录video_normal。

    4. 事件订阅:开启以后会用onvif的机制订阅报警事件。

    5. 自动校时:开启后摄像机上线立即同步本地时间到设备。

    6. 人工智能:用于演示绘制osd标签和添加各种图形绘制到视频图片上。

    7. 画面显示:可选自动调整、等比缩放、拉伸填充三种图片显示策略。

    8. 显示模式:可选句柄、绘制、GPU三种模式,在ffmpeg内核下句柄和GPU都是同一种处理。

    9. 硬件加速:会根据不同的内核以及不同的系统自动显示不同的可用的加速器名称,默认none表示不启用硬件加速,ffmpeg可选dxva2和d3d11va,建议用dxva2。

    10. 通信方式:视频流采用何种通信方式,默认TCP(可靠连接,不会丢包,缺点就是慢),可选UDP(不可靠连接,容易丢包,但是速度快)。

    11. 解码策略:ffmpeg内核专用,可选速度优先、质量优先、均衡处理、最快速度,如果对实时视频流rtsp有实时性要求建议选择最快速度,可以看到无论是打开加载视频流还是响应都是最快的。

    12. 缓存大小:vlc内核专用,值越小响应速度越快,受限于网络环境和硬件性能。

    13. 读取超时:读取视频流过程的超时时间,可选不处理或者具体的秒数,不处理则一直等待直到系统层通知读取失败,选择的话可以加快速度跳出并立即通知失败,建议设置5s,在网络环境不好或者网络中断的情况下能够快速识别到掉线。

    14. 连接超时:对于视频流地址可用,先探测对应的地址是否通,不通则不用继续,加载很慢的一些网络地址需要把时间设置大一些,可以尝试用vlc等第三方播放器打开地址对比速度,如果确实很慢,这个值可以设置大一些。

    15. 分组双击:可选最后空白通道、从头清空通道,就是双击设备父节点的时候,是从哪个通道开始打开,如果选择的是最后空白通道,则会从通道1开始遍历找到第一个空白的通道依次打开,如果选择的是从头清空通道,则每次都是全部清空再从通道1开始打开。

    16. 设备双击:可选最后空白通道、最后按下通道,就是双击设备子节点的时候,是在哪个通道打开视频,如果选择的是最后空白通道,则会从通道1开始遍历找到第一个空白的通道打开视频,如果选择的是最后按下通道,则对按下的通道先删除再打开视频。

    17. 表格策略:摄像机管理中,对应表格是按下进入编辑状态还是双击进入编辑状态。

    18. 视频边框:视频控件边框大小,用户根据实际需要选择即可。

    6.1.3 数据库设置

    参数说明

    1. 远程同步:开启后将会启用云端数据同步功能,将本地数据实时同步到远程数据库中。

    2. 主机类型:和本地数据库设置一样,可选多种。

    3. 数据库名:对应数据库的数据库名称,一个数据库系统中可以有多个数据库实例。

    4. 主机地址:数据库所在的网络地址,可以是IP地址或者网址。

    5. 通信端口:数据库开放通信的端口,不同数据库默认端口不同,比如mysql是3306,postgres是5432,sqlserver是1433。

    6. 用户名称:登录到网络数据库对应的用户名称,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。

    7. 用户密码:登录到网络数据库对应的用户密码,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。

    8. 连接测试:单击后主动连接一次当前填入的数据库信息,连接成功与失败都会弹框提示。

    9. 初始数据:单击后会执行sql脚本文件,重置数据库,会将原来的数据一并清空。务必记得只有需要的时候才执行。

    其他说明

    1. 默认提供了数据库脚本文件(源码下的file/db/video_system.sql)。

    2. 单击初始化数据按钮可以对整个数据库进行新建和重置,相当于恢复出厂。

    3. 系统支持多种数据库,默认sqlite(Qt内置的数据库,无需安装),可选mysql、postgresql、oracle、人大金仓等。

    4. 具体还需要对应Qt版本有数据库插件支持,没有插件支持可以自行编译对应缺失的插件比如mysql,也可选直接通过万能的ODBC来连接。

    5. 除了sqlite数据库外,其余数据库都需要输入数据库名称、主机地址、通信端口、用户名称、用户密码信息,输入好以后可以单击连接测试按钮测试下是否正常。

    6. 默认提供的是mysql的动态库libmysql.dll,需要放到可执行文件同一目录,严格区分32位和64位的动态库。

    6.1.4 地图配置

    参数说明

    1. 地图秘钥:对应百度地图的秘钥,默认内置的作者的秘钥,很多软件系统都用的这个秘钥,用户数较多,可能有并发限制,为了不影响体验,强烈建议改成自己的,可以自行去官网申请,免费。

    2. 地图中心:默认地图的中心点坐标。

    3. 地图级别:默认地图打开以后的缩放级别。

    6.1.5 功能激活

    参数说明

    1. 勾选则表示启用。

    2. 可以对各种分屏进行功能激活。

    3. 需要重启应用。

    4. 没有勾选的,不会显示对应的菜单切换和分屏快捷按钮。

    5. 多个子界面模块也可以选择显示或者隐藏,以便将不需要的模块隐藏掉,碍眼。

    6.1.6 颜色配置

    可以设置不同的场景不同的颜色,比如正常的系统消息显示白色,异常消息红色。

    6.2 录像机管理

    本系统所用的录像机信息,并没有实际的作用,也就是不一定要填写实际的录像机信息,留作备用后期使用,目前仅仅是作为生成设备的树状列表使用(类似于区域或分组),如果一个录像机都没有填写,则会自动生成一个默认的录像机信息。

    字段说明

    1. 设备编号:录像机的编号,唯一字段。

    2. 设备名称:录像机的别名,建议不要重复。

    3. 设备类型:录像机的厂家类型,可选海康、大华、宇视、其他等。

    4. 设备地址:录像机的IP地址。

    5. 用户姓名:录像机的登录用户名称。

    6. 用户密码:录像机的登录用户密码。

    7. 启用状态:录像机设备是否启用。

    8. 安装位置:录像机的安装位置。

    6.2.1 录像机添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    6.2.2 录像机删除

    如果要删除某个录像机信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    6.2.3 录像机清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    6.2.4 录像机信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    6.2.5 录像机信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    6.2.6 录像机信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    6.2.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    6.3 摄像机管理

    摄像机表信息,是整个系统中最核心的表,这里管理的所有的摄像机信息,并不是所有的字段都显示出来了,比如onvif地址、云台地址等都是隐藏的,因为无需添加更改,需要搜索自动添加的。

    字段说明

    1. 设备编号:摄像机的唯一编号。

    2. 设备名称:摄像机的别名,建议不要重复。

    3. 录 像 机:该摄像机对应所属的录像机,随便选择一个就行。

    4. 设备厂家:摄像机的厂家类型,通过onvif搜索会自动有厂家信息,没有的就选择其他。

    5. 主码流地址:摄像机的主码流地址。

    6. 子码流地址:摄像机的子码流地址。

    7. 经 纬 度:摄像机的经纬度信息,用来地图上显示位置,中间用 | 隔开。

    8. 背景地图:摄像机对应的平面地图,下拉选择,默认从可执行文件下的map目录下读取图片文件列表生成。

    9. 用户姓名:摄像机登录的用户名称。

    10. 用户密码:摄像机登录的用户密码。

    11. 启用状态:摄像机是否启用。

    12. 安装位置:摄像机的安装位置。

    6.3.1 摄像机添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    6.3.2 摄像机删除

    如果要删除某个摄像机信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    6.3.3 摄像机清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    6.3.4 摄像机信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    6.3.5 摄像机信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。

    6.3.6 摄像机信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    6.3.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    6.3.8 设备搜索

    如果摄像机已经添加过,则搜索出来的摄像机对应行禁用不可选中。

    基本步骤

    • 第一步:单击广播搜索按钮,搜索到的设备会显示在左侧表格中。

    • 第二步:输入onvif用户名和密码,注意是onvif的用户信息,一个摄像机可能有多种用户,比如登录用户,远程用户,onvif用户,务必记得要用onvif用户信息,可参阅说明书的末尾 海康大华onvif设置

    • 第三步:单击获取所有,会自动以填写的onvif用户信息,去拉取具体摄像机的码流地址、云台地址等信息,可以拉动底部的横向滚动条查看具体是否获取到信息。

    • 第四步:单击添加选中按钮将所有勾选了复选框的设备添加到摄像机信息表中。

    特别说明

    1. 如果没有码流地址,是添加不了的,必须有码流地址才能添加。

    2. 一般一个项目上的摄像机都是同一个品牌的,onvif用户信息也都一样,所以单击获取所有可以把所有摄像机的信息获取到。

    3. 可以填入不同的onvif用户信息,单击获取当前按钮来指定摄像机获取onvif信息。

    4. 如果有些设备不支持广播,只支持单播(比如不是同一网段的设备,但是路由器设置过,是通的),则指定设备右侧填写好IP地址或者onvif地址,再单击单播搜索即可。

    5. 一台电脑可能多个网卡和IP网段,可以选择不同的网卡进行搜索,相当于不同的网段。

    6. 录像机信息和摄像机信息的更改,是自动应用的,无需重启。

    7. 搜索后的设备信息自动添加到表格中,按照IP地址升序排序,支持跨网段排序,自动将IP地址转为quint32整型进行排序,而不是取IP地址末尾。

    参数说明

    1. 用户姓名:onvif用户的名称,默认admin。

    2. 用户密码:onvif用户的密码,默认admin。

    3. 选择网卡:选择对应电脑的网卡IP,可能有多个网段,onvif只能同一个网段。

    4. 指定设备:对指定的IP地址或者onvif地址进行onvif搜索。

    5. 过滤设备:对返回的onvif地址进行过滤,一种厂家的类别的设备地址格式一样。

    6. 搜索间隔:默认onvif搜索指令有好几种,会重发几次,指定发送的间隔。

    7. 搜索策略:默认自动清空,每次都重新添加搜索到的设备,如果选择设备累加则多次搜索后只会将新增加的设备加到设备列表,这个非常有用,在很多设备现场建议用设备累加策略而不是自动清空,因为onvif协议是udp协议,在大量数据的情况下会导致丢包,需要多次搜索,取最终的设备集合。

    8. 广播搜索:广播搜索指定网卡的所有onvif设备。

    9. 单播搜索:对指定设备进行单个搜索。

    10. 获取所有:按照当前填入的用户姓名和密码,填充到onvif请求鉴权中对所有搜索的设备进行媒体地址的获取、云台控制地址的获取、视频流地址的获取等。

    11. 获取当前:很多时候并不是所有的设备onvif用户信息一样,对于不一样的,可以先选中设备所在行,然后输入不同的用户信息,单击获取当前即可,会对当前选中的设备重新获取onvif信息。

    12. 添加选中:搜索到的设备前面都有个复选框,单击添加选中以后会对所有打钩的设备批量添加到摄像机信息表中,会自动过滤已经添加过的设备以及没有视频流地址的设备。

    13. 添加当前:对应获取当前,一般来说单个添加用户信息不一样的设备,因为批量添加不了,他的信息需要单独获取。

    6.4 轮询配置

    轮询点管理界面,上侧是轮询点信息表,可以直接添加、删除、修改、清空轮询点信息,下侧是摄像机信息表,会自动加载,当摄像机信息变动后,这里会自动加载最新的数据。右下角是批量生成轮询点和轮询分组管理。

    6.4.1 轮询点添加

    轮询点的添加有三种方式:手动添加、单个添加、批量添加。允许重复添加,没有过滤机制。

    添加方式

    1. 手动添加:单击添加按钮,在右侧轮询信息表格中自动生成默认轮询点信息,手动输入和修改信息然后单击保存按钮即可。

    2. 单个添加:左侧摄像机信息表中选中一行,单击添加当前按钮,会将选中的摄像机信息添加到右侧轮询点信息中,自动保存。

    3. 批量添加:单击添加所有按钮,会将所有摄像机信息添加到右侧轮询点信息中,自动保存。

    6.4.2 轮询点删除

    如果要删除某个轮询点信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    6.4.3 轮询点清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    6.4.4 轮询点信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    6.4.5 轮询点信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。

    6.4.5 轮询点信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    6.4.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    6.4.8 参数设置

    参数说明

    1. 自动轮询:开启以后,启动软件后自动轮询。

    2. 轮询间隔:画面切换的间隔,单位秒,建议时间长一点。

    3. 轮询画面:轮询的画面数,可选1画面、4画面、9画面、16画面。

    4. 码流类型:默认子码流,超过4画面建议子码流。

    6.4.9 批量生成

    轮询表信息可以通过已添加的摄像机信息表选中添加,也可以自定义规则批量生成视频流地址添加,这种应用场景非常多,比如现场是某一种品牌的摄像机,视频流格式固定,只需要设置好主码流子码流的视频流格式,便可批量生成。

    参数说明

    1. 生成数量: 需要批量生成多少个。

    2. 起始地址:如果选择的是文件,则填写对应的数字,其他则填写IP地址。

    3. 地址格式:可选各种厂家类型,还可选择文件,这个用于测试软件非常有用。

    6.4.10 分组设置

    可添加、删除、修改、清空轮询分组名称,相当于轮询预案。

    6.5 用户管理

    用户管理是后面增加的一个模块,用于设置不同的用户不同的类型+权限,可以细分到每个模块的权限,勾选表示具有该权限,内置了7种权限选择,后期还可以在此基础上增加其他权限等。

    6.5.1 用户添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    6.5.2 用户删除

    如果要删除某个用户信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。不允许删除内置的admin用户。

    6.5.3 用户清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    6.5.4 用户信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    6.5.5 用户信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。

    6.5.6 用户信息打印

    +单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    6.5.7 导出到Excel

    +单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    6.5.8 权限验证

    +

    假设设置了用户没有退出系统和电子地图的权限,则关闭系统的时候会弹出错误信息提示当前用户没有权限。

    6.6 录像计划

    + + +

    录像文件严格按照30分钟一个文件,除了首个文件和末尾文件不一定是30分钟的文件,中间的肯定是完整的30分钟的文件,时间从00:00到29:59或者30:00到59:59。由于文件打开和保存需要时间以及保证首帧是关键帧(有些设备可以设置I帧间隔50/意味着接近2s一个关键帧),文件可能会有1-2s的偏差。

    基本步骤:

    1. 单击批量按钮可以批量添加1-64通道7 * 24小时录像计划到数据库中。

    2. 每个通道可以设置周一到周日7天的每个半小时时段是否录像。

    3. 上面表格中选中通道,下面录像计划控件选择对应的格子即可。

    4. 可以鼠标右键选择全选、反选、清空操作。

    5. 录像计划控件更改后会立即更新表格中对应通道的录像计划值,1表示该时间段录像,0表示不录像。

    6. 选中通道表格行,下面会自动显示对应的录像计划,一目了然。

    6.7 其他设置

    其他设置里面的内容之前在基本设置中,现在重新开一个窗体,因为后面可能还有各种各样的设置,预留空间。

    6.6.1 串口配置

    系统中可能用到了多个串口通信,可以在这里选择对应的串口号和波特率。

    6.6.2 网络配置

    系统中可能用到多种网络通信,比如软件主动连接服务器,需要填写TCP地址和端口,也可能软件作为服务端,填写TCP或者UDP监听端口。

    7 简易使用步骤

    7.1 添加摄像机

    1. 切换到系统设置-》摄像机管理,单击添加,输入码流地址,单击保存。如果不知道码流地址,需要通过onvif搜索,具体参见 6.3.8 设备搜索 ,有非常详细的步骤。

    2. 在不知道主码流和子码流是啥的情况下,两个地方填一样的,其余默认即可。

    3. 本地文件格式:g:/mp4/1.mp4

    4. USB摄像机:默认ffmpeg内核为 video=USB2.0 PC CAMERA

    5. 摄像机视频流:直接填入rtsp、rtmp、http的视频流地址,该地址可以先用vlc播放器或者potplay等播放器先试试是否能正常播放,不能的话就别添加了,添加了也没卵用,别费力气了。

    7.2 视频播放

    切换到视频监控主界面,左侧设备列表,双击摄像机,自动通道播放,双击录像机则整个录像机下面的摄像机全部加载。

    7.3 云台控制

    云台控制的前提是摄像机是通过onvif搜索的形式添加的,不然没有云台地址没法进行云台控制,当然也必须要求摄像机带云台,不带云台的摄像机是不能进行云台控制的。 +先选中要进行云台控制的摄像机通道,边缘高亮,然后再单击右侧的云台控件,可以上下左右等移动,变倍和光圈没有用。

    7.4 自动校时

    在系统设置中开启自动校时后,设备自动上线后会自动将本地时间同步到设备。

    7.5 事件订阅

    在系统设置中开启事件订阅后,一旦接收到设备的报警信息会显示到主界面左下角的信息栏,右下角弹出对应的报警信息。 +摄像机要响应事件订阅,具体详细设置说明参见说明书其他说明中的摄像机报警输入设置。

    7.6 图片参数

    操作说明

    • 用onvif也可以对摄像机的明亮度、对比度、饱和度进行设置。

    • 先选中对应的通道,然后右下角这里找到设置的区域。

    • 单击获取参数,会自动将对应摄像机的明亮度、对比度、饱和度值读回来,显示在对应文本框和滑块中。

    • 如果需要设置图片参数,先移动滑块到需要的值,然后单击设置参数按钮即可。

    • 设置完以后会立即应用,传过来的视频流就能看到效果。

    • 下面还有两个按钮可以手动重启设备以及校时。后期可能还会增加一些按钮。

    8 内核模块说明

    1. 本系统支持多种内核,方便不同的用户选择,适应不同的应用场景。

    2. 本系统默认集成的是ffmpeg内核,其他内核需要额外购买或者定制,支持定制内核。

    3. 每个内核实现的功能不一定完全一致(可能受限于对应组件源头本身的功能缺失),推荐用默认的ffmpeg内核。

    8.1 视频监控内核

    8.1.1 效果图

    + + + + +

    8.1.2 基础功能

    1. 支持各种音频视频文件格式,比如mp3、wav、mp4、asf、rm、rmvb、mkv等。

    2. 支持本地摄像头设备和本地桌面采集,支持多设备和多屏幕。

    3. 支持各种视频流格式,比如rtp、rtsp、rtmp、http、udp等。

    4. 本地音视频文件和网络音视频文件,自动识别文件长度、播放进度、音量大小、静音状态等。

    5. 文件可以指定播放位置、调节音量大小、设置静音状态等。

    6. 支持倍速播放文件,可选0.5倍、1.0倍、2.5倍、5.0倍等速度,相当于慢放和快放。

    7. 支持开始播放、停止播放、暂停播放、继续播放。

    8. 支持抓拍截图,可指定文件路径,可选抓拍完成是否自动显示预览。

    9. 支持录像存储,手动开始录像、停止录像,部分内核支持暂停录像后继续录像,跳过不需要录像的部分。

    10. 支持无感知切换循环播放、自动重连等机制。

    11. 提供播放成功、播放完成、收到解码图片、收到抓拍图片、视频尺寸变化、录像状态变化等信号。

    12. 多线程处理,一个解码一个线程,不卡主界面。

    8.1.3 特色功能

    1. 同时支持多种解码内核,包括qmedia内核(Qt4/Qt5/Qt6)、ffmpeg内核(ffmpeg2/ffmpeg3/ffmpeg4/ffmpeg5/ffmpeg6)、vlc内核(vlc2/vlc3)、mpv内核(mpv1/mp2)、mdk内核、海康sdk、easyplayer内核等。

    2. 非常完善的多重基类设计,新增一种解码内核只需要实现极少的代码量,就可以应用整套机制,极易拓展。

    3. 同时支持多种画面显示策略,自动调整(原始分辨率小于显示控件尺寸则按照原始分辨率大小显示,否则等比缩放)、等比缩放(永远等比缩放)、拉伸填充(永远拉伸填充)。所有内核和所有视频显示模式下都支持三种画面显示策略。

    4. 同时支持多种视频显示模式,句柄模式(传入控件句柄交给对方绘制控制)、绘制模式(回调拿到数据后转成QImage用QPainter绘制)、GPU模式(回调拿到数据后转成yuv用QOpenglWidget绘制)。

    5. 支持多种硬件加速类型,ffmpeg可选dxva2、d3d11va等,vlc可选any、dxva2、d3d11va,mpv可选auto、dxva2、d3d11va,mdk可选dxva2、d3d11va、cuda、mft等。不同的系统环境有不同的类型选择,比如linux系统有vaapi、vdpau,macos系统有videotoolbox。

    6. 解码线程和显示窗体分离,可指定任意解码内核挂载到任意显示窗体,动态切换。

    7. 支持共享解码线程,默认开启并且自动处理,当识别到相同的视频地址,共享一个解码线程,在网络视频环境中可以大大节约网络流量以及对方设备的推流压力。国内顶尖视频厂商均采用此策略。这样只要拉一路视频流就可以共享到几十个几百个通道展示。

    8. 自动识别视频旋转角度并绘制,比如手机上拍摄的视频一般是旋转了90度的,播放的时候要自动旋转处理,不然默认是倒着的。

    9. 自动识别视频流播放过程中分辨率的变化,在视频控件上自动调整尺寸。比如摄像机可以在使用过程中动态配置分辨率,当分辨率改动后对应视频控件也要做出同步反应。

    10. 音视频文件无感知自动切换循环播放,不会出现切换期间黑屏等肉眼可见的切换痕迹。

    11. 视频控件同时支持任意解码内核、任意画面显示策略、任意视频显示模式。

    12. 视频控件悬浮条同时支持句柄、绘制、GPU三种模式,非绝对坐标移来移去。

    13. 本地摄像头设备支持指定设备名称、分辨率、帧率进行播放。

    14. 本地桌面采集支持设定采集区域、偏移值、指定桌面索引、帧率、多个桌面同时采集等。

    15. 录像文件同时支持打开的视频文件、本地摄像头、本地桌面、网络视频流等。

    16. 瞬间响应打开和关闭,无论是打开不存在的视频或者网络流,探测设备是否存在,读取中的超时等待,收到关闭指令立即中断之前的操作并响应。

    17. 支持打开各种图片文件,支持本地音视频文件拖曳播放。

    18. 视频流通信方式可选tcp/udp,有些设备可能只提供了某一种协议通信比如tcp,需要指定该种协议方式打开。

    19. 可设置连接超时时间(视频流探测用的超时时间)、读取超时时间(采集过程中的超时时间)。

    20. 支持逐帧播放,提供上一帧/下一帧函数接口,可以逐帧查阅采集到的图像。

    21. 音频文件自动提取专辑信息比如标题、艺术家、专辑、专辑封面,自动显示专辑封面。

    22. 视频响应极低延迟0.2s左右,极速响应打开视频流0.5s左右,专门做了优化处理。

    23. 支持H264/H265编码(现在越来越多的监控摄像头是H265视频流格式)生成视频文件,内部自动识别切换编码格式。

    24. 支持用户信息中包含特殊字符(比如用户信息中包含+#@等字符)的视频流播放,内置解析转义处理。

    25. 支持滤镜,各种水印及图形效果,支持多个水印和图像,可以将OSD标签信息和各种图形信息写入到MP4文件。

    26. 支持视频流中的各种音频格式,AAC、PCM、G.726、G.711A、G.711Mu、G.711ulaw、G.711alaw、MP2L2等都支持,推荐选择AAC兼容性跨平台性最好。

    27. 内核ffmpeg采用纯qt+ffmpeg解码,非sdl等第三方绘制播放依赖,gpu绘制采用qopenglwidget,音频播放采用qaudiooutput。

    28. 内核ffmpeg和内核mdk支持安卓,其中mdk支持安卓硬解码,性能非常凶残。

    29. 可以切换音视频轨道,也就是节目通道,可能ts文件带了多个音视频节目流,可以分别设置要播放哪一个,可以播放前设置好和播放过程中动态设置。

    30. 可以设置视频旋转角度,可以播放前设置好和播放过程中动态设置。

    31. 视频控件悬浮条自带开始和停止录像切换、声音静音切换、抓拍截图、关闭视频等功能。

    32. 音频组件支持声音波形值数据解析,可以根据该值绘制波形曲线和柱状声音条,默认提供了声音振幅信号。

    33. 标签和图形信息支持三种绘制方式,绘制到遮罩层、绘制到图片、源头绘制(对应信息可以存储到文件)。

    34. 通过传入一个url地址,该地址可以带上通信协议、分辨率、帧率等信息,无需其他设置。

    35. 保存视频到文件支持三种策略,自动处理、仅限文件、全部转码,转码策略支持自动识别、转264、转265,编码保存支持指定分辨率缩放或者等比例缩放。比如对保存文件体积有要求可以指定缩放后再存储。

    36. 支持加密保存文件和解密播放文件,可以指定秘钥文本。

    37. 支持电子放大,在悬浮条切换到电子放大模式,在画面上选择需要放大的区域,选取完毕后自动放大,再次切换放大模式可以复位。

    38. 各组件中极其详细的打印信息提示,尤其是报错信息提示,封装的统一打印格式。针对现场复杂的设备环境测试极其方便有用,相当于精确定位到具体哪个通道哪个步骤出错。

    39. 同时提供了简单示例、视频播放器、多画面视频监控、监控回放、逐帧播放、多屏渲染等单独窗体示例,专门演示对应功能如何使用。

    40. 代码框架和结构优化到最优,性能强悍,持续迭代更新升级。

    41. 源码支持Qt4、Qt5、Qt6,兼容所有版本。

    8.1.4 视频控件

    1. 可动态添加任意多个osd标签信息,标签信息包括名字、是否可见、字号大小、文本文字、文本颜色、背景颜色、标签图片、标签坐标、标签格式(文本、日期、时间、日期时间、图片)、标签位置(左上角、左下角、右上角、右下角、居中、自定义坐标)。

    2. 可动态添加任意多个图形信息,这个非常有用,比如人工智能算法解析后的图形区域信息直接发给视频控件即可。图形信息支持任意形状,直接绘制在原始图片上,采用绝对坐标。

    3. 图形信息包括名字、边框大小、边框颜色、背景颜色、矩形区域、路径集合、点坐标集合等。

    4. 每个图形信息都可指定三种区域中的一种或者多种,指定了的都会绘制。

    5. 内置悬浮条控件,悬浮条位置支持顶部、底部、左侧、右侧。

    6. 悬浮条控件参数包括边距、间距、背景透明度、背景颜色、文本颜色、按下颜色、位置、按钮图标代码集合、按钮名称标识集合、按钮提示信息集合。

    7. 悬浮条控件一排工具按钮可自定义,通过结构体参数设置,图标可选图形字体还是自定义图片。

    8. 悬浮条按钮内部实现了录像切换、抓拍截图、静音切换、关闭视频等功能,也可以自行在源码中增加自己对应的功能。

    9. 悬浮条按钮对应实现了功能的按钮,有对应图标切换处理,比如录像按钮按下后会切换到正在录像中的图标,声音按钮切换后变成静音图标,再次切换还原。

    10. 悬浮条按钮单击后都用名称唯一标识作为信号发出,可以自行关联响应处理。

    11. 悬浮条空白区域可以显示提示信息,默认显示当前视频分辨率大小,可以增加帧率、码流大小等信息。

    12. 视频控件参数包括边框大小、边框颜色、焦点颜色、背景颜色(默认透明)、文字颜色(默认全局文字颜色)、填充颜色(视频外的空白处填充黑色)、背景文字、背景图片(如果设置了图片优先取图片)、是否拷贝图片、缩放显示模式(自动调整、等比缩放、拉伸填充)、视频显示模式(句柄、绘制、GPU)、启用悬浮条、悬浮条尺寸(横向为高度、纵向为宽度)、悬浮条位置(顶部、底部、左侧、右侧)。

    8.2 onvif搜索模块

    8.2.1 效果图

    + + +

    8.2.2 功能介绍

    1. 广播搜索设备,支持IPC和NVR,依次返回。

    2. 可选择不同的网卡IP进行对应网段设备的搜索。

    3. 依次获取Onvif地址、Media地址、Profile文件、Rtsp地址。

    4. 可对指定的Profile获取视频流Rtsp地址,比如主码流地址、子码流地址。

    5. 可对每个设备设置Onvif用户信息,用于认证获取详细信息。

    6. 可实时预览摄像机图像。

    7. 支持云台控制,可上下左右调节云台,支持绝对移动、相对移动、连续移动三种方式,可对图像拉近拉远。

    8. 支持获取预置位集合、调用预置位、添加预置位、删除预置位等。

    9. 支持图片参数设置,包括亮度、对比度、饱和度、锐度等。

    10. 支持Qt4和Qt6任意Qt版本以及后续Qt版本,亲测Qt4.7.0到Qt6.2。

    11. 支持任意编译器,亲测mingw、msvc、gcc、clang。

    12. 支持任意操作系统,亲测xp、win7、win10、android、linux、嵌入式linux、树莓派全志H3等。

    13. 支持任意Onvif摄像机和NVR,亲测海康、大华、宇视、天地伟业、华为、海思芯片内核等,可定制开发。

    14. 支持对指定IP地址及onvif地址进行单播搜索,比如跨网段情况下非常有用。

    15. 支持指定过滤条件过滤搜索设备。

    16. 支持搜索间隔和搜索策略设置,保证所有设备搜索回来,在大量设备现场很有用(亲测上千个摄像机现场,搜索回来的设备数量比摄像机厂家自带搜索工具还要准确)。

    17. 可对设备进行重启、网络参数获取等。

    18. 支持各种事件订阅、Onvif抓图等操作。

    19. 支持NTP校时和时间同步设置。

    20. 内置了线程实时执行Onvif指令队列,排队最大速度的执行对应的指令,执行结果信号发出。

    21. 采用的最底层的TCP+UDP通信机制,原创最底层协议解析,纯QtWidget编写。

    22. 超级小巧轻量,总共约3000行代码,不依赖任何第三方的库和组件,跨平台。

    23. 封装好了通用的数据发送和接收解析的函数,可以非常方便的自行拓展其他Onvif处理。

    24. 工具上提供了收发数据文本框,显示收发的数据,方便查看和分析。

    25. 支持所有Onvif设备,代码工整,接口友好,直接引入pri即可使用。

    8.2.3 云台说明

    1. x、y、z 范围都在0-1之间。

    2. x为负数,表示左转,x为正数,表示右转。

    3. y为负数,表示下转,y为正数,表示上转。

    4. z为正数,表示拉近,z为负数,表示拉远。

    5. 通过x和y的组合,来实现云台的控制。

    6. 通过z的组合,来实现焦距控制。

    8.2.4 主要功能

    1. 搜索设备,获取设备的信息比如厂家、型号等。

    2. 获取设备的多个配置文件信息profile。

    3. 获取对应配置文件的视频流地址rtsp,以及分辨率等参数。

    4. 云台控制,上下左右移动,焦距放大缩小,相对和绝对移动。

    5. 获取预置位信息,触发预置位。

    6. 订阅事件,接收设备的各种消息尤其是报警事件比如IO口的报警。

    7. 抓图,获取设备当前的图片。

    8. 获取、创建、删除用户信息。

    9. 获取和设备网络配置信息比如IP地址等。

    10. 获取和设置NTP时间同步。

    11. 获取和设置设备时间。

    12. 重启设备。

    8.2.5 处理流程

    1. 绑定组播IP(239.255.255.250)和端口(3702),发送固定的xml格式的数据搜索设备。

    2. 接收到的xml格式的数据解析,得到设备的Onvif地址。

    3. 对Onvif地址发送对应的数据,收到数据取出对应的节点数据。

    4. 请求Onvif地址获取Media地址和Ptz地址,Media地址用来获取详细的配置文件,Ptz地址用来云台控制。

    5. ptz控制是对Ptz地址发送对应的数据即可。

    6. 设置了用户认证的需要组织用户token信息一块发送,每次都需要作鉴权处理。

    7. 接收到的数据不是标准的xml数据,没法按照正常的节点解析来处理,只能用QXmlQuery来做。

    8. 每个厂家设备返回的数据未必完全一致,基本上都不一致,需要进行模糊查找节点值。

    9. 特意采用底层协议解析,因为soap太臃肿函数名称太另类,特意做的轻量级的。

    10. 两个必备工具,Onvif Device Manager 和 Onvif Device Test Tool。

    8.3 gb28181处理模块

    暂未实现

    9 主界面模块说明

    本系统主界面采用QMainWindow停靠窗体模式设计,这样可以自定义各种各样的子模块停靠悬浮等,不同的工作模式可以对应不同的模块,甚至可以拓展成不同的用户权限对应不同的主界面模块。所有子模块都是new出来的,支持任意多个。

    9.0 主界面

    视频监控系统支持多种工作模式,不同的工作模式可以有不同的主界面、悬停模块、布局方案。互相不影响。悬停模块可以有透明度,更具科幻感。

    9.0.1 视频监控-普通模式

    9.0.2 视频监控-全屏模式

    9.0.3 机器人监控-普通模式

    9.0.4 机器人监控-全屏模式

    9.0.5 无人机监控-普通模式

    9.0.6 无人机监控-全屏模式

    9.1 设备列表

    设备列表通过读取录像机信息(生成父节点,相当于区域,录像机信息本身在整个系统中目前就一个作为设备列表的区域信息功能,用户可以自行拓展作为其他用途。)、摄像机信息,自动生成设备列表,每个摄像机都对应一个主码流和子码流,支持各种视频流、本地视频文件、USB摄像机等。

    9.2 窗口信息

    窗口信息负责显示一些打印信息,比如串口是否打开成功,摄像机是否异常,各种报警日志等,可以在系统设置中设置不同的文字颜色,窗口信息的信息条数自动计算应用,保证最大可能的适应高度。

    9.3 图文警情

    图文警情模块负责以图文的形式显示对应的警情或者提示信息,有时间、内容、图片,双击对应图片可以放大查看具体图片,为了方便演示如何使用,在此模块增加了右键菜单,可以添加消息、删除消息、清空消息。

    9.4 云台控制

    云台控制模块,可以对选中的通道的摄像机(ONVIF协议),进行云台控制,可以控制球机的上下左右等各个方位的移动,还可以调节变倍步长,至于变焦和光圈,目前onvif协议中没看到对应的协议支持,没有实现。

    云台移动总共有3种策略:绝对移动、相对移动、连续移动,本系统都支持三种策略,默认采用的连续移动,这也是大部分应用场景需要的,按下对应的方位进行移动,松开立即停止移动,非常人性化。

    9.5 设备控制

    设备控制模块,可以对选中的通道的摄像机(ONVIF协议),进行获取参数、设置参数、手动校时、重启设备、抓拍图片、模拟报警等操作,可以对摄像机的明亮度、对比度、饱和度进行设置。后期还可能不断增加新的功能。

    9.6 预置位置

    预置位功能,只对带有预置位的球机才起作用,有云台的球机未必有预置位,要仔细查看清楚,不清楚可以询问厂家或者查阅手册,在本模块中,可以获取预置位、添加预置位、调用预置位、删除预置位、调用起始位、设置起始位、开始巡航、停止巡航等。

    获取预置位以后,会将获取到的预置位集合(一般有255个甚至更多)显示到列表中,前面是编号token,后面是预置位的别名name,别名可以是中文的,可以通过添加预置位的时候设置中文的名称。在每个预置位信息后面都有三个按钮:调用、添加、删除,直接单击即可执行相应的动作,拉伸子模块窗体对应名称列自动拉伸填充。

    自动巡航目前采用的策略是通过勾选查询回来的预置位信息,勾选,然后定时器每隔一段时间调用一次对应的预置位来实现,每次正在执行哪个预置位会在列表中自动选中该预置位,后期如果有更好的处理方法会自动更新改进代码。

    9.7 巡航设置

    目前放在预置位中,后期可能会有改动。

    9.8 悬浮地图

    悬浮地图子模块,使用的百度地图,支持在线和离线,用于显示对于设备的位置,支持鼠标直接拖动和缩放。具体和飞行轨迹模块类似。

    9.9 飞行轨迹

    专为无人机打造的模块,也可以作为机器人移动模块,通过传入一个经纬度值,实时更新设备的位置和绘制轨迹,模块已经内置了接口进行处理,支持不同设备不同的轨迹颜色(这个功能好)。

    9.10 备用模块

    此模块留给用户自行填入内容。

    9.11 数据调试

    数据调试模块,用于显示通信串口的数据,自定义不同颜色显示,可以勾选过滤某个串口进行数据查看,也可以选择所有数据,还可以勾选暂停显示复选框用来暂停打印显示信息。

    9.12 运动仿真

    此模块留给用户自行填入内容。

    9.13 图像增强

    此模块留给用户自行填入内容。

    9.14 网页浏览

    网页浏览模块,用于传入一个网页地址,打开对应的网页进行浏览,可用于网页展示信息,支持多个,可以自行增加,代码中演示了一个。

    10 各系统运行图

    10.0 样式风格

    + + + + + +

    本系统内置高达18+套皮肤样式供用户选择,可以在系统设置中随意切换立即应用。

    10.1 windows-7

    10.2 windows-11

    10.3 linux-ubuntu

    10.4 linux-fedora

    10.5 linux-centos

    10.6 linux-uos

    10.7 linux-kylin

    10.8 linux-neokylin

    10.9 linux-newstart

    10.10 linux-debian

    10.11 unix-mac

    11 程序框架说明

    备注:下面的截图和说明未必是最新的,但是大部分是一致的,整体的框架不会改变,可能会有新增加子模块和代码,或者部分类文件有调整或者删除,具体以最新的代码为准。

    11.1 整体代码结构

    本系统采用模块化的设备,有用到第三方开源类库比如串口通信qextserialport,全部放在3rd下面,有用到很多自己封装完善的通用类库比如ffmpeg视频监控,全部放在core下面,设备通信和辅助处理全部放在class下面,所有界面全部放在ui下面,相当于一个个小的组件合起来,最终形成了整个监控系统的完整代码。

    11.2 主模块说明

    名称说明
    3rd一些第三方开源的类库,比如串口通信qextserialport。
    class存放系统初始化、样式控制、自定义控件、设备通信等。
    core本人一直持续更新完善的通用的类库,比如ffmpeg视频监控。
    ui所有的界面都分门别类放在这里。

    11.3 子模块说明

    11.3.1 第三方类库

    这里放的全部是第三方开源的轮子,感谢开源、感谢github、gitee等开源社区。

    名称说明
    3rd_qextserialport第三方串口通信qextserialport,这个类比较稳定可靠,经过了几十个项目持续数十年运行的考验,不用Qt自带的串口类。

    具体代码不做过多说明。

    11.3.2 通信及辅助类

    这里放的都是一些系统初始化、设备通信相关的类。

    名称说明
    api存放数据库表映射成对应的全局队列数据、通用的辅助函数类。
    app全局配置参数管理类、秘钥管理类、通用函数。
    devicecustom用户自定义设备通信管理,比如机器人通信、无人机通信等。
    devicevideo视频监控相关处理类,包括设备地图、表格消息、线程UI通信、人工智能处理等。
    usercontrol当前系统的自定义控件全部放在这里,其中包括云台仪表盘、天气面板等控件。
    11.3.2.1 模块-api
    名称说明
    dbdata将数据库表映射到全局变量数据队列,比如将摄像机表ipcinfo转成QStringList存放一行行数据,这样在程序中运算比较速度极快,直接内存比较,不用每次都去读取数据库。
    dbquery所有的数据库查询插入更新等操作都在这里,比如查询摄像机表、插入日志记录等。
    11.3.2.2 模块-app
    名称说明
    appconfig配置参数类,整个系统的配置参数存放在ini文件中,跨平台,所有参数都对应一个变量,读取配置参数的时候将值赋值给变量,写入的时候将变量值写入到配置文件。
    appdata全局变量类,系统中无可避免需要一些全局变量方便处理,都放在此类,比如版本号、录像机类型、摄像机类型、当前用户信息、地图宽度高度、左侧右侧顶部底部宽高等。
    appevent全局事件转发类,系统越复杂信号需要传递的层级越多,所以需要一个全局事件转发类,用来中转这些事件,这样永远只需要两层就可以收到信号进行处理,而且整个系统看起来干净整洁,不会说一个信号传递到了N个地方乱七八糟,建议需要跨层级传递的信号都放在这里中转。比如软件退出信号,可能多个界面需要收到退出信号进行保存和其他处理,如果从关闭界面发出信号传递给需要的界面,那不知道要中间层层传递多少次,有了这个全局事件转发类,你只需要将事件传给appevent,需要接收事件的地方关联这个信号就行,appevent为全局单例类,整个系统唯一。通用的一些信号有软件退出、全局样式改变、主窗体变化(0-最小化 1-最大化 2-恢复 3-关闭 4-移动 5-尺寸变化)等。
    appinit程序初始化类,在main函数中,会先执行这个初始化的类,比如初始化皮肤、字体、数据库、样式等操作,这些都是要优先在窗体加载前执行的,执行完毕以后再打开窗体主界面。
    appstyle全局样式管理类,整个系统的样式全部放在这里,一般加载流程是先读取样式表文件,然后将本系统独特的样式(比如开关按钮、视频监控、云台仪表盘)内容追加到后面,最后统一设置全局样式,在main函数中加载,和appinit类一样放在最前面执行。
    appurl视频监控系统中常用的默认的视频地址集合。
    11.3.2.3 模块-devicecustom
    名称说明
    devicerobot机器人串口通信管理类。
    devicerobot2机器人串口通信管理类2,有串口数据转发功能。
    deviceuavsserver无人机后端服务类,当前为空,用户自己添加。
    deviceuavsvideo无人机视频监控类,将视频控件设置过来,然后就可以将自己人工智能算法处理后的图片传过来进行绘制,类似于实时视频效果。
    11.3.2.4 模块-devicevideo
    名称说明
    devicehelper整个系统设备管理辅助类,比如插入窗口消息、加载设备列表、加载图片地图、加载设备按钮、初始化视频控件等。
    devicemap设备图片地图管理类,相当于一次性加载所有图片到内存,当要切换或者显示的时候,直接从内存取出来设置即可,速度极快,瞬间相应,纯粹是为了加快相应速度以及可能在图片上进行绘制增加的功能,比从文件系统读取图片文件显示快N倍。
    deviceonvif设备onvif通信管理类,比如获取当前选中通道的onvif地址、开启事件订阅、校对时间、重启设备、获取视频参数、设置视频参数、云台控制等,这里是具体的需要和摄像机信息表及视频通道关联的处理,所以不能放到通用的onvif模块中。
    devicethreadui演示线程通知UI更新,包括每隔一段时间插入消息、异步调用添加表格消息和图文警情、设备GPS移动、报警闪烁、指定通道编号设置视频和通道交换等。
    devicevideosmart人工智能处理类,最常见的应用就是设置一个视频控件,然后在视频控件上绘制人脸框、文字信息等,比如设备的实时运行状态。
    11.3.2.5 模块-usercontrol
    名称说明
    gaugecloud云台仪表盘控件。
    cityhelper省市县联动类,通过从json文件读取省市县信息。
    weather城市天气类,最后显示在标题栏上,实时显示设置的城市的最近几天的天气。
    widgetsound声音面板控件,主界面右下角单击弹出音量条。

    11.3.3 核心通用类库

    这里放的全部是个人一直持续更新完善的独创的轮子,所有的项目都公用这些轮子,用到哪个就包含哪个进来,更新只需要更新轮子代码就行。

    视频监控系统包含的轮子超级丰富给力,物超所值,涵盖了数据导出模块、数据库应用、音频播放和录制、视频播放和录制、ONVIF通信、TCP文件传输、地图应用、通用浏览器内核等。

    名称说明
    core_audio音频播放和录制,包括音频输入输出管理、音频曲线、音频播放、音频录制、音频振幅控件等。
    core_common通用函数,包括通用秘钥、通用导航、通用样式、声音播放、日志记录、运行时间记录等。
    core_control通用自定义控件,很多系统经常用到的控件全部放在这里,比如开关按钮、设备容器、设备按钮、颜色下拉框等。
    core_dataout数据导入导出到xls/pdf和打印类库,极速、跨平台、无依赖。
    core_db数据库通用类库比如数据库线程管理、数据清理、数据采集等。
    core_form通用的用户登录、用户退出、用户管理、数据库配置界面类等。
    core_map地图综合应用类库,百度地图(支持在线离线)和echart封装类等。
    core_onvifonvif功能封装类,包括设备搜索、云台控制、设备参数设置等。
    core_qthelper通用的辅助类,包括自定义对话框,全局辅助函数,图形字体等。
    core_tcpfile文件多线程收发类,支持多个并发。
    core_video视频播放核心类,包括了监控画面切换控件、视频回放控件、视频播放组件结构体、视频播放辅助函数、视频解码线程类、视频显示控件类等。
    core_videobase视频相关基类,包括音视频文件保存基类、视频解码基类、视频控件基类、视频悬浮工具栏、视频控件结构体等。
    core_videoffmpeg视频监控内核ffmpeg版本,本系统默认采用的内核。
    core_videoopenglopengl封装类,支持打开yuv/nv12文件,绘制yuv/nv12帧数据,一般搭配ffmpeg视频内核显示视频,直接走GPU绘制。
    core_videosave音视频保存组件,包括音频保存类、视频保存类、保存相关辅助函数类。
    core_webview通用浏览器控件类,同时支持webkit、wenengine、miniblink三种内核,打通了所有的Qt版本。
    11.3.3.1 模块-core_audio
    名称说明
    audiohelper音频相关辅助函数,比如获取音频输入输出设备、根据设备名称查找设备对象、初始化音频格式、获取对应音频格式最大振幅、获取对应音频格式音频数据的振幅级别等。
    audiolevel音频振幅控件,根据传入的音频振幅大小绘制振幅,可设置颜色。
    audioplayer音频播放类,可以设置声音大小和静音状态,支持带参数打开音频输入和输出设备,自动关联音频输入输出设备形成话筒和音响联动。
    audiorecorder音频录制类,可以设置音频录制的参数,包括采样大小、比特率、通道数、质量级别、编码模式等。
    11.3.3.2 模块-core_common
    名称说明
    base64helper图片及文字和base64编码之间转换的类。
    commonkey通用秘钥管理类,指定校验秘钥文件,可设置运行时间、设备数量等限制,支持根据硬件指纹特征生成机器码文件等。
    commonnav通用菜单导航管理类,用来控制和显示顶部导航栏、左侧导航栏的样式。很多子界面需要用到,所以封装成一个专门管理这个的类。
    commonstyle通用样式管理类,比如Qt自带类窗体样式、自定义控件样式、分页导航样式、导航按钮样式、开关按钮样式等。相当于将多个项目常用的自定义样式封装一起做成通用。
    framelesswidget2无边框窗体拉伸类,边框四周八个方位都可以自由拉伸,可设置是否允许拖动和拉伸。
    playwav声音文件播放类,通用Qt456,自动识别当前Qt版本使用对应的类,Qt4采用QSound,Qt5以上采用QSoundEffect,嵌入式采用对应的命令行aplay、mpv来播放。
    savelog日志钩子类,将系统中所有的打印信息转为日志存储或者输出到网络等,可以开启用来打印输出日志信息。
    saveruntime保存运行时间类,用来存储系统启动后每隔一段时间就输出一条记录用来记录启动后软件运行了多久,方便分析问题。
    11.3.3.3 模块-core_control
    名称说明
    bottomwidget通用底部状态栏控件,可以设置软件名称、版本号、运行时间等。
    colorcombobox颜色下拉框控件,在系统设置中有。
    cpumemorylabelCPU和内存使用情况标签控件,主界面右上角显示。
    customtitlebar停靠窗体自定义标题栏控件。
    devicebutton设备按钮控件,比如图片地图模块中用到,可设置不同的图标样式和状态等,双击发出信号进行相应处理比如弹出对应窗体等。
    lcddatetime软件右上角显示时间的控件。
    panelwidget面板容器控件,主界面子模块表格消息,就用到此控件,用于将一堆widget放到此容器进行管理,自动形成滚动条等。
    switchbutton开关按钮控件,在系统设置中存在大量该控件。
    xslider滑动条控件,在原有滑动条基础上增加了鼠标按下立即定位等。
    11.3.3.4 模块-core_dataout
    名称说明
    datacreat通用数据报表内容创建类,比如生成表格格式的html内容,然后赋值给dataprint直接打印,里面举例了图文混排的报告内容,后期会不断增加其他模板,也可以自行增加其他模板数据。
    datacsv导入导出数据,csv格式,可设置分隔符。拓展名。过滤条件等。
    datahead当前组件通用头文件。
    datahelper辅助类,比如校验规则函数,通用数据导出+打印函数。
    dataprint数据打印到pdf及纸张,支持多线程。
    dataxls数据导出到xls类,支持多线程导出。
    11.3.3.5 模块-core_db
    名称说明
    dbcleanthread自动清理数据线程类。
    dbconnthread数据库通信管理线程类。
    dbdelegate自定义委托全家桶,包括复选框、下拉框、密码框、按钮等。
    dbhead当前组件通用头文件。
    dbhelper各种数据库应用函数封装,比如初始化数据库、执行sql语句等。
    dbhttpthread网络请求数据采集类。
    dbpage数据库通用翻页类。
    dbpagemodel数据库翻页类数据模型。
    navpage分页导航控件。
    11.3.3.6 模块-core_form
    名称说明
    formhelper封装的导入导出、导出数据到xls/pdf和打印数据、自动备份数据、保存最后打开的文件夹等。
    frmconfigdb通用数据库管理界面类,可选不同的数据库类型,填入用户信息,执行检测连接和初始化数据操作。
    frmconfiguser通用用户管理界面类,可添加、删除、修改用户信息,包括权限分配等,可导入导出打印用户信息。
    frmlogin通用用户登录界面类,包括自动登录和记住密码复选框,多次密码错误校验,记住当前用户信息等。三次错误关闭,下拉可选用户,内置超级密码。
    frmlogout通用用户退出界面类,三次错误关闭,下拉可选用户,内置超级密码。
    userhelper通用用户权限管理类,内置7种类型权限,对应权限名称可自定义,一般在用户切换对应界面或者单击了对应功能按钮的时候触发。
    11.3.3.7 模块-core_map
    名称说明
    echartjsechart模块中用到的json文件转js文件,获取js文件中的名字和经纬度等处理。
    echartsechart封装类,可加载仪表盘、闪烁点图、迁徙图、世界地图、区域地图等,每个点可自定义颜色和提示信息等。
    mapbaidu百度地图封装类,支持在线和离线两种模式。
    11.3.3.8 模块-core_onvif
    名称说明
    onvifbase基础类,用于获取设备信息、服务文件地址、能力文件地址、媒体文件地址、视频流地址等。
    onvifdevice设备类,核心处理及管理,包括设置用户信息请求onvif地址、获取设备信息、云台控制、事件订阅、抓拍图片等。
    onvifevent事件订阅具体实现类,可设置请求超时时间等。
    onvifhead当前组件通用头文件。
    onvifhelper辅助类,比如获取UUID用于请求、判断IP合法、获取本机IP地址集合、管理系统中所有onvif设备对象等。
    onvifmedia获取媒体文件具体解析类。
    onvifother其他处理类,比如系统重启、NTP校时、获取和设置网络信息、获取和设备时间、获取和设置图片参数等。
    onvifptz云台控制实现类,包括绝对移动、相对移动等。
    onvifquery数据查询类,用于将接收到的xml数据解析,并赋值字符串比如命名空间、设备地址、媒体地址、事件地址等。
    onvifrequest网络请求类,包括设置用户信息、获取用户token数据、获取xml头部数据等,通用的请求数据返回结果函数。
    onvifsearch设备搜索类,支持广播搜索、指定地址搜索,可获取设备信息集合、获取设备地址集合。
    onvifservices服务类,用于获取媒体地址、云台地址等。
    onvifsnap图片抓拍实现类,包括获取抓图地址、抓拍图片等。
    11.3.3.9 模块-core_qthelper

    本组件涵盖的功能较多,所以采用了分层管理代码结构。

    名称说明
    iconhelper万能图形字体类,可传入多种图形字体文件,一个类通用所有图形字体。
    globalconfig存储当前组件的配置参数信息,比如全局的字体名称、字号、无边框窗体的最小化最大化关闭等图标、样式表的颜色值。
    globalhead当前组件通用头文件。
    globalstyle当前组件通用样式设置管理类,可以指定枚举类型样式、传入样式内容设置、获取样式表文件对应的颜色值等。当前组件样式相关的处理函数都放在这里,统一管理。
    名称说明
    qtabout关于系统对话框,可传入软件标题、版本、版权、网址等信息。
    qtdateselect自定义日期范围选择对话框。
    qtinputbox自定义输入框窗体,可指定不同的输入类型比如文本框、下拉框等。
    qtmessagebox自定义信息消息框窗体,可设置关闭倒计时,不同的类型比如信息框、询问框、错误框等。
    qtsplash自定义弹出提示信息,提示完自动消息关闭。
    qttipbox自定义右下角信息对话框,可设置对齐方式、关闭倒计时等。
    qtform自定义无边框窗体,可设置标题,各种图标等。
    名称说明
    qthelper项目通用辅助类,各种常用函数的封装,比如获取当前屏幕分辨率、设置字体、设置编码、加载翻译文件、各种进制数据转换、弹出各种对话框、设置延时时间等。
    qthelpercore获取当前桌面分辨率,设置编码、字体、翻译文件等。
    qthelperdata16进制、2进制、10进制互相转换,16进制字符串、字节数组互相转换,字节数组转int和short,CRC校验等。
    qthelperfile选择文件、保存文件、选择目录等对话框,复制文件、删除文件等。
    qthelperform设置无边框窗体、边框阴影,弹出信息框、错误框、询问框、日期选择框、关于对话框、中间提示框等。
    qthelperimage获取等比例缩放图片,通用设置logo图片,支持资源文件、本地图片、图形字体、svg自动变色等多种形式。
    qthelpernet获取本机IP地址集合,获取外网IP地址,判断IP、MAC等是否合法,下载网络文件,IP地址字符串与整型互相转换。
    qthelperother初始化数据库文件,设置系统时间、开机启动,设置图标到按钮,写入临时消息的文本文件等。
    11.3.3.10 模块-core_tcpfile
    名称说明
    tcpfilehead当前组件通用头文件。
    tcpfilehelper辅助类,包括将字节转为MB单位、初始化表格控件、生成表格行、数据加密解密、解压文件、重启系统等。
    tcpreceivefileserver接收文件服务类,管理多个接收文件线程,支持监听端口被动接收文件和主动连接服务器接收文件。
    tcpreceivefilethread接收文件线程类,根据发送的文件名、包编号、块大小、挨个接收数据最终形成文件,可设置保存文件夹等。
    tcpsearchfileserver搜索文件服务类,目前没用,用于接收请求搜索文件是否存在。
    tcpsendfilethread发送文件线程类,按照 文件开始符+文件大小+文件内容+文件结束符 逐个分包发送,可对文件的每个包进行加密传输。
    11.3.3.11 模块-core_video

    视频组件继承和依赖关系说明:

    1. videobase是基类组件,video是视频播放组件,依赖基类组件,videoffmpeg是具体的内核实现组件,依赖视频播放组件,videosave是视频保存组件,依赖基类组件。

    2. video组件中的videothread解码线程类继承自videobase基类组件中的abstractvideothread。

    3. video组件中的videowidgetx视频显示类继承自videobase基类组件中的abstractvideowidget。

    4. videosave组件中的saveaudio和savevideo继承自videobase组件中的abstractsavethread。

    5. videoffmpeg组件中的ffmpegthread继承自video组件中的videothread。

    6. videoffmpeg组件中的ffmpegsave继承自videobase组件中的abstractsavethread。

    7. 按照此规则还有其他内核比如vlc组件中的vlcthread也是继承自videothread,mpv组件中的mpvthread也是继承自videothread。这样新增一种内核只要具体实现部分处理函数即可应用整个视频框架。

    8. 通过多层基类继承关系,使得动态挂载任意解码内核极为方便。

    9. 为何在video视频组件的基础上还要提炼一个videobase基类组件?因为该基类组件还可以提供给QCamera本地摄像头采集组件使用,基类中的变量、函数、处理逻辑几乎一致,但是又有特殊性,所以需要分开再提炼出videobase基类。

    名称说明
    videobox监控画面切换控件,将所有通道切换处理全部集中到一个类,通用异形布局切换函数,可以参考进行自定义异形布局,通道布局切换发出信号通知,支持自定义子菜单布局内容。
    videohelper视频播放内核辅助函数,比如根据url地址取出ip地址、校验网络地址是否可达、检查地址是否正常、加载解析内核到下拉框、根据地址获取本地摄像头参数、创建视频采集类、对采集线程设置参数等。
    videomanage视频线程管理类,全局单例,将所有视频控件发给此类管理,负责挨个打开视频、应用录像计划等。
    videoplayback视频回放控件,支持多个通道,显示每个通道对应的视频段。
    videostruct视频播放组件结构体定义类,包括解析内核枚举值、视频类型枚举值、解码策略枚举值、视频采集参数结构体。
    videotask视频任务线程类,全局单例,可以随时插入一些视频相关的任务进行处理,比如vlc录制视频后需要重命名文件,mpv内核关闭视频后鼠标指针打圈圈需要复位。
    videothread视频解码线程类,内置了共享解码线程处理逻辑,可以打开视频、关闭视频、设置视频宽高比例、获取文件总时长、获取媒体信息、获取和设置播放位置、获取和设置播放速度、获取和设置音量大小、获取和设置静音状态等。
    videourl视频地址相关静态函数,可以读取和写入地址到文本文件,用作历史记录,内置了各种类型(rtsp、http、音频文件、视频文件、网络文件、本地摄像头)的测试音视频地址集合。
    videowidgetx视频播放控件,一个控件对应一个解码线程,提供播放成功、播放结束、收到截图、工具栏按钮单击等处理,提供开始播放、停止播放、暂停播放、继续播放、抓拍截图、开始录制、暂停录制、停止录制等接口。
    11.3.3.12 模块-core_videobase
    名称说明
    abstractsavethread音视频存储基类,可以设置需要保存的音视频文件类型,比如音频文件类型有pcm、wav、aac,视频文件类型有yuv、h264、mp4,提供开始保存、暂停保存、停止保存等接口。
    abstractvideosurface视频回调基类,用于Qt中的QCamera和QMedia类播放后拿到回调视频数据,这样可以取到一张张图片。
    abstractvideothread视频解码线程基类,摄像头采集线程和视频采集线程都继承自此类,将各种公用的变量、函数、接口、信号槽全部放在基类,包括了停止线程标志位、打开是否成功标志位、暂停采集标志位、开始截图标志位、正在录制标志位,提供了虚函数开始播放、停止播放、暂停播放、继续播放、抓拍截图、截图完成、开始录制、暂停录制、停止录制等,提供写入视频数据到文件、写入音频数据到文件槽函数。
    abstractvideowidget视频显示控件基类,
    audioplayer音频播放类,空的,纯粹为了在没有Qt音频播放类QAudioOutput的时候使用,有些Qt版本或者嵌入式板子环境未必有这个类,但是又不能影响整个组件的运行,于是定义了空的类,函数正常调用但是不做任何处理。
    bannerwidget悬浮工具栏控件,可以设置各种颜色、按钮图标集合、按钮名称集合、按钮提示信息集合等,悬浮条位置支持上下左右四个方位。
    imagelabel图片标签控件,多线程绘制传入的图片,性能比setpixmap更优。
    widgethelper窗体相关辅助函数,包括传入图片尺寸和窗体区域及边框大小返回居中区域(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充)、绘制矩形区域比如人脸框、绘制点集合多边形路径比如三角形、绘制路径集合、显示截图预览等。
    11.3.3.13 模块-core_videoffmpeg
    名称说明
    ffmpeghelper相关辅助函数,包括打印输出各种信息、打印设备列表和参数、格式枚举值转字符串、视频帧旋转、通用硬解码、通用软解码、通用软编码、释放数据帧数据包、超时回调(包括打开超时和读取超时)等。
    ffmpegrun执行ffmpeg命令,包括yuv420p文件转mp4文件、mp4文件转yuv420p文件、wav文件转aac文件、合并aac以及h264文件或者mp4文件到带声音的mp4文件、转换视频文件到mp4文件等。
    ffmpegrunthread执行ffmpeg命令行线程,可以设置执行完成是否删除转换前的文件、可执行文件路径,传入需要执行的指令即可。
    ffmpegsave视频存储类,用于保存h264和mp4文件。
    ffmpegsync音视频同步线程类,解码后的音视频数据发给本类进行时间同步处理,采用的外部时钟同步策略。音视频播放的进度也在本类中。
    ffmpegthread视频解码线程核心,从打开地址、分配解码器、初始化参数、取出音视频数据解码、关闭并释放资源等都在本类实现。
    11.3.3.14 模块-core_videoopengl
    名称说明
    openglinclude当前组件头文件。
    nv12glwidget空类,用于没有opengl的Qt版本中保证程序能够继续运行。
    nv12openglwidget继承自QOpenGLWidget的NV12格式OPENGL绘制窗体。
    yuvglwidget空类,用于没有opengl的Qt版本中保证程序能够继续运行。
    yuvopenglwidget继承自QOpenGLWidget的YUV格式OPENGL绘制窗体。
    11.3.3.15 模块-core_videosave
    名称说明
    saveaudio音频保存类,继承自videobase组件中的abstractsavethread,可以设置音频文件类型、采样率、通道数等,支持pcm、wav、aac三种格式。
    savevideo视频保存类,继承自videobase组件中的abstractsavethread,可以设置视频文件类型、宽度、高度、帧率,支持yuv原始数据格式。
    savehelper音视频保存相关辅助函数,包括pcm文件转wav文件、aac文件采样率下标、aac文件添加adts头等。
    11.3.3.16 模块-core_webview
    名称说明
    webcore.pri通用的根据不同的Qt版本、不同的编译器环境、不同的操作系统,加载对应的浏览器内核模块和定义不同的变量。
    miniblinkminiblink封装处理类。
    webhelper经纬度转换、获取小数点经纬度值等常用处理函数。
    webjsdata通用的浏览器控件和Qt程序交互数据中转类。
    webview通用浏览器控件,支持webkit、webengine、miniblink。

    11.3.4 界面UI

    界面说明

    1. 这里分门别类存放的各种功能集合的界面类。

    2. 每个类都一个ui文件、一个h头文件、一个cpp实现文件。

    3. 可以方便快速查找对应功能的界面,也方便拓展增加界面。

    4. 不仅分文件夹存放的,而且命名也尽量按照对应功能打头,比如系统设置模块中的都用frmconfig打头。

    5. 外层文件夹是整齐的,内部代码也是整齐的。

    名称说明
    frmconfig系统设置模块,包括基本设置、录像机管理、摄像机管理、轮询管理、用户管理、视频上传等。
    frmdata日志查询模块,包括本地日志、设备日志等。
    frmdemo演示demo示例,用于演示具体控件或者功能的使用,方便学习参考,比如视频图片、视频控件、视频存储都单独的使用demo。
    frmipc存放摄像机处理相关的模块,比如设备控制,云台控制、预置位、巡航设置等。之前放在frmmodule模块中,后面独立出来管理更方便。
    frmmain主界面模块,包括登录登出界面、主界面、右上角时间组件、欢迎组件等。
    frmmap地图模块,包括通用地图内核界面、图片地图、在线地图、离线地图、路径规划等。
    frmmodule停靠子窗体模块,包括停靠窗体管理核心类、设备列表、窗口信息、图文警情、设备轨迹、网页浏览等模块。将摄像机、机器人、无人机相关的模块放到了对应的模块文件夹,这里放的是系统通用的模块。
    frmrobot无人机模块,包括图像增强、飞行监控等模块。
    frmuavs无人机模块,包括图像增强、飞行监控等模块。
    frmvideo视频监控模块,所有视频监控相关的都放在这里,包括主界面的视频监控布局窗体、视频回放、远程回放、图片回放等。
    11.3.4.1 模块-frmconfig
    名称说明
    frmconfig系统设置模块主界面,采用堆栈窗体形式,加载多个子界面比如摄像机管理、轮询管理等。
    frmconfigipc摄像机管理,可以增加、删除、修改、清空、导入、导出、打印摄像机信息。
    frmconfigipcsearchonvif设备搜索,独立出来的窗体,可以搜索局域网内的所有onvif摄像机信息,搜索完以后获取摄像机的视频流地址等,最后可以单个添加或者批量选中添加到摄像机信息表格中。
    frmconfignvr录像机管理,可以增加、删除、修改、清空、导入、导出、打印录像机信息。
    frmconfigpoll轮询管理,可以增加、删除、修改、清空、导入、导出、打印轮询点信息。可以按照设定规则批量生成轮询点信息。
    frmconfigpollplus将轮询管理中的轮询参数配置、分组管理、批量添加等独立出来的界面,方便管理和拓展。
    frmconfigsave录像计划,可以对每个通道每周每天每半小时时间段设置是否存储录像。
    frmconfigsystem系统设置,包括基本设置、视频参数、数据库设置、地图配置、功能激活、颜色配置、串口配置、网络配置等。
    11.3.4.2 模块-frmdata
    名称说明
    frmdata日志查询模块主界面,采用堆栈窗体形式,加载多个子界面包括本地日志、设备日志等。
    frmdatadevice设备日志,通过私有协议从NVR取对应设备日志信息。
    frmdatauser本地地址,用户操作的日志信息,可查询和导出打印数据记录。
    11.3.4.3 模块-frmdemo
    名称说明
    frmdemo单独的功能演示示例主窗体,加载多个子界面比如视频控件等。
    frmdemohelper通用辅助示例,主要演示qthelper通用组件中封装的函数如何使用,比如各种消息框、提示框等。
    frmdemovideochange通道交换示例,演示两个视频通道如何无缝切换。
    frmdemovideodrag拖曳播放示例,演示从文件夹拖曳文件到视频控件播放。
    frmdemovideodraw标签绘制示例,演示各种OSD标签示例和各种图形绘制示例。
    frmdemovideoimage视频图片示例,从图片文件夹读取图片集合,定时器绘制取出图片发给视频控件绘制。
    frmdemovideoosd动态标签示例,演示动态更新和插入OSD标签。
    frmdemovideoplay4同步播放示例,演示4个通道切换进度条同步播放进度。
    frmdemovideoplus视频叠加示例,多个视频控件叠加在一起同时播放,可以设置在四个角落位置。
    frmdemovideosave视频保存示例,演示如何对视频控件进行视频保存,可动态保存。
    frmdemovideovolume音频振幅示例,演示实时显示当前播放的音量大小音频振幅,柱状条显示。
    frmdemovideowidget视频控件示例,演示视频控件如何使用。
    11.3.4.4 模块-frmipc
    名称说明
    frmipccontrol设备控制模块,可对选中设备进行图片参数调节、NTP校时、设备重启、抓拍图片(ONVIF抓图)等。
    frmipcnavigate巡航管理模块,暂未实现,后期完善。
    frmipcreset预置位管理模块,暂未实现,后期完善。
    frmipcptz云台控制模块,可对选中的摄像机进行云台控制。
    11.3.4.5 模块-frmmain
    名称说明
    frmmain系统主界面,采用堆栈窗体,加载各个子模块。
    frmmain1备用模块1界面,根据参数设置决定是否启用。
    frmtimecpu右上角日期时间+CPU内存显示。
    frmwelcome右上角欢迎信息界面。
    11.3.4.6 模块-frmmap
    名称说明
    frmmap地图管理主界面,采用堆栈窗体形式,加载各个子界面比如图片地图、在线地图、离线地图、路径规划等。
    frmmapcore通用百度地图内核界面,用来加载百度地图,可设置在线、离线模式,有很多个窗体用到类似功能特意封装到一个类,重复利用,比如悬浮地图、飞行轨迹、路径规划等模块都用到了此内核。
    frmmapdevice通用的设备地图界面,在线地图和离线地图界面公用这个界面,唯一区别就是设置下地图的模式是在线还是离线。
    frmmapimage图片地图界面,设备作为一个个按钮点显示在对应地图上,可以拖动,双击弹出预览实时视频。
    frmmaplocal离线地图界面,可更新经纬度值、模拟运动轨迹等。
    frmmapweb在线地图界面,可更新经纬度值、模拟运动轨迹等。
    frmmaproute路径规划界面,可查询路线得到路线的经纬度坐标集合。
    11.3.4.7 模块-frmmodule
    名称说明
    frmdevicegps设备轨迹模块,对设定的设备随机模拟轨迹,也可传入经纬度坐标值自动移动并绘制轨迹线条,不同设备可以不同颜色。
    frmdevicetree设备列表模块,读取设备信息加载形成树状列表,双击或者拖动到视频监控窗体直接播放视频,提供右键菜单作为演示如何使用。
    frmmodule主界面中心部分窗体,采用QMainWindow类,中间加载的视频监控面板,其余new出来每个子模块,子模块可停靠和悬浮拖动等。不同工作模式下的各种子模块都在此加载。同时负责管理模块的显示隐藏菜单。
    frmmsglist图文警情模块,也叫消息列表模块,带有右键菜单添加、删除、清空列表中的消息,双击可以弹出大图预览。
    frmmsglistitem图文警情模块子类,都是由一个个item组成放到panelwidget面板控件中,自动形成滚动条。
    frmmsgtable窗口消息模块,也叫表格消息模块,表格形式显示打印信息,不同的内容可以不同颜色区分。
    frmwebview网页浏览模块,传入一个url地址打开对应的网页,比如打开一个3D的网页。
    11.3.4.8 模块-frmrobot
    名称说明
    frmrobotdata仿真数据模块,启动机器人通信服务,接收数据解析显示。
    frmrobotdebug数据调试模块,可模拟发送轨迹数据测试解析类。
    frmrobotdebug2新数据调试模块,打印多个串口数据,不同颜色显示。
    frmrobotemulate运动仿真模块,预留给用户实现,一般放个3D效果。
    frmrobotlog机器人实时数据模块,预留给用户实现。
    11.3.4.9 模块-frmvideo
    名称说明
    frmvideo视频回放模块主界面,堆栈窗体形式,加载多个子界面比如本地回放、远程回放、设备播放等。
    frmvideopanel视频监控面板,主界面中间部分,这是核心,管理多个通道,通道可移除删除,拖曳打开,拖曳交换等。
    frmvideopaneltool视频监控底部工具栏,独立出来一个类专门管理。
    frmvideoplayimage图片回放模块,按照规则查询图片目录,然后可设定播放速度进行图片序列播放。
    frmvideoplaylocal本地回放模块,查询对应通道的本地存储的视频文件,双击播放,可暂停和拖动进度条位置。
    frmvideoplaynvr设备播放模块,通过RTSP视频流的形式从远程设备取视频进行播放,支持摄像机和录像机,手动填入地址也行。
    frmvideoplayweb远程回放模块,需要用厂家sdk去实现,从NVR回放录像。
    frmvideopreview视频预览窗体,比如图片或者地图上双击设备弹出的视频预览,可以多个,关闭的时候自动释放资源。
    frmvideoupload视频上传,将本地存储的视频文件上传到服务器。

    12 二次开发说明

    12.1 通用开发环境搭建

    1. 第一步:安装系统,推荐用vmware虚拟机。

    2. 第二步:安装qt环境,可以直接用官方下载的run安装包安装,有些要求用命令行安装。

    3. 第三步:写个空白窗体程序测试下是否环境正常。

    4. 第四步:拷贝ffmpeg库文件,也可自行编译ffmpeg,生成对应的动态库或者静态库。

    5. 第五步:打开video_system.pro项目进行编译。

    6. 第六步:打包发布,为了发布方便,推荐用静态编译的Qt+静态编译的ffmpeg,这样打包发布很清爽,就一个可执行文件。

    12.2 不同系统注意事项

    12.3 监控系统组件示例

    本系统功能比较多,封装了多个控件,尤其是核心的视频监控控件,所以特意安排了独立的使用示例演示如何使用,可以在main函数找到 AppConfig::IndexStart = 0; 改成AppConfig::IndexStart = 1;即可,这样编译运行的是监控系统组件示例。

    12.3.1 通用辅助

    演示通用组件比如qthelper封装的类的使用。

    1. 弹出信息框

    2. 弹出错误框

    3. 弹出询问框

    4. 带自动关闭倒计时

    5. 弹出右下角信息框

    6. 隐藏右下角信息框

    7. 弹出时间选择框

    8. 弹出中间提示信息

    9. 弹出关于对话框

    12.3.2 视频图片

    演示加载图片文件夹,进行图片序列的播放。

    12.3.3 视频控件

    演示通用视频控件如何使用,包括打开、关闭、暂停、继续、截图、自动抓拍等功能。

    12.3.4 视频存储

    演示视频控件如何存储视频文件到本地,单击开始按钮开始存储视频,单击关闭则关闭存储。

    12.3.5 视频叠加

    演示如何用多个视频控件做视频叠加播放,可以设置叠加的位置在四个角落。

    12.3.6 同步播放

    演示如何同步播放多个视频,切换进度条自动全部切换播放进度。

    12.3.7 音频频谱

    演示如何关联视频声音左右通道频谱信号,界面中音量控件实时显示当前的左右通道音量值。

    12.3.8 拖曳播放

    演示关联拖曳文件信号,识别本地文件拖曳到视频控件中播放。

    12.3.9 视频切换

    演示如何无缝切换打开不同视频,避免关闭后打开中间产生的空白缝隙。

    12.3.10 标签图形

    演示如何添加各种osd标签信息和各种图形信息,osd标签信息可以设置字体、颜色、位置等,图形信息可以是矩形、三角形、多边形、圆形等。都支持批量多个添加。

    12.3.11 文字水印

    演示视频控件文字水印功能,可以添加日期时间水印、自定义文字水印、实时码率帧率水印,提供按钮主动更新自定义文字水印。

    12.4 人工智能集成

    13 其他说明

    13.1 海康onvif设置

    新版的海康的摄像机,默认onvif是关闭的,需要手动开启,开启以后记得添加onvif用户,并重启摄像机应用。提示:海康旗下的萤石目前暂时不支持onvif协议。这里添加的用户,如果选择视频用户类型,则只能观看视频不能云台控制,只有管理员权限才能云台控制。

    13.2 大华onvif设置

    +

    大华摄像机,先要在安全管理中开启onvif服务,然后在用户管理中添加onvif用户,添加好以后建议重启摄像机应用。

    13.3 国际onvif工具

    工具的名字叫ONVIF Device Manager(还有个工具叫ONVIF Device Test Tool,专用于程序员测试各种数据交互),可以自行搜索下载,此工具位国际官方工具,如果此工具搜索不到摄像机,则说明该摄像机不是真正的onvif摄像机,不是标准的摄像机,目前市面上的绝大部分网络摄像机都支持onvif。具体用法可以参考 https://www.cnblogs.com/lsdb/p/9157302.html

    现在大部分厂家的NVR也逐渐支持onvif,并将每个通道都可以单独列出来。

    切换到ptz页面可以进行云台控制和预置位管理。

    切换到event页面可以查看各种订阅的事件,比如入侵报警、开关量报警等。

    13.4 报警输入设置

    + + +

    操作说明

    1. 默认摄像机IO输入或者开关量输入是关闭的,需要手动开启。

    2. 一般都是登录到摄像机的web页面找到开关量的地方,可能描述不一样但是大致的意思差不多。

    3. 一般摄像机会有两组开关量输入,而且开关量报警有常开常闭两种,都需要自己手动选择。

    4. 如果是常开的话意味着闭合是属于报警,反之亦然。

    5. 找两个导线接在对应口子(详见摄像机厂家的说明书,摄像机背面板也会有对应字样标识一般叫 in)。

    6. 短接或者扒开,都会有反应,onvif工具都能接收到信息(前提是单击过订阅事件按钮,而且顺利返回了订阅地址才行)。

    7. 会收到LogicalState关键字的信息,true或者1表示报警,false或者0表示正常。

    8. 可能每个厂家会有所区别,需要自己拿到数据后做特殊处理,但是大部分厂家都是相似的,实在不行无非搞个contains方法判断好了。

    13.5 环境使用qt+vs

    +

    打开项目:QT VS TOOLS – Open Qt Project File 选择 video_system.pro,然后等待项目加载完毕。 +由于项目中用到了ffmpeg和vlc,引用了对应的lib库,所以在用vs+qt的开发环境中,很可能报错提示映像是不安全的错误,导致编译通不过,需要做个设置。

    解决方法

    1. 第一步:打开该项目的“属性页”对话框。

    2. 第二步:单击“链接器”文件夹。

    3. 第三步:单击“命令行”属性页。

    4. 第四步:将 /SAFESEH:NO 键入“附加选项”框中,然后点击应用。

    5. 如果设置完发现还是不行,那应该是没有一开始就设置这个步骤,你需要打开项目以后就设置好这个步骤,再去编译,建议重新解压项目来一遍。

    vs中增加DEFINES定义,如果是导入的方式添加的pro或者pri,会自动将DEFINES中的值加入到项目中,如果是自己手动添加的,则需要手动添加对应的DEFINES定义值。 +

    13.6 数据库设置mysql

    如果在数据库设置中选择了mysql数据库,需要对mysql数据库做个设置,就是将编码设置成utf8,已设置可以跳过,不然很可能数据库无法正常使用。

    32位的Qt程序,带对应32位的libmysql动态库(对应文件是libmysql.dll,如果是64位的则需要将libmysql64.dll重命名为libmysql.dll),可以访问32/64位的mysql数据库,64位的也是一样可以访问32/64位的mysql数据库,只需要带上对应位数的动态库就行。查看mysql是32位还是64位命令 mysql.exe -V。 +

    13.7 打开本地摄像头

    在加载USB摄像机的时候,需要填写对应USB设备的名称,可以通过命令行和设备管理器查看对应的名称,要英文的。

    在需要加载多个USB摄像机的场景下,有时候会遇到同名的USB名称设备,此时需要打开注册表(计算机\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses\{65E8773D-8F56-11D0-A3B9-00A0C9223196}\##?#USB#VID_XXXXXXX\#GLOBAL\Device Parameters\FriendlyName)进行设备名称修改后,按照新修改后的设备名称填入即可。

    + +

    如果是在虚拟机中打开本地摄像头,你需要对虚拟机做点设置,默认USB2.0需要改成USB3.1。 +

    13.8 项目代码行数

    整个项目源代码行数大概30W行,其中代码13.5W行(占比45%),注释12.7W行(占比42%),空行3.5W行。分层设计注释详细。

    13.9 编译ffmpeg

    13.9.1 本地编译

    1. 第一步:下载好ffmpeg,这个可以去官网 http://ffmpeg.org/ 或者第三方下载地址 https://www.videohelp.com/software/ffmpeg/old-versions (推荐这个地址,官网很多人找不到下载地址)自行找到下载位置下载。要注意的是有些很老的嵌入式linux系统的编译器未必支持最新的ffmpeg4。下面用ffmpeg-3.4.5.tar.gz举例子。

    2. 第二步:复制ffmpeg-3.4.5.tar.gz 到自定义文件夹下,我这里是/home/liu

    3. 第三步:解压ffmpeg,tar –zxvf ffmpeg-3.4.5.tar.gz –C /home/liu

    4. 第四步:安装编译ffmpeg依赖的包 apt-get install yasm

    5. 第五步:编译ffmpeg cd /home/liu/ffmpeg-3.4.5

    • 如果编译静态库执行以下命令

    • ./configure --prefix=host --enable-static --disable-shared --disable-doc --disable-sdl2

    • 如果编译动态库执行以下命令

    • ./configure --prefix=host --enable-shared --disable-static --disable-doc

    • 如果需要编译ffplay以便直接用其打开测试,可以在参数后面加上--enable-ffplay

    • 如果提示 ERROR: freetype2 not found 需要安装 sudo apt install libfreetype6-dev

    • ./configure --prefix=host --enable-shared --disable-static --disable-doc --enable-ffplay

    • 其他常用参数 --disable-zlib --disable-xlib --enable-x11grab --disable-libxcb

    • 可以执行./configure –help 来查看支持哪些参数,尤其是各种解码器的开关,具体可搜索。

    • 其他参数可参见网页 https://blog.csdn.net/momo0853/article/details/78043903

    • make (还可以开启多线程编译加快速度 make –j4)

    • make install

    1. 第六步:打开ffmpeg3.4.5/host目录,生成的文件都在这里,拿去用吧。

    13.9.2 交叉编译

    • 在宿主主机交叉编译ffmpeg,只需要增加指定编译器路径 --cross-prefix=... --arch=arm --target-os=linux。完整命令:./configure --prefix=host --enable-shared --disable-static --disable-doc --cross-prefix=/usr/local/arm-linux-gcc-4.9.2/gcc-linaro-arm-linux-gnueabihf-4.9-2014.08_linux/bin/arm-linux-gnueabihf- --arch=arm --target-os=linux

    • 在宿主主机交叉编译x264,完整命令:./configure --prefix=/home/liu/host --enable-shared --disable-asm --host=arm-linux --cross-prefix=/usr/local/arm-linux-gcc-4.9.2/gcc-linaro-arm-linux-gnueabihf-4.9-2014.08_linux/bin/arm-linux-gnueabihf-

    • 在宿主主机交叉编译x265,完整命令:cmake -DCMAKE_TOOLCHAIN_FILE=crosscompile.cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="/home/liu/host" -DENABLE_SHARED:bool=on ../../source

    • 在宿主主机交叉编译带264/265的ffmpeg:./configure --prefix=host --disable-static --enable-shared --disable-doc --enable-libx264 --enable-libx265 --enable-gpl --enable-rpath --disable-sdl2 --extra-cflags=-I/home/liu/host/include --extra-ldflags=-L/home/liu/host/lib --cross-prefix=/usr/local/arm-linux-gcc-4.9.2/gcc-linaro-arm-linux-gnueabihf-4.9-2014.08_linux/bin/arm-linux-gnueabihf- --arch=arm --target-os=linux

    • 网上看到的其他几个参数:--extra-libs=-ldl --extra-cflags="-fPIC" --extra-ldflags=-Wl,-Bsymbolic --extra-libs="-lpthread -lm"

    windows系统采用mingw编译ffmpeg https://blog.csdn.net/yp18792574062/article/details/108962638

    13.9.3 编译x264/x265

    1. 在linux上默认编译ffmpeg出来的库支持h264/h265的解码,编码并不支持,所以需要单独加上x264/x265的库再编译。

    2. 首先要下载好x264/x265的源码包(https://www.videolan.org/developers/x264.html / https://www.x265.org/downloads/),解压到目录,切换到管理员权限(需要编译后拷贝库到/usr/lib)。

    3. 编译libx264以便支持h264编码。

    • ./configure --disable-asm --enable-shared --prefix=/home/liu/host

    • make -j4

    • make install

    1. 编译libx265以便支持h265(hevc)编码。

    • 定位到x265的build/linux目录

    • 执行编译方式1 ./make-Makefiles.bash (或者执行命令用来重新定义拷贝目录 cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="/home/liu/host" -DENABLE_SHARED:bool=on ../../source)

    • make -j4

    • make install

    • 如果提示cmake:command not found 需要安装 apt install cmake-curses-gui

    1. 编译ffmpeg加入x264/x265支持。

    • 指定位置链接libx264头文件和库写法

    • ./configure --prefix=host --disable-static --enable-shared --disable-doc --enable-libx264 --enable-libx265 --enable-gpl --enable-rpath --enable-libfreetype --disable-sdl2 --extra-cflags=-I/home/liu/host/include --extra-ldflags=-L/home/liu/host/lib

    • 如果头文件和库已经在系统目录中则不需要指定

    • ./configure --prefix=host --disable-static --enable-shared --disable-doc --enable-libx264 --enable-libx265 --enable-gpl --enable-rpath

    • 链接多个写法:--extra-cflags=“-I/usr/local/x264/include -I/usr/local/x265/include/” --extra-ldflags=“-L/usr/local/x264/lib -L/usr/local/x265/lib/”

    • 如果需要滤镜支持比如文字水印用到了drawtext,还依赖freetype库,还需要加上 --enable-libfreetype。

    • 如果环境中有sdl的库则编译ffmpeg的时候默认会开启依赖sdl,avdevice库依赖他,也可以手动指定禁用sdl --disable-sdl2。

    • 在做静态编译的时候如果提示 ERROR: x265 not found using pkg-config,打开/home/liu/host/lib/pkgconfig/x265.pc文件 ,末尾两行改成 Libs: -L${libdir} -lx265 -lstdc++ -pthread -lm -lrt -ldl / Libs.private: -lstdc++ -pthread -lm -lrt -ldl

    1. 参考网页 https://www.cnblogs.com/yongdaimi/p/15526838.html

    2. 如果有需要可以对编译出来的ffmpeg可执行文件设置rpath以便文件和库在一起可以找到库并运行。

    3. 查看ffmpeg可执行文件rpath命令 readelf -d ffmpeg | grep 'RPATH'

    4. 修改ffmpeg可执行文件rpath命令 chrpath -r "$ORIGIN" ffmpeg

    5. 如果在ffmpeg/configure后提示找不到x264,可以尝试 export PKG_CONFIG_PATH=/home/liu/qt/host/lib/pkgconfig:$PKG_CONFIG_PATH 。

    13.9.4 硬件解码

    • 默认提供的windows平台的ffmpeg库内置了硬解码支持,走系统层的dxva2/d3d11va。

    • linux编译支持硬解码的ffmpeg,需要先安装对应的开发包,比如 sudo apt install libvdpau*

    •  

    13.10 高分屏缩放

    • 在windows上经常遇到高分屏缩放的问题,很头疼,貌似这东西就是windows首发的。

    • 在Qt4时代的程序遇到高分屏缩放,不作任何处理,毕竟Qt4时代(2010年以前)出来的时候几乎还没高分屏缩放这东西。

    • 从Qt5.6开始提供了高分屏缩放支持,需要在main函数前面设置 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    • 从Qt5.14开始提供了高分屏缩放策略设置,需要在main函数前面设置 QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);

    • 从Qt6.0开始默认就开启高分屏属性Qt::AA_EnableHighDpiScaling,而且不允许关闭(所以你会发现程序用Qt6编译后界面变得很大)。可以通过setHighDpiScaleFactorRoundingPolicy函数设置策略。

    • 如果不想要高分屏,希望程序永远保持默认的尺寸,你需要在main函数前面设置 QApplication::setAttribute(Qt::AA_Use96Dpi); 表示永远不缩放。

    • 如果希望启用Qt的高分屏则需要设置Qt::AA_EnableHighDpiScaling和setHighDpiScaleFactorRoundingPolicy。缺点是图片容易发虚,比如复选框的边框,哪怕是Qt内置样式风格或者系统默认风格也一样。

    • 另外一种办法就是写个文本文件qt.conf(Qt程序默认的标准配置文件,必须是这个名字),写入内容后,放到可执行文件同一目录即可,此方法采用操作系统的策略进行缩放,推荐此方法,虽然看起来稍微有点模糊,但不会出现发虚等问题,整体一致。

    • 没有完美的高分屏支持方法,都是只能尽量满足,哪怕是windows系统本身,在开启缩放的时候,任务管理器也是模糊的很(尽管改成124%可以改变,但总归不是好办法),还有很多其他知名软件也是如此。

    • 参考文章 https://blog.csdn.net/startl/article/details/105862817

    + +

    13.11 浏览器内核

    • 本系统的电子地图模块支持三种浏览器内核:webkit、webengine、miniblink,编译的时候会自动识别。

    • 其中Qt5.6以前用的是webkit,Qt5.6版本以后分两种情况,一种是mingw编译器(windows系统)对应的Qt库不再提供浏览器模块,所以本系统为了兼容各种编译器,特意封装了miniblink浏览器内核,弥补这个不足。

    • Qt5.6以后的版本在linux系统和mac等系统,都不存在没有浏览器控件的情况,都使用的webengine。

    • 仅仅是windows上的mingw编译器的Qt版本没有,其他系统其实都有的。很多人在这个地方都有疑问,都以为只有msvc编译器有浏览器控件,其实确切的说是在windows上msvc的Qt库带浏览器控件。

    • 安装Qt的时候webengine模块默认不勾选,需要主动勾选才会安装。

    • 也不是所有的msvc的Qt版本都有webengine浏览器模块,哪怕你勾选了也没用,有些版本官方并没有编译,需要自行编译。需要到对应的Qt安装目录查看是否有 Qt5WebEngine.dll 文件。

    • windows目录一般是 Qt5.7.1\5.7\msvc2013\bin\Qt5WebEngine.dll

    • linux对应目录一般是 Qt5.14.2/5.14.2/gcc_64/lib/libQt5WebEngine.so

    +

    13.12 ODBC数据源

    本系统除了支持直连各种数据库比如mysql、postgresql、sqlserver、oracle数据库,也支持odbc数据源的形式连接以上各种数据库,在配置数据源的时候,记得区分32、64位,对应数据源后面带有32/64一起字样的说明该数据源可以同时支持32位和64位的程序访问,不带的要用对应位数的才能访问。数据库名称记得填写的是数据源对应的名称,而不是数据源连接的数据库名称,很多人会搞错。

    13.13 摄像机音频设置

    摄像机音频编码可选多种格式,建议选择用AAC格式。

    +

    13.14 数据库插件

    使用对应的数据库需要Qt中对应的数据库插件支持才行,由于Qt版本众多,数据库插件有增有减,在打开数据库失败的时候如果提示数据库驱动未找到,一定先要看下自己所用Qt套件版本有没有该数据库插件,没有的话要自行编译,或者更换其他版本试试。 +大概从Qt5.12.5版本开始不自带mysql数据库插件,一定要自己编译。编译的过程有一定难度,建议耐心多试几次。

    编译数据库插件通用步骤:

    1. 安装对应的数据库,安装后会有include头文件和lib链接库文件,这是基本的前提,编译数据库插件必须要有这两个东西。

    2. 准备好数据库插件源码,比如qt-everywhere-src-5.14.2\qtbase\src\plugins\sqldrivers\mysql,可以在安装Qt的时候勾选src,或者后期直接官网重新下载源码解压出来。

    3. 打开你要编译的数据库插件源码,比如mysql就打开mysql.pro,oracle就打开oci.pro。

    4. 在pro中注释掉一行 #QMAKE_USE += mysql,如果是oci项目则是#QMAKE_USE += oci。

    5. qsqldriverbase.pri文件中注释掉 #include($$shadowed($$PWD)/qtsqldrivers-config.pri)。

    6. mysql.pro文件内容下面加上如下代码。

    1. oci.pro文件内容下面加上如下代码。

    1. 以上写法同时支持mingw和msvc,其他系统编译过程也是类似。编译完成后默认会在你当前源码所在盘符的根目录下,会出现plugins目录,里面sqldrivers目录下就是对应编译生成好的插件动态库。

    2. 默认oracle的插件驱动代码是按照oracle12的函数写的,如果链接的是oracle11,则需要改动两行代码才能编译成功。打开qsql_oci.cpp文件大概在1559行代码左右,有个OCIBindByPos2函数改成OCIBindByPos,下面还有一行bindColumn.lengths改成(ub2*)bindColumn.lengths。

    13.15 端口映射

    可以通过端口映射,外网访问摄像头或者NVR等,基本步骤如下。

    1. 进入到路由器配置界面,查看分配的外网IP地址,记下来。

    2. 进入到端口映射配置界面,不同路由器位置不一样,可以找找端口映射之类的字眼,也可能叫虚拟服务器。

    3. 添加对应的端口映射信息,外部端口对应外部访问该设备的端口,内部端口对应之前内网访问该设备的端口。

    4. 在设备搜索那边指定设备填入IP地址和端口,单击单播搜索按钮,会自动搜索到设备的onvif地址,然后填入onvif用户信息,此时再去单击获取所有,如果有返回信息则表示正常。

    + +

    13.16 linux-wayland

    大概从ubuntu21开始,默认桌面系统采用wayland,这种桌面环境中无法抓取桌面,需要在登录的时候右下角选择Ubuntu on Xorg。 +参考链接 https://blog.csdn.net/daocaokafei/article/details/117200692

    13.17 --no-sandbox

    如果在部分linux系统运行的时候提示 unning as root without --no-sandbox is not supported,说明当前是以root身份运行的程序,监控系统中用到了浏览器模块,该模块要求安全性沙箱运行,需要手动在运行的时候末尾加上指令。

    + + + \ No newline at end of file diff --git a/docs/video_system/snap/0-7-4.jpg b/docs/video_system/snap/0-7-4.jpg new file mode 100644 index 0000000..baa2b32 Binary files /dev/null and b/docs/video_system/snap/0-7-4.jpg differ diff --git a/docs/video_system/snap/1-1-1.jpg b/docs/video_system/snap/1-1-1.jpg new file mode 100644 index 0000000..37f20ff Binary files /dev/null and b/docs/video_system/snap/1-1-1.jpg differ diff --git a/docs/video_system/snap/1-1-2.jpg b/docs/video_system/snap/1-1-2.jpg new file mode 100644 index 0000000..4573e62 Binary files /dev/null and b/docs/video_system/snap/1-1-2.jpg differ diff --git a/docs/video_system/snap/1-2-1.jpg b/docs/video_system/snap/1-2-1.jpg new file mode 100644 index 0000000..a8b99c9 Binary files /dev/null and b/docs/video_system/snap/1-2-1.jpg differ diff --git a/docs/video_system/snap/10-0-1.jpg b/docs/video_system/snap/10-0-1.jpg new file mode 100644 index 0000000..906ca6e Binary files /dev/null and b/docs/video_system/snap/10-0-1.jpg differ diff --git a/docs/video_system/snap/10-0-10.jpg b/docs/video_system/snap/10-0-10.jpg new file mode 100644 index 0000000..8a50062 Binary files /dev/null and b/docs/video_system/snap/10-0-10.jpg differ diff --git a/docs/video_system/snap/10-0-11.jpg b/docs/video_system/snap/10-0-11.jpg new file mode 100644 index 0000000..44a2697 Binary files /dev/null and b/docs/video_system/snap/10-0-11.jpg differ diff --git a/docs/video_system/snap/10-0-12.jpg b/docs/video_system/snap/10-0-12.jpg new file mode 100644 index 0000000..5d209b7 Binary files /dev/null and b/docs/video_system/snap/10-0-12.jpg differ diff --git a/docs/video_system/snap/10-0-13.jpg b/docs/video_system/snap/10-0-13.jpg new file mode 100644 index 0000000..e38a13b Binary files /dev/null and b/docs/video_system/snap/10-0-13.jpg differ diff --git a/docs/video_system/snap/10-0-14.jpg b/docs/video_system/snap/10-0-14.jpg new file mode 100644 index 0000000..41037f8 Binary files /dev/null and b/docs/video_system/snap/10-0-14.jpg differ diff --git a/docs/video_system/snap/10-0-15.jpg b/docs/video_system/snap/10-0-15.jpg new file mode 100644 index 0000000..b60f091 Binary files /dev/null and b/docs/video_system/snap/10-0-15.jpg differ diff --git a/docs/video_system/snap/10-0-16.jpg b/docs/video_system/snap/10-0-16.jpg new file mode 100644 index 0000000..e423daf Binary files /dev/null and b/docs/video_system/snap/10-0-16.jpg differ diff --git a/docs/video_system/snap/10-0-17.jpg b/docs/video_system/snap/10-0-17.jpg new file mode 100644 index 0000000..cf1eb8d Binary files /dev/null and b/docs/video_system/snap/10-0-17.jpg differ diff --git a/docs/video_system/snap/10-0-18.jpg b/docs/video_system/snap/10-0-18.jpg new file mode 100644 index 0000000..939b9a1 Binary files /dev/null and b/docs/video_system/snap/10-0-18.jpg differ diff --git a/docs/video_system/snap/10-0-2.jpg b/docs/video_system/snap/10-0-2.jpg new file mode 100644 index 0000000..a792ee0 Binary files /dev/null and b/docs/video_system/snap/10-0-2.jpg differ diff --git a/docs/video_system/snap/10-0-3.jpg b/docs/video_system/snap/10-0-3.jpg new file mode 100644 index 0000000..360c1df Binary files /dev/null and b/docs/video_system/snap/10-0-3.jpg differ diff --git a/docs/video_system/snap/10-0-4.jpg b/docs/video_system/snap/10-0-4.jpg new file mode 100644 index 0000000..54cd450 Binary files /dev/null and b/docs/video_system/snap/10-0-4.jpg differ diff --git a/docs/video_system/snap/10-0-5.jpg b/docs/video_system/snap/10-0-5.jpg new file mode 100644 index 0000000..8da5391 Binary files /dev/null and b/docs/video_system/snap/10-0-5.jpg differ diff --git a/docs/video_system/snap/10-0-6.jpg b/docs/video_system/snap/10-0-6.jpg new file mode 100644 index 0000000..b65d5ee Binary files /dev/null and b/docs/video_system/snap/10-0-6.jpg differ diff --git a/docs/video_system/snap/10-0-7.jpg b/docs/video_system/snap/10-0-7.jpg new file mode 100644 index 0000000..79637b2 Binary files /dev/null and b/docs/video_system/snap/10-0-7.jpg differ diff --git a/docs/video_system/snap/10-0-8.jpg b/docs/video_system/snap/10-0-8.jpg new file mode 100644 index 0000000..24b1de1 Binary files /dev/null and b/docs/video_system/snap/10-0-8.jpg differ diff --git a/docs/video_system/snap/10-0-9.jpg b/docs/video_system/snap/10-0-9.jpg new file mode 100644 index 0000000..d826a7f Binary files /dev/null and b/docs/video_system/snap/10-0-9.jpg differ diff --git a/docs/video_system/snap/10-1-1.jpg b/docs/video_system/snap/10-1-1.jpg new file mode 100644 index 0000000..570b22a Binary files /dev/null and b/docs/video_system/snap/10-1-1.jpg differ diff --git a/docs/video_system/snap/10-10-1.jpg b/docs/video_system/snap/10-10-1.jpg new file mode 100644 index 0000000..13d403c Binary files /dev/null and b/docs/video_system/snap/10-10-1.jpg differ diff --git a/docs/video_system/snap/10-11-1.jpg b/docs/video_system/snap/10-11-1.jpg new file mode 100644 index 0000000..13ab7da Binary files /dev/null and b/docs/video_system/snap/10-11-1.jpg differ diff --git a/docs/video_system/snap/10-2-1.jpg b/docs/video_system/snap/10-2-1.jpg new file mode 100644 index 0000000..b0b22a2 Binary files /dev/null and b/docs/video_system/snap/10-2-1.jpg differ diff --git a/docs/video_system/snap/10-3-1.jpg b/docs/video_system/snap/10-3-1.jpg new file mode 100644 index 0000000..2b6d745 Binary files /dev/null and b/docs/video_system/snap/10-3-1.jpg differ diff --git a/docs/video_system/snap/10-4-1.jpg b/docs/video_system/snap/10-4-1.jpg new file mode 100644 index 0000000..3606154 Binary files /dev/null and b/docs/video_system/snap/10-4-1.jpg differ diff --git a/docs/video_system/snap/10-5-1.jpg b/docs/video_system/snap/10-5-1.jpg new file mode 100644 index 0000000..1254c82 Binary files /dev/null and b/docs/video_system/snap/10-5-1.jpg differ diff --git a/docs/video_system/snap/10-6-1.jpg b/docs/video_system/snap/10-6-1.jpg new file mode 100644 index 0000000..3cd6a2e Binary files /dev/null and b/docs/video_system/snap/10-6-1.jpg differ diff --git a/docs/video_system/snap/10-7-1.jpg b/docs/video_system/snap/10-7-1.jpg new file mode 100644 index 0000000..a903d9c Binary files /dev/null and b/docs/video_system/snap/10-7-1.jpg differ diff --git a/docs/video_system/snap/10-8-1.jpg b/docs/video_system/snap/10-8-1.jpg new file mode 100644 index 0000000..abf5316 Binary files /dev/null and b/docs/video_system/snap/10-8-1.jpg differ diff --git a/docs/video_system/snap/10-9-1.jpg b/docs/video_system/snap/10-9-1.jpg new file mode 100644 index 0000000..e63488f Binary files /dev/null and b/docs/video_system/snap/10-9-1.jpg differ diff --git a/docs/video_system/snap/11-1-1.jpg b/docs/video_system/snap/11-1-1.jpg new file mode 100644 index 0000000..4cbf273 Binary files /dev/null and b/docs/video_system/snap/11-1-1.jpg differ diff --git a/docs/video_system/snap/11-3-1.jpg b/docs/video_system/snap/11-3-1.jpg new file mode 100644 index 0000000..35173e8 Binary files /dev/null and b/docs/video_system/snap/11-3-1.jpg differ diff --git a/docs/video_system/snap/11-3-2.jpg b/docs/video_system/snap/11-3-2.jpg new file mode 100644 index 0000000..4964f02 Binary files /dev/null and b/docs/video_system/snap/11-3-2.jpg differ diff --git a/docs/video_system/snap/11-3-3.jpg b/docs/video_system/snap/11-3-3.jpg new file mode 100644 index 0000000..5f61efa Binary files /dev/null and b/docs/video_system/snap/11-3-3.jpg differ diff --git a/docs/video_system/snap/11-3-4.jpg b/docs/video_system/snap/11-3-4.jpg new file mode 100644 index 0000000..7759f16 Binary files /dev/null and b/docs/video_system/snap/11-3-4.jpg differ diff --git a/docs/video_system/snap/12-3-1.jpg b/docs/video_system/snap/12-3-1.jpg new file mode 100644 index 0000000..a4450c1 Binary files /dev/null and b/docs/video_system/snap/12-3-1.jpg differ diff --git a/docs/video_system/snap/12-3-10.jpg b/docs/video_system/snap/12-3-10.jpg new file mode 100644 index 0000000..bc84333 Binary files /dev/null and b/docs/video_system/snap/12-3-10.jpg differ diff --git a/docs/video_system/snap/12-3-11.jpg b/docs/video_system/snap/12-3-11.jpg new file mode 100644 index 0000000..22d3606 Binary files /dev/null and b/docs/video_system/snap/12-3-11.jpg differ diff --git a/docs/video_system/snap/12-3-2.jpg b/docs/video_system/snap/12-3-2.jpg new file mode 100644 index 0000000..0d9ca1b Binary files /dev/null and b/docs/video_system/snap/12-3-2.jpg differ diff --git a/docs/video_system/snap/12-3-3.jpg b/docs/video_system/snap/12-3-3.jpg new file mode 100644 index 0000000..b9172a0 Binary files /dev/null and b/docs/video_system/snap/12-3-3.jpg differ diff --git a/docs/video_system/snap/12-3-4.jpg b/docs/video_system/snap/12-3-4.jpg new file mode 100644 index 0000000..5ab4b97 Binary files /dev/null and b/docs/video_system/snap/12-3-4.jpg differ diff --git a/docs/video_system/snap/12-3-5.jpg b/docs/video_system/snap/12-3-5.jpg new file mode 100644 index 0000000..57febe7 Binary files /dev/null and b/docs/video_system/snap/12-3-5.jpg differ diff --git a/docs/video_system/snap/12-3-6.jpg b/docs/video_system/snap/12-3-6.jpg new file mode 100644 index 0000000..ad72905 Binary files /dev/null and b/docs/video_system/snap/12-3-6.jpg differ diff --git a/docs/video_system/snap/12-3-7.jpg b/docs/video_system/snap/12-3-7.jpg new file mode 100644 index 0000000..798126d Binary files /dev/null and b/docs/video_system/snap/12-3-7.jpg differ diff --git a/docs/video_system/snap/12-3-8.jpg b/docs/video_system/snap/12-3-8.jpg new file mode 100644 index 0000000..8c1c19b Binary files /dev/null and b/docs/video_system/snap/12-3-8.jpg differ diff --git a/docs/video_system/snap/12-3-9.jpg b/docs/video_system/snap/12-3-9.jpg new file mode 100644 index 0000000..c1ff25e Binary files /dev/null and b/docs/video_system/snap/12-3-9.jpg differ diff --git a/docs/video_system/snap/13-1-1.jpg b/docs/video_system/snap/13-1-1.jpg new file mode 100644 index 0000000..67fecb3 Binary files /dev/null and b/docs/video_system/snap/13-1-1.jpg differ diff --git a/docs/video_system/snap/13-10-1.jpg b/docs/video_system/snap/13-10-1.jpg new file mode 100644 index 0000000..5f81b38 Binary files /dev/null and b/docs/video_system/snap/13-10-1.jpg differ diff --git a/docs/video_system/snap/13-10-2.jpg b/docs/video_system/snap/13-10-2.jpg new file mode 100644 index 0000000..57c21d8 Binary files /dev/null and b/docs/video_system/snap/13-10-2.jpg differ diff --git a/docs/video_system/snap/13-10-3.jpg b/docs/video_system/snap/13-10-3.jpg new file mode 100644 index 0000000..9460472 Binary files /dev/null and b/docs/video_system/snap/13-10-3.jpg differ diff --git a/docs/video_system/snap/13-11-1.jpg b/docs/video_system/snap/13-11-1.jpg new file mode 100644 index 0000000..3ddfc38 Binary files /dev/null and b/docs/video_system/snap/13-11-1.jpg differ diff --git a/docs/video_system/snap/13-11-2.jpg b/docs/video_system/snap/13-11-2.jpg new file mode 100644 index 0000000..d293f9b Binary files /dev/null and b/docs/video_system/snap/13-11-2.jpg differ diff --git a/docs/video_system/snap/13-12-1.jpg b/docs/video_system/snap/13-12-1.jpg new file mode 100644 index 0000000..38fd21f Binary files /dev/null and b/docs/video_system/snap/13-12-1.jpg differ diff --git a/docs/video_system/snap/13-13-1.jpg b/docs/video_system/snap/13-13-1.jpg new file mode 100644 index 0000000..6d57cc2 Binary files /dev/null and b/docs/video_system/snap/13-13-1.jpg differ diff --git a/docs/video_system/snap/13-13-2.jpg b/docs/video_system/snap/13-13-2.jpg new file mode 100644 index 0000000..1a76007 Binary files /dev/null and b/docs/video_system/snap/13-13-2.jpg differ diff --git a/docs/video_system/snap/13-14-1.jpg b/docs/video_system/snap/13-14-1.jpg new file mode 100644 index 0000000..a5b274c Binary files /dev/null and b/docs/video_system/snap/13-14-1.jpg differ diff --git a/docs/video_system/snap/13-15-1.jpg b/docs/video_system/snap/13-15-1.jpg new file mode 100644 index 0000000..729b3b6 Binary files /dev/null and b/docs/video_system/snap/13-15-1.jpg differ diff --git a/docs/video_system/snap/13-15-2.jpg b/docs/video_system/snap/13-15-2.jpg new file mode 100644 index 0000000..8682b6d Binary files /dev/null and b/docs/video_system/snap/13-15-2.jpg differ diff --git a/docs/video_system/snap/13-15-3.jpg b/docs/video_system/snap/13-15-3.jpg new file mode 100644 index 0000000..40796dc Binary files /dev/null and b/docs/video_system/snap/13-15-3.jpg differ diff --git a/docs/video_system/snap/13-16-1.jpg b/docs/video_system/snap/13-16-1.jpg new file mode 100644 index 0000000..57dcd7a Binary files /dev/null and b/docs/video_system/snap/13-16-1.jpg differ diff --git a/docs/video_system/snap/13-17-1.jpg b/docs/video_system/snap/13-17-1.jpg new file mode 100644 index 0000000..505730b Binary files /dev/null and b/docs/video_system/snap/13-17-1.jpg differ diff --git a/docs/video_system/snap/13-2-1.jpg b/docs/video_system/snap/13-2-1.jpg new file mode 100644 index 0000000..35ab7d6 Binary files /dev/null and b/docs/video_system/snap/13-2-1.jpg differ diff --git a/docs/video_system/snap/13-2-2.jpg b/docs/video_system/snap/13-2-2.jpg new file mode 100644 index 0000000..52c5c39 Binary files /dev/null and b/docs/video_system/snap/13-2-2.jpg differ diff --git a/docs/video_system/snap/13-3-1.jpg b/docs/video_system/snap/13-3-1.jpg new file mode 100644 index 0000000..b36cafe Binary files /dev/null and b/docs/video_system/snap/13-3-1.jpg differ diff --git a/docs/video_system/snap/13-3-2.jpg b/docs/video_system/snap/13-3-2.jpg new file mode 100644 index 0000000..65c816a Binary files /dev/null and b/docs/video_system/snap/13-3-2.jpg differ diff --git a/docs/video_system/snap/13-3-3.jpg b/docs/video_system/snap/13-3-3.jpg new file mode 100644 index 0000000..64e6dbe Binary files /dev/null and b/docs/video_system/snap/13-3-3.jpg differ diff --git a/docs/video_system/snap/13-3-4.jpg b/docs/video_system/snap/13-3-4.jpg new file mode 100644 index 0000000..c0b2cbc Binary files /dev/null and b/docs/video_system/snap/13-3-4.jpg differ diff --git a/docs/video_system/snap/13-4-1.jpg b/docs/video_system/snap/13-4-1.jpg new file mode 100644 index 0000000..7efbd69 Binary files /dev/null and b/docs/video_system/snap/13-4-1.jpg differ diff --git a/docs/video_system/snap/13-4-2.jpg b/docs/video_system/snap/13-4-2.jpg new file mode 100644 index 0000000..cd17e89 Binary files /dev/null and b/docs/video_system/snap/13-4-2.jpg differ diff --git a/docs/video_system/snap/13-4-3.jpg b/docs/video_system/snap/13-4-3.jpg new file mode 100644 index 0000000..5fc2633 Binary files /dev/null and b/docs/video_system/snap/13-4-3.jpg differ diff --git a/docs/video_system/snap/13-4-4.jpg b/docs/video_system/snap/13-4-4.jpg new file mode 100644 index 0000000..93db888 Binary files /dev/null and b/docs/video_system/snap/13-4-4.jpg differ diff --git a/docs/video_system/snap/13-5-1.jpg b/docs/video_system/snap/13-5-1.jpg new file mode 100644 index 0000000..860641b Binary files /dev/null and b/docs/video_system/snap/13-5-1.jpg differ diff --git a/docs/video_system/snap/13-5-2.jpg b/docs/video_system/snap/13-5-2.jpg new file mode 100644 index 0000000..00f1f9d Binary files /dev/null and b/docs/video_system/snap/13-5-2.jpg differ diff --git a/docs/video_system/snap/13-5-3.jpg b/docs/video_system/snap/13-5-3.jpg new file mode 100644 index 0000000..142684f Binary files /dev/null and b/docs/video_system/snap/13-5-3.jpg differ diff --git a/docs/video_system/snap/13-6-1.jpg b/docs/video_system/snap/13-6-1.jpg new file mode 100644 index 0000000..7cbc610 Binary files /dev/null and b/docs/video_system/snap/13-6-1.jpg differ diff --git a/docs/video_system/snap/13-6-2.jpg b/docs/video_system/snap/13-6-2.jpg new file mode 100644 index 0000000..7763a98 Binary files /dev/null and b/docs/video_system/snap/13-6-2.jpg differ diff --git a/docs/video_system/snap/13-7-1.jpg b/docs/video_system/snap/13-7-1.jpg new file mode 100644 index 0000000..500b6a7 Binary files /dev/null and b/docs/video_system/snap/13-7-1.jpg differ diff --git a/docs/video_system/snap/13-7-2.jpg b/docs/video_system/snap/13-7-2.jpg new file mode 100644 index 0000000..395967d Binary files /dev/null and b/docs/video_system/snap/13-7-2.jpg differ diff --git a/docs/video_system/snap/13-7-3.jpg b/docs/video_system/snap/13-7-3.jpg new file mode 100644 index 0000000..d0e9948 Binary files /dev/null and b/docs/video_system/snap/13-7-3.jpg differ diff --git a/docs/video_system/snap/13-7-4.jpg b/docs/video_system/snap/13-7-4.jpg new file mode 100644 index 0000000..4c8dea6 Binary files /dev/null and b/docs/video_system/snap/13-7-4.jpg differ diff --git a/docs/video_system/snap/13-7-5.jpg b/docs/video_system/snap/13-7-5.jpg new file mode 100644 index 0000000..af6d78c Binary files /dev/null and b/docs/video_system/snap/13-7-5.jpg differ diff --git a/docs/video_system/snap/13-8-1.jpg b/docs/video_system/snap/13-8-1.jpg new file mode 100644 index 0000000..dc725b5 Binary files /dev/null and b/docs/video_system/snap/13-8-1.jpg differ diff --git a/docs/video_system/snap/2-0-1.jpg b/docs/video_system/snap/2-0-1.jpg new file mode 100644 index 0000000..34815e3 Binary files /dev/null and b/docs/video_system/snap/2-0-1.jpg differ diff --git a/docs/video_system/snap/2-0-2.jpg b/docs/video_system/snap/2-0-2.jpg new file mode 100644 index 0000000..58e61ed Binary files /dev/null and b/docs/video_system/snap/2-0-2.jpg differ diff --git a/docs/video_system/snap/2-1-1.jpg b/docs/video_system/snap/2-1-1.jpg new file mode 100644 index 0000000..1d15e0a Binary files /dev/null and b/docs/video_system/snap/2-1-1.jpg differ diff --git a/docs/video_system/snap/2-1-2.jpg b/docs/video_system/snap/2-1-2.jpg new file mode 100644 index 0000000..23c01b2 Binary files /dev/null and b/docs/video_system/snap/2-1-2.jpg differ diff --git a/docs/video_system/snap/2-10-1.jpg b/docs/video_system/snap/2-10-1.jpg new file mode 100644 index 0000000..0f32ea2 Binary files /dev/null and b/docs/video_system/snap/2-10-1.jpg differ diff --git a/docs/video_system/snap/2-11-1.jpg b/docs/video_system/snap/2-11-1.jpg new file mode 100644 index 0000000..185d227 Binary files /dev/null and b/docs/video_system/snap/2-11-1.jpg differ diff --git a/docs/video_system/snap/2-12-1.jpg b/docs/video_system/snap/2-12-1.jpg new file mode 100644 index 0000000..cbe3137 Binary files /dev/null and b/docs/video_system/snap/2-12-1.jpg differ diff --git a/docs/video_system/snap/2-12-2.jpg b/docs/video_system/snap/2-12-2.jpg new file mode 100644 index 0000000..e95dfdf Binary files /dev/null and b/docs/video_system/snap/2-12-2.jpg differ diff --git a/docs/video_system/snap/2-13-1.jpg b/docs/video_system/snap/2-13-1.jpg new file mode 100644 index 0000000..6fd7270 Binary files /dev/null and b/docs/video_system/snap/2-13-1.jpg differ diff --git a/docs/video_system/snap/2-14-1.jpg b/docs/video_system/snap/2-14-1.jpg new file mode 100644 index 0000000..6bb3b1f Binary files /dev/null and b/docs/video_system/snap/2-14-1.jpg differ diff --git a/docs/video_system/snap/2-15-1.jpg b/docs/video_system/snap/2-15-1.jpg new file mode 100644 index 0000000..0d4716a Binary files /dev/null and b/docs/video_system/snap/2-15-1.jpg differ diff --git a/docs/video_system/snap/2-16-1.jpg b/docs/video_system/snap/2-16-1.jpg new file mode 100644 index 0000000..46d627f Binary files /dev/null and b/docs/video_system/snap/2-16-1.jpg differ diff --git a/docs/video_system/snap/2-17-1.jpg b/docs/video_system/snap/2-17-1.jpg new file mode 100644 index 0000000..f86306a Binary files /dev/null and b/docs/video_system/snap/2-17-1.jpg differ diff --git a/docs/video_system/snap/2-2-1.jpg b/docs/video_system/snap/2-2-1.jpg new file mode 100644 index 0000000..07d6650 Binary files /dev/null and b/docs/video_system/snap/2-2-1.jpg differ diff --git a/docs/video_system/snap/2-3-1.jpg b/docs/video_system/snap/2-3-1.jpg new file mode 100644 index 0000000..129e955 Binary files /dev/null and b/docs/video_system/snap/2-3-1.jpg differ diff --git a/docs/video_system/snap/2-4-1.jpg b/docs/video_system/snap/2-4-1.jpg new file mode 100644 index 0000000..155e828 Binary files /dev/null and b/docs/video_system/snap/2-4-1.jpg differ diff --git a/docs/video_system/snap/2-4-2.jpg b/docs/video_system/snap/2-4-2.jpg new file mode 100644 index 0000000..dbf8f5b Binary files /dev/null and b/docs/video_system/snap/2-4-2.jpg differ diff --git a/docs/video_system/snap/2-5-1.jpg b/docs/video_system/snap/2-5-1.jpg new file mode 100644 index 0000000..f73f751 Binary files /dev/null and b/docs/video_system/snap/2-5-1.jpg differ diff --git a/docs/video_system/snap/2-5-2.jpg b/docs/video_system/snap/2-5-2.jpg new file mode 100644 index 0000000..d3e4119 Binary files /dev/null and b/docs/video_system/snap/2-5-2.jpg differ diff --git a/docs/video_system/snap/2-6-1.jpg b/docs/video_system/snap/2-6-1.jpg new file mode 100644 index 0000000..b1ca286 Binary files /dev/null and b/docs/video_system/snap/2-6-1.jpg differ diff --git a/docs/video_system/snap/2-6-2.jpg b/docs/video_system/snap/2-6-2.jpg new file mode 100644 index 0000000..36df4a7 Binary files /dev/null and b/docs/video_system/snap/2-6-2.jpg differ diff --git a/docs/video_system/snap/2-6-3.jpg b/docs/video_system/snap/2-6-3.jpg new file mode 100644 index 0000000..7e53173 Binary files /dev/null and b/docs/video_system/snap/2-6-3.jpg differ diff --git a/docs/video_system/snap/2-7-1.jpg b/docs/video_system/snap/2-7-1.jpg new file mode 100644 index 0000000..ccd9724 Binary files /dev/null and b/docs/video_system/snap/2-7-1.jpg differ diff --git a/docs/video_system/snap/2-7-2.jpg b/docs/video_system/snap/2-7-2.jpg new file mode 100644 index 0000000..b703c63 Binary files /dev/null and b/docs/video_system/snap/2-7-2.jpg differ diff --git a/docs/video_system/snap/2-8-1.jpg b/docs/video_system/snap/2-8-1.jpg new file mode 100644 index 0000000..6e5d360 Binary files /dev/null and b/docs/video_system/snap/2-8-1.jpg differ diff --git a/docs/video_system/snap/2-9-1.jpg b/docs/video_system/snap/2-9-1.jpg new file mode 100644 index 0000000..75c0f56 Binary files /dev/null and b/docs/video_system/snap/2-9-1.jpg differ diff --git a/docs/video_system/snap/3-1-1.jpg b/docs/video_system/snap/3-1-1.jpg new file mode 100644 index 0000000..cbd4c8d Binary files /dev/null and b/docs/video_system/snap/3-1-1.jpg differ diff --git a/docs/video_system/snap/3-1-2.jpg b/docs/video_system/snap/3-1-2.jpg new file mode 100644 index 0000000..2cb6795 Binary files /dev/null and b/docs/video_system/snap/3-1-2.jpg differ diff --git a/docs/video_system/snap/3-2-1.jpg b/docs/video_system/snap/3-2-1.jpg new file mode 100644 index 0000000..a899bc2 Binary files /dev/null and b/docs/video_system/snap/3-2-1.jpg differ diff --git a/docs/video_system/snap/3-3-1.jpg b/docs/video_system/snap/3-3-1.jpg new file mode 100644 index 0000000..78147c4 Binary files /dev/null and b/docs/video_system/snap/3-3-1.jpg differ diff --git a/docs/video_system/snap/3-4-1.jpg b/docs/video_system/snap/3-4-1.jpg new file mode 100644 index 0000000..af20aa4 Binary files /dev/null and b/docs/video_system/snap/3-4-1.jpg differ diff --git a/docs/video_system/snap/3-4-2.jpg b/docs/video_system/snap/3-4-2.jpg new file mode 100644 index 0000000..f8ff64c Binary files /dev/null and b/docs/video_system/snap/3-4-2.jpg differ diff --git a/docs/video_system/snap/3-4-3.jpg b/docs/video_system/snap/3-4-3.jpg new file mode 100644 index 0000000..9bebd8a Binary files /dev/null and b/docs/video_system/snap/3-4-3.jpg differ diff --git a/docs/video_system/snap/3-5-1.jpg b/docs/video_system/snap/3-5-1.jpg new file mode 100644 index 0000000..c566655 Binary files /dev/null and b/docs/video_system/snap/3-5-1.jpg differ diff --git a/docs/video_system/snap/3-5-2.jpg b/docs/video_system/snap/3-5-2.jpg new file mode 100644 index 0000000..2e8d89c Binary files /dev/null and b/docs/video_system/snap/3-5-2.jpg differ diff --git a/docs/video_system/snap/4-1-1.jpg b/docs/video_system/snap/4-1-1.jpg new file mode 100644 index 0000000..d0eb716 Binary files /dev/null and b/docs/video_system/snap/4-1-1.jpg differ diff --git a/docs/video_system/snap/4-2-1.jpg b/docs/video_system/snap/4-2-1.jpg new file mode 100644 index 0000000..35018da Binary files /dev/null and b/docs/video_system/snap/4-2-1.jpg differ diff --git a/docs/video_system/snap/4-3-1.jpg b/docs/video_system/snap/4-3-1.jpg new file mode 100644 index 0000000..d13a94c Binary files /dev/null and b/docs/video_system/snap/4-3-1.jpg differ diff --git a/docs/video_system/snap/4-4-1.jpg b/docs/video_system/snap/4-4-1.jpg new file mode 100644 index 0000000..6adea14 Binary files /dev/null and b/docs/video_system/snap/4-4-1.jpg differ diff --git a/docs/video_system/snap/4-5-1.jpg b/docs/video_system/snap/4-5-1.jpg new file mode 100644 index 0000000..73893fd Binary files /dev/null and b/docs/video_system/snap/4-5-1.jpg differ diff --git a/docs/video_system/snap/5-1-1.jpg b/docs/video_system/snap/5-1-1.jpg new file mode 100644 index 0000000..1ca53fd Binary files /dev/null and b/docs/video_system/snap/5-1-1.jpg differ diff --git a/docs/video_system/snap/5-1-2.jpg b/docs/video_system/snap/5-1-2.jpg new file mode 100644 index 0000000..5558098 Binary files /dev/null and b/docs/video_system/snap/5-1-2.jpg differ diff --git a/docs/video_system/snap/5-1-3.jpg b/docs/video_system/snap/5-1-3.jpg new file mode 100644 index 0000000..c85e422 Binary files /dev/null and b/docs/video_system/snap/5-1-3.jpg differ diff --git a/docs/video_system/snap/5-1-4.jpg b/docs/video_system/snap/5-1-4.jpg new file mode 100644 index 0000000..2656172 Binary files /dev/null and b/docs/video_system/snap/5-1-4.jpg differ diff --git a/docs/video_system/snap/5-1-5.jpg b/docs/video_system/snap/5-1-5.jpg new file mode 100644 index 0000000..4ee1f10 Binary files /dev/null and b/docs/video_system/snap/5-1-5.jpg differ diff --git a/docs/video_system/snap/5-2-1.jpg b/docs/video_system/snap/5-2-1.jpg new file mode 100644 index 0000000..63315fc Binary files /dev/null and b/docs/video_system/snap/5-2-1.jpg differ diff --git a/docs/video_system/snap/6-1-0.jpg b/docs/video_system/snap/6-1-0.jpg new file mode 100644 index 0000000..cf6860c Binary files /dev/null and b/docs/video_system/snap/6-1-0.jpg differ diff --git a/docs/video_system/snap/6-1-1.jpg b/docs/video_system/snap/6-1-1.jpg new file mode 100644 index 0000000..010b2aa Binary files /dev/null and b/docs/video_system/snap/6-1-1.jpg differ diff --git a/docs/video_system/snap/6-1-2.jpg b/docs/video_system/snap/6-1-2.jpg new file mode 100644 index 0000000..7b0d193 Binary files /dev/null and b/docs/video_system/snap/6-1-2.jpg differ diff --git a/docs/video_system/snap/6-1-3.jpg b/docs/video_system/snap/6-1-3.jpg new file mode 100644 index 0000000..318f29f Binary files /dev/null and b/docs/video_system/snap/6-1-3.jpg differ diff --git a/docs/video_system/snap/6-1-4.jpg b/docs/video_system/snap/6-1-4.jpg new file mode 100644 index 0000000..cc1d6f0 Binary files /dev/null and b/docs/video_system/snap/6-1-4.jpg differ diff --git a/docs/video_system/snap/6-1-5.jpg b/docs/video_system/snap/6-1-5.jpg new file mode 100644 index 0000000..71f5181 Binary files /dev/null and b/docs/video_system/snap/6-1-5.jpg differ diff --git a/docs/video_system/snap/6-1-6.jpg b/docs/video_system/snap/6-1-6.jpg new file mode 100644 index 0000000..d88597b Binary files /dev/null and b/docs/video_system/snap/6-1-6.jpg differ diff --git a/docs/video_system/snap/6-2-1.jpg b/docs/video_system/snap/6-2-1.jpg new file mode 100644 index 0000000..348e7ad Binary files /dev/null and b/docs/video_system/snap/6-2-1.jpg differ diff --git a/docs/video_system/snap/6-2-6.jpg b/docs/video_system/snap/6-2-6.jpg new file mode 100644 index 0000000..c62d4ca Binary files /dev/null and b/docs/video_system/snap/6-2-6.jpg differ diff --git a/docs/video_system/snap/6-2-7.jpg b/docs/video_system/snap/6-2-7.jpg new file mode 100644 index 0000000..a4747f1 Binary files /dev/null and b/docs/video_system/snap/6-2-7.jpg differ diff --git a/docs/video_system/snap/6-3-1.jpg b/docs/video_system/snap/6-3-1.jpg new file mode 100644 index 0000000..479415e Binary files /dev/null and b/docs/video_system/snap/6-3-1.jpg differ diff --git a/docs/video_system/snap/6-3-6.jpg b/docs/video_system/snap/6-3-6.jpg new file mode 100644 index 0000000..6ec8a2c Binary files /dev/null and b/docs/video_system/snap/6-3-6.jpg differ diff --git a/docs/video_system/snap/6-3-7.jpg b/docs/video_system/snap/6-3-7.jpg new file mode 100644 index 0000000..6474334 Binary files /dev/null and b/docs/video_system/snap/6-3-7.jpg differ diff --git a/docs/video_system/snap/6-3-8.jpg b/docs/video_system/snap/6-3-8.jpg new file mode 100644 index 0000000..d83b72e Binary files /dev/null and b/docs/video_system/snap/6-3-8.jpg differ diff --git a/docs/video_system/snap/6-4-1.jpg b/docs/video_system/snap/6-4-1.jpg new file mode 100644 index 0000000..ffae3fb Binary files /dev/null and b/docs/video_system/snap/6-4-1.jpg differ diff --git a/docs/video_system/snap/6-4-10.jpg b/docs/video_system/snap/6-4-10.jpg new file mode 100644 index 0000000..550f7f4 Binary files /dev/null and b/docs/video_system/snap/6-4-10.jpg differ diff --git a/docs/video_system/snap/6-4-8.jpg b/docs/video_system/snap/6-4-8.jpg new file mode 100644 index 0000000..a5cb8c8 Binary files /dev/null and b/docs/video_system/snap/6-4-8.jpg differ diff --git a/docs/video_system/snap/6-4-9.jpg b/docs/video_system/snap/6-4-9.jpg new file mode 100644 index 0000000..e3029cb Binary files /dev/null and b/docs/video_system/snap/6-4-9.jpg differ diff --git a/docs/video_system/snap/6-5-1.jpg b/docs/video_system/snap/6-5-1.jpg new file mode 100644 index 0000000..71cd325 Binary files /dev/null and b/docs/video_system/snap/6-5-1.jpg differ diff --git a/docs/video_system/snap/6-5-6.jpg b/docs/video_system/snap/6-5-6.jpg new file mode 100644 index 0000000..43fe0cf Binary files /dev/null and b/docs/video_system/snap/6-5-6.jpg differ diff --git a/docs/video_system/snap/6-5-7.jpg b/docs/video_system/snap/6-5-7.jpg new file mode 100644 index 0000000..3888e80 Binary files /dev/null and b/docs/video_system/snap/6-5-7.jpg differ diff --git a/docs/video_system/snap/6-5-8-1.jpg b/docs/video_system/snap/6-5-8-1.jpg new file mode 100644 index 0000000..9f248e1 Binary files /dev/null and b/docs/video_system/snap/6-5-8-1.jpg differ diff --git a/docs/video_system/snap/6-5-8-2.jpg b/docs/video_system/snap/6-5-8-2.jpg new file mode 100644 index 0000000..60f4c67 Binary files /dev/null and b/docs/video_system/snap/6-5-8-2.jpg differ diff --git a/docs/video_system/snap/6-6-1.jpg b/docs/video_system/snap/6-6-1.jpg new file mode 100644 index 0000000..ba1fabb Binary files /dev/null and b/docs/video_system/snap/6-6-1.jpg differ diff --git a/docs/video_system/snap/6-6-2.jpg b/docs/video_system/snap/6-6-2.jpg new file mode 100644 index 0000000..a6311a4 Binary files /dev/null and b/docs/video_system/snap/6-6-2.jpg differ diff --git a/docs/video_system/snap/6-6-3.jpg b/docs/video_system/snap/6-6-3.jpg new file mode 100644 index 0000000..1a81f11 Binary files /dev/null and b/docs/video_system/snap/6-6-3.jpg differ diff --git a/docs/video_system/snap/6-6-4.jpg b/docs/video_system/snap/6-6-4.jpg new file mode 100644 index 0000000..034bd35 Binary files /dev/null and b/docs/video_system/snap/6-6-4.jpg differ diff --git a/docs/video_system/snap/6-7-0.jpg b/docs/video_system/snap/6-7-0.jpg new file mode 100644 index 0000000..f6321cd Binary files /dev/null and b/docs/video_system/snap/6-7-0.jpg differ diff --git a/docs/video_system/snap/6-7-1.jpg b/docs/video_system/snap/6-7-1.jpg new file mode 100644 index 0000000..9713981 Binary files /dev/null and b/docs/video_system/snap/6-7-1.jpg differ diff --git a/docs/video_system/snap/6-7-2.jpg b/docs/video_system/snap/6-7-2.jpg new file mode 100644 index 0000000..0a1f726 Binary files /dev/null and b/docs/video_system/snap/6-7-2.jpg differ diff --git a/docs/video_system/snap/7-6-1.jpg b/docs/video_system/snap/7-6-1.jpg new file mode 100644 index 0000000..c492c24 Binary files /dev/null and b/docs/video_system/snap/7-6-1.jpg differ diff --git a/docs/video_system/snap/8-1-1.jpg b/docs/video_system/snap/8-1-1.jpg new file mode 100644 index 0000000..41fc6e3 Binary files /dev/null and b/docs/video_system/snap/8-1-1.jpg differ diff --git a/docs/video_system/snap/8-1-2.jpg b/docs/video_system/snap/8-1-2.jpg new file mode 100644 index 0000000..f91b2c4 Binary files /dev/null and b/docs/video_system/snap/8-1-2.jpg differ diff --git a/docs/video_system/snap/8-1-3.jpg b/docs/video_system/snap/8-1-3.jpg new file mode 100644 index 0000000..0e6a39c Binary files /dev/null and b/docs/video_system/snap/8-1-3.jpg differ diff --git a/docs/video_system/snap/8-1-4.jpg b/docs/video_system/snap/8-1-4.jpg new file mode 100644 index 0000000..b9ca403 Binary files /dev/null and b/docs/video_system/snap/8-1-4.jpg differ diff --git a/docs/video_system/snap/8-1-5.jpg b/docs/video_system/snap/8-1-5.jpg new file mode 100644 index 0000000..a42a39e Binary files /dev/null and b/docs/video_system/snap/8-1-5.jpg differ diff --git a/docs/video_system/snap/8-1-6.jpg b/docs/video_system/snap/8-1-6.jpg new file mode 100644 index 0000000..5bc2828 Binary files /dev/null and b/docs/video_system/snap/8-1-6.jpg differ diff --git a/docs/video_system/snap/8-2-1.jpg b/docs/video_system/snap/8-2-1.jpg new file mode 100644 index 0000000..94ea728 Binary files /dev/null and b/docs/video_system/snap/8-2-1.jpg differ diff --git a/docs/video_system/snap/8-2-2.jpg b/docs/video_system/snap/8-2-2.jpg new file mode 100644 index 0000000..d54da93 Binary files /dev/null and b/docs/video_system/snap/8-2-2.jpg differ diff --git a/docs/video_system/snap/8-2-3.jpg b/docs/video_system/snap/8-2-3.jpg new file mode 100644 index 0000000..94ced5c Binary files /dev/null and b/docs/video_system/snap/8-2-3.jpg differ diff --git a/docs/video_system/snap/8-2-4.jpg b/docs/video_system/snap/8-2-4.jpg new file mode 100644 index 0000000..2fec784 Binary files /dev/null and b/docs/video_system/snap/8-2-4.jpg differ diff --git a/docs/video_system/snap/9-0-1.jpg b/docs/video_system/snap/9-0-1.jpg new file mode 100644 index 0000000..490fed8 Binary files /dev/null and b/docs/video_system/snap/9-0-1.jpg differ diff --git a/docs/video_system/snap/9-0-2.jpg b/docs/video_system/snap/9-0-2.jpg new file mode 100644 index 0000000..a8431bd Binary files /dev/null and b/docs/video_system/snap/9-0-2.jpg differ diff --git a/docs/video_system/snap/9-0-3.jpg b/docs/video_system/snap/9-0-3.jpg new file mode 100644 index 0000000..7b89630 Binary files /dev/null and b/docs/video_system/snap/9-0-3.jpg differ diff --git a/docs/video_system/snap/9-0-4.jpg b/docs/video_system/snap/9-0-4.jpg new file mode 100644 index 0000000..104c357 Binary files /dev/null and b/docs/video_system/snap/9-0-4.jpg differ diff --git a/docs/video_system/snap/9-0-5.jpg b/docs/video_system/snap/9-0-5.jpg new file mode 100644 index 0000000..df02526 Binary files /dev/null and b/docs/video_system/snap/9-0-5.jpg differ diff --git a/docs/video_system/snap/9-0-6.jpg b/docs/video_system/snap/9-0-6.jpg new file mode 100644 index 0000000..d01b982 Binary files /dev/null and b/docs/video_system/snap/9-0-6.jpg differ diff --git a/docs/video_system/snap/9-1-1.jpg b/docs/video_system/snap/9-1-1.jpg new file mode 100644 index 0000000..b491981 Binary files /dev/null and b/docs/video_system/snap/9-1-1.jpg differ diff --git a/docs/video_system/snap/9-11-1.jpg b/docs/video_system/snap/9-11-1.jpg new file mode 100644 index 0000000..b5faf4b Binary files /dev/null and b/docs/video_system/snap/9-11-1.jpg differ diff --git a/docs/video_system/snap/9-14-1.jpg b/docs/video_system/snap/9-14-1.jpg new file mode 100644 index 0000000..711b953 Binary files /dev/null and b/docs/video_system/snap/9-14-1.jpg differ diff --git a/docs/video_system/snap/9-2-1.jpg b/docs/video_system/snap/9-2-1.jpg new file mode 100644 index 0000000..eb0c380 Binary files /dev/null and b/docs/video_system/snap/9-2-1.jpg differ diff --git a/docs/video_system/snap/9-3-1.jpg b/docs/video_system/snap/9-3-1.jpg new file mode 100644 index 0000000..0e28a0a Binary files /dev/null and b/docs/video_system/snap/9-3-1.jpg differ diff --git a/docs/video_system/snap/9-4-1.jpg b/docs/video_system/snap/9-4-1.jpg new file mode 100644 index 0000000..45c9468 Binary files /dev/null and b/docs/video_system/snap/9-4-1.jpg differ diff --git a/docs/video_system/snap/9-5-1.jpg b/docs/video_system/snap/9-5-1.jpg new file mode 100644 index 0000000..17d319a Binary files /dev/null and b/docs/video_system/snap/9-5-1.jpg differ diff --git a/docs/video_system/snap/9-6-1.jpg b/docs/video_system/snap/9-6-1.jpg new file mode 100644 index 0000000..890a02c Binary files /dev/null and b/docs/video_system/snap/9-6-1.jpg differ diff --git a/docs/video_system/snap/9-8-1.jpg b/docs/video_system/snap/9-8-1.jpg new file mode 100644 index 0000000..2d3f9fb Binary files /dev/null and b/docs/video_system/snap/9-8-1.jpg differ diff --git a/docs/video_system/snap/9-9-1.jpg b/docs/video_system/snap/9-9-1.jpg new file mode 100644 index 0000000..c80035e Binary files /dev/null and b/docs/video_system/snap/9-9-1.jpg differ