├── pages
├── index
│ ├── index.json
│ ├── index.wxss
│ ├── index.wxml
│ └── index.js
└── logs
│ ├── logs.json
│ ├── logs.wxss
│ ├── logs.wxml
│ └── logs.js
├── img
├── screen1.PNG
└── screen2.jpg
├── sitemap.json
├── app.wxss
├── .idea
├── modules.xml
├── bluetoothprinter.iml
└── workspace.xml
├── app.json
├── utils
└── util.js
├── app.js
├── README.md
├── project.config.json
├── printer
├── printerutil.js
├── printerjobs.js
└── commands.js
└── miniprogram_npm
└── text-encoding
└── index.js.map
/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "蓝牙打印"
3 | }
--------------------------------------------------------------------------------
/pages/logs/logs.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "查看启动日志"
3 | }
--------------------------------------------------------------------------------
/img/screen1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilien1010/wechat-miniprogram-bluetooth-ble-scanner/HEAD/img/screen1.PNG
--------------------------------------------------------------------------------
/img/screen2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilien1010/wechat-miniprogram-bluetooth-ble-scanner/HEAD/img/screen2.jpg
--------------------------------------------------------------------------------
/pages/logs/logs.wxss:
--------------------------------------------------------------------------------
1 | .log-list {
2 | display: flex;
3 | flex-direction: column;
4 | padding: 40rpx;
5 | }
6 | .log-item {
7 | margin: 10rpx;
8 | }
9 |
--------------------------------------------------------------------------------
/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/pages/logs/logs.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{index + 1}}. {{log}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | page {
3 | background-color: #F8F8F8;
4 | height: 100%;
5 | }
6 |
7 | .container {
8 | min-height: 100%;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/pages/logs/logs.js:
--------------------------------------------------------------------------------
1 | //logs.js
2 | const util = require('../../utils/util.js')
3 |
4 | Page({
5 | data: {
6 | logs: []
7 | },
8 | onLoad: function () {
9 | this.setData({
10 | logs: (wx.getStorageSync('logs') || []).map(log => {
11 | return util.formatTime(new Date(log))
12 | })
13 | })
14 | }
15 | })
16 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index",
4 | "pages/logs/logs"
5 | ],
6 | "window": {
7 | "backgroundTextStyle": "light",
8 | "navigationBarBackgroundColor": "#fff",
9 | "navigationBarTitleText": "WeChat",
10 | "navigationBarTextStyle": "black"
11 | },
12 | "sitemapLocation": "sitemap.json"
13 | }
--------------------------------------------------------------------------------
/.idea/bluetoothprinter.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/utils/util.js:
--------------------------------------------------------------------------------
1 | const formatTime = date => {
2 | const year = date.getFullYear()
3 | const month = date.getMonth() + 1
4 | const day = date.getDate()
5 | const hour = date.getHours()
6 | const minute = date.getMinutes()
7 | const second = date.getSeconds()
8 |
9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
10 | }
11 |
12 | const formatNumber = n => {
13 | n = n.toString()
14 | return n[1] ? n : '0' + n
15 | }
16 |
17 | module.exports = {
18 | formatTime: formatTime
19 | }
20 |
--------------------------------------------------------------------------------
/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | .page-section {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | width: 100%;
6 | box-sizing: border-box;
7 | border-bottom: 2rpx solid #EEE;
8 | padding: 30rpx 0;
9 | }
10 |
11 | .devices-summary {
12 | padding: 10rpx;
13 | font-size: 30rpx;
14 | }
15 |
16 | .device-list {
17 | height: 700rpx;
18 | }
19 |
20 | .device-item {
21 | border-bottom: 1rpx solid #EEE;
22 | padding: 10rpx;
23 | color: #666;
24 | }
25 |
26 | .device-item-hover {
27 | background-color: rgba(0, 0, 0, .1);
28 | }
29 |
30 | .btn-area {
31 | box-sizing: border-box;
32 | width: 100%;
33 | padding: 0 30rpx;
34 | margin: 30rpx 0;
35 | }
36 |
37 | .connected-area {
38 | font-size: 22rpx;
39 | }
40 |
41 | .connected-info {}
42 |
43 | .input-area {
44 | background: #fff;
45 | margin-top: 10rpx;
46 | width: 100%;
47 | }
48 |
49 | .input {
50 | font-size: 28rpx;
51 | height: 2.58823529em;
52 | min-height: 2.58823529em;
53 | line-height: 2.58823529em;
54 | padding: 10rpx;
55 | }
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | //app.js
2 | App({
3 | onLaunch: function () {
4 | // 展示本地存储能力
5 | var logs = wx.getStorageSync('logs') || []
6 | logs.unshift(Date.now())
7 | wx.setStorageSync('logs', logs)
8 |
9 | // 登录
10 | wx.login({
11 | success: res => {
12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId
13 | }
14 | })
15 | // 获取用户信息
16 | wx.getSetting({
17 | success: res => {
18 | if (res.authSetting['scope.userInfo']) {
19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
20 | wx.getUserInfo({
21 | success: res => {
22 | // 可以将 res 发送给后台解码出 unionId
23 | this.globalData.userInfo = res.userInfo
24 |
25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
26 | // 所以此处加入 callback 以防止这种情况
27 | if (this.userInfoReadyCallback) {
28 | this.userInfoReadyCallback(res)
29 | }
30 | }
31 | })
32 | }
33 | }
34 | })
35 | },
36 | globalData: {
37 | userInfo: null
38 | }
39 | })
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 小程序蓝牙扫码枪实例
2 | 微信小程序蓝牙打印示例,代码参考[微信小程序示例](https://github.com/benioZhang/miniprogram-bluetoothprinter/)。官方Demo总比网上随便找的强吧。
3 |
4 | * 测试扫码枪:[维融(weirong)LP1无线红光蓝牙扫描器 一维 蓝牙 1100mAh](https://u.jd.com/ZtHT8dm)
5 | * 测试设备:iPhone 11 Pro Max
6 | * 扫码枪设备必须支持 :BLE模式 (无论安卓 还是 iOS 打开扫码枪之后都要进入 BLE模式)
7 |
8 | ### 效果图
9 |
10 |


11 |
12 |
13 | ### 流程
14 | * 初始化蓝牙模块 `wx.openBluetoothAdapter()`
15 | * 搜寻附近的蓝牙外围设备 `wx.startBluetoothDevicesDiscovery()`
16 | * 监听寻找到新设备的事件 `wx.onBluetoothDeviceFound()`
17 | * 连接低功耗蓝牙设备 `wx.createBLEConnection()`
18 | * 获取蓝牙设备服务 `wx.getBLEDeviceServices()`
19 | * 获取蓝牙设备服务的特征值 `wx.getBLEDeviceCharacteristics()`
20 | * 对支持notify 和 indicate的特征执行 `wx.notifyBLECharacteristicValueChange()` 和 `wx.onBLECharacteristicValueChange()`
21 | * 关闭蓝牙模块 `wx.closeBluetoothAdapter()`
22 |
23 | ### 注意点
24 | **1.与蓝牙设备通信很重要的就是找到对应的Characteristic。如何找到这个Characteristic?**
25 | 目前只能一个个去试!!!如果有更好的做法请告诉我。
26 |
27 |
28 | 连接成功之后,在程序的任何地方,做如下监听,都可以实现读取条码
29 | ```
30 | function ab2str(buf) {
31 | return String.fromCharCode.apply(null, new Uint8Array(buf));
32 | }
33 |
34 |
35 | wx.onBLECharacteristicValueChange((result) => {
36 | console.log('监听特征值变化',result);
37 | const barcode = ab2str(result.value);
38 | that.setData({barcode})
39 | })
40 | ```
41 |
42 | ### 参考
43 | * [微信小程序API](https://developers.weixin.qq.com/miniprogram/dev/api/)
44 | * [微信小程序示例](https://github.com/wechat-miniprogram/miniprogram-demo)
45 | * [低功耗蓝牙能力](https://developers.weixin.qq.com/community/develop/doc/0008acd004ccd86b37d649ee55b009?highLine=%25E8%2593%259D%25E7%2589%2599)
46 | * [微信小程序 - 蓝牙接口](https://www.jianshu.com/p/d01dbca67461)
47 | * [ESC(POS)打印控制命令](http://www.xmjjdz.com/downloads/manual/cn/ESC(POS)%E6%89%93%E5%8D%B0%E6%8E%A7%E5%88%B6%E5%91%BD%E4%BB%A4.pdf)
48 | * [ESCPOS](https://github.com/song940/node-escpos)
49 |
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件",
3 | "packOptions": {
4 | "ignore": []
5 | },
6 | "setting": {
7 | "urlCheck": true,
8 | "es6": true,
9 | "enhance": true,
10 | "postcss": true,
11 | "preloadBackgroundData": false,
12 | "minified": true,
13 | "newFeature": true,
14 | "coverView": true,
15 | "nodeModules": true,
16 | "autoAudits": false,
17 | "showShadowRootInWxmlPanel": true,
18 | "scopeDataCheck": false,
19 | "uglifyFileName": false,
20 | "checkInvalidKey": true,
21 | "checkSiteMap": true,
22 | "uploadWithSourceMap": true,
23 | "compileHotReLoad": false,
24 | "lazyloadPlaceholderEnable": false,
25 | "useMultiFrameRuntime": true,
26 | "useApiHook": true,
27 | "useApiHostProcess": true,
28 | "babelSetting": {
29 | "ignore": [],
30 | "disablePlugins": [],
31 | "outputPath": ""
32 | },
33 | "useIsolateContext": false,
34 | "userConfirmedBundleSwitch": false,
35 | "packNpmManually": false,
36 | "packNpmRelationList": [],
37 | "minifyWXSS": true,
38 | "disableUseStrict": false,
39 | "minifyWXML": true,
40 | "showES6CompileOption": false,
41 | "useCompilerPlugins": false,
42 | "ignoreUploadUnusedFiles": true
43 | },
44 | "compileType": "miniprogram",
45 | "libVersion": "2.4.0",
46 | "appid": "wxbaa5f6ae19c82ce0",
47 | "projectname": "miniprogram-bluetoothprinter",
48 | "debugOptions": {
49 | "hidedInDevtools": []
50 | },
51 | "isGameTourist": false,
52 | "condition": {
53 | "search": {
54 | "list": []
55 | },
56 | "conversation": {
57 | "list": []
58 | },
59 | "game": {
60 | "currentL": -1,
61 | "list": []
62 | },
63 | "miniprogram": {
64 | "list": []
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/printer/printerutil.js:
--------------------------------------------------------------------------------
1 | // 打印机纸宽58mm,页的宽度384,字符宽度为1,每行最多盛放32个字符
2 | const PAGE_WIDTH = 384;
3 | const MAX_CHAR_COUNT_EACH_LINE = 32;
4 |
5 | /**
6 | * @param str
7 | * @returns {boolean} str是否全是中文
8 | */
9 | function isChinese(str) {
10 | return /^[\u4e00-\u9fa5]$/.test(str);
11 | }
12 |
13 | /**
14 | * 返回字符串宽度(1个中文=2个英文字符)
15 | * @param str
16 | * @returns {number}
17 | */
18 | function getStringWidth(str) {
19 | let width = 0;
20 | for (let i = 0, len = str.length; i < len; i++) {
21 | width += isChinese(str.charAt(i)) ? 2 : 1;
22 | }
23 | return width;
24 | }
25 |
26 | /**
27 | * 同一行输出str1, str2,str1居左, str2居右
28 | * @param {string} str1 内容1
29 | * @param {string} str2 内容2
30 | * @param {number} fontWidth 字符宽度 1/2
31 | * @param {string} fillWith str1 str2之间的填充字符
32 | *
33 | */
34 | function inline(str1, str2, fillWith = ' ', fontWidth = 1) {
35 | const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
36 | // 需要填充的字符数量
37 | let fillCount = lineWidth - (getStringWidth(str1) + getStringWidth(str2)) % lineWidth;
38 | let fillStr = new Array(fillCount).fill(fillWith.charAt(0)).join('');
39 | return str1 + fillStr + str2;
40 | }
41 |
42 | /**
43 | * 用字符填充一整行
44 | * @param {string} fillWith 填充字符
45 | * @param {number} fontWidth 字符宽度 1/2
46 | */
47 | function fillLine(fillWith = '-', fontWidth = 1) {
48 | const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
49 | return new Array(lineWidth).fill(fillWith.charAt(0)).join('');
50 | }
51 |
52 | /**
53 | * 文字内容居中,左右用字符填充
54 | * @param {string} str 文字内容
55 | * @param {number} fontWidth 字符宽度 1/2
56 | * @param {string} fillWith str1 str2之间的填充字符
57 | */
58 | function fillAround(str, fillWith = '-', fontWidth = 1) {
59 | const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
60 | let strWidth = getStringWidth(str);
61 | // 内容已经超过一行了,没必要填充
62 | if (strWidth >= lineWidth) {
63 | return str;
64 | }
65 | // 需要填充的字符数量
66 | let fillCount = lineWidth - strWidth;
67 | // 左侧填充的字符数量
68 | let leftCount = Math.round(fillCount / 2);
69 | // 两侧的填充字符,需要考虑左边需要填充,右边不需要填充的情况
70 | let fillStr = new Array(leftCount).fill(fillWith.charAt(0)).join('');
71 | return fillStr + str + fillStr.substr(0, fillCount - leftCount);
72 | }
73 |
74 | module.exports = {
75 | inline: inline,
76 | fillLine: fillLine,
77 | fillAround: fillAround,
78 | };
--------------------------------------------------------------------------------
/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | module.exports.max = function(n1, n2) {
3 | return Math.max(n1, n2)
4 | }
5 | module.exports.len = function(arr) {
6 | arr = arr || [];
7 | return arr.length;
8 | }
9 |
10 |
11 |
12 |
13 |
14 | 条码:{{item}}
15 |
16 |
17 | 已发现 {{devices.length}} 个外围设备:
18 |
19 |
20 | {{item.name}}
21 | 信号强度: {{item.RSSI}}dBm ({{utils.max(0, item.RSSI + 100)}}%)
22 | UUID: {{item.deviceId}}
23 | Service数量: {{utils.len(item.advertisServiceUUIDs)}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 最近连接的设备
33 | {{lastDevice}}
34 |
35 |
36 |
37 |
38 |
39 |
40 | 已连接到 {{name}}
41 |
42 | 特性UUID: {{item.uuid}}
43 | 特性值: {{item.value}}
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/printer/printerjobs.js:
--------------------------------------------------------------------------------
1 | const commands = require('commands');
2 | const TextEncoder = require('text-encoding/index').TextEncoder;
3 |
4 | const printerJobs = function () {
5 | this._queue = Array.from(commands.HARDWARE.HW_INIT);
6 | this._encoder = new TextEncoder("gb2312", {NONSTANDARD_allowLegacyEncoding: true});
7 | this._enqueue = function (cmd) {
8 | this._queue.push.apply(this._queue, cmd);
9 | }
10 | };
11 |
12 | /**
13 | * 增加打印内容
14 | * @param {string} content 文字内容
15 | */
16 | printerJobs.prototype.text = function (content) {
17 | if (content) {
18 | let uint8Array = this._encoder.encode(content);
19 | let encoded = Array.from(uint8Array);
20 | this._enqueue(encoded);
21 | }
22 | return this;
23 | };
24 |
25 | /**
26 | * 打印文字
27 | * @param {string} content 文字内容
28 | */
29 | printerJobs.prototype.print = function (content) {
30 | this.text(content);
31 | this._enqueue(commands.LF);
32 | return this;
33 | };
34 |
35 | /**
36 | * 打印文字并换行
37 | * @param {string} content 文字内容
38 | */
39 | printerJobs.prototype.println = function (content = '') {
40 | return this.print(content + commands.EOL);
41 | };
42 |
43 | /**
44 | * 设置对齐方式
45 | * @param {string} align 对齐方式 LT/CT/RT
46 | */
47 | printerJobs.prototype.setAlign = function (align) {
48 | this._enqueue(commands.TEXT_FORMAT['TXT_ALIGN_' + align.toUpperCase()]);
49 | return this;
50 | };
51 |
52 | /**
53 | * 设置字体
54 | * @param {string} family A/B/C
55 | */
56 | printerJobs.prototype.setFont = function (family) {
57 | this._enqueue(commands.TEXT_FORMAT['TXT_FONT_' + family.toUpperCase()]);
58 | return this;
59 | };
60 |
61 | /**
62 | * 设定字体尺寸
63 | * @param {number} width 字体宽度 1~2
64 | * @param {number} height 字体高度 1~2
65 | */
66 | printerJobs.prototype.setSize = function (width, height) {
67 | if (2 >= width && 2 >= height) {
68 | this._enqueue(commands.TEXT_FORMAT.TXT_NORMAL);
69 | if (2 === width && 2 === height) {
70 | this._enqueue(commands.TEXT_FORMAT.TXT_4SQUARE);
71 | } else if (1 === width && 2 === height) {
72 | this._enqueue(commands.TEXT_FORMAT.TXT_2HEIGHT);
73 | } else if (2 === width && 1 === height) {
74 | this._enqueue(commands.TEXT_FORMAT.TXT_2WIDTH);
75 | }
76 | }
77 | return this;
78 | };
79 |
80 | /**
81 | * 设定字体是否加粗
82 | * @param {boolean} bold
83 | */
84 | printerJobs.prototype.setBold = function (bold) {
85 | if (typeof bold !== 'boolean') {
86 | bold = true;
87 | }
88 | this._enqueue(bold ? commands.TEXT_FORMAT.TXT_BOLD_ON : commands.TEXT_FORMAT.TXT_BOLD_OFF);
89 | return this;
90 | };
91 |
92 | /**
93 | * 设定是否开启下划线
94 | * @param {boolean} underline
95 | */
96 | printerJobs.prototype.setUnderline = function (underline) {
97 | if (typeof underline !== 'boolean') {
98 | underline = true;
99 | }
100 | this._enqueue(underline ? commands.TEXT_FORMAT.TXT_UNDERL_ON : commands.TEXT_FORMAT.TXT_UNDERL_OFF);
101 | return this;
102 | };
103 |
104 | /**
105 | * 设置行间距为 n 点行,默认值行间距是 30 点
106 | * @param {number} n 0≤n≤255
107 | */
108 | printerJobs.prototype.setLineSpacing = function (n) {
109 | if (n === undefined || n === null) {
110 | this._enqueue(commands.LINE_SPACING.LS_DEFAULT);
111 | } else {
112 | this._enqueue(commands.LINE_SPACING.LS_SET);
113 | this._enqueue([n]);
114 | }
115 | return this;
116 | };
117 |
118 | /**
119 | * 打印空行
120 | * @param {number} n
121 | */
122 | printerJobs.prototype.lineFeed = function (n = 1) {
123 | return this.print(new Array(n).fill(commands.EOL).join(''));
124 | };
125 |
126 | /**
127 | * 设置字体颜色,需要打印机支持
128 | * @param {number} color - 0 默认颜色黑色 1 红色
129 | */
130 | printerJobs.prototype.setColor = function (color) {
131 | this._enqueue(commands.COLOR[color === 1 ? 1 : 0]);
132 | return this;
133 | };
134 |
135 | /**
136 | * https://support.loyverse.com/hardware/printers/use-the-beeper-in-a-escpos-printers
137 | * 蜂鸣警报,需要打印机支持
138 | * @param {number} n 蜂鸣次数,1-9
139 | * @param {number} t 蜂鸣长短,1-9
140 | */
141 | printerJobs.prototype.beep = function (n, t) {
142 | this._enqueue(commands.BEEP);
143 | this._enqueue([n, t]);
144 | return this;
145 | };
146 |
147 | /**
148 | * 清空任务
149 | */
150 | printerJobs.prototype.clear = function () {
151 | this._queue = Array.from(commands.HARDWARE.HW_INIT);
152 | return this;
153 | };
154 |
155 | /**
156 | * 返回ArrayBuffer
157 | */
158 | printerJobs.prototype.buffer = function () {
159 | return new Uint8Array(this._queue).buffer;
160 | };
161 |
162 | module.exports = printerJobs;
--------------------------------------------------------------------------------
/printer/commands.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 修改自https://github.com/song940/node-escpos/blob/master/commands.js
3 | * ESC/POS _ (Constants)
4 | */
5 | var _ = {
6 | LF: [0x0a],
7 | FS: [0x1c],
8 | FF: [0x0c],
9 | GS: [0x1d],
10 | DLE: [0x10],
11 | EOT: [0x04],
12 | NUL: [0x00],
13 | ESC: [0x1b],
14 | EOL: '\n',
15 | };
16 |
17 | /**
18 | * [FEED_CONTROL_SEQUENCES Feed control sequences]
19 | * @type {Object}
20 | */
21 | _.FEED_CONTROL_SEQUENCES = {
22 | CTL_LF: [0x0a], // Print and line feed
23 | CTL_GLF: [0x4a, 0x00], // Print and feed paper (without spaces between lines)
24 | CTL_FF: [0x0c], // Form feed
25 | CTL_CR: [0x0d], // Carriage return
26 | CTL_HT: [0x09], // Horizontal tab
27 | CTL_VT: [0x0b], // Vertical tab
28 | };
29 |
30 | _.CHARACTER_SPACING = {
31 | CS_DEFAULT: [0x1b, 0x20, 0x00],
32 | CS_SET: [0x1b, 0x20]
33 | };
34 |
35 | _.LINE_SPACING = {
36 | LS_DEFAULT: [0x1b, 0x32],
37 | LS_SET: [0x1b, 0x33]
38 | };
39 |
40 | /**
41 | * [HARDWARE Printer hardware]
42 | * @type {Object}
43 | */
44 | _.HARDWARE = {
45 | HW_INIT: [0x1b, 0x40], // Clear data in buffer and reset modes
46 | HW_SELECT: [0x1b, 0x3d, 0x01], // Printer select
47 | HW_RESET: [0x1b, 0x3f, 0x0a, 0x00], // Reset printer hardware
48 | };
49 |
50 | /**
51 | * [CASH_DRAWER Cash Drawer]
52 | * @type {Object}
53 | */
54 | _.CASH_DRAWER = {
55 | CD_KICK_2: [0x1b, 0x70, 0x00], // Sends a pulse to pin 2 []
56 | CD_KICK_5: [0x1b, 0x70, 0x01], // Sends a pulse to pin 5 []
57 | };
58 |
59 | /**
60 | * [MARGINS Margins sizes]
61 | * @type {Object}
62 | */
63 | _.MARGINS = {
64 | BOTTOM: [0x1b, 0x4f], // Fix bottom size
65 | LEFT: [0x1b, 0x6c], // Fix left size
66 | RIGHT: [0x1b, 0x51], // Fix right size
67 | };
68 |
69 | /**
70 | * [PAPER Paper]
71 | * @type {Object}
72 | */
73 | _.PAPER = {
74 | PAPER_FULL_CUT: [0x1d, 0x56, 0x00], // Full cut paper
75 | PAPER_PART_CUT: [0x1d, 0x56, 0x01], // Partial cut paper
76 | PAPER_CUT_A: [0x1d, 0x56, 0x41], // Partial cut paper
77 | PAPER_CUT_B: [0x1d, 0x56, 0x42], // Partial cut paper
78 | };
79 |
80 | /**
81 | * [TEXT_FORMAT Text format]
82 | * @type {Object}
83 | */
84 | _.TEXT_FORMAT = {
85 | TXT_NORMAL: [0x1b, 0x21, 0x00], // Normal text
86 | TXT_2HEIGHT: [0x1b, 0x21, 0x10], // Double height text
87 | TXT_2WIDTH: [0x1b, 0x21, 0x20], // Double width text
88 | TXT_4SQUARE: [0x1b, 0x21, 0x30], // Double width & height text
89 |
90 | TXT_UNDERL_OFF: [0x1b, 0x2d, 0x00], // Underline font OFF
91 | TXT_UNDERL_ON: [0x1b, 0x2d, 0x01], // Underline font 1-dot ON
92 | TXT_UNDERL2_ON: [0x1b, 0x2d, 0x02], // Underline font 2-dot ON
93 | TXT_BOLD_OFF: [0x1b, 0x45, 0x00], // Bold font OFF
94 | TXT_BOLD_ON: [0x1b, 0x45, 0x01], // Bold font ON
95 | TXT_ITALIC_OFF: [0x1b, 0x35], // Italic font ON
96 | TXT_ITALIC_ON: [0x1b, 0x34], // Italic font ON
97 |
98 | TXT_FONT_A: [0x1b, 0x4d, 0x00], // Font type A
99 | TXT_FONT_B: [0x1b, 0x4d, 0x01], // Font type B
100 | TXT_FONT_C: [0x1b, 0x4d, 0x02], // Font type C
101 |
102 | TXT_ALIGN_LT: [0x1b, 0x61, 0x00], // Left justification
103 | TXT_ALIGN_CT: [0x1b, 0x61, 0x01], // Centering
104 | TXT_ALIGN_RT: [0x1b, 0x61, 0x02], // Right justification
105 | };
106 |
107 | /**
108 | * [BARCODE_FORMAT Barcode format]
109 | * @type {Object}
110 | */
111 | _.BARCODE_FORMAT = {
112 | BARCODE_TXT_OFF: [0x1d, 0x48, 0x00], // HRI barcode chars OFF
113 | BARCODE_TXT_ABV: [0x1d, 0x48, 0x01], // HRI barcode chars above
114 | BARCODE_TXT_BLW: [0x1d, 0x48, 0x02], // HRI barcode chars below
115 | BARCODE_TXT_BTH: [0x1d, 0x48, 0x03], // HRI barcode chars both above and below
116 |
117 | BARCODE_FONT_A: [0x1d, 0x66, 0x00], // Font type A for HRI barcode chars
118 | BARCODE_FONT_B: [0x1d, 0x66, 0x01], // Font type B for HRI barcode chars
119 |
120 | BARCODE_HEIGHT: function (height) { // Barcode Height [1-255]
121 | return [0x1d, 0x68, height];
122 | },
123 | BARCODE_WIDTH: function (width) { // Barcode Width [2-6]
124 | return [0x1d, 0x77, width];
125 | },
126 | BARCODE_HEIGHT_DEFAULT: [0x1d, 0x68, 0x64], // Barcode height default:100
127 | BARCODE_WIDTH_DEFAULT: [0x1d, 0x77, 0x01], // Barcode width default:1
128 |
129 | BARCODE_UPC_A: [0x1d, 0x6b, 0x00], // Barcode type UPC-A
130 | BARCODE_UPC_E: [0x1d, 0x6b, 0x01], // Barcode type UPC-E
131 | BARCODE_EAN13: [0x1d, 0x6b, 0x02], // Barcode type EAN13
132 | BARCODE_EAN8: [0x1d, 0x6b, 0x03], // Barcode type EAN8
133 | BARCODE_CODE39: [0x1d, 0x6b, 0x04], // Barcode type CODE39
134 | BARCODE_ITF: [0x1d, 0x6b, 0x05], // Barcode type ITF
135 | BARCODE_NW7: [0x1d, 0x6b, 0x06], // Barcode type NW7
136 | BARCODE_CODE93: [0x1d, 0x6b, 0x48], // Barcode type CODE93
137 | BARCODE_CODE128: [0x1d, 0x6b, 0x49], // Barcode type CODE128
138 | };
139 |
140 | /**
141 | * [IMAGE_FORMAT Image format]
142 | * @type {Object}
143 | */
144 | _.IMAGE_FORMAT = {
145 | S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], // Set raster image normal size
146 | S_RASTER_2W: [0x1d, 0x76, 0x30, 0x01], // Set raster image double width
147 | S_RASTER_2H: [0x1d, 0x76, 0x30, 0x02], // Set raster image double height
148 | S_RASTER_Q: [0x1d, 0x76, 0x30, 0x03], // Set raster image quadruple
149 | };
150 |
151 | /**
152 | * [BITMAP_FORMAT description]
153 | * @type {Object}
154 | */
155 | _.BITMAP_FORMAT = {
156 | BITMAP_S8: [0x1b, 0x2a, 0x00],
157 | BITMAP_D8: [0x1b, 0x2a, 0x01],
158 | BITMAP_S24: [0x1b, 0x2a, 0x20],
159 | BITMAP_D24: [0x1b, 0x2a, 0x21]
160 | };
161 |
162 | /**
163 | * [GSV0_FORMAT description]
164 | * @type {Object}
165 | */
166 | _.GSV0_FORMAT = {
167 | GSV0_NORMAL: [0x1d, 0x76, 0x30, 0x00],
168 | GSV0_DW: [0x1d, 0x76, 0x30, 0x01],
169 | GSV0_DH: [0x1d, 0x76, 0x30, 0x02],
170 | GSV0_DWDH: [0x1d, 0x76, 0x30, 0x03]
171 | };
172 |
173 | /**
174 | * [BEEP description]
175 | * @type {string}
176 | */
177 | _.BEEP = [0x1b, 0x42]; // Printer Buzzer pre hex
178 |
179 | /**
180 | * [COLOR description]
181 | * @type {Object}
182 | */
183 |
184 | _.COLOR = {
185 | 0: [0x1b, 0x72, 0x00], // black
186 | 1: [0x1b, 0x72, 0x01] // red
187 | };
188 |
189 | /**
190 | * [exports description]
191 | * @type {[type]}
192 | */
193 | module.exports = _;
--------------------------------------------------------------------------------
/pages/index/index.js:
--------------------------------------------------------------------------------
1 | const LAST_CONNECTED_DEVICE = 'last_connected_device'
2 | const PrinterJobs = require('../../printer/printerjobs')
3 | const printerUtil = require('../../printer/printerutil')
4 |
5 | function inArray(arr, key, val) {
6 | for (let i = 0; i < arr.length; i++) {
7 | if (arr[i][key] === val) {
8 | return i
9 | }
10 | }
11 | return -1
12 | }
13 |
14 | function ab2str(buf) {
15 | return String.fromCharCode.apply(null, new Uint8Array(buf));
16 | }
17 |
18 | // ArrayBuffer转16进度字符串示例
19 | function ab2hex(buffer) {
20 | const hexArr = Array.prototype.map.call(
21 | new Uint8Array(buffer),
22 | function (bit) {
23 | return ('00' + bit.toString(16)).slice(-2)
24 | }
25 | )
26 | return hexArr.join(',')
27 | }
28 |
29 | function str2ab(str) {
30 | // Convert str to ArrayBuff and write to printer
31 | let buffer = new ArrayBuffer(str.length)
32 | let dataView = new DataView(buffer)
33 | for (let i = 0; i < str.length; i++) {
34 | dataView.setUint8(i, str.charAt(i).charCodeAt(0))
35 | }
36 | return buffer;
37 | }
38 |
39 | Page({
40 | data: {
41 | devices: [],
42 | connected: false,
43 | chs: [],
44 | barcode :[],
45 | },
46 | onUnload() {
47 | this.closeBluetoothAdapter()
48 | },
49 | openBluetoothAdapter() {
50 | if (!wx.openBluetoothAdapter) {
51 | wx.showModal({
52 | title: '提示',
53 | content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
54 | })
55 | return
56 | }
57 | wx.openBluetoothAdapter({
58 | success: (res) => {
59 | console.log('openBluetoothAdapter success', res)
60 | this.startBluetoothDevicesDiscovery()
61 | },
62 | fail: (res) => {
63 | console.log('openBluetoothAdapter fail', res)
64 | if (res.errCode === 10001) {
65 | wx.showModal({
66 | title: '错误',
67 | content: '未找到蓝牙设备, 请打开蓝牙后重试。',
68 | showCancel: false
69 | })
70 | wx.onBluetoothAdapterStateChange((res) => {
71 | console.log('onBluetoothAdapterStateChange', res)
72 | if (res.available) {
73 | // 取消监听,否则stopBluetoothDevicesDiscovery后仍会继续触发onBluetoothAdapterStateChange,
74 | // 导致再次调用startBluetoothDevicesDiscovery
75 | wx.onBluetoothAdapterStateChange(() => {
76 | });
77 | this.startBluetoothDevicesDiscovery()
78 | }
79 | })
80 | }
81 | }
82 | })
83 | wx.onBLEConnectionStateChange((res) => {
84 | // 该方法回调中可以用于处理连接意外断开等异常情况
85 | console.log('onBLEConnectionStateChange', `device ${res.deviceId} state has changed, connected: ${res.connected}`)
86 | this.setData({
87 | connected: res.connected
88 | })
89 | if (!res.connected) {
90 | wx.showModal({
91 | title: '错误',
92 | content: '蓝牙连接已断开',
93 | showCancel: false
94 | })
95 | }
96 | });
97 | },
98 | getBluetoothAdapterState() {
99 | wx.getBluetoothAdapterState({
100 | success: (res) => {
101 | console.log('getBluetoothAdapterState', res)
102 | if (res.discovering) {
103 | this.onBluetoothDeviceFound()
104 | } else if (res.available) {
105 | this.startBluetoothDevicesDiscovery()
106 | }
107 | }
108 | })
109 | },
110 | startBluetoothDevicesDiscovery() {
111 | if (this._discoveryStarted) {
112 | return
113 | }
114 | this._discoveryStarted = true
115 | wx.startBluetoothDevicesDiscovery({
116 | success: (res) => {
117 | console.log('startBluetoothDevicesDiscovery success', res)
118 | this.onBluetoothDeviceFound()
119 | },
120 | fail: (res) => {
121 | console.log('startBluetoothDevicesDiscovery fail', res)
122 | }
123 | })
124 | },
125 | stopBluetoothDevicesDiscovery() {
126 | wx.stopBluetoothDevicesDiscovery({
127 | complete: () => {
128 | console.log('stopBluetoothDevicesDiscovery')
129 | this._discoveryStarted = false
130 | }
131 | })
132 | },
133 | onBluetoothDeviceFound() {
134 | wx.onBluetoothDeviceFound((res) => {
135 |
136 | console.log('onBluetoothDeviceFound res',res)
137 | res.devices.forEach(device => {
138 | if (!device.name && !device.localName) {
139 | return
140 | }
141 |
142 | console.log('onBluetoothDeviceFound device',device)
143 |
144 | const foundDevices = this.data.devices
145 | const idx = inArray(foundDevices, 'deviceId', device.deviceId)
146 | const data = {}
147 | if (idx === -1) {
148 | data[`devices[${foundDevices.length}]`] = device
149 | } else {
150 | data[`devices[${idx}]`] = device
151 | }
152 | this.setData(data)
153 | })
154 | })
155 | },
156 | createBLEConnection(e) {
157 | const ds = e.currentTarget.dataset
158 | const deviceId = ds.deviceId
159 | const name = ds.name
160 | this._createBLEConnection(deviceId, name)
161 | },
162 | _createBLEConnection(deviceId, name) {
163 | wx.showLoading()
164 | wx.createBLEConnection({
165 | deviceId,
166 | success: () => {
167 | console.log('createBLEConnection success');
168 | this.setData({
169 | connected: true,
170 | name,
171 | deviceId,
172 | })
173 | this.getBLEDeviceServices(deviceId)
174 | wx.setStorage({
175 | key: LAST_CONNECTED_DEVICE,
176 | data: name + ':' + deviceId
177 | })
178 | },
179 | complete() {
180 | wx.hideLoading()
181 | },
182 | fail: (res) => {
183 | console.log('createBLEConnection fail', res)
184 | }
185 | })
186 | this.stopBluetoothDevicesDiscovery()
187 | },
188 | closeBLEConnection() {
189 | wx.closeBLEConnection({
190 | deviceId: this.data.deviceId
191 | })
192 | this.setData({
193 | connected: false,
194 | chs: [],
195 | canWrite: false,
196 | barcode:[],
197 | })
198 | },
199 | getBLEDeviceServices(deviceId) {
200 | wx.getBLEDeviceServices({
201 | deviceId,
202 | success: (res) => {
203 | console.log('getBLEDeviceServices', res)
204 | for (let i = 0; i < res.services.length; i++) {
205 | if (res.services[i].isPrimary) {
206 | this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
207 | }
208 | }
209 | }
210 | })
211 | },
212 | getBLEDeviceCharacteristics(deviceId, serviceId) {
213 | let that = this;
214 | wx.getBLEDeviceCharacteristics({
215 | deviceId,
216 | serviceId,
217 | success: (res) => {
218 | console.log('getBLEDeviceCharacteristics success', res.characteristics)
219 | // 这里会存在特征值是支持write,写入成功但是没有任何反应的情况
220 | // 只能一个个去试
221 | for (let i = 0; i < res.characteristics.length; i++) {
222 | const item = res.characteristics[i]
223 | if (item.properties.indicate){
224 | console.log('getBLEDeviceCharacteristics indicate item is true', item)
225 | }else{
226 | console.log('getBLEDeviceCharacteristics indicate item is false', item)
227 | return
228 | }
229 | if ( item.properties.notify && item.properties.indicate) {
230 | this.setData({
231 | canWrite: true
232 | })
233 | this._deviceId = deviceId
234 | this._serviceId = serviceId
235 | this._characteristicId = item.uuid
236 |
237 |
238 | wx.notifyBLECharacteristicValueChange({
239 | characteristicId: item.uuid,
240 |
241 | deviceId: deviceId,
242 |
243 | serviceId: serviceId,
244 |
245 | state: true,
246 | type:'notification',
247 | fail (res) {
248 | console.log({res})
249 | },
250 | complete:function(res){
251 | console.log('44444444444444444444444',res)
252 |
253 | },
254 | success:function(res){
255 |
256 | console.log('notify启用',res);
257 | wx.onBLECharacteristicValueChange((result) => {
258 | console.log('监听特征值变化',result);
259 | const barcode = [ab2str(result.value),...that.data.barcode];
260 | that.setData({barcode})
261 | })
262 | }
263 | });
264 | break;
265 | }
266 | }
267 | },
268 | fail(res) {
269 | console.error('getBLEDeviceCharacteristics', res)
270 | }
271 | })
272 | },
273 | writeBLECharacteristicValue() {
274 | let printerJobs = new PrinterJobs();
275 | printerJobs
276 | .print('2018年12月5日17:34')
277 | .print(printerUtil.fillLine())
278 | .setAlign('ct')
279 | .setSize(2, 2)
280 | .print('#20饿了么外卖')
281 | .setSize(1, 1)
282 | .print('切尔西Chelsea')
283 | .setSize(2, 2)
284 | .print('在线支付(已支付)')
285 | .setSize(1, 1)
286 | .print('订单号:5415221202244734')
287 | .print('下单时间:2017-07-07 18:08:08')
288 | .setAlign('lt')
289 | .print(printerUtil.fillAround('一号口袋'))
290 | .print(printerUtil.inline('意大利茄汁一面 * 1', '15'))
291 | .print(printerUtil.fillAround('其他'))
292 | .print('餐盒费:1')
293 | .print('[赠送康师傅冰红茶] * 1')
294 | .print(printerUtil.fillLine())
295 | .setAlign('rt')
296 | .print('原价:¥16')
297 | .print('总价:¥16')
298 | .setAlign('lt')
299 | .print(printerUtil.fillLine())
300 | .print('备注')
301 | .print("无")
302 | .print(printerUtil.fillLine())
303 | .println();
304 |
305 | let buffer = printerJobs.buffer();
306 | console.log('ArrayBuffer', 'length: ' + buffer.byteLength, ' hex: ' + ab2hex(buffer));
307 | // 1.并行调用多次会存在写失败的可能性
308 | // 2.建议每次写入不超过20字节
309 | // 分包处理,延时调用
310 | const maxChunk = 20;
311 | const delay = 20;
312 | for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) {
313 | let subPackage = buffer.slice(i, i + maxChunk <= length ? (i + maxChunk) : length);
314 | setTimeout(this._writeBLECharacteristicValue, j * delay, subPackage);
315 | }
316 | },
317 | _writeBLECharacteristicValue(buffer) {
318 | wx.writeBLECharacteristicValue({
319 | deviceId: this._deviceId,
320 | serviceId: this._serviceId,
321 | characteristicId: this._characteristicId,
322 | value: buffer,
323 | success(res) {
324 | console.log('writeBLECharacteristicValue success', res)
325 | },
326 | fail(res) {
327 | console.log('writeBLECharacteristicValue fail', res)
328 | }
329 | })
330 | },
331 | closeBluetoothAdapter() {
332 | wx.closeBluetoothAdapter()
333 | this._discoveryStarted = false
334 | },
335 | onLoad(options) {
336 | const lastDevice = wx.getStorageSync(LAST_CONNECTED_DEVICE);
337 | this.setData({
338 | lastDevice: lastDevice
339 | })
340 | },
341 | createBLEConnectionWithDeviceId(e) {
342 | // 小程序在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备
343 | const device = this.data.lastDevice
344 | if (!device) {
345 | return
346 | }
347 | const index = device.indexOf(':');
348 | const name = device.substring(0, index);
349 | const deviceId = device.substring(index + 1, device.length);
350 | console.log('createBLEConnectionWithDeviceId', name + ':' + deviceId)
351 | wx.openBluetoothAdapter({
352 | success: (res) => {
353 | console.log('openBluetoothAdapter success', res)
354 | this._createBLEConnection(deviceId, name)
355 | },
356 | fail: (res) => {
357 | console.log('openBluetoothAdapter fail', res)
358 | if (res.errCode === 10001) {
359 | wx.showModal({
360 | title: '错误',
361 | content: '未找到蓝牙设备, 请打开蓝牙后重试。',
362 | showCancel: false
363 | })
364 | wx.onBluetoothAdapterStateChange((res) => {
365 | console.log('onBluetoothAdapterStateChange', res)
366 | if (res.available) {
367 | // 取消监听
368 | wx.onBluetoothAdapterStateChange(() => {
369 | });
370 | this._createBLEConnection(deviceId, name)
371 | }
372 | })
373 | }
374 | }
375 | })
376 | }
377 | })
--------------------------------------------------------------------------------
/miniprogram_npm/text-encoding/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["..\\..\\node_modules\\text-encoding\\index.js","..\\..\\node_modules\\text-encoding\\lib\\encoding.js","..\\..\\node_modules\\text-encoding\\lib\\encoding-indexes.js"],"names":[],"mappings":";;;;;;;AAAA;AACA;AACA;AACA,ACHA;ADIA,ACHA;ADIA,ACHA;ADIA,AENA,ADGA;ADIA,AENA,ADGA;ADIA,AENA,ADGA;ADIA,AENA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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;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"}
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
61 |
62 |
63 |
64 | function
65 | =>
66 | 0A
67 | 1B
68 | buffer
69 | PrinterJob
70 | COLOR
71 | 21
72 | FEED_CONTROL_SEQUENCES
73 | CS_DEFAULT
74 | TXT_FONT_
75 | 25
76 | ff
77 | 24
78 | the code point
79 | utf
80 | gbk
81 | '\x
82 | '
83 | \x
84 | ab2hex
85 | CHARACTER_SPACING
86 | getBLEDeviceServices
87 | onBLEConnectionStateChange
88 | openBluetoothAdapter
89 | onBluetoothAdapterStateChange
90 | _discoveryStarted
91 | startBluetoothDevicesDiscovery
92 | connected
93 | name
94 |
95 |
96 | [0x
97 | ]
98 | ,0x
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | true
128 | DEFINITION_ORDER
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 | General
148 |
149 |
150 | JavaScript
151 |
152 |
153 | Naming conventionsJavaScript
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 | 1543547960238
243 |
244 |
245 | 1543547960238
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 | 1543832773328
256 |
257 |
258 |
259 | 1543832773328
260 |
261 |
262 | 1543834392860
263 |
264 |
265 |
266 | 1543834392860
267 |
268 |
269 | 1544080328425
270 |
271 |
272 |
273 | 1544080328425
274 |
275 |
276 | 1544155442455
277 |
278 |
279 |
280 | 1544155442455
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
--------------------------------------------------------------------------------