├── pages
├── index.js
├── index.json
├── index.wxss
└── index.wxml
├── app.js
├── go_dev
├── sample.wasm
├── assets
│ ├── app.css
│ ├── wasm_exec.js
│ └── vue.min.js
├── main.go
└── lesson1.html
├── package_lesson1
├── index.json
├── assets
│ ├── sample.wasm.br
│ └── wasm_exec.js
├── index.wxss
├── index.js
└── index.wxml
├── package_lesson2
├── index.json
├── assets
│ ├── sampleImage1.jpg
│ └── opencv3.4.16.wasm.br
├── index.wxss
├── index.wxml
└── index.js
├── screenshot
├── 1.jpg
├── 2-1.jpg
├── 2-2.jpg
├── 2-3.jpg
├── 3-1.jpg
├── 3-2.jpg
├── 4-1.jpg
├── 4-2.jpg
└── 4-3.jpg
├── opencv_dev
├── opencv3.4.16.wasm
├── assets
│ ├── sampleImage1.jpg
│ └── app.css
└── lesson2.html
├── sitemap.json
├── package.json
├── node_dev
├── package.json
├── package-lock.json
└── main.js
├── app.json
├── app.wxss
├── LICENSE
├── miniprogram_npm
└── text-encoder
│ ├── index.js.map
│ └── index.js
├── project.config.json
├── README.md
└── style
└── weui.wxss
/pages/index.js:
--------------------------------------------------------------------------------
1 | Page({})
2 |
--------------------------------------------------------------------------------
/pages/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | //app.js
2 | App({
3 | onLaunch: function () {
4 | },
5 | globalData: {
6 | }
7 | })
--------------------------------------------------------------------------------
/go_dev/sample.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/go_dev/sample.wasm
--------------------------------------------------------------------------------
/package_lesson1/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "navigationBarTitleText": "Lesson 1"
4 | }
--------------------------------------------------------------------------------
/package_lesson2/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "navigationBarTitleText": "Lesson 2"
4 | }
--------------------------------------------------------------------------------
/screenshot/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/1.jpg
--------------------------------------------------------------------------------
/screenshot/2-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/2-1.jpg
--------------------------------------------------------------------------------
/screenshot/2-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/2-2.jpg
--------------------------------------------------------------------------------
/screenshot/2-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/2-3.jpg
--------------------------------------------------------------------------------
/screenshot/3-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/3-1.jpg
--------------------------------------------------------------------------------
/screenshot/3-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/3-2.jpg
--------------------------------------------------------------------------------
/screenshot/4-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/4-1.jpg
--------------------------------------------------------------------------------
/screenshot/4-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/4-2.jpg
--------------------------------------------------------------------------------
/screenshot/4-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/screenshot/4-3.jpg
--------------------------------------------------------------------------------
/opencv_dev/opencv3.4.16.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/opencv_dev/opencv3.4.16.wasm
--------------------------------------------------------------------------------
/opencv_dev/assets/sampleImage1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/opencv_dev/assets/sampleImage1.jpg
--------------------------------------------------------------------------------
/package_lesson1/assets/sample.wasm.br:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/package_lesson1/assets/sample.wasm.br
--------------------------------------------------------------------------------
/package_lesson2/assets/sampleImage1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/package_lesson2/assets/sampleImage1.jpg
--------------------------------------------------------------------------------
/package_lesson2/assets/opencv3.4.16.wasm.br:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-WASM/HEAD/package_lesson2/assets/opencv3.4.16.wasm.br
--------------------------------------------------------------------------------
/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "visit https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/pages/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | .button-sp-area{
3 | margin: 0 auto;
4 | padding-top: 15px;
5 | width: 60%;
6 | }
7 | .mini-btn{
8 | margin-right: 5px;
9 | }
10 | .weui-panel__hd{
11 | font-weight:bold;
12 | color:#333;
13 | }
--------------------------------------------------------------------------------
/package_lesson1/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | .button-sp-area{
3 | margin: 0 auto;
4 | padding-top: 15px;
5 | width: 60%;
6 | }
7 | .mini-btn{
8 | margin-right: 5px;
9 | }
10 | .weui-panel__hd{
11 | font-weight:bold;
12 | color:#333;
13 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wechat-ar-wasm",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "text-encoder": "0.0.4"
13 | },
14 | "devDependencies": {}
15 | }
16 |
--------------------------------------------------------------------------------
/package_lesson2/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | .button-sp-area{
3 | margin: 0 auto;
4 | padding-top: 15px;
5 | width: 60%;
6 | }
7 | .mini-btn{
8 | margin-right: 5px;
9 | }
10 | .weui-panel__hd{
11 | font-weight:bold;
12 | color:#333;
13 | }
14 |
15 | .visibleCanvas{
16 | margin:auto;
17 | }
18 |
19 | .inputImage{
20 | width:375px;
21 | }
--------------------------------------------------------------------------------
/node_dev/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node_dev",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "node main.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "wasm-brotli": "^2.0.2"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/node_dev/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node_dev",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "wasm-brotli": {
8 | "version": "2.0.2",
9 | "resolved": "https://registry.npmmirror.com/wasm-brotli/download/wasm-brotli-2.0.2.tgz",
10 | "integrity": "sha1-9TF6+w0+Ll/pCma21h5Ck5KE8cc="
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index"
4 | ],
5 | "subpackages": [
6 | {
7 | "root": "package_lesson1",
8 | "pages": [
9 | "index"
10 | ]
11 | },
12 | {
13 | "root": "package_lesson2",
14 | "pages": [
15 | "index"
16 | ]
17 | }
18 | ],
19 | "window": {
20 | "backgroundTextStyle": "light",
21 | "navigationBarBackgroundColor": "#fff",
22 | "navigationBarTitleText": "运行WASM",
23 | "navigationBarTextStyle": "black"
24 | },
25 | "sitemapLocation": "sitemap.json"
26 | }
--------------------------------------------------------------------------------
/go_dev/assets/app.css:
--------------------------------------------------------------------------------
1 | .page{
2 | background-color: #F8F8F8;
3 | font-size: 16px;
4 | }
5 | .page__hd {
6 | padding: 40px;
7 | }
8 | .page__bd {
9 | padding-bottom: 40px;
10 | }
11 | .page__bd_spacing {
12 | padding-left: 15px;
13 | padding-right: 15px;
14 | }
15 |
16 | .page__ft{
17 | padding-bottom: 10px;
18 | text-align: center;
19 | }
20 |
21 | .page__title {
22 | text-align: left;
23 | font-size: 20px;
24 | font-weight: 400;
25 | }
26 |
27 | .page__desc {
28 | margin-top: 5px;
29 | color: #888888;
30 | text-align: left;
31 | font-size: 14px;
32 | }
33 |
34 | .marginTop10{
35 | margin-top: 10px;
36 | }
37 |
38 | .loading{
39 | text-align: center;
40 | }
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | @import "style/weui.wxss"
3 |
4 | page{
5 | background-color: #F8F8F8;
6 | font-size: 16px;
7 | font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif;
8 | }
9 | .page__hd {
10 | padding: 40px;
11 | }
12 | .page__bd {
13 | padding-bottom: 40px;
14 | }
15 | .page__bd_spacing {
16 | padding-left: 15px;
17 | padding-right: 15px;
18 | }
19 |
20 | .page__ft{
21 | padding-bottom: 10px;
22 | text-align: center;
23 | }
24 |
25 | .page__title {
26 | text-align: left;
27 | font-size: 20px;
28 | font-weight: 400;
29 | }
30 |
31 | .page__desc {
32 | margin-top: 5px;
33 | color: #888888;
34 | text-align: left;
35 | font-size: 14px;
36 | }
37 |
38 | .marginTop10{
39 | margin-top: 10px;
40 | }
--------------------------------------------------------------------------------
/package_lesson2/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 图像处理
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/opencv_dev/assets/app.css:
--------------------------------------------------------------------------------
1 | .page{
2 | background-color: #F8F8F8;
3 | font-size: 16px;
4 | }
5 | .page__hd {
6 | padding: 40px;
7 | }
8 | .page__bd {
9 | padding-bottom: 40px;
10 | }
11 | .page__bd_spacing {
12 | padding-left: 15px;
13 | padding-right: 15px;
14 | }
15 |
16 | .page__ft{
17 | padding-bottom: 10px;
18 | text-align: center;
19 | }
20 |
21 | .page__title {
22 | text-align: left;
23 | font-size: 20px;
24 | font-weight: 400;
25 | }
26 |
27 | .page__desc {
28 | margin-top: 5px;
29 | color: #888888;
30 | text-align: left;
31 | font-size: 14px;
32 | }
33 |
34 | .marginTop10{
35 | margin-top: 10px;
36 | }
37 |
38 | .loading{
39 | text-align: center;
40 | }
41 |
42 | .button-sp-area{
43 | margin: 0 auto;
44 | padding-top: 15px;
45 | width: 60%;
46 | }
47 | .mini-btn{
48 | margin-right: 5px;
49 | }
50 | .weui-panel__hd{
51 | font-weight:bold;
52 | color:#333;
53 | }
54 |
55 | .visibleCanvas{
56 | margin:10px auto;
57 | display: block;
58 | }
59 |
60 | .hiddenCanvas{
61 | position:fixed;
62 | left:1000px;
63 | width:800%;
64 | height:400%;
65 | }
66 |
67 | .inputImage{
68 | width:375px;
69 | display: block;
70 | margin: auto;
71 | }
--------------------------------------------------------------------------------
/go_dev/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | 使用方法:在终端运行“go build -o sample.wasm main.go”,会生成sample.wasm。
3 | */
4 | package main
5 |
6 | import (
7 | "syscall/js"
8 | "time"
9 | )
10 |
11 | var totalNum int = 0
12 |
13 | // js调用Go。点击按钮一次,增加一次计数。
14 | func addTotal(this js.Value, args []js.Value) interface{} {
15 | totalNum = totalNum + 1
16 | return js.ValueOf(totalNum)
17 | }
18 |
19 | // js调用Go, Go回调js。Go等待2秒后,才回调js。
20 | func asyncAndCallbak(this js.Value, args []js.Value) interface{} {
21 | // js输入参数
22 | input := args[0].String()
23 | // js回调函数
24 | callback := args[1]
25 | // 协程
26 | go func() {
27 | // 等待2秒
28 | time.Sleep(2 * time.Second)
29 | result := "回复:" + input
30 | // 运行js回调函数
31 | callback.Invoke(result)
32 | }()
33 |
34 | return nil
35 | }
36 |
37 | func main() {
38 | // 创建通道
39 | channel := make(chan int)
40 | // 1.Go调用js的console.log()方法,在开发者工具的Consol面板中查看。
41 | console := js.Global().Get("console")
42 | console.Call("log", "hello, world!")
43 |
44 | // 2.js调用Go的addTotal()方法
45 | js.Global().Set("addTotal", js.FuncOf(addTotal))
46 |
47 | // 3.js调用Go的asyncAndCallbak()方法, Go回调js。
48 | js.Global().Set("asyncAndCallbak", js.FuncOf(asyncAndCallbak))
49 |
50 | // 通道阻塞了main()方法
51 | <-channel
52 |
53 | // main()方法在结束之前,不会运行到这个位置。
54 | console.Call("log", "exit")
55 | }
56 |
--------------------------------------------------------------------------------
/package_lesson1/index.js:
--------------------------------------------------------------------------------
1 | require('./assets/wasm_exec.js');
2 | const wasm_url = '/package_lesson1/assets/sample.wasm.br'
3 |
4 | Page({
5 | data: {
6 | notice: '',
7 | inputText: '你好!Go语言。',
8 | test_result1: '0',
9 | test_result2: '',
10 | },
11 | async onReady() {
12 | // 在小程序基础类库的global对象上,增加console对象。
13 | global.console = console
14 | // 使用小程序类库的WXWebAssembly,初始化Go运行环境。
15 | await this.initGo()
16 | },
17 | async initGo() {
18 | var _that = this;
19 | const go = new global.Go();
20 | try {
21 | const result = await WXWebAssembly.instantiate(wasm_url, go.importObject)
22 | var msg = 'Go初始化成功,在小程序调试窗口查看console的信息。'
23 | _that.setData({
24 | notice: msg,
25 | })
26 | console.log('initGo', msg)
27 |
28 | // 运行go程序的main()方法
29 | await go.run(result.instance);
30 | // 注意:在go程序的main()方法退出之前,小程序不会运行到这个位置。
31 | console.log('initGo', '运行完成')
32 | } catch (err) {
33 | console.error('initGo', err)
34 | }
35 | },
36 | btnRun1() {
37 | var _that = this;
38 | var res = global.addTotal()
39 | _that.setData({
40 | test_result1: res,
41 | })
42 | console.log(res)
43 | },
44 | btnRun2() {
45 | var _that = this;
46 | wx.showLoading({
47 | title: '请等待2秒',
48 | mask:true,
49 | })
50 | global.asyncAndCallbak(_that.data.inputText, function (res) {
51 | wx.hideLoading()
52 |
53 | _that.setData({
54 | test_result2: _that.data.test_result2+res+' ',
55 | })
56 | console.log(res)
57 | })
58 | },
59 | })
60 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2021, AR Fashion
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/pages/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Go和小程序互操作
6 |
7 |
8 |
9 | 使用WXWebAssembly.instantiate初始化Go运行环境。
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 小程序使用OpenCV
22 |
23 |
24 |
25 | 使用WXWebAssembly.instantiate初始化OpenCV运行环境。
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/node_dev/main.js:
--------------------------------------------------------------------------------
1 | /*
2 | 使用方法:在终端运行“node main.js”,会将../go_dev/sample.wasm压缩为../package_lesson1/assets/sample.wasm.br。
3 | */
4 |
5 | // 第三方的wasm版本brotli压缩和解压缩,安装方法:npm install wasm-brotli
6 | var brotli = require('wasm-brotli');
7 | // node自带的库
8 | var fs = require('fs');
9 | // node自带的库
10 | var util = require('util');
11 |
12 | // 将方法包装成promise风格,以使用async/await。
13 | const writeFileAsync = util.promisify(fs.writeFile);
14 | const readFileAsync = util.promisify(fs.readFile);
15 |
16 | // 压缩的示例
17 | async function compress(){
18 | const content = Buffer.from('Hello, world!', 'utf8');
19 | const compressedContent = await brotli.compress(content);
20 | await writeFileAsync('./hello_world.txt.br', compressedContent);
21 |
22 | console.log('compress completed')
23 | }
24 |
25 | // 解压缩的示例
26 | async function decompress(){
27 | const compressedContent = await readFileAsync('./hello_world.txt.br');
28 | const contenArray = await brotli.decompress(compressedContent);
29 | const content = Buffer.from(contenArray).toString('utf8');
30 |
31 | console.log('decompress result',content)
32 | }
33 |
34 | // 压缩文件的示例
35 | async function compressFile(){
36 | console.log('compress start...')
37 | var start = Date.now()
38 | const content = await readFileAsync('../go_dev/sample.wasm');
39 | const compressedContent = await brotli.compress(content);
40 | await writeFileAsync('../package_lesson1/assets/sample.wasm.br', compressedContent);
41 | var end = Date.now()-start
42 | console.log('compress completed. cost',end/1000,'seconds.')
43 | }
44 |
45 | compressFile()
46 |
--------------------------------------------------------------------------------
/miniprogram_npm/text-encoder/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["index.js"],"names":[],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"index.js","sourcesContent":["var utf8Encodings = [\n 'utf8',\n 'utf-8',\n 'unicode-1-1-utf-8'\n];\n\nfunction TextEncoder(encoding) {\n if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {\n throw new RangeError('Invalid encoding type. Only utf-8 is supported');\n } else {\n this.encoding = 'utf-8';\n this.encode = function(str) {\n if (typeof str !== 'string') {\n throw new TypeError('passed argument must be of tye string');\n }\n var binstr = unescape(encodeURIComponent(str)),\n arr = new Uint8Array(binstr.length);\n const split = binstr.split('');\n for (let i = 0; i < split.length; i++) {\n arr[i] = split[i].charCodeAt(0);\n }\n return arr;\n };\n }\n}\n\nfunction TextDecoder(encoding) {\n if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {\n throw new RangeError('Invalid encoding type. Only utf-8 is supported');\n }\n else {\n this.encoding = 'utf-8';\n this.decode = function (view, options) {\n if (typeof view === 'undefined') {\n return '';\n }\n\n var stream = (typeof options !== 'undefined' && stream in options) ? options.stream : false;\n if (typeof stream !== 'boolean') {\n throw new TypeError('stream option must be boolean');\n }\n\n if (!ArrayBuffer.isView(view)) {\n throw new TypeError('passed argument must be an array buffer view');\n } else {\n var arr = new Uint8Array(view.buffer, view.byteOffset, view.byteLength),\n charArr = new Array(arr.length);\n for (let i = 0; i < arr.length; i++) {\n charArr[i] = String.fromCharCode(arr[i]);\n }\n return decodeURIComponent(escape(charArr.join('')));\n }\n }\n }\n}\n\nmodule.exports = {\n TextEncoder,\n TextDecoder,\n};\n"]}
--------------------------------------------------------------------------------
/package_lesson1/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Go调用小程序的函数
5 |
6 |
7 | {{notice}}
8 |
9 |
10 |
11 |
12 |
13 | 小程序调用Go的函数,每次点击增加次数。
14 |
15 |
16 | 点击了{{test_result1}}次
17 |
18 |
19 |
20 |
21 |
22 | 小程序调用Go的函数,Go在等待2秒后回调小程序。
23 |
24 |
25 |
26 | 表单
27 |
28 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "project config file",
3 | "packOptions": {
4 | "ignore": [
5 | {
6 | "type": "folder",
7 | "value": "screenshot"
8 | },
9 | {
10 | "type": "folder",
11 | "value": "node_dev"
12 | },
13 | {
14 | "type": "folder",
15 | "value": "go_dev"
16 | },
17 | {
18 | "type": "folder",
19 | "value": "opencv_dev"
20 | }
21 | ]
22 | },
23 | "setting": {
24 | "urlCheck": false,
25 | "es6": false,
26 | "enhance": false,
27 | "postcss": false,
28 | "preloadBackgroundData": false,
29 | "minified": false,
30 | "newFeature": true,
31 | "coverView": true,
32 | "nodeModules": true,
33 | "autoAudits": false,
34 | "showShadowRootInWxmlPanel": true,
35 | "scopeDataCheck": false,
36 | "uglifyFileName": false,
37 | "checkInvalidKey": true,
38 | "checkSiteMap": true,
39 | "uploadWithSourceMap": true,
40 | "compileHotReLoad": false,
41 | "lazyloadPlaceholderEnable": false,
42 | "useMultiFrameRuntime": true,
43 | "useApiHook": true,
44 | "useApiHostProcess": true,
45 | "babelSetting": {
46 | "ignore": [],
47 | "disablePlugins": [],
48 | "outputPath": ""
49 | },
50 | "enableEngineNative": false,
51 | "useIsolateContext": false,
52 | "userConfirmedBundleSwitch": false,
53 | "packNpmManually": false,
54 | "packNpmRelationList": [],
55 | "minifyWXSS": false,
56 | "disableUseStrict": false,
57 | "minifyWXML": false,
58 | "showES6CompileOption": false,
59 | "useCompilerPlugins": false
60 | },
61 | "compileType": "miniprogram",
62 | "libVersion": "2.16.1",
63 | "appid": "wxb4cdacc73d2d71c7",
64 | "projectname": "WeChat-WebAR",
65 | "debugOptions": {
66 | "hidedInDevtools": []
67 | },
68 | "isGameTourist": false,
69 | "simulatorType": "wechat",
70 | "simulatorPluginLibVersion": {},
71 | "condition": {
72 | "search": {
73 | "list": []
74 | },
75 | "conversation": {
76 | "list": []
77 | },
78 | "game": {
79 | "currentL": -1,
80 | "list": []
81 | },
82 | "miniprogram": {
83 | "list": []
84 | }
85 | }
86 | }
--------------------------------------------------------------------------------
/miniprogram_npm/text-encoder/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1638331248814, function(require, module, exports) {
8 | var utf8Encodings = [
9 | 'utf8',
10 | 'utf-8',
11 | 'unicode-1-1-utf-8'
12 | ];
13 |
14 | function TextEncoder(encoding) {
15 | if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {
16 | throw new RangeError('Invalid encoding type. Only utf-8 is supported');
17 | } else {
18 | this.encoding = 'utf-8';
19 | this.encode = function(str) {
20 | if (typeof str !== 'string') {
21 | throw new TypeError('passed argument must be of tye string');
22 | }
23 | var binstr = unescape(encodeURIComponent(str)),
24 | arr = new Uint8Array(binstr.length);
25 | const split = binstr.split('');
26 | for (let i = 0; i < split.length; i++) {
27 | arr[i] = split[i].charCodeAt(0);
28 | }
29 | return arr;
30 | };
31 | }
32 | }
33 |
34 | function TextDecoder(encoding) {
35 | if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {
36 | throw new RangeError('Invalid encoding type. Only utf-8 is supported');
37 | }
38 | else {
39 | this.encoding = 'utf-8';
40 | this.decode = function (view, options) {
41 | if (typeof view === 'undefined') {
42 | return '';
43 | }
44 |
45 | var stream = (typeof options !== 'undefined' && stream in options) ? options.stream : false;
46 | if (typeof stream !== 'boolean') {
47 | throw new TypeError('stream option must be boolean');
48 | }
49 |
50 | if (!ArrayBuffer.isView(view)) {
51 | throw new TypeError('passed argument must be an array buffer view');
52 | } else {
53 | var arr = new Uint8Array(view.buffer, view.byteOffset, view.byteLength),
54 | charArr = new Array(arr.length);
55 | for (let i = 0; i < arr.length; i++) {
56 | charArr[i] = String.fromCharCode(arr[i]);
57 | }
58 | return decodeURIComponent(escape(charArr.join('')));
59 | }
60 | }
61 | }
62 | }
63 |
64 | module.exports = {
65 | TextEncoder,
66 | TextDecoder,
67 | };
68 |
69 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
70 | return __REQUIRE__(1638331248814);
71 | })()
72 | //miniprogram-npm-outsideDeps=[]
73 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/opencv_dev/lesson2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | OpenCV WebAssembly
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
图像处理
17 |
18 |
![]()
19 |
20 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 |
39 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/go_dev/lesson1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Go WebAssembly
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Go调用小程序的函数
18 |
23 |
24 |
25 |
26 |
小程序调用Go的函数,每次点击增加次数。
27 |
33 |
34 |
35 |
小程序调用Go的函数,Go在等待2秒后回调小程序。
36 |
63 |
64 |
65 |
66 |
67 |
68 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/package_lesson2/index.js:
--------------------------------------------------------------------------------
1 | // 画布
2 | const canvas1 = 'canvas1'
3 | // 示例图片
4 | const sampleImage1 = './assets/sampleImage1.jpg'
5 | // 画布最大宽度
6 | const maxCanvasWidth = 375
7 | // wasm路径
8 | global.wasm_url = '/package_lesson2/assets/opencv3.4.16.wasm.br'
9 | // opencv_exec.js会从global.wasm_url获取wasm路径
10 | let cv = require('./assets/opencv_exec.js');
11 |
12 | Page({
13 | // 画布的dom对象
14 | canvasDom: null,
15 | data: {
16 | canvas1Width: 375,
17 | canvas1Height: 150,
18 | // 示例图片
19 | sampleImage1Url: sampleImage1,
20 | },
21 | onReady() {
22 | // 可见的画布
23 | this.initCanvas(canvas1)
24 | },
25 | // 获取画布
26 | initCanvas(canvasId) {
27 | var _that = this;
28 | wx.createSelectorQuery()
29 | .select('#' + canvasId)
30 | .fields({ node: true, size: true })
31 | .exec((res) => {
32 | const canvas2d = res[0].node;
33 | // 设置画布的宽度和高度
34 | canvas2d.width = res[0].width;
35 | canvas2d.height = res[0].height;
36 | _that.canvasDom = canvas2d
37 | });
38 | },
39 | // 获取图像数据和调整图像大小
40 | getImageData(image,offscreenCanvas) {
41 | var _that = this
42 | // const ctx = wx.createCanvasContext(canvasId);
43 | var canvasWidth = image.width;
44 | if (canvasWidth > maxCanvasWidth) {
45 | canvasWidth = maxCanvasWidth;
46 | }
47 | // canvas Height
48 | var canvasHeight = Math.floor(canvasWidth * (image.height / image.width));
49 | // 离屏画布的宽度和高度不能小于图像的
50 | offscreenCanvas.width = canvasWidth;
51 | offscreenCanvas.height = canvasHeight;
52 | // draw image on canvas
53 | var ctx = offscreenCanvas.getContext('2d')
54 | ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);
55 | // get image data from canvas
56 | var imgData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
57 |
58 | return imgData
59 | },
60 | // 创建图像对象
61 | async createImageElement(imgUrl) {
62 | var _that = this
63 | // 创建2d类型的离屏画布(需要微信基础库2.16.1以上)
64 | var offscreenCanvas = wx.createOffscreenCanvas({type: '2d'});
65 | const image = offscreenCanvas.createImage();
66 | await new Promise(function (resolve, reject) {
67 | image.onload = resolve
68 | image.onerror = reject
69 | image.src = imgUrl
70 | })
71 | const imageData = _that.getImageData(image,offscreenCanvas)
72 | return imageData
73 | },
74 | imgProcess1(imageData, canvasDom) {
75 | // 读取图像
76 | let src = cv.imread(imageData);
77 | let dst = new cv.Mat();
78 | // 灰度化
79 | cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
80 | // 显示图像
81 | cv.imshow(canvasDom, dst);
82 | // 回收对象
83 | src.delete();
84 | dst.delete()
85 | },
86 | imgProcess2(imageData, canvasDom) {
87 | let src = cv.imread(imageData);
88 | let dst = new cv.Mat();
89 |
90 | // 灰度化
91 | cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
92 | // 边缘检测
93 | cv.Canny(src, dst, 50, 100, 3, false);
94 |
95 | cv.imshow(canvasDom, dst);
96 | src.delete();
97 | dst.delete()
98 | },
99 | imgProcess3(imageData, canvasDom) {
100 | let src = cv.imread(imageData);
101 | let dst = new cv.Mat();
102 |
103 | // 灰度化
104 | cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
105 |
106 | var orb = new cv.ORB();
107 | var keypoints = new cv.KeyPointVector();
108 | var descriptors = new cv.Mat();
109 | // 特征点
110 | orb.detect(src, keypoints)
111 | // 特征点的描述因子
112 | orb.compute(src, keypoints, descriptors)
113 | // 绘制特征点
114 | cv.drawKeypoints(src, keypoints, dst)
115 |
116 | cv.imshow(canvasDom, dst);
117 | src.delete();
118 | dst.delete()
119 | },
120 | async btnRun1() {
121 | var _that = this;
122 | // 将图像转换为ImageData
123 | const image1Data = await _that.createImageElement(sampleImage1)
124 | // 设置画布的显示大小
125 | _that.setData({
126 | canvas1Width: image1Data.width,
127 | canvas1Height: image1Data.height,
128 | })
129 | _that.imgProcess1(image1Data, _that.canvasDom)
130 | },
131 | async btnRun2() {
132 | // 同上
133 | var _that = this;
134 | const image1Data = await _that.createImageElement(sampleImage1)
135 | _that.setData({
136 | canvas1Width: image1Data.width,
137 | canvas1Height: image1Data.height,
138 | })
139 | _that.imgProcess2(image1Data, _that.canvasDom)
140 | },
141 | async btnRun3() {
142 | // 同上
143 | var _that = this;
144 | const image1Data = await _that.createImageElement(sampleImage1)
145 | _that.setData({
146 | canvas1Width: image1Data.width,
147 | canvas1Height: image1Data.height,
148 | })
149 | _that.imgProcess3(image1Data, _that.canvasDom)
150 | },
151 | })
152 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 更新日志
2 |
3 | | 日期 | 内容 |
4 | | -- | -- |
5 | | 2022-08-29 | 修复:如果微信开发者工具设置“将JS编译成ES5”,则opencv_exec.js文件提示“Module未定义”的问题。 |
6 | | 2021-12-05 | 新增:微信小程序运行OpenCV的示例。也包含网页运行OpenCV的示例。 |
7 | | 2021-12-03 | 新增:微信小程序运行Go语言的示例。也包含网页运行Go语言的示例。 |
8 |
9 | ## 介绍
10 |
11 | 1、将Go语言编译为WebAssembly,使用微信小程序的WXWebAssembly功能运行WebAssembly。
12 |
13 | 因为Go语言能快速开发WebAssembly,所以使用Go语言能为小程序快速开发WebAssembly。
14 |
15 | 2、在微信小程序中使用WebAssembly版的OpenCV,让我们开发图像视觉。
16 |
17 | [WXWebAssembly官方文档](https://developers.weixin.qq.com/miniprogram/dev/framework/performance/wasm.html)
18 |
19 | ## 网页版
20 |
21 | 在线预览,和小程序版使用的是相同的wasm文件。
22 |
23 | 运行Go
24 |
25 | [https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/go_dev/lesson1.html](https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/go_dev/lesson1.html)
26 |
27 | 运行OpenCV
28 |
29 | [https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/opencv_dev/lesson2.html](https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/opencv_dev/lesson2.html)
30 |
31 | ## 小程序版
32 |
33 | 首页
34 |
35 | 
36 |
37 | ## Go调用小程序的函数
38 |
39 | Go运行时,会调用小程序的console.log()输出信息。
40 |
41 | 
42 |
43 | 在调试窗口的Console面板查看
44 |
45 | 
46 |
47 | ## 小程序调用Go的函数
48 |
49 | 每次点击按钮,次数会增加1。
50 |
51 | 
52 |
53 | ## 小程序调用Go的函数, Go回调小程序。
54 |
55 | 输入内容是可编辑的自定义文本。
56 |
57 | 
58 |
59 | 点击按钮后,输出内容会返回输入的自定义文本。Go语言一侧使用了time.Sleep()和协程,模拟了等待2秒的异步方法调用。
60 |
61 | 
62 |
63 | ## 小程序调用OpenCV的函数。
64 |
65 | 灰度化
66 |
67 | 
68 |
69 | 边缘检测
70 |
71 | 
72 |
73 | 特征点检测
74 |
75 | 
76 |
77 | ## 目录结构
78 |
79 | /:小程序一侧的源代码
80 |
81 | /go_dev:Go一侧的源代码
82 |
83 | /node_dev: Node一侧的源代码
84 |
85 | /miniprogram_npm:微信开发者工具将npm包text-encoder编译后的文件。
86 |
87 | /project.config.json:小程序打包时,排除node_dev、go_dev等目录。
88 |
89 | ```javascript
90 | "packOptions": {
91 | "ignore": [
92 | {
93 | "type": "folder",
94 | "value": "screenshot"
95 | },
96 | {
97 | "type": "folder",
98 | "value": "node_dev"
99 | },
100 | {
101 | "type": "folder",
102 | "value": "go_dev"
103 | }
104 | ]
105 | },
106 |
107 | ```
108 |
109 | ## Go一侧的源代码
110 |
111 | Go一侧和网页版wasm的开发完全一样,没有区别。但不要调用fmt.Println()。
112 |
113 | ```javascript
114 | func main() {
115 | // 创建通道
116 | channel := make(chan int)
117 | // Go调用js的console.log()方法,在开发者工具的Consol面板中查看。
118 | console := js.Global().Get("console")
119 | console.Call("log", "hello, world!")
120 | // 其它代码省略
121 |
122 | // 通道阻塞了main()方法
123 | <-channel
124 |
125 | ```
126 |
127 | 网页端运行Go:/go_dev/lesson1.html
128 |
129 | ```javascript
130 | const go = new global.Go();
131 | try {
132 | const result = await WebAssembly.instantiateStreaming(fetch(wasm_url), go.importObject)
133 | // 运行go程序的main()方法
134 | await go.run(result.instance);
135 | // 其它代码省略
136 | } catch (err) {
137 | console.error('initGo', err)
138 | }
139 |
140 | ```
141 |
142 | 小程序端运行Go:/package_lesson1/index.js
143 |
144 | 注意:wasm_url必须是小程序打包的文件,不能是网络文件和下载后保存的文件。wasm文件会占用小程序打包后的大小,所以小程序每个分包中的wasm文件不能大于2MB。
145 |
146 | ```javascript
147 | const go = new global.Go();
148 | try {
149 | const result = await WXWebAssembly.instantiate(wasm_url, go.importObject)
150 | // 运行go程序的main()方法
151 | await go.run(result.instance);
152 | // 其它代码省略
153 | } catch (err) {
154 | console.error('initGo', err)
155 | }
156 |
157 | ```
158 |
159 | ## Node一侧的源代码
160 |
161 | Node一侧是将.wasm压缩为.wasm.br文件。小程序每个分包限制大小为2MB,但支持.wasm.br压缩文件。使用brotli压缩.wasm文件,能压缩到原始.wasm文件大小的20%至25%。
162 |
163 | 但是brotli压缩速度很慢。1.4MB的.wasm,压缩为.wasm.br,花费时间约6秒。文件更大的.wasm,压缩时间更长,可能花费几分钟。
164 |
165 | ```javascript
166 | // 第三方的wasm版本brotli压缩和解压缩
167 | var brotli = require('wasm-brotli');
168 | // 压缩文件的示例
169 | async function compressFile(){
170 | const content = await readFileAsync('../go_dev/sample.wasm');
171 | const compressedContent = await brotli.compress(content);
172 | // 其它代码省略
173 | }
174 |
175 | ```
176 |
177 | ## 技术难点
178 |
179 | ### 1、小程序分包大小不能超过2MB,Go的Hello World示例编译为wasm文件大小就超过2MB了。
180 |
181 | 解决方法:1、使用brotli工具压缩wasm,压缩率约22%,理论上支持最大8MB的未压缩wasm。
182 |
183 | ### 2、如何修改wasm_exec.js文件?
184 |
185 | 解决方法:修改的位置使用了变量IsWechat,判断是否是小程序环境。具体修改请见源代码。
186 | ```javascript
187 | const IsWechat = true;
188 | ```
189 |
190 | ### 3、小程序没有crypto.getRandomValues()方法。
191 | 解决方法:
192 | ```javascript
193 | if (!global.crypto) {
194 | global.crypto = {
195 | getRandomValues(b) {
196 | let byteRange = 256;
197 | for (var i = 0; i < b.length; i++) {
198 | b[i] = Math.floor(byteRange * Math.random());
199 | }
200 | },
201 | };
202 | }
203 | ```
204 |
205 | ### 4、小程序没有performance.now()方法。
206 | 解决方法:
207 | ```javascript
208 | if (!global.performance) {
209 | global.performance = {
210 | now() {
211 | return Date.now()
212 | },
213 | };
214 | }
215 | ```
216 |
217 | ### 5、小程序没有TextDecoder和TextDecoder对象。
218 | 解决方法:
219 | ```javascript
220 | if (!global.TextEncoder) {
221 | global.TextEncoder = require("text-encoder").TextEncoder;
222 | }
223 | if (!global.TextDecoder) {
224 | global.TextDecoder = require("text-encoder").TextDecoder;
225 | }
226 | ```
227 |
228 | ## Go和小程序互操作
229 |
230 | js.Global() :获取js运行环境的global对象。
231 | ```javascript
232 | console := js.Global().Get("console")
233 | ```
234 |
235 | js.ValueOf :Go对象的值转换为js对象。
236 | ```javascript
237 | func addTotal(this js.Value, args []js.Value) interface{} {
238 | // 其它省略
239 | return js.ValueOf(totalNum)
240 | }
241 | ```
242 |
243 | js.Value :js对象的值转换为Go对象。
244 | ```javascript
245 | func asyncAndCallbak(this js.Value, args []js.Value) interface{} {
246 | // js输入参数
247 | input := args[0].String()
248 | // js回调函数
249 | callback := args[1]
250 | // 其它省略
251 | }
252 | ```
253 |
254 | js.FuncOf :Go函数转换为js函数。
255 | ```javascript
256 | // js调用Go的addTotal()方法
257 | js.Global().Set("addTotal", js.FuncOf(addTotal))
258 | ```
259 |
260 | Object.Call(function1,arg1,arg2) :在js对象上调用方法function1,输入参数arg1、arg2等。
261 | ```javascript
262 | // Go调用js的console.log()方法,在开发者工具的Consol面板中查看。
263 | console := js.Global().Get("console")
264 | console.Call("log", "hello, world!")
265 | ```
266 |
267 | function1.Invoke(arg1,arg2) :调用方法function1,输入参数arg1、arg2等。
268 | ```javascript
269 | func asyncAndCallbak(this js.Value, args []js.Value) interface{} {
270 | // js回调函数
271 | callback := args[1]
272 | // 运行js回调函数
273 | callback.Invoke(result)
274 | // 其它省略
275 | }
276 | ```
277 |
278 | Object.Get(prop1) :获取js对象的子对象、属性、方法等。
279 | ```javascript
280 | console := js.Global().Get("console")
281 | ```
282 |
283 | 注意:使用js.Global().Get("console"),需要在小程序基础类库的global对象上,增加console对象。
284 | ```javascript
285 | async onReady() {
286 | // 在小程序基础类库的global对象上,增加console对象。
287 | global.console = console
288 | // 使用小程序类库的WXWebAssembly,初始化Go运行环境。
289 | await this.initGo()
290 | },
291 | ```
292 |
293 | Object.Set(prop1,value1):设置js对象的子对象、属性、方法等。
294 | ```javascript
295 | // 在js运行环境,设置Go的addTotal()方法
296 | js.Global().Set("addTotal", js.FuncOf(addTotal))
297 | ```
298 |
299 |
300 | ## Go和JavaScript的变量类型
301 |
302 | ```javascript
303 | | Go | JavaScript |
304 | | ---------------------- | ---------------------- |
305 | | js.Value | [its value] |
306 | | js.Func | function |
307 | | nil | null |
308 | | bool | boolean |
309 | | integers and floats | number |
310 | | string | string |
311 | | []interface{} | new array |
312 | | map[string]interface{} | new object |
313 |
314 | ```
315 |
316 | ## 已知问题
317 |
318 | ### Q1:syscall/js: call of Value.Invoke on undefined
319 |
320 | A:使用fmt.Println("hello,world")会发生该错误,但使用fmt.Sprintf("%d", 123) 正常。不要使用fmt.Println()方法,而使用console.log()方法向小程序输出调试信息。
321 |
322 | ### Q2:LinkError: WebAssembly.instantiate(): Import #4 module="go"
323 |
324 | A: wasm_exec.js中的方法有的能去掉,有的不能去掉。 如果修改wasm_exec.js,则importObject.go对象中的所有方法名称需要保留。
325 |
326 | ### Q3:从Go调用小程序的wx.showModal({title:"123"})等API发生错误
327 |
328 | A:如果运行wx := js.Global().Get("wx");wx.Call("showModal", "");,则可以显示一个空白的对话框。Go可以调用小程序API,问题出在wx.Call("showModal", object)的输入参数是Object类型。
329 |
330 | 在网页端WebAssembly,Go能正常传递Object给网页。
331 |
332 | 在小程序端WebAssembly,Go无法正常传递Object给小程序。将方法的输入参数从Object类型暂时换成其他变量类型。
333 |
334 | ### Q4:作者的wasm_exec.js与读者的Go版本不匹配
335 |
336 | A:作者的wasm_exec.js来自 “/Go安装目录/misc/wasm/wasm_exec.js”,版本号是1.16.3。如果与作者的Go版本号不同,则可以根据“\package_lesson1\assets\wasm_exec.js”文件中的变量“IsWechat”,修改不同版本号的wasm_exec.js文件中6处代码即可。
--------------------------------------------------------------------------------
/style/weui.wxss:
--------------------------------------------------------------------------------
1 | /*!
2 | * WeUI v1.1.1 (https://github.com/weui/weui-wxss)
3 | * Copyright 2017 Tencent, Inc.
4 | * Licensed under the MIT license
5 | */
6 | page{line-height:1.6;font-family:-apple-system-font,Helvetica Neue,sans-serif}icon{vertical-align:middle}.weui-cells{position:relative;margin-top:1.17647059em;background-color:#fff;line-height:1.41176471;font-size:17px}.weui-cells:before{top:0;border-top:1rpx solid #d9d9d9}.weui-cells:after,.weui-cells:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#d9d9d9}.weui-cells:after{bottom:0;border-bottom:1rpx solid #d9d9d9}.weui-cells__title{margin-top:.77em;margin-bottom:.3em;padding-left:15px;padding-right:15px;color:#999;font-size:14px}.weui-cells_after-title{margin-top:0}.weui-cells__tips{margin-top:.3em;color:#999;padding-left:15px;padding-right:15px;font-size:14px}.weui-cell{padding:10px 15px;position:relative;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-cell:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1rpx solid #d9d9d9;color:#d9d9d9;left:15px}.weui-cell:first-child:before{display:none}.weui-cell_active{background-color:#ececec}.weui-cell_primary{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start}.weui-cell__bd{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-cell__ft{text-align:right;color:#999}.weui-cell_access{color:inherit}.weui-cell__ft_in-access{padding-right:13px;position:relative}.weui-cell__ft_in-access:after{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;margin-top:-4px;right:2px}.weui-cell_link{color:#586c94;font-size:14px}.weui-cell_link:active{background-color:#ececec}.weui-cell_link:first-child:before{display:block}.weui-icon-radio{margin-left:3.2px;margin-right:3.2px}.weui-icon-checkbox_circle,.weui-icon-checkbox_success{margin-left:4.6px;margin-right:4.6px}.weui-check__label:active{background-color:#ececec}.weui-check{position:absolute;left:-9999px}.weui-check__hd_in-checkbox{padding-right:.35em}.weui-cell__ft_in-radio{padding-left:.35em}.weui-cell_input{padding-top:0;padding-bottom:0}.weui-label{width:105px;word-wrap:break-word;word-break:break-all}.weui-input{height:2.58823529em;min-height:2.58823529em;line-height:2.58823529em}.weui-toptips{position:fixed;-webkit-transform:translateZ(0);transform:translateZ(0);top:0;left:0;right:0;padding:5px;font-size:14px;text-align:center;color:#fff;z-index:5000;word-wrap:break-word;word-break:break-all}.weui-toptips_warn{background-color:#e64340}.weui-textarea{display:block;width:100%}.weui-textarea-counter{color:#b2b2b2;text-align:right}.weui-cell_warn,.weui-textarea-counter_warn{color:#e64340}.weui-form-preview{position:relative;background-color:#fff}.weui-form-preview:before{top:0;border-top:1rpx solid #d9d9d9}.weui-form-preview:after,.weui-form-preview:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#d9d9d9}.weui-form-preview:after{bottom:0;border-bottom:1rpx solid #d9d9d9}.weui-form-preview__value{font-size:14px}.weui-form-preview__value_in-hd{font-size:26px}.weui-form-preview__hd{position:relative;padding:10px 15px;text-align:right;line-height:2.5em}.weui-form-preview__hd:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1rpx solid #d9d9d9;color:#d9d9d9;left:15px}.weui-form-preview__bd{padding:10px 15px;font-size:.9em;text-align:right;color:#999;line-height:2}.weui-form-preview__ft{position:relative;line-height:50px;display:-webkit-box;display:-webkit-flex;display:flex}.weui-form-preview__ft:after{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1rpx solid #d5d5d6;color:#d5d5d6}.weui-form-preview__item{overflow:hidden}.weui-form-preview__label{float:left;margin-right:1em;min-width:4em;color:#999;text-align:justify;text-align-last:justify}.weui-form-preview__value{display:block;overflow:hidden;word-break:normal;word-wrap:break-word}.weui-form-preview__btn{position:relative;display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;color:#3cc51f;text-align:center}.weui-form-preview__btn:after{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1rpx solid #d5d5d6;color:#d5d5d6}.weui-form-preview__btn:first-child:after{display:none}.weui-form-preview__btn_active{background-color:#eee}.weui-form-preview__btn_default{color:#999}.weui-form-preview__btn_primary{color:#0bb20c}.weui-cell_select{padding:0}.weui-select{position:relative;padding-left:15px;padding-right:30px;height:2.58823529em;min-height:2.58823529em;line-height:2.58823529em;border-right:1rpx solid #d9d9d9}.weui-select:before{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;right:15px;margin-top:-4px}.weui-select_in-select-after{padding-left:0}.weui-cell__bd_in-select-before,.weui-cell__hd_in-select-after{padding-left:15px}.weui-cell_vcode{padding-right:0}.weui-vcode-btn,.weui-vcode-img{margin-left:5px;height:2.58823529em;vertical-align:middle}.weui-vcode-btn{display:inline-block;padding:0 .6em 0 .7em;border-left:1px solid #e5e5e5;line-height:2.58823529em;font-size:17px;color:#3cc51f;white-space:nowrap}.weui-vcode-btn:active{color:#52a341}.weui-cell_switch{padding-top:6px;padding-bottom:6px}.weui-uploader__hd{display:-webkit-box;display:-webkit-flex;display:flex;padding-bottom:10px;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-uploader__title{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-uploader__info{color:#b2b2b2}.weui-uploader__bd{margin-bottom:-4px;margin-right:-9px;overflow:hidden}.weui-uploader__file{float:left;margin-right:9px;margin-bottom:9px}.weui-uploader__img{display:block;width:79px;height:79px}.weui-uploader__file_status{position:relative}.weui-uploader__file_status:before{content:" ";position:absolute;top:0;right:0;bottom:0;left:0;background-color:rgba(0,0,0,.5)}.weui-uploader__file-content{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#fff}.weui-uploader__input-box{float:left;position:relative;margin-right:9px;margin-bottom:9px;width:77px;height:77px;border:1px solid #d9d9d9}.weui-uploader__input-box:after,.weui-uploader__input-box:before{content:" ";position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);background-color:#d9d9d9}.weui-uploader__input-box:before{width:2px;height:39.5px}.weui-uploader__input-box:after{width:39.5px;height:2px}.weui-uploader__input-box:active{border-color:#999}.weui-uploader__input-box:active:after,.weui-uploader__input-box:active:before{background-color:#999}.weui-uploader__input{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;opacity:0}.weui-article{padding:20px 15px;font-size:15px}.weui-article__section{margin-bottom:1.5em}.weui-article__h1{font-size:18px;font-weight:400;margin-bottom:.9em}.weui-article__h2{font-size:16px;font-weight:400;margin-bottom:.34em}.weui-article__h3{font-weight:400;font-size:15px;margin-bottom:.34em}.weui-article__p{margin:0 0 .8em}.weui-msg{padding-top:36px;text-align:center}.weui-msg__link{display:inline;color:#586c94}.weui-msg__icon-area{margin-bottom:30px}.weui-msg__text-area{margin-bottom:25px;padding:0 20px}.weui-msg__title{margin-bottom:5px;font-weight:400;font-size:20px}.weui-msg__desc{font-size:14px;color:#999}.weui-msg__opr-area{margin-bottom:25px}.weui-msg__extra-area{margin-bottom:15px;font-size:14px;color:#999}@media screen and (min-height:438px){.weui-msg__extra-area{position:fixed;left:0;bottom:0;width:100%;text-align:center}}.weui-flex{display:-webkit-box;display:-webkit-flex;display:flex}.weui-flex__item{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-btn{margin-top:15px}.weui-btn:first-child{margin-top:0}.weui-btn-area{margin:1.17647059em 15px .3em}.weui-agree{display:block;padding:.5em 15px;font-size:13px}.weui-agree__text{color:#999}.weui-agree__link{display:inline;color:#586c94}.weui-agree__checkbox{position:absolute;left:-9999px}.weui-agree__checkbox-icon{position:relative;top:2px;display:inline-block;border:1px solid #d1d1d1;background-color:#fff;border-radius:3px;width:11px;height:11px}.weui-agree__checkbox-icon-check{position:absolute;top:1px;left:1px}.weui-footer{color:#999;font-size:14px;text-align:center}.weui-footer_fixed-bottom{position:fixed;bottom:.52em;left:0;right:0}.weui-footer__links{font-size:0}.weui-footer__link{display:inline-block;vertical-align:top;margin:0 .62em;position:relative;font-size:14px;color:#586c94}.weui-footer__link:before{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1rpx solid #c7c7c7;color:#c7c7c7;left:-.65em;top:.36em;bottom:.36em}.weui-footer__link:first-child:before{display:none}.weui-footer__text{padding:0 .34em;font-size:12px}.weui-grids{border-top:1rpx solid #d9d9d9;border-left:1rpx solid #d9d9d9;overflow:hidden}.weui-grid{position:relative;float:left;padding:20px 10px;width:33.33333333%;box-sizing:border-box;border-right:1rpx solid #d9d9d9;border-bottom:1rpx solid #d9d9d9}.weui-grid_active{background-color:#ececec}.weui-grid__icon{display:block;width:28px;height:28px;margin:0 auto}.weui-grid__label{margin-top:5px;display:block;text-align:center;color:#000;font-size:14px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.weui-loading{margin:0 5px;width:20px;height:20px;display:inline-block;vertical-align:middle;-webkit-animation:a 1s steps(12) infinite;animation:a 1s steps(12) infinite;background:transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=) no-repeat;background-size:100%}.weui-loading.weui-loading_transparent{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 100 100'%3E%3Cpath fill='none' d='M0 0h100v100H0z'/%3E%3Crect xmlns='http://www.w3.org/2000/svg' width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.56)' rx='5' ry='5' transform='translate(0 -30)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.5)' rx='5' ry='5' transform='rotate(30 105.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.43)' rx='5' ry='5' transform='rotate(60 75.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.38)' rx='5' ry='5' transform='rotate(90 65 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.32)' rx='5' ry='5' transform='rotate(120 58.66 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.28)' rx='5' ry='5' transform='rotate(150 54.02 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.25)' rx='5' ry='5' transform='rotate(180 50 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.2)' rx='5' ry='5' transform='rotate(-150 45.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.17)' rx='5' ry='5' transform='rotate(-120 41.34 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.14)' rx='5' ry='5' transform='rotate(-90 35 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.1)' rx='5' ry='5' transform='rotate(-60 24.02 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.03)' rx='5' ry='5' transform='rotate(-30 -5.98 65)'/%3E%3C/svg%3E")}@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.weui-badge{display:inline-block;padding:.15em .4em;min-width:8px;border-radius:18px;background-color:#e64340;color:#fff;line-height:1.2;text-align:center;font-size:12px;vertical-align:middle}.weui-badge_dot{padding:.4em;min-width:0}.weui-loadmore{width:65%;margin:1.5em auto;line-height:1.6em;font-size:14px;text-align:center}.weui-loadmore__tips{display:inline-block;vertical-align:middle}.weui-loadmore_line{border-top:1px solid #e5e5e5;margin-top:2.4em}.weui-loadmore__tips_in-line{position:relative;top:-.9em;padding:0 .55em;background-color:#fff;color:#999}.weui-loadmore__tips_in-dot{position:relative;padding:0 .16em;width:4px;height:1.6em}.weui-loadmore__tips_in-dot:before{content:" ";position:absolute;top:50%;left:50%;margin-top:-1px;margin-left:-2px;width:4px;height:4px;border-radius:50%;background-color:#e5e5e5}.weui-panel{background-color:#fff;margin-top:10px;position:relative;overflow:hidden}.weui-panel:first-child{margin-top:0}.weui-panel:before{top:0;border-top:1rpx solid #e5e5e5}.weui-panel:after,.weui-panel:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#e5e5e5}.weui-panel:after{bottom:0;border-bottom:1rpx solid #e5e5e5}.weui-panel__hd{padding:14px 15px 10px;color:#999;font-size:13px;position:relative}.weui-panel__hd:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1rpx solid #e5e5e5;color:#e5e5e5;left:15px}.weui-media-box{padding:15px;position:relative}.weui-media-box:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1rpx solid #e5e5e5;color:#e5e5e5;left:15px}.weui-media-box:first-child:before{display:none}.weui-media-box__title{font-weight:400;font-size:17px;width:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-wrap:normal;word-wrap:break-word;word-break:break-all}.weui-media-box__desc{color:#999;font-size:13px;line-height:1.2;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.weui-media-box__info{margin-top:15px;padding-bottom:5px;font-size:13px;color:#cecece;line-height:1em;list-style:none;overflow:hidden}.weui-media-box__info__meta{float:left;padding-right:1em}.weui-media-box__info__meta_extra{padding-left:1em;border-left:1px solid #cecece}.weui-media-box__title_in-text{margin-bottom:8px}.weui-media-box_appmsg{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-media-box__thumb{width:100%;height:100%;vertical-align:top}.weui-media-box__hd_in-appmsg{margin-right:.8em;width:60px;height:60px;line-height:60px;text-align:center}.weui-media-box__bd_in-appmsg{-webkit-box-flex:1;-webkit-flex:1;flex:1;min-width:0}.weui-media-box_small-appmsg{padding:0}.weui-cells_in-small-appmsg{margin-top:0}.weui-cells_in-small-appmsg:before{display:none}.weui-progress{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-progress__bar{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-progress__opr{margin-left:15px;font-size:0}.weui-navbar{display:-webkit-box;display:-webkit-flex;display:flex;position:absolute;z-index:500;top:0;width:100%;border-bottom:1rpx solid #ccc}.weui-navbar__item{position:relative;display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;padding:13px 0;text-align:center;font-size:0}.weui-navbar__item.weui-bar__item_on{color:#1aad19}.weui-navbar__slider{position:absolute;content:" ";left:0;bottom:0;width:6em;height:3px;background-color:#1aad19;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.weui-navbar__title{display:inline-block;font-size:15px;max-width:8em;width:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-wrap:normal}.weui-tab{position:relative;height:100%}.weui-tab__panel{box-sizing:border-box;height:100%;padding-top:50px;overflow:auto;-webkit-overflow-scrolling:touch}.weui-search-bar{position:relative;padding:8px 10px;display:-webkit-box;display:-webkit-flex;display:flex;box-sizing:border-box;background-color:#efeff4;border-top:1rpx solid #d7d6dc;border-bottom:1rpx solid #d7d6dc}.weui-icon-search{margin-right:8px;font-size:inherit}.weui-icon-search_in-box{position:absolute;left:10px;top:7px}.weui-search-bar__text{display:inline-block;font-size:14px;vertical-align:middle}.weui-search-bar__form{position:relative;-webkit-box-flex:1;-webkit-flex:auto;flex:auto;border-radius:5px;background:#fff;border:1rpx solid #e6e6ea}.weui-search-bar__box{position:relative;padding-left:30px;padding-right:30px;width:100%;box-sizing:border-box;z-index:1}.weui-search-bar__input{height:28px;line-height:28px;font-size:14px}.weui-icon-clear{position:absolute;top:0;right:0;padding:7px 8px;font-size:0}.weui-search-bar__label{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;border-radius:3px;text-align:center;color:#9b9b9b;background:#fff;line-height:28px}.weui-search-bar__cancel-btn{margin-left:10px;line-height:28px;color:#09bb07;white-space:nowrap}
--------------------------------------------------------------------------------
/go_dev/assets/wasm_exec.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | (() => {
6 | // Map multiple JavaScript environments to a single common API,
7 | // preferring web standards over Node.js API.
8 | //
9 | // Environments considered:
10 | // - Browsers
11 | // - Node.js
12 | // - Electron
13 | // - Parcel
14 | // - Webpack
15 |
16 | if (typeof global !== "undefined") {
17 | // global already exists
18 | } else if (typeof window !== "undefined") {
19 | window.global = window;
20 | } else if (typeof self !== "undefined") {
21 | self.global = self;
22 | } else {
23 | throw new Error("cannot export Go (neither global, window nor self is defined)");
24 | }
25 |
26 | if (!global.require && typeof require !== "undefined") {
27 | global.require = require;
28 | }
29 |
30 | if (!global.fs && global.require) {
31 | const fs = require("fs");
32 | if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
33 | global.fs = fs;
34 | }
35 | }
36 |
37 | const enosys = () => {
38 | const err = new Error("not implemented");
39 | err.code = "ENOSYS";
40 | return err;
41 | };
42 |
43 | if (!global.fs) {
44 | let outputBuf = "";
45 | global.fs = {
46 | constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
47 | writeSync(fd, buf) {
48 | outputBuf += decoder.decode(buf);
49 | const nl = outputBuf.lastIndexOf("\n");
50 | if (nl != -1) {
51 | console.log(outputBuf.substr(0, nl));
52 | outputBuf = outputBuf.substr(nl + 1);
53 | }
54 | return buf.length;
55 | },
56 | write(fd, buf, offset, length, position, callback) {
57 | if (offset !== 0 || length !== buf.length || position !== null) {
58 | callback(enosys());
59 | return;
60 | }
61 | const n = this.writeSync(fd, buf);
62 | callback(null, n);
63 | },
64 | chmod(path, mode, callback) { callback(enosys()); },
65 | chown(path, uid, gid, callback) { callback(enosys()); },
66 | close(fd, callback) { callback(enosys()); },
67 | fchmod(fd, mode, callback) { callback(enosys()); },
68 | fchown(fd, uid, gid, callback) { callback(enosys()); },
69 | fstat(fd, callback) { callback(enosys()); },
70 | fsync(fd, callback) { callback(null); },
71 | ftruncate(fd, length, callback) { callback(enosys()); },
72 | lchown(path, uid, gid, callback) { callback(enosys()); },
73 | link(path, link, callback) { callback(enosys()); },
74 | lstat(path, callback) { callback(enosys()); },
75 | mkdir(path, perm, callback) { callback(enosys()); },
76 | open(path, flags, mode, callback) { callback(enosys()); },
77 | read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
78 | readdir(path, callback) { callback(enosys()); },
79 | readlink(path, callback) { callback(enosys()); },
80 | rename(from, to, callback) { callback(enosys()); },
81 | rmdir(path, callback) { callback(enosys()); },
82 | stat(path, callback) { callback(enosys()); },
83 | symlink(path, link, callback) { callback(enosys()); },
84 | truncate(path, length, callback) { callback(enosys()); },
85 | unlink(path, callback) { callback(enosys()); },
86 | utimes(path, atime, mtime, callback) { callback(enosys()); },
87 | };
88 | }
89 |
90 | if (!global.process) {
91 | global.process = {
92 | getuid() { return -1; },
93 | getgid() { return -1; },
94 | geteuid() { return -1; },
95 | getegid() { return -1; },
96 | getgroups() { throw enosys(); },
97 | pid: -1,
98 | ppid: -1,
99 | umask() { throw enosys(); },
100 | cwd() { throw enosys(); },
101 | chdir() { throw enosys(); },
102 | }
103 | }
104 |
105 | if (!global.crypto && global.require) {
106 | const nodeCrypto = require("crypto");
107 | global.crypto = {
108 | getRandomValues(b) {
109 | nodeCrypto.randomFillSync(b);
110 | },
111 | };
112 | }
113 | if (!global.crypto) {
114 | throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
115 | }
116 |
117 | if (!global.performance) {
118 | global.performance = {
119 | now() {
120 | const [sec, nsec] = process.hrtime();
121 | return sec * 1000 + nsec / 1000000;
122 | },
123 | };
124 | }
125 |
126 | if (!global.TextEncoder && global.require) {
127 | global.TextEncoder = require("util").TextEncoder;
128 | }
129 | if (!global.TextEncoder) {
130 | throw new Error("global.TextEncoder is not available, polyfill required");
131 | }
132 |
133 | if (!global.TextDecoder && global.require) {
134 | global.TextDecoder = require("util").TextDecoder;
135 | }
136 | if (!global.TextDecoder) {
137 | throw new Error("global.TextDecoder is not available, polyfill required");
138 | }
139 |
140 | // End of polyfills for common API.
141 |
142 | const encoder = new TextEncoder("utf-8");
143 | const decoder = new TextDecoder("utf-8");
144 |
145 | global.Go = class {
146 | constructor() {
147 | this.argv = ["js"];
148 | this.env = {};
149 | this.exit = (code) => {
150 | if (code !== 0) {
151 | console.warn("exit code:", code);
152 | }
153 | };
154 | this._exitPromise = new Promise((resolve) => {
155 | this._resolveExitPromise = resolve;
156 | });
157 | this._pendingEvent = null;
158 | this._scheduledTimeouts = new Map();
159 | this._nextCallbackTimeoutID = 1;
160 |
161 | const setInt64 = (addr, v) => {
162 | this.mem.setUint32(addr + 0, v, true);
163 | this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
164 | }
165 |
166 | const getInt64 = (addr) => {
167 | const low = this.mem.getUint32(addr + 0, true);
168 | const high = this.mem.getInt32(addr + 4, true);
169 | return low + high * 4294967296;
170 | }
171 |
172 | const loadValue = (addr) => {
173 | const f = this.mem.getFloat64(addr, true);
174 | if (f === 0) {
175 | return undefined;
176 | }
177 | if (!isNaN(f)) {
178 | return f;
179 | }
180 |
181 | const id = this.mem.getUint32(addr, true);
182 | return this._values[id];
183 | }
184 |
185 | const storeValue = (addr, v) => {
186 | const nanHead = 0x7FF80000;
187 |
188 | if (typeof v === "number" && v !== 0) {
189 | if (isNaN(v)) {
190 | this.mem.setUint32(addr + 4, nanHead, true);
191 | this.mem.setUint32(addr, 0, true);
192 | return;
193 | }
194 | this.mem.setFloat64(addr, v, true);
195 | return;
196 | }
197 |
198 | if (v === undefined) {
199 | this.mem.setFloat64(addr, 0, true);
200 | return;
201 | }
202 |
203 | let id = this._ids.get(v);
204 | if (id === undefined) {
205 | id = this._idPool.pop();
206 | if (id === undefined) {
207 | id = this._values.length;
208 | }
209 | this._values[id] = v;
210 | this._goRefCounts[id] = 0;
211 | this._ids.set(v, id);
212 | }
213 | this._goRefCounts[id]++;
214 | let typeFlag = 0;
215 | switch (typeof v) {
216 | case "object":
217 | if (v !== null) {
218 | typeFlag = 1;
219 | }
220 | break;
221 | case "string":
222 | typeFlag = 2;
223 | break;
224 | case "symbol":
225 | typeFlag = 3;
226 | break;
227 | case "function":
228 | typeFlag = 4;
229 | break;
230 | }
231 | this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
232 | this.mem.setUint32(addr, id, true);
233 | }
234 |
235 | const loadSlice = (addr) => {
236 | const array = getInt64(addr + 0);
237 | const len = getInt64(addr + 8);
238 | return new Uint8Array(this._inst.exports.mem.buffer, array, len);
239 | }
240 |
241 | const loadSliceOfValues = (addr) => {
242 | const array = getInt64(addr + 0);
243 | const len = getInt64(addr + 8);
244 | const a = new Array(len);
245 | for (let i = 0; i < len; i++) {
246 | a[i] = loadValue(array + i * 8);
247 | }
248 | return a;
249 | }
250 |
251 | const loadString = (addr) => {
252 | const saddr = getInt64(addr + 0);
253 | const len = getInt64(addr + 8);
254 | return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
255 | }
256 |
257 | const timeOrigin = Date.now() - performance.now();
258 | this.importObject = {
259 | go: {
260 | // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
261 | // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
262 | // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
263 | // This changes the SP, thus we have to update the SP used by the imported function.
264 |
265 | // func wasmExit(code int32)
266 | "runtime.wasmExit": (sp) => {
267 | sp >>>= 0;
268 | const code = this.mem.getInt32(sp + 8, true);
269 | this.exited = true;
270 | delete this._inst;
271 | delete this._values;
272 | delete this._goRefCounts;
273 | delete this._ids;
274 | delete this._idPool;
275 | this.exit(code);
276 | },
277 |
278 | // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
279 | "runtime.wasmWrite": (sp) => {
280 | sp >>>= 0;
281 | const fd = getInt64(sp + 8);
282 | const p = getInt64(sp + 16);
283 | const n = this.mem.getInt32(sp + 24, true);
284 | fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
285 | },
286 |
287 | // func resetMemoryDataView()
288 | "runtime.resetMemoryDataView": (sp) => {
289 | sp >>>= 0;
290 | this.mem = new DataView(this._inst.exports.mem.buffer);
291 | },
292 |
293 | // func nanotime1() int64
294 | "runtime.nanotime1": (sp) => {
295 | sp >>>= 0;
296 | setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
297 | },
298 |
299 | // func walltime1() (sec int64, nsec int32)
300 | "runtime.walltime1": (sp) => {
301 | sp >>>= 0;
302 | const msec = (new Date).getTime();
303 | setInt64(sp + 8, msec / 1000);
304 | this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
305 | },
306 |
307 | // func scheduleTimeoutEvent(delay int64) int32
308 | "runtime.scheduleTimeoutEvent": (sp) => {
309 | sp >>>= 0;
310 | const id = this._nextCallbackTimeoutID;
311 | this._nextCallbackTimeoutID++;
312 | this._scheduledTimeouts.set(id, setTimeout(
313 | () => {
314 | this._resume();
315 | while (this._scheduledTimeouts.has(id)) {
316 | // for some reason Go failed to register the timeout event, log and try again
317 | // (temporary workaround for https://github.com/golang/go/issues/28975)
318 | console.warn("scheduleTimeoutEvent: missed timeout event");
319 | this._resume();
320 | }
321 | },
322 | getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
323 | ));
324 | this.mem.setInt32(sp + 16, id, true);
325 | },
326 |
327 | // func clearTimeoutEvent(id int32)
328 | "runtime.clearTimeoutEvent": (sp) => {
329 | sp >>>= 0;
330 | const id = this.mem.getInt32(sp + 8, true);
331 | clearTimeout(this._scheduledTimeouts.get(id));
332 | this._scheduledTimeouts.delete(id);
333 | },
334 |
335 | // func getRandomData(r []byte)
336 | "runtime.getRandomData": (sp) => {
337 | sp >>>= 0;
338 | crypto.getRandomValues(loadSlice(sp + 8));
339 | },
340 |
341 | // func finalizeRef(v ref)
342 | "syscall/js.finalizeRef": (sp) => {
343 | sp >>>= 0;
344 | const id = this.mem.getUint32(sp + 8, true);
345 | this._goRefCounts[id]--;
346 | if (this._goRefCounts[id] === 0) {
347 | const v = this._values[id];
348 | this._values[id] = null;
349 | this._ids.delete(v);
350 | this._idPool.push(id);
351 | }
352 | },
353 |
354 | // func stringVal(value string) ref
355 | "syscall/js.stringVal": (sp) => {
356 | sp >>>= 0;
357 | storeValue(sp + 24, loadString(sp + 8));
358 | },
359 |
360 | // func valueGet(v ref, p string) ref
361 | "syscall/js.valueGet": (sp) => {
362 | sp >>>= 0;
363 | const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
364 | sp = this._inst.exports.getsp() >>> 0; // see comment above
365 | storeValue(sp + 32, result);
366 | },
367 |
368 | // func valueSet(v ref, p string, x ref)
369 | "syscall/js.valueSet": (sp) => {
370 | sp >>>= 0;
371 | Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
372 | },
373 |
374 | // func valueDelete(v ref, p string)
375 | "syscall/js.valueDelete": (sp) => {
376 | sp >>>= 0;
377 | Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
378 | },
379 |
380 | // func valueIndex(v ref, i int) ref
381 | "syscall/js.valueIndex": (sp) => {
382 | sp >>>= 0;
383 | storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
384 | },
385 |
386 | // valueSetIndex(v ref, i int, x ref)
387 | "syscall/js.valueSetIndex": (sp) => {
388 | sp >>>= 0;
389 | Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
390 | },
391 |
392 | // func valueCall(v ref, m string, args []ref) (ref, bool)
393 | "syscall/js.valueCall": (sp) => {
394 | sp >>>= 0;
395 | try {
396 | const v = loadValue(sp + 8);
397 | const m = Reflect.get(v, loadString(sp + 16));
398 | const args = loadSliceOfValues(sp + 32);
399 | const result = Reflect.apply(m, v, args);
400 | sp = this._inst.exports.getsp() >>> 0; // see comment above
401 | storeValue(sp + 56, result);
402 | this.mem.setUint8(sp + 64, 1);
403 | } catch (err) {
404 | storeValue(sp + 56, err);
405 | this.mem.setUint8(sp + 64, 0);
406 | }
407 | },
408 |
409 | // func valueInvoke(v ref, args []ref) (ref, bool)
410 | "syscall/js.valueInvoke": (sp) => {
411 | sp >>>= 0;
412 | try {
413 | const v = loadValue(sp + 8);
414 | const args = loadSliceOfValues(sp + 16);
415 | const result = Reflect.apply(v, undefined, args);
416 | sp = this._inst.exports.getsp() >>> 0; // see comment above
417 | storeValue(sp + 40, result);
418 | this.mem.setUint8(sp + 48, 1);
419 | } catch (err) {
420 | storeValue(sp + 40, err);
421 | this.mem.setUint8(sp + 48, 0);
422 | }
423 | },
424 |
425 | // func valueNew(v ref, args []ref) (ref, bool)
426 | "syscall/js.valueNew": (sp) => {
427 | sp >>>= 0;
428 | try {
429 | const v = loadValue(sp + 8);
430 | const args = loadSliceOfValues(sp + 16);
431 | const result = Reflect.construct(v, args);
432 | sp = this._inst.exports.getsp() >>> 0; // see comment above
433 | storeValue(sp + 40, result);
434 | this.mem.setUint8(sp + 48, 1);
435 | } catch (err) {
436 | storeValue(sp + 40, err);
437 | this.mem.setUint8(sp + 48, 0);
438 | }
439 | },
440 |
441 | // func valueLength(v ref) int
442 | "syscall/js.valueLength": (sp) => {
443 | sp >>>= 0;
444 | setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
445 | },
446 |
447 | // valuePrepareString(v ref) (ref, int)
448 | "syscall/js.valuePrepareString": (sp) => {
449 | sp >>>= 0;
450 | const str = encoder.encode(String(loadValue(sp + 8)));
451 | storeValue(sp + 16, str);
452 | setInt64(sp + 24, str.length);
453 | },
454 |
455 | // valueLoadString(v ref, b []byte)
456 | "syscall/js.valueLoadString": (sp) => {
457 | sp >>>= 0;
458 | const str = loadValue(sp + 8);
459 | loadSlice(sp + 16).set(str);
460 | },
461 |
462 | // func valueInstanceOf(v ref, t ref) bool
463 | "syscall/js.valueInstanceOf": (sp) => {
464 | sp >>>= 0;
465 | this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
466 | },
467 |
468 | // func copyBytesToGo(dst []byte, src ref) (int, bool)
469 | "syscall/js.copyBytesToGo": (sp) => {
470 | sp >>>= 0;
471 | const dst = loadSlice(sp + 8);
472 | const src = loadValue(sp + 32);
473 | if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
474 | this.mem.setUint8(sp + 48, 0);
475 | return;
476 | }
477 | const toCopy = src.subarray(0, dst.length);
478 | dst.set(toCopy);
479 | setInt64(sp + 40, toCopy.length);
480 | this.mem.setUint8(sp + 48, 1);
481 | },
482 |
483 | // func copyBytesToJS(dst ref, src []byte) (int, bool)
484 | "syscall/js.copyBytesToJS": (sp) => {
485 | sp >>>= 0;
486 | const dst = loadValue(sp + 8);
487 | const src = loadSlice(sp + 16);
488 | if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
489 | this.mem.setUint8(sp + 48, 0);
490 | return;
491 | }
492 | const toCopy = src.subarray(0, dst.length);
493 | dst.set(toCopy);
494 | setInt64(sp + 40, toCopy.length);
495 | this.mem.setUint8(sp + 48, 1);
496 | },
497 |
498 | "debug": (value) => {
499 | console.log(value);
500 | },
501 | }
502 | };
503 | }
504 |
505 | async run(instance) {
506 | if (!(instance instanceof WebAssembly.Instance)) {
507 | throw new Error("Go.run: WebAssembly.Instance expected");
508 | }
509 | this._inst = instance;
510 | this.mem = new DataView(this._inst.exports.mem.buffer);
511 | this._values = [ // JS values that Go currently has references to, indexed by reference id
512 | NaN,
513 | 0,
514 | null,
515 | true,
516 | false,
517 | global,
518 | this,
519 | ];
520 | this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
521 | this._ids = new Map([ // mapping from JS values to reference ids
522 | [0, 1],
523 | [null, 2],
524 | [true, 3],
525 | [false, 4],
526 | [global, 5],
527 | [this, 6],
528 | ]);
529 | this._idPool = []; // unused ids that have been garbage collected
530 | this.exited = false; // whether the Go program has exited
531 |
532 | // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
533 | let offset = 4096;
534 |
535 | const strPtr = (str) => {
536 | const ptr = offset;
537 | const bytes = encoder.encode(str + "\0");
538 | new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
539 | offset += bytes.length;
540 | if (offset % 8 !== 0) {
541 | offset += 8 - (offset % 8);
542 | }
543 | return ptr;
544 | };
545 |
546 | const argc = this.argv.length;
547 |
548 | const argvPtrs = [];
549 | this.argv.forEach((arg) => {
550 | argvPtrs.push(strPtr(arg));
551 | });
552 | argvPtrs.push(0);
553 |
554 | const keys = Object.keys(this.env).sort();
555 | keys.forEach((key) => {
556 | argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
557 | });
558 | argvPtrs.push(0);
559 |
560 | const argv = offset;
561 | argvPtrs.forEach((ptr) => {
562 | this.mem.setUint32(offset, ptr, true);
563 | this.mem.setUint32(offset + 4, 0, true);
564 | offset += 8;
565 | });
566 |
567 | this._inst.exports.run(argc, argv);
568 | if (this.exited) {
569 | this._resolveExitPromise();
570 | }
571 | await this._exitPromise;
572 | }
573 |
574 | _resume() {
575 | if (this.exited) {
576 | throw new Error("Go program has already exited");
577 | }
578 | this._inst.exports.resume();
579 | if (this.exited) {
580 | this._resolveExitPromise();
581 | }
582 | }
583 |
584 | _makeFuncWrapper(id) {
585 | const go = this;
586 | return function () {
587 | const event = { id: id, this: this, args: arguments };
588 | go._pendingEvent = event;
589 | go._resume();
590 | return event.result;
591 | };
592 | }
593 | }
594 |
595 | if (
596 | typeof module !== "undefined" &&
597 | global.require &&
598 | global.require.main === module &&
599 | global.process &&
600 | global.process.versions &&
601 | !global.process.versions.electron
602 | ) {
603 | if (process.argv.length < 3) {
604 | console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
605 | process.exit(1);
606 | }
607 |
608 | const go = new Go();
609 | go.argv = process.argv.slice(2);
610 | go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
611 | go.exit = process.exit;
612 | WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
613 | process.on("exit", (code) => { // Node.js exits if no event handler is pending
614 | if (code === 0 && !go.exited) {
615 | // deadlock, make Go print error and stack traces
616 | go._pendingEvent = { id: 0 };
617 | go._resume();
618 | }
619 | });
620 | return go.run(result.instance);
621 | }).catch((err) => {
622 | console.error(err);
623 | process.exit(1);
624 | });
625 | }
626 | })();
627 |
--------------------------------------------------------------------------------
/package_lesson1/assets/wasm_exec.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | (() => {
6 | // Map multiple JavaScript environments to a single common API,
7 | // preferring web standards over Node.js API.
8 | //
9 | // Environments considered:
10 | // - Browsers
11 | // - Node.js
12 | // - Electron
13 | // - Parcel
14 | // - Webpack
15 | const IsWechat = true;
16 |
17 | if (!IsWechat) {
18 | if (typeof global !== "undefined") {
19 | // global already exists
20 | } else if (typeof window !== "undefined") {
21 | window.global = window;
22 | } else if (typeof self !== "undefined") {
23 | self.global = self;
24 | } else {
25 | throw new Error("cannot export Go (neither global, window nor self is defined)");
26 | }
27 |
28 | if (!global.require && typeof require !== "undefined") {
29 | global.require = require;
30 | }
31 |
32 | if (!global.fs && global.require) {
33 | const fs = require("fs");
34 | if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
35 | global.fs = fs;
36 | }
37 | }
38 | }
39 |
40 | const enosys = () => {
41 | const err = new Error("not implemented");
42 | err.code = "ENOSYS";
43 | return err;
44 | };
45 |
46 | if (!global.fs) {
47 | let outputBuf = "";
48 | global.fs = {
49 | constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
50 | writeSync(fd, buf) {
51 | outputBuf += decoder.decode(buf);
52 | const nl = outputBuf.lastIndexOf("\n");
53 | if (nl != -1) {
54 | console.log(outputBuf.substr(0, nl));
55 | outputBuf = outputBuf.substr(nl + 1);
56 | }
57 | return buf.length;
58 | },
59 | write(fd, buf, offset, length, position, callback) {
60 | if (offset !== 0 || length !== buf.length || position !== null) {
61 | callback(enosys());
62 | return;
63 | }
64 | const n = this.writeSync(fd, buf);
65 | callback(null, n);
66 | },
67 | chmod(path, mode, callback) { callback(enosys()); },
68 | chown(path, uid, gid, callback) { callback(enosys()); },
69 | close(fd, callback) { callback(enosys()); },
70 | fchmod(fd, mode, callback) { callback(enosys()); },
71 | fchown(fd, uid, gid, callback) { callback(enosys()); },
72 | fstat(fd, callback) { callback(enosys()); },
73 | fsync(fd, callback) { callback(null); },
74 | ftruncate(fd, length, callback) { callback(enosys()); },
75 | lchown(path, uid, gid, callback) { callback(enosys()); },
76 | link(path, link, callback) { callback(enosys()); },
77 | lstat(path, callback) { callback(enosys()); },
78 | mkdir(path, perm, callback) { callback(enosys()); },
79 | open(path, flags, mode, callback) { callback(enosys()); },
80 | read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
81 | readdir(path, callback) { callback(enosys()); },
82 | readlink(path, callback) { callback(enosys()); },
83 | rename(from, to, callback) { callback(enosys()); },
84 | rmdir(path, callback) { callback(enosys()); },
85 | stat(path, callback) { callback(enosys()); },
86 | symlink(path, link, callback) { callback(enosys()); },
87 | truncate(path, length, callback) { callback(enosys()); },
88 | unlink(path, callback) { callback(enosys()); },
89 | utimes(path, atime, mtime, callback) { callback(enosys()); },
90 | };
91 | }
92 |
93 | if (!global.process) {
94 | global.process = {
95 | getuid() { return -1; },
96 | getgid() { return -1; },
97 | geteuid() { return -1; },
98 | getegid() { return -1; },
99 | getgroups() { throw enosys(); },
100 | pid: -1,
101 | ppid: -1,
102 | umask() { throw enosys(); },
103 | cwd() { throw enosys(); },
104 | chdir() { throw enosys(); },
105 | }
106 | }
107 |
108 | if (!IsWechat) {
109 | if (!global.crypto && global.require) {
110 | const nodeCrypto = require("crypto");
111 | global.crypto = {
112 | getRandomValues(b) {
113 | nodeCrypto.randomFillSync(b);
114 | },
115 | };
116 | }
117 | if (!global.crypto) {
118 | throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
119 | }
120 | } else {
121 | if (!global.crypto) {
122 | global.crypto = {
123 | getRandomValues(b) {
124 | let byteRange = 256;
125 | for (var i = 0; i < b.length; i++) {
126 | b[i] = Math.floor(byteRange * Math.random());
127 | }
128 | },
129 | };
130 | }
131 | }
132 | if (!IsWechat) {
133 | if (!global.performance) {
134 | global.performance = {
135 | now() {
136 | const [sec, nsec] = process.hrtime();
137 | return sec * 1000 + nsec / 1000000;
138 | },
139 | };
140 | }
141 | } else {
142 | if (!global.performance) {
143 | global.performance = {
144 | now() {
145 | return Date.now()
146 | },
147 | };
148 | }
149 | }
150 |
151 | if (!IsWechat) {
152 | if (!global.TextEncoder && global.require) {
153 | global.TextEncoder = require("util").TextEncoder;
154 | }
155 | if (!global.TextEncoder) {
156 | throw new Error("global.TextEncoder is not available, polyfill required");
157 | }
158 |
159 | if (!global.TextDecoder && global.require) {
160 | global.TextDecoder = require("util").TextDecoder;
161 | }
162 | if (!global.TextDecoder) {
163 | throw new Error("global.TextDecoder is not available, polyfill required");
164 | }
165 | } else {
166 | if (!global.TextEncoder) {
167 | global.TextEncoder = require("text-encoder").TextEncoder;
168 | }
169 | if (!global.TextDecoder) {
170 | global.TextDecoder = require("text-encoder").TextDecoder;
171 | }
172 |
173 | }
174 | // End of polyfills for common API.
175 |
176 | const encoder = new global.TextEncoder("utf-8");
177 | const decoder = new global.TextDecoder("utf-8");
178 |
179 | global.Go = class {
180 | constructor() {
181 | this.argv = ["js"];
182 | this.env = {};
183 | this.exit = (code) => {
184 | if (code !== 0) {
185 | console.warn("exit code:", code);
186 | }
187 | };
188 | this._exitPromise = new Promise((resolve) => {
189 | this._resolveExitPromise = resolve;
190 | });
191 | this._pendingEvent = null;
192 | this._scheduledTimeouts = new Map();
193 | this._nextCallbackTimeoutID = 1;
194 |
195 | const setInt64 = (addr, v) => {
196 | this.mem.setUint32(addr + 0, v, true);
197 | this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
198 | }
199 |
200 | const getInt64 = (addr) => {
201 | const low = this.mem.getUint32(addr + 0, true);
202 | const high = this.mem.getInt32(addr + 4, true);
203 | return low + high * 4294967296;
204 | }
205 |
206 | const loadValue = (addr) => {
207 | const f = this.mem.getFloat64(addr, true);
208 | if (f === 0) {
209 | return undefined;
210 | }
211 | if (!isNaN(f)) {
212 | return f;
213 | }
214 |
215 | const id = this.mem.getUint32(addr, true);
216 | return this._values[id];
217 | }
218 |
219 | const storeValue = (addr, v) => {
220 | const nanHead = 0x7FF80000;
221 |
222 | if (typeof v === "number" && v !== 0) {
223 | if (isNaN(v)) {
224 | this.mem.setUint32(addr + 4, nanHead, true);
225 | this.mem.setUint32(addr, 0, true);
226 | return;
227 | }
228 | this.mem.setFloat64(addr, v, true);
229 | return;
230 | }
231 |
232 | if (v === undefined) {
233 | this.mem.setFloat64(addr, 0, true);
234 | return;
235 | }
236 |
237 | let id = this._ids.get(v);
238 | if (id === undefined) {
239 | id = this._idPool.pop();
240 | if (id === undefined) {
241 | id = this._values.length;
242 | }
243 | this._values[id] = v;
244 | this._goRefCounts[id] = 0;
245 | this._ids.set(v, id);
246 | }
247 | this._goRefCounts[id]++;
248 | let typeFlag = 0;
249 | switch (typeof v) {
250 | case "object":
251 | if (v !== null) {
252 | typeFlag = 1;
253 | }
254 | break;
255 | case "string":
256 | typeFlag = 2;
257 | break;
258 | case "symbol":
259 | typeFlag = 3;
260 | break;
261 | case "function":
262 | typeFlag = 4;
263 | break;
264 | }
265 | this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
266 | this.mem.setUint32(addr, id, true);
267 | }
268 |
269 | const loadSlice = (addr) => {
270 | const array = getInt64(addr + 0);
271 | const len = getInt64(addr + 8);
272 | return new Uint8Array(this._inst.exports.mem.buffer, array, len);
273 | }
274 |
275 | const loadSliceOfValues = (addr) => {
276 | const array = getInt64(addr + 0);
277 | const len = getInt64(addr + 8);
278 | const a = new Array(len);
279 | for (let i = 0; i < len; i++) {
280 | a[i] = loadValue(array + i * 8);
281 | }
282 | return a;
283 | }
284 |
285 | const loadString = (addr) => {
286 | const saddr = getInt64(addr + 0);
287 | const len = getInt64(addr + 8);
288 | return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
289 | }
290 |
291 | const timeOrigin = Date.now() - global.performance.now();
292 |
293 | this.importObject = {
294 | go: {
295 | // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
296 | // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
297 | // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
298 | // This changes the SP, thus we have to update the SP used by the imported function.
299 |
300 | // func wasmExit(code int32)
301 | "runtime.wasmExit": (sp) => {
302 | sp >>>= 0;
303 | const code = this.mem.getInt32(sp + 8, true);
304 | this.exited = true;
305 | delete this._inst;
306 | delete this._values;
307 | delete this._goRefCounts;
308 | delete this._ids;
309 | delete this._idPool;
310 | this.exit(code);
311 | },
312 |
313 | // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
314 | "runtime.wasmWrite": (sp) => {
315 | sp >>>= 0;
316 | const fd = getInt64(sp + 8);
317 | const p = getInt64(sp + 16);
318 | const n = this.mem.getInt32(sp + 24, true);
319 | global.fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
320 | },
321 |
322 | // func resetMemoryDataView()
323 | "runtime.resetMemoryDataView": (sp) => {
324 | sp >>>= 0;
325 | this.mem = new DataView(this._inst.exports.mem.buffer);
326 | },
327 |
328 | // func nanotime1() int64
329 | "runtime.nanotime1": (sp) => {
330 | sp >>>= 0;
331 | setInt64(sp + 8, (timeOrigin + global.performance.now()) * 1000000);
332 | },
333 |
334 | // func walltime1() (sec int64, nsec int32)
335 | "runtime.walltime1": (sp) => {
336 | sp >>>= 0;
337 | const msec = (new Date).getTime();
338 | setInt64(sp + 8, msec / 1000);
339 | this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
340 | },
341 |
342 | // func scheduleTimeoutEvent(delay int64) int32
343 | "runtime.scheduleTimeoutEvent": (sp) => {
344 | sp >>>= 0;
345 | const id = this._nextCallbackTimeoutID;
346 | this._nextCallbackTimeoutID++;
347 | this._scheduledTimeouts.set(id, setTimeout(
348 | () => {
349 | this._resume();
350 | while (this._scheduledTimeouts.has(id)) {
351 | // for some reason Go failed to register the timeout event, log and try again
352 | // (temporary workaround for https://github.com/golang/go/issues/28975)
353 | console.warn("scheduleTimeoutEvent: missed timeout event");
354 | this._resume();
355 | }
356 | },
357 | getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
358 | ));
359 | this.mem.setInt32(sp + 16, id, true);
360 | },
361 |
362 | // func clearTimeoutEvent(id int32)
363 | "runtime.clearTimeoutEvent": (sp) => {
364 | sp >>>= 0;
365 | const id = this.mem.getInt32(sp + 8, true);
366 | clearTimeout(this._scheduledTimeouts.get(id));
367 | this._scheduledTimeouts.delete(id);
368 | },
369 |
370 | // func getRandomData(r []byte)
371 | "runtime.getRandomData": (sp) => {
372 | sp >>>= 0;
373 | global.crypto.getRandomValues(loadSlice(sp + 8));
374 | },
375 |
376 | // func finalizeRef(v ref)
377 | "syscall/js.finalizeRef": (sp) => {
378 | sp >>>= 0;
379 | const id = this.mem.getUint32(sp + 8, true);
380 | this._goRefCounts[id]--;
381 | if (this._goRefCounts[id] === 0) {
382 | const v = this._values[id];
383 | this._values[id] = null;
384 | this._ids.delete(v);
385 | this._idPool.push(id);
386 | }
387 | },
388 |
389 | // func stringVal(value string) ref
390 | "syscall/js.stringVal": (sp) => {
391 | sp >>>= 0;
392 | storeValue(sp + 24, loadString(sp + 8));
393 | },
394 |
395 | // func valueGet(v ref, p string) ref
396 | "syscall/js.valueGet": (sp) => {
397 | sp >>>= 0;
398 | const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
399 | sp = this._inst.exports.getsp() >>> 0; // see comment above
400 | storeValue(sp + 32, result);
401 | },
402 |
403 | // func valueSet(v ref, p string, x ref)
404 | "syscall/js.valueSet": (sp) => {
405 | sp >>>= 0;
406 | Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
407 | },
408 |
409 | // func valueDelete(v ref, p string)
410 | "syscall/js.valueDelete": (sp) => {
411 | sp >>>= 0;
412 | Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
413 | },
414 |
415 | // func valueIndex(v ref, i int) ref
416 | "syscall/js.valueIndex": (sp) => {
417 | sp >>>= 0;
418 | storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
419 | },
420 |
421 | // valueSetIndex(v ref, i int, x ref)
422 | "syscall/js.valueSetIndex": (sp) => {
423 | sp >>>= 0;
424 | Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
425 | },
426 |
427 | // func valueCall(v ref, m string, args []ref) (ref, bool)
428 | "syscall/js.valueCall": (sp) => {
429 | sp >>>= 0;
430 | try {
431 | const v = loadValue(sp + 8);
432 | const m = Reflect.get(v, loadString(sp + 16));
433 | const args = loadSliceOfValues(sp + 32);
434 | const result = Reflect.apply(m, v, args);
435 | sp = this._inst.exports.getsp() >>> 0; // see comment above
436 | storeValue(sp + 56, result);
437 | this.mem.setUint8(sp + 64, 1);
438 | } catch (err) {
439 | storeValue(sp + 56, err);
440 | this.mem.setUint8(sp + 64, 0);
441 | }
442 | },
443 |
444 | // func valueInvoke(v ref, args []ref) (ref, bool)
445 | "syscall/js.valueInvoke": (sp) => {
446 | sp >>>= 0;
447 | try {
448 | const v = loadValue(sp + 8);
449 | const args = loadSliceOfValues(sp + 16);
450 | const result = Reflect.apply(v, undefined, args);
451 | sp = this._inst.exports.getsp() >>> 0; // see comment above
452 | storeValue(sp + 40, result);
453 | this.mem.setUint8(sp + 48, 1);
454 | } catch (err) {
455 | storeValue(sp + 40, err);
456 | this.mem.setUint8(sp + 48, 0);
457 | }
458 | },
459 |
460 | // func valueNew(v ref, args []ref) (ref, bool)
461 | "syscall/js.valueNew": (sp) => {
462 | sp >>>= 0;
463 | try {
464 | const v = loadValue(sp + 8);
465 | const args = loadSliceOfValues(sp + 16);
466 | const result = Reflect.construct(v, args);
467 | sp = this._inst.exports.getsp() >>> 0; // see comment above
468 | storeValue(sp + 40, result);
469 | this.mem.setUint8(sp + 48, 1);
470 | } catch (err) {
471 | storeValue(sp + 40, err);
472 | this.mem.setUint8(sp + 48, 0);
473 | }
474 | },
475 |
476 | // func valueLength(v ref) int
477 | "syscall/js.valueLength": (sp) => {
478 | sp >>>= 0;
479 | setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
480 | },
481 |
482 | // valuePrepareString(v ref) (ref, int)
483 | "syscall/js.valuePrepareString": (sp) => {
484 | sp >>>= 0;
485 | const str = encoder.encode(String(loadValue(sp + 8)));
486 | storeValue(sp + 16, str);
487 | setInt64(sp + 24, str.length);
488 | },
489 |
490 | // valueLoadString(v ref, b []byte)
491 | "syscall/js.valueLoadString": (sp) => {
492 | sp >>>= 0;
493 | const str = loadValue(sp + 8);
494 | loadSlice(sp + 16).set(str);
495 | },
496 |
497 | // func valueInstanceOf(v ref, t ref) bool
498 | "syscall/js.valueInstanceOf": (sp) => {
499 | sp >>>= 0;
500 | this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
501 | },
502 |
503 | // func copyBytesToGo(dst []byte, src ref) (int, bool)
504 | "syscall/js.copyBytesToGo": (sp) => {
505 | sp >>>= 0;
506 | const dst = loadSlice(sp + 8);
507 | const src = loadValue(sp + 32);
508 | if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
509 | this.mem.setUint8(sp + 48, 0);
510 | return;
511 | }
512 | const toCopy = src.subarray(0, dst.length);
513 | dst.set(toCopy);
514 | setInt64(sp + 40, toCopy.length);
515 | this.mem.setUint8(sp + 48, 1);
516 | },
517 |
518 | // func copyBytesToJS(dst ref, src []byte) (int, bool)
519 | "syscall/js.copyBytesToJS": (sp) => {
520 | sp >>>= 0;
521 | const dst = loadValue(sp + 8);
522 | const src = loadSlice(sp + 16);
523 | if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
524 | this.mem.setUint8(sp + 48, 0);
525 | return;
526 | }
527 | const toCopy = src.subarray(0, dst.length);
528 | dst.set(toCopy);
529 | setInt64(sp + 40, toCopy.length);
530 | this.mem.setUint8(sp + 48, 1);
531 | },
532 |
533 | "debug": (value) => {
534 | console.log(value);
535 | },
536 | }
537 | };
538 | }
539 |
540 | async run(instance) {
541 | if (!IsWechat) {
542 | if (!(instance instanceof WebAssembly.Instance)) {
543 | throw new Error("Go.run: WebAssembly.Instance expected");
544 | }
545 | }
546 | this._inst = instance;
547 | this.mem = new DataView(this._inst.exports.mem.buffer);
548 | this._values = [ // JS values that Go currently has references to, indexed by reference id
549 | NaN,
550 | 0,
551 | null,
552 | true,
553 | false,
554 | global,
555 | this,
556 | ];
557 | this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
558 | this._ids = new Map([ // mapping from JS values to reference ids
559 | [0, 1],
560 | [null, 2],
561 | [true, 3],
562 | [false, 4],
563 | [global, 5],
564 | [this, 6],
565 | ]);
566 | this._idPool = []; // unused ids that have been garbage collected
567 | this.exited = false; // whether the Go program has exited
568 |
569 | // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
570 | let offset = 4096;
571 |
572 | const strPtr = (str) => {
573 | const ptr = offset;
574 | const bytes = encoder.encode(str + "\0");
575 | new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
576 | offset += bytes.length;
577 | if (offset % 8 !== 0) {
578 | offset += 8 - (offset % 8);
579 | }
580 | return ptr;
581 | };
582 |
583 | const argc = this.argv.length;
584 |
585 | const argvPtrs = [];
586 | this.argv.forEach((arg) => {
587 | argvPtrs.push(strPtr(arg));
588 | });
589 | argvPtrs.push(0);
590 |
591 | const keys = Object.keys(this.env).sort();
592 | keys.forEach((key) => {
593 | argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
594 | });
595 | argvPtrs.push(0);
596 |
597 | const argv = offset;
598 | argvPtrs.forEach((ptr) => {
599 | this.mem.setUint32(offset, ptr, true);
600 | this.mem.setUint32(offset + 4, 0, true);
601 | offset += 8;
602 | });
603 |
604 | this._inst.exports.run(argc, argv);
605 | if (this.exited) {
606 | this._resolveExitPromise();
607 | }
608 | await this._exitPromise;
609 | }
610 |
611 | _resume() {
612 | if (this.exited) {
613 | throw new Error("Go program has already exited");
614 | }
615 | this._inst.exports.resume();
616 | if (this.exited) {
617 | this._resolveExitPromise();
618 | }
619 | }
620 |
621 | _makeFuncWrapper(id) {
622 | const go = this;
623 | return function () {
624 | const event = { id: id, this: this, args: arguments };
625 | go._pendingEvent = event;
626 | go._resume();
627 | return event.result;
628 | };
629 | }
630 | }
631 |
632 | if (
633 | typeof module !== "undefined" &&
634 | global.require &&
635 | global.require.main === module &&
636 | global.process &&
637 | global.process.versions &&
638 | !global.process.versions.electron
639 | ) {
640 | if (process.argv.length < 3) {
641 | console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
642 | process.exit(1);
643 | }
644 |
645 | const go = new Go();
646 | go.argv = process.argv.slice(2);
647 | go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
648 | go.exit = process.exit;
649 | WebAssembly.instantiate(global.fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
650 | process.on("exit", (code) => { // Node.js exits if no event handler is pending
651 | if (code === 0 && !go.exited) {
652 | // deadlock, make Go print error and stack traces
653 | go._pendingEvent = { id: 0 };
654 | go._resume();
655 | }
656 | });
657 | return go.run(result.instance);
658 | }).catch((err) => {
659 | console.error(err);
660 | process.exit(1);
661 | });
662 | }
663 | })();
664 |
--------------------------------------------------------------------------------
/go_dev/assets/vue.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Vue.js v2.5.16
3 | * (c) 2014-2018 Evan You
4 | * Released under the MIT License.
5 | */
6 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Vue=t()}(this,function(){"use strict";var y=Object.freeze({});function M(e){return null==e}function D(e){return null!=e}function S(e){return!0===e}function T(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function P(e){return null!==e&&"object"==typeof e}var r=Object.prototype.toString;function l(e){return"[object Object]"===r.call(e)}function i(e){var t=parseFloat(String(e));return 0<=t&&Math.floor(t)===t&&isFinite(e)}function t(e){return null==e?"":"object"==typeof e?JSON.stringify(e,null,2):String(e)}function F(e){var t=parseFloat(e);return isNaN(t)?e:t}function s(e,t){for(var n=Object.create(null),r=e.split(","),i=0;ie.id;)n--;bt.splice(n+1,0,e)}else bt.push(e);Ct||(Ct=!0,Ze(At))}}(this)},St.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||P(e)||this.deep){var t=this.value;if(this.value=e,this.user)try{this.cb.call(this.vm,e,t)}catch(e){Fe(e,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,e,t)}}},St.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},St.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},St.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||f(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var Tt={enumerable:!0,configurable:!0,get:$,set:$};function Et(e,t,n){Tt.get=function(){return this[t][n]},Tt.set=function(e){this[t][n]=e},Object.defineProperty(e,n,Tt)}function jt(e){e._watchers=[];var t=e.$options;t.props&&function(n,r){var i=n.$options.propsData||{},o=n._props={},a=n.$options._propKeys=[];n.$parent&&ge(!1);var e=function(e){a.push(e);var t=Ie(e,r,i,n);Ce(o,e,t),e in n||Et(n,"_props",e)};for(var t in r)e(t);ge(!0)}(e,t.props),t.methods&&function(e,t){e.$options.props;for(var n in t)e[n]=null==t[n]?$:v(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;l(t=e._data="function"==typeof t?function(e,t){se();try{return e.call(t,t)}catch(e){return Fe(e,t,"data()"),{}}finally{ce()}}(t,e):t||{})||(t={});var n=Object.keys(t),r=e.$options.props,i=(e.$options.methods,n.length);for(;i--;){var o=n[i];r&&p(r,o)||(void 0,36!==(a=(o+"").charCodeAt(0))&&95!==a&&Et(e,"_data",o))}var a;we(t,!0)}(e):we(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),r=Y();for(var i in t){var o=t[i],a="function"==typeof o?o:o.get;r||(n[i]=new St(e,a||$,$,Nt)),i in e||Lt(e,i,o)}}(e,t.computed),t.watch&&t.watch!==G&&function(e,t){for(var n in t){var r=t[n];if(Array.isArray(r))for(var i=0;iparseInt(this.max)&&bn(a,s[0],s,this._vnode)),t.data.keepAlive=!0}return t||e&&e[0]}}};$n=hn,Cn={get:function(){return j}},Object.defineProperty($n,"config",Cn),$n.util={warn:re,extend:m,mergeOptions:Ne,defineReactive:Ce},$n.set=xe,$n.delete=ke,$n.nextTick=Ze,$n.options=Object.create(null),k.forEach(function(e){$n.options[e+"s"]=Object.create(null)}),m(($n.options._base=$n).options.components,kn),$n.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(-1=a&&l()};setTimeout(function(){c\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,oo="[a-zA-Z_][\\w\\-\\.]*",ao="((?:"+oo+"\\:)?"+oo+")",so=new RegExp("^<"+ao),co=/^\s*(\/?)>/,lo=new RegExp("^<\\/"+ao+"[^>]*>"),uo=/^]+>/i,fo=/^",""":'"',"&":"&","
":"\n"," ":"\t"},go=/&(?:lt|gt|quot|amp);/g,_o=/&(?:lt|gt|quot|amp|#10|#9);/g,bo=s("pre,textarea",!0),$o=function(e,t){return e&&bo(e)&&"\n"===t[0]};var wo,Co,xo,ko,Ao,Oo,So,To,Eo=/^@|^v-on:/,jo=/^v-|^@|^:/,No=/([^]*?)\s+(?:in|of)\s+([^]*)/,Lo=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,Io=/^\(|\)$/g,Mo=/:(.*)$/,Do=/^:|^v-bind:/,Po=/\.[^.]+/g,Fo=e(eo);function Ro(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:function(e){for(var t={},n=0,r=e.length;n]*>)","i")),n=i.replace(t,function(e,t,n){return r=n.length,ho(o)||"noscript"===o||(t=t.replace(//g,"$1").replace(//g,"$1")),$o(o,t)&&(t=t.slice(1)),d.chars&&d.chars(t),""});a+=i.length-n.length,i=n,A(o,a-r,a)}else{var s=i.indexOf("<");if(0===s){if(fo.test(i)){var c=i.indexOf("--\x3e");if(0<=c){d.shouldKeepComment&&d.comment(i.substring(4,c)),C(c+3);continue}}if(po.test(i)){var l=i.indexOf("]>");if(0<=l){C(l+2);continue}}var u=i.match(uo);if(u){C(u[0].length);continue}var f=i.match(lo);if(f){var p=a;C(f[0].length),A(f[1],p,a);continue}var _=x();if(_){k(_),$o(v,i)&&C(1);continue}}var b=void 0,$=void 0,w=void 0;if(0<=s){for($=i.slice(s);!(lo.test($)||so.test($)||fo.test($)||po.test($)||(w=$.indexOf("<",1))<0);)s+=w,$=i.slice(s);b=i.substring(0,s),C(s)}s<0&&(b=i,i=""),d.chars&&b&&d.chars(b)}if(i===e){d.chars&&d.chars(i);break}}function C(e){a+=e,i=i.substring(e)}function x(){var e=i.match(so);if(e){var t,n,r={tagName:e[1],attrs:[],start:a};for(C(e[0].length);!(t=i.match(co))&&(n=i.match(io));)C(n[0].length),r.attrs.push(n);if(t)return r.unarySlash=t[1],C(t[0].length),r.end=a,r}}function k(e){var t=e.tagName,n=e.unarySlash;m&&("p"===v&&ro(t)&&A(v),g(t)&&v===t&&A(t));for(var r,i,o,a=y(t)||!!n,s=e.attrs.length,c=new Array(s),l=0;l-1"+("true"===d?":("+l+")":":_q("+l+","+d+")")),Ar(c,"change","var $$a="+l+",$$el=$event.target,$$c=$$el.checked?("+d+"):("+v+");if(Array.isArray($$a)){var $$v="+(f?"_n("+p+")":p)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Er(l,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Er(l,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Er(l,"$$c")+"}",null,!0);else if("input"===$&&"radio"===w)r=e,i=_,a=(o=b)&&o.number,s=Or(r,"value")||"null",Cr(r,"checked","_q("+i+","+(s=a?"_n("+s+")":s)+")"),Ar(r,"change",Er(i,s),null,!0);else if("input"===$||"textarea"===$)!function(e,t,n){var r=e.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,l=o?"change":"range"===r?Pr:"input",u="$event.target.value";s&&(u="$event.target.value.trim()"),a&&(u="_n("+u+")");var f=Er(t,u);c&&(f="if($event.target.composing)return;"+f),Cr(e,"value","("+t+")"),Ar(e,l,f,null,!0),(s||a)&&Ar(e,"blur","$forceUpdate()")}(e,_,b);else if(!j.isReservedTag($))return Tr(e,_,b),!1;return!0},text:function(e,t){t.value&&Cr(e,"textContent","_s("+t.value+")")},html:function(e,t){t.value&&Cr(e,"innerHTML","_s("+t.value+")")}},isPreTag:function(e){return"pre"===e},isUnaryTag:to,mustUseProp:Sn,canBeLeftOpenTag:no,isReservedTag:Un,getTagNamespace:Vn,staticKeys:(Go=Wo,Go.reduce(function(e,t){return e.concat(t.staticKeys||[])},[]).join(","))},Qo=e(function(e){return s("type,tag,attrsList,attrsMap,plain,parent,children,attrs"+(e?","+e:""))});function ea(e,t){e&&(Zo=Qo(t.staticKeys||""),Xo=t.isReservedTag||O,function e(t){t.static=function(e){if(2===e.type)return!1;if(3===e.type)return!0;return!(!e.pre&&(e.hasBindings||e.if||e.for||c(e.tag)||!Xo(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(Zo)))}(t);if(1===t.type){if(!Xo(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var n=0,r=t.children.length;n|^function\s*\(/,na=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,ra={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},ia={esc:"Escape",tab:"Tab",enter:"Enter",space:" ",up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete"]},oa=function(e){return"if("+e+")return null;"},aa={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:oa("$event.target !== $event.currentTarget"),ctrl:oa("!$event.ctrlKey"),shift:oa("!$event.shiftKey"),alt:oa("!$event.altKey"),meta:oa("!$event.metaKey"),left:oa("'button' in $event && $event.button !== 0"),middle:oa("'button' in $event && $event.button !== 1"),right:oa("'button' in $event && $event.button !== 2")};function sa(e,t,n){var r=t?"nativeOn:{":"on:{";for(var i in e)r+='"'+i+'":'+ca(i,e[i])+",";return r.slice(0,-1)+"}"}function ca(t,e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map(function(e){return ca(t,e)}).join(",")+"]";var n=na.test(e.value),r=ta.test(e.value);if(e.modifiers){var i="",o="",a=[];for(var s in e.modifiers)if(aa[s])o+=aa[s],ra[s]&&a.push(s);else if("exact"===s){var c=e.modifiers;o+=oa(["ctrl","shift","alt","meta"].filter(function(e){return!c[e]}).map(function(e){return"$event."+e+"Key"}).join("||"))}else a.push(s);return a.length&&(i+="if(!('button' in $event)&&"+a.map(la).join("&&")+")return null;"),o&&(i+=o),"function($event){"+i+(n?"return "+e.value+"($event)":r?"return ("+e.value+")($event)":e.value)+"}"}return n||r?e.value:"function($event){"+e.value+"}"}function la(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=ra[e],r=ia[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}var ua={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(t,n){t.wrapData=function(e){return"_b("+e+",'"+t.tag+"',"+n.value+","+(n.modifiers&&n.modifiers.prop?"true":"false")+(n.modifiers&&n.modifiers.sync?",true":"")+")"}},cloak:$},fa=function(e){this.options=e,this.warn=e.warn||$r,this.transforms=wr(e.modules,"transformCode"),this.dataGenFns=wr(e.modules,"genData"),this.directives=m(m({},ua),e.directives);var t=e.isReservedTag||O;this.maybeComponent=function(e){return!t(e.tag)},this.onceId=0,this.staticRenderFns=[]};function pa(e,t){var n=new fa(t);return{render:"with(this){return "+(e?da(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function da(e,t){if(e.staticRoot&&!e.staticProcessed)return va(e,t);if(e.once&&!e.onceProcessed)return ha(e,t);if(e.for&&!e.forProcessed)return f=t,v=(u=e).for,h=u.alias,m=u.iterator1?","+u.iterator1:"",y=u.iterator2?","+u.iterator2:"",u.forProcessed=!0,(d||"_l")+"(("+v+"),function("+h+m+y+"){return "+(p||da)(u,f)+"})";if(e.if&&!e.ifProcessed)return ma(e,t);if("template"!==e.tag||e.slotTarget){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',r=_a(e,t),i="_t("+n+(r?","+r:""),o=e.attrs&&"{"+e.attrs.map(function(e){return g(e.name)+":"+e.value}).join(",")+"}",a=e.attrsMap["v-bind"];!o&&!a||r||(i+=",null");o&&(i+=","+o);a&&(i+=(o?"":",null")+","+a);return i+")"}(e,t);var n;if(e.component)a=e.component,c=t,l=(s=e).inlineTemplate?null:_a(s,c,!0),n="_c("+a+","+ya(s,c)+(l?","+l:"")+")";else{var r=e.plain?void 0:ya(e,t),i=e.inlineTemplate?null:_a(e,t,!0);n="_c('"+e.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o':'',0