├── README.md ├── main.js ├── 前端网页1203 ├── index.html ├── js │ ├── hanzi-writer-lib.js │ ├── hanzi-writer-lib.min.js │ ├── hanzi-writer.js │ ├── hanzi-writer.min.js │ ├── polyfill.js │ ├── test.js │ └── test_data.js └── styles.css ├── 微信小程序二维码.jpg ├── 直书小程序源代码 ├── App.vue ├── Readme.md ├── cloudfunctionTemplate │ └── mlkit.json ├── cloudfunctions │ └── mlkit │ │ ├── config.json │ │ ├── index.js │ │ └── package.json ├── colorui │ ├── animation.css │ ├── components │ │ └── cu-custom.vue │ ├── icon.css │ └── main.css ├── components │ ├── centerImg.vue │ ├── clickLink.vue │ ├── selectWord.vue │ ├── textTitle.vue │ └── textView.vue ├── lib │ ├── convertSimpleTraditionCN │ │ └── index.js │ └── hanzi-writer │ │ ├── EventEmitter.js │ │ ├── RenderTarget.js │ │ ├── defaultCharDataLoader.js │ │ ├── hanzi-writer-context.js │ │ ├── hanzi-writer.vue │ │ ├── index.js │ │ └── utils.js ├── locale.json ├── main.js ├── manifest.json ├── mixin.js ├── package-lock.json ├── package.json ├── pages.json ├── pages │ ├── about │ │ └── about.vue │ └── index │ │ ├── asr.vue │ │ ├── example.vue │ │ ├── index.vue │ │ ├── ocr.vue │ │ ├── translate.vue │ │ ├── tts.vue │ │ └── writer.vue ├── static │ └── characterBg.svg ├── vue.config.js └── yarn.lock └── 秉笔直书——汉字笔画学习小程序.assets ├── 微信图片_20191216182410.jpg ├── 微信图片_20191216182435.jpg ├── 微信图片_20191216182439.jpg ├── 微信图片_20191216182642.jpg ├── 微信小程序二维码.jpg ├── 微信截图_20191216182729.png └── 汉字笔画.jpg /README.md: -------------------------------------------------------------------------------- 1 | # 直书—基于华为HMS Core ML Kit的人工智能趣学汉字小程序 2 | 3 | > 2019-12-15、2022-5-11 4 | 5 | ## 直书—即查即用的AI学汉字小程序 6 | 7 | “直书”—基于华为HMS Core ML Kit的人工智能趣学汉字小程序。 8 | 9 | 搭载拍照识别、语音识别、AI翻译、语音生成等人工智能黑科技,外国人也可轻松上手,即查即用,一站式掌握汉字音、形、写、义。 10 | 11 | “直书”提供各国语言的微信小程序、华为快应用、网页、手机APP、平板APP。 12 | 13 | 讲好中国故事,提升文化自信,助力全球二十亿汉语学习者。 14 | 15 | 项目主页:https://github.com/TommyZihao/EasyHanzi 16 | 17 | ![微信截图_20191216182729](秉笔直书——汉字笔画学习小程序.assets/微信截图_20191216182729.png) 18 | 19 | ![微信小程序二维码](秉笔直书——汉字笔画学习小程序.assets/微信小程序二维码.jpg) 20 | 21 | ## 支持平台 22 | 23 | | 平台 | 适用场景 | 常见地区 | 24 | | ----------------- | -------------------------- | ------------------------ | 25 | | 微信小程序 | 有微信有网络就能用 | 全球 | 26 | | 华为快应用 | 华为手机 | 全球 | 27 | | QQ小程序 | 有QQ有网络就能用 | 中国大陆 | 28 | | 网页 | 有网就能用 | 全球孔子学院、汉语文化圈 | 29 | | 安卓APP、IOS端APP | 智能手机或平板 | 全球汉语学习者 | 30 | | 平板APP | 触摸交互沉浸式智能笔画校对 | 中小学、图书馆、博物馆 | 31 | 32 | 不需安装,扫码即开,打开即用,用完即走,跨平台兼容,充分体现互联网产品轻量化、智能化、云计算的用户交互特点。 33 | 34 | 支持常见九千个简体、繁体字。 35 | 36 | ## 用户群体:二十亿汉语文化圈 37 | 38 | - 中国大陆中小学校 39 | - 图书馆、博物馆等科普机构 40 | - 书法与国学爱好者 41 | - 港澳台地区学习繁体字、推广简体字 42 | - 在华留学生 43 | - “一带一路”沿线汉语学习者 44 | - 全球孔子学院 45 | - 全球汉语文化圈 46 | 47 | ## 功能说明 48 | 49 | - 笔顺动画演示 50 | 51 | - 交互式摹写与临写。 52 | 53 | - 简繁体转换 54 | - AI智能拍照识字:方便不会使用汉语拼音和输入法的朋友。基于华为ML Kit OCR文字识别API。 55 | - 机器翻译:输入英文,生成对应汉语。基于华为ML Kit 机器翻译API。 56 | - 文本转语音:输入汉字文本,生成朗读语音。基于华为ML Kit语音合成接口。 57 | - 语音识别:开启麦克风输入语音,识别对应的汉语。基于华为ML Kit语音识别接口。 58 | 59 | ## 愿景:讲好中国故事,树立文化自信 60 | 61 | > 坚定中国特色社会主义道路自信、理论自信、制度自信,说到底是要坚定文化自信。文化自信是更基本、更深沉、更持久的力量。 62 | > 63 | > ——总书记在全国宣传思想工作会议重要讲话。 64 | 65 | 随着中国改革开放的迅速崛起,来华留学生数量逐年增加,各类汉语诗词国学综艺节目广受好评,海外孔子学院全球推广,全球汉语教育呈现火热趋势。 66 | 67 | 世界上使用汉语的人数至少15亿 ,超过世界人口的五分之一。汉语是中国官方语言,也是新加坡、联合国工作语言之一。 68 | 69 | 2016年时,英当局耗资近8700万人民币投入到了在公立学校推进汉语教学的计划中。 70 | 71 | 早在十年前,日本就有630家大学开设了中文课程,而汉语学习的人数则超200万人,学习汉语已经成为日本学生必备的一项课程。汉语也是日本除了英语外的第二大外语。 72 | 73 | 汉语也是全世界公认最难学的语言之一。 74 | 75 | 俗话说:“人生聪明写字始”。掌握好笔顺是写字的基本功,也是学习汉语的第一关。 76 | 77 | 然而,汉字数量繁杂、笔画各异,不易记忆,难倒了众多汉语初学者。很多学习汉语多年的在华留学生,虽然说着流利的汉语,却提笔难言。 78 | 79 | 甚至有些土生土长的中国人,写字的笔顺也是错误的。 80 | 81 | 例如: 82 | 83 | “匕”应该先写撇,后写竖弯钩。 84 | 85 | “火”应该先写上面两笔,即点和撇,再写人字。 86 | 87 | 港澳台同胞不写简体字,然而我们同样也不会写繁体字,十九大报告指出,实现祖国完全统一。简繁体汉字在无形中形成一道文化的隔膜,阻碍了文化认同和文化自信。 88 | 所以,我们为小程序增加了简繁体两个界面。 89 | 90 | 既方便港澳台同胞学习简体字,也方便内地的书法爱好者,国学爱好者学习繁体字,繁体字其实有更复杂的笔画,查字典是效率最低的方式,我们的小程序就是不二之选。 91 | 92 | ![汉字笔画](秉笔直书——汉字笔画学习小程序.assets/汉字笔画.jpg) 93 | 94 | ## 开发团队:在华留学生+全栈工程师 95 | 96 | 产品经理:同济子豪兄 97 | 98 | 前端开发、UI设计、全栈开发:Maxoyed 99 | 100 | 用户交互优化、法语界面:Itoua Prince Igor(刚果布留学生) 101 | 102 | PPT设计:向凤麟、郑雨涵 103 | 104 | ## 参考资料 105 | 106 | - 华为 ML Kit开发者文档:https://developer.huawei.com/consumer/cn/hms/huawei-locationkit 107 | 108 | - Javascript 开源库 Hanzi Writer 109 | 110 | 文档: https://chanind.github.io/hanzi-writer/cn/docs.html 111 | 112 | Github开源地址:https://github.com/chanind/hanzi-writer 113 | 114 | 作者: https://github.com/chanind 115 | 116 | 汉字数据来自 [Make Me a Hanzi](https://github.com/skishore/makemeahanzi) 项目, 提供 9000 +常用简体字和繁体字。 117 | 118 | Hanzi Writer 库仅仅 30 kb (压缩后仅 9kb!), 所以添加它不会使网页体积增大。 119 | 120 | Hanzi Writer 使用Javascript, HTML5 and SVG, 所以它能嵌入到任何平台,包括 iOS 、安卓、桌面端应用和网页、微信小程序。 121 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | 4 | // 导入 hanzi-writer 5 | import hanziWriter from './lib/hanzi-writer/hanzi-writer.vue' 6 | Vue.component('hanzi-writer', hanziWriter) 7 | 8 | // 导入简繁转化库 9 | import { 10 | convert 11 | } from './lib/convertSimpleTraditionCN/index.js' 12 | Vue.prototype.convert = convert; 13 | 14 | // 导入 vue-i18n多语言库 15 | import VueI18n from 'vue-i18n' 16 | Vue.use(VueI18n) 17 | const i18n = new VueI18n({ 18 | locale: 'zh-CN', 19 | messages: { 20 | 'zh-CN': { 21 | index: { 22 | appTitle: '学写汉字', 23 | changeLang: '切换语言', 24 | aboutUs: '关于我们', 25 | updateText: '更新文字', 26 | animation: '动画', 27 | traditional: '繁体', 28 | simplified: '简体', 29 | quiz: '我来写', 30 | changeSample: '点击下列图片切换示例文字' 31 | } 32 | }, 33 | 'zh-TW': { 34 | index: { 35 | appTitle: '學寫漢字', 36 | changeLang: '切換語言', 37 | aboutUs: '關於我們', 38 | updateText: '更新文字', 39 | animation: '動畫', 40 | traditional: '繁體', 41 | simplified: '簡體', 42 | quiz: '我來寫', 43 | changeSample: '點擊下列圖片切換示例文字' 44 | } 45 | }, 46 | 'en-US': { 47 | index: { 48 | appTitle: 'Easy Hanzi', 49 | changeLang: 'Change Language', 50 | aboutUs: 'About Us', 51 | updateText: 'Update Text', 52 | animation: 'Animation', 53 | traditional: 'Traditional', 54 | simplified: 'Simplified', 55 | quiz: 'Write Myself', 56 | changeSample: 'Switch the sample text' 57 | } 58 | }, 59 | } 60 | }) 61 | 62 | Vue.prototype._i18n = i18n 63 | 64 | Vue.config.productionTip = false 65 | 66 | App.mpType = 'app' 67 | 68 | const app = new Vue({ 69 | i18n, 70 | ...App 71 | }) 72 | app.$mount() 73 | -------------------------------------------------------------------------------- /前端网页1203/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 汉字笔画 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

秉笔直书——汉字笔画小程序

19 |
20 | 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 |
36 |

秉笔直书——汉字笔画学习小程序

37 |

一句话介绍

38 |

提供常用汉字笔画的即查即用、动画书写流程、交互式书写检查矫正。

39 |

帮助全球汉语学习者养成正确书写习惯,降低汉语学习门槛,传播中国文化。

40 |

提供微信小程序、网页、手机APP等使用方式。

41 |

使用说明

42 |

输入汉字,点击更新,即可看到笔画。

43 |

可以播放动画,逐步演示书写顺序,也可以交互式摹写与临写。

44 |

支持所有常见简体字、繁体字。

45 |

 

46 |

项目背景

47 |

俗话说:“人生聪明写字始”。掌握好笔顺是写好一笔字的开始。

48 |

笔顺是学习汉语的第一关,也是写字基本功,然而,汉字数量繁杂、笔画各异,不易记忆,难倒了众多汉语初学者。很多学习汉语多年的在华留学生,虽然说着流利的汉语,却提笔难言。

49 |

甚至有些土生土长的中国人,写字的笔顺也是错误的。

50 |

例如:

51 |

“匕”应该先写撇,后写竖弯钩。

52 |

“火”应该先写上面两笔,即点和撇,再写人字。

53 |

1965年1月30日中华人民共和国文化部和中国文字改革委员会发布的《印刷通用汉字字形表》和1988年3月国家语言文字工作委员会、中华人民共和国新闻出版署发布的《现代汉语通用字表》规定了5类基本笔画:横类、竖类、撇类、点类、折类。 54 |

55 |

 

56 |

随着各类汉语综艺节目、海外孔子学院的推广,来华留学生数量逐年增加,全球汉语教育呈现火热趋势。

57 |

世界上使用汉语的人数至少15亿 ,超过世界总人口的20%,是中国的官方语言,是新加坡的四种官方语言之一,亦是联合国六种工作语言之一。汉语也是全世界公认最难学的语言之一。

58 |

2016年时,英当局耗资近8700万人民币投入到了在公立学校推进汉语教学的计划中。

59 |

早在十年前,日本就有630家大学开设了中文课程,而汉语学习的人数则超200万人,学习汉语已经成为日本学生必备的一项课程。汉语也是日本除了英语外的第二大外语。

60 |

 

61 |

项目愿景

62 |

中国大陆中小学校及港澳台简体字推广集构

63 |

在华留学生

64 |

一带一路沿线汉语学习者

65 |

全球汉语文化圈

66 |

讲好中国故事,传播中国文化,推动文化自信。

67 |

 

68 |

项目负责人

69 |

同济大学开源软件协会 Itoua Prince Igor(刚果布留学生)

70 |

子豪兄 Maxoyed

71 |

 

72 |

参考资料

73 |

Javascript 免费开源库 Hanzi Writer

74 |

汉字数据来自 Make Me a Hanzi 项目, 提供 9000 多常用简体字和繁体字。

75 |

 

76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /前端网页1203/js/hanzi-writer-lib.min.js: -------------------------------------------------------------------------------- 1 | /*! Hanzi Writer v1.3.1 | https://chanind.github.io/hanzi-writer */ 2 | module.exports=function(t){var i={};function n(r){if(i[r])return i[r].exports;var o=i[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=i,n.d=function(t,i,r){n.o(t,i)||Object.defineProperty(t,i,{configurable:!1,enumerable:!0,get:r})},n.n=function(t){var i=t&&t.t?function(){return t.default}:function(){return t};return n.d(i,"a",i),i},n.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},n.p="",n(n.s=6)}([function(t,i,n){"use strict";(function(i){var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};var r=i.performance&&function(){return i.performance.now()}||function(){return Date.now()},o=i.requestAnimationFrame||function(t){return setTimeout(function(){return t(r())},1e3/60)},s=i.cancelAnimationFrame||clearTimeout,e=function(t){for(var i=Object(t),n=arguments.length,r=Array(n>1?n-1:0),o=1;o0&&void 0!==arguments[0]?arguments[0]:0;return new Promise(function(i,n){setTimeout(i,t)})},trim:function(t){return t.replace(/^\s+/,"").replace(/\s+$/,"")}}}).call(i,n(3))},function(t,i,n){"use strict";(function(i){var r=n(2).round;function o(t){return i.document.createElementNS("http://www.w3.org/2000/svg",t)}function s(t,i,n){t.setAttributeNS(null,i,n)}function e(t,i){Object.keys(i).forEach(function(n){return s(t,n,i[n])})}function u(t,i){this.svg=t,this.defs=i}u.prototype.createSubCanvas=function(){var t=o("g");return this.svg.appendChild(t),new u(t,this.defs)},u.init=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"100%",r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"100%",s=void 0,h=t;"string"==typeof t&&(h=i.document.getElementById(t));var a=h.nodeName.toUpperCase();"SVG"===a||"G"===a?s=h:(s=o("svg"),h.appendChild(s)),e(s,{width:n,height:r});var c=o("defs");return s.appendChild(c),new u(s,c)},t.exports={createElm:o,attrs:e,attr:s,Canvas:u,getPathString:function(t){var i=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=r(t[0]),o=t.slice(1),s="M "+n.x+" "+n.y;return o.forEach(function(t){var i=r(t);s+=" L "+i.x+" "+i.y}),i&&(s+="Z"),s},removeElm:function(t){t&&t.parentNode.removeChild(t)},urlIdRef:function(t){var n="";return i.location&&i.location.href&&(n=i.location.href.replace(/#[^#]*$/,"")),"url("+n+"#"+t+")"}}}).call(i,n(3))},function(t,i,n){"use strict";var r=n(0),o=r.average,s=r.arrLast,e=function(t,i){return{x:t.x-i.x,y:t.y-i.y}},u=function(t){return Math.sqrt(Math.pow(t.x,2)+Math.pow(t.y,2))},h=function(t,i){return u(e(t,i))},a=function(t){var i=t[0];return t.slice(1).reduce(function(t,n){var r=h(n,i);return i=n,t+r},0)},c=function(t,i,n){var r=e(i,t),o=n/u(r);return{x:i.x+o*r.x,y:i.y+o*r.y}},f=function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.05,n=t.slice(0,1);return t.slice(1).forEach(function(t){var r=n[n.length-1],o=h(t,r);if(o>i)for(var s=Math.ceil(o/i),e=o/s,u=0;u1&&void 0!==arguments[1]?arguments[1]:30,n=a(t)/(i-1),r=[t[0]],o=s(t),e=t.slice(1),u=0;u1&&void 0!==arguments[1]?arguments[1]:1);return{x:Math.round(i*t.x)/i,y:Math.round(i*t.y)/i}},equals:function(t,i){return t.x===i.x&&t.y===i.y},distance:h,frechetDist:function(t,i){for(var n=[],r=0;r-1?n[o][s]:(n[o][s]=0===o&&0===s?h(t[0],i[0]):o>0&&0===s?Math.max(r(o-1,0),h(t[o],i[0])):0===o&&s>0?Math.max(r(0,s-1),h(t[0],i[s])):o>0&&s>0?Math.max(Math.min(r(o-1,s),r(o-1,s-1),r(o,s-1)),h(t[o],i[s])):1/0,n[o][s])}(t.length-1,i.length-1)},length:a,rotate:function(t,i){return t.map(function(t){return{x:Math.cos(i)*t.x-Math.sin(i)*t.y,y:Math.sin(i)*t.x+Math.cos(i)*t.y}})},subtract:e,cosineSimilarity:function(t,i){return(t.x*i.x+t.y*i.y)/u(t)/u(i)},outlineCurve:v,extendPointOnLine:c,filterParallelPoints:function(t){if(t.length<3)return t;var i=[t[0],t[1]];return t.slice(2).forEach(function(t,n){var r=i.length,o=e(t,i[r-1]),s=e(i[r-1],i[r-2]);o.y*s.x-o.x*s.y==0&&i.pop(),i.push(t)}),i},subdivideCurve:f,normalizeCurve:function(t){var i=v(t),n={x:o(i.map(function(t){return t.x})),y:o(i.map(function(t){return t.y}))},r=i.map(function(t){return e(t,n)}),u=Math.sqrt(o([Math.pow(r[0].x,2)+Math.pow(r[0].y,2),Math.pow(s(r).x,2)+Math.pow(s(r).y,2)])),h=r.map(function(t){return{x:t.x/u,y:t.y/u}});return f(h)}}},function(t,i){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,i,n){"use strict";var r=n(5),o=n(0).objRepeat,s=function(t,i,n){return[new r("character."+t+".strokes",o({opacity:1,displayPortion:1},i.strokes.length),{duration:n,force:!0})]},e=function(t,i,n){return[new r("character."+t+".opacity",0,{duration:n,force:!0})].concat(s(t,i,0))},u=function(t,i,n){var o,s,e,u=i.strokeNum,h=(i.getLength()+600)/(3*n);return[new r("character."+t,{opacity:1,strokes:(o={},s=u,e={displayPortion:0,opacity:1},s in o?Object.defineProperty(o,s,{value:e,enumerable:!0,configurable:!0,writable:!0}):o[s]=e,o)}),new r("character."+t+".strokes."+u+".displayPortion",1,{duration:h})]},h=function(t,i,n,h,a){var c=e(t,i,n);return(c=c.concat(s(t,i,0))).push(new r("character."+t,{opacity:1,strokes:o({opacity:0},i.strokes.length)},{force:!0})),i.strokes.forEach(function(i,n){n>0&&c.push(new r.Pause(a)),c=c.concat(u(t,i,h))}),c};t.exports={showStrokes:s,showCharacter:function(t,i,n){return[new r("character."+t,{opacity:1,strokes:o({opacity:1,displayPortion:1},i.strokes.length)},{duration:n,force:!0})]},hideCharacter:e,animateCharacter:h,animateCharacterLoop:function(t,i,n,o,s,e){var u=h(t,i,n,o,s);return u.push(new r.Pause(e)),u},animateStroke:u,animateSingleStroke:function(t,i,n,o){return[new r("character."+t,function(n){for(var r=n.character[t],o={opacity:1,strokes:{}},s=0;s2&&void 0!==arguments[2]?arguments[2]:{};this.scope=t,this.u=i,this.h=n.duration||0,this.f=n.force,this.v=this.w.bind(this)}function a(t){this.h=t}h.prototype.run=function(t){var i=this;return this.k||this.C(t),0===this.h&&t.updateState(this.k),0===this.h||function t(i,n){for(var r in n)if(n.hasOwnProperty(r)){var o=n[r],s=i[r];if(o>=0){if(o!==s)return!1}else if(!t(s,o))return!1}return!0}(t.state,this.k)?Promise.resolve():(this.M=t,this.S=t.state,this.P=s(),this.j=e(this.v),new Promise(function(t){i.F=t}))},h.prototype.w=function(t){var i,n=Math.min(1,(t-this.P)/this.h);if(1===n)this.M.updateState(this.k),this.j=null,this.cancel(this.M);else{var r=(i=n,-Math.cos(i*Math.PI)/2+.5);this.M.updateState(function t(i,n,r){var o={};for(var s in n){var e=n[s],u=i[s];o[s]=e>=0?r*(e-u)+u:t(u,e,r)}return o}(this.S,this.k,r)),this.j=e(this.v)}},h.prototype.C=function(t){var i=this.u;"function"==typeof this.u&&(i=this.u(t.state)),this.k=o(this.scope,i)},h.prototype.cancel=function(t){this.F&&this.F(),this.F=null,this.j&&u(this.j),this.j=null,this.f&&(this.k||this.C(t),t.updateState(this.k))},a.prototype.run=function(){var t=this,i=new Promise(function(i){t.F=i});return this.O=setTimeout(function(){return t.cancel()},this.h),i},a.prototype.cancel=function(){clearTimeout(this.O),this.F&&this.F(),this.F=!1},h.Pause=a,t.exports=h},function(t,i,n){"use strict";(function(i){var r=n(7),o=n(11),s=n(12),e=n(15),u=n(16),h=n(1),a=n(20),c=n(21),f=n(4),v=n(0),l=v.assign,d=v.callIfExists,p=v.trim,y=v.colorStringToVals,w={charDataLoader:a,onLoadCharDataError:null,onLoadCharDataSuccess:null,showOutline:!0,showCharacter:!0,width:null,height:null,padding:20,strokeAnimationSpeed:1,strokeFadeDuration:400,strokeHighlightDuration:200,strokeHighlightSpeed:2,delayBetweenStrokes:1e3,delayBetweenLoops:2e3,strokeColor:"#555",radicalColor:null,highlightColor:"#AAF",outlineColor:"#DDD",drawingColor:"#333",leniency:1,showHintAfterMisses:3,highlightOnComplete:!0,highlightCompleteColor:null,drawingFadeDuration:300,drawingWidth:4,strokeWidth:2,outlineWidth:2};function g(){if(arguments.length>0){var t=void 0,i={},n=arguments.length<=0?void 0:arguments[0];arguments.length>1&&("string"==typeof(arguments.length<=1?void 0:arguments[1])?(console.warn("Using new HanziWriter() to set a character is deprecated. Use HanziWriter.create() instead"),t=arguments.length<=1?void 0:arguments[1],i=(arguments.length<=2?void 0:arguments[2])||{}):i=arguments.length<=1?void 0:arguments[1]),this.D(n,i),t&&this.setCharacter(t)}}g.prototype.showCharacter=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showCharacter=!0,this.U(function(){return t.M.run(f.showCharacter("main",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.hideCharacter=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showCharacter=!1,this.U(function(){return t.M.run(f.hideCharacter("main",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.animateCharacter=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.cancelQuiz(),this.U(function(){return t.M.run(f.animateCharacter("main",t.I,t.A.strokeFadeDuration,t.A.strokeAnimationSpeed,t.A.delayBetweenStrokes)).then(function(t){return d(i.onComplete,t)})})},g.prototype.animateStroke=function(t){var i=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return this.cancelQuiz(),this.U(function(){return i.M.run(f.animateSingleStroke("main",i.I,t,i.A.strokeAnimationSpeed)).then(function(t){return d(n.onComplete,t)})})},g.prototype.loopCharacterAnimation=function(){var t=this;arguments.length>0&&void 0!==arguments[0]&&arguments[0];return this.cancelQuiz(),this.U(function(){return t.M.run(f.animateCharacterLoop("main",t.I,t.A.strokeFadeDuration,t.A.strokeAnimationSpeed,t.A.delayBetweenStrokes,t.A.delayBetweenLoops),{loop:!0})})},g.prototype.showOutline=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showOutline=!0,this.U(function(){return t.M.run(f.showCharacter("outline",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.hideOutline=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showOutline=!1,this.U(function(){return t.M.run(f.hideCharacter("outline",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.updateColor=function(t,i){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return this.U(function(){var o="number"==typeof r.duration?r.duration:n.A.strokeFadeDuration,s=i;"radicalColor"!==t||i||(s=n.A.strokeColor);var e=y(s);n.A[t]=i;var u=f.updateColor(t,e,o);return"radicalColor"!==t||i||(u=u.concat(f.updateColor(t,null,0))),n.M.run(u).then(function(t){return d(r.onComplete,t)})})},g.prototype.quiz=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.U(function(){t.cancelQuiz(),t.L=new u(t.I,t.M,t.T),t.L.startQuiz(l({},t.A,i))})},g.prototype.cancelQuiz=function(){this.L&&(this.L.cancel(),this.L=null)},g.prototype.setCharacter=function(t){var i=this;return this.cancelQuiz(),this.W=t,this._&&this._.destroy(),this.M&&this.M.cancelAll(),this._=null,this.z=this.H.loadCharData(t).then(function(n){if(!i.H.loadingFailed){var u=new s;i.I=u.generateCharacter(t,n),i.T=new e(i.A);var h=new r(i.I,i.T);i._=h,i.M=new o(i.I,i.A,function(t){h.render(t)}),i._.mount(i.R,i.M.state),i._.render(i.M.state)}}),this.z},g.prototype.D=function(t,i){return this.R=h.Canvas.init(t,i.width,i.height),this.R.svg.createSVGPoint&&(this.G=this.R.svg.createSVGPoint()),this.A=this.N(i),this.H=new c(this.A),this.$(),this.L=null,this},g.prototype.N=function(t){var i=l({},w,t);return t.strokeAnimationDuration&&!t.strokeAnimationSpeed&&(i.strokeAnimationSpeed=500/i.strokeAnimationDuration),t.strokeHighlightDuration&&!t.strokeHighlightSpeed&&(i.strokeHighlightSpeed=500/i.strokeHighlightDuration),t.highlightCompleteColor||(i.highlightCompleteColor=i.highlightColor),this.q(i)},g.prototype.q=function(t){var i=l({},t);if(i.width&&!i.height)i.height=i.width;else if(i.height&&!i.width)i.width=i.height;else if(!i.width&&!i.height){var n=this.R.svg.getBoundingClientRect(),r=n.width,o=n.height,s=Math.min(r,o);i.width=s,i.height=s}return i},g.prototype.U=function(t){var i=this;if(this.H.loadingFailed)throw Error("Failed to load character data. Call setCharacter and try again.");return this.z.then(function(){if(!i.H.loadingFailed)return t()})},g.prototype.$=function(){var t=this;this.R.svg.addEventListener("mousedown",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("startUserStroke",t.V(i)))}),this.R.svg.addEventListener("touchstart",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("startUserStroke",t.J(i)))}),this.R.svg.addEventListener("mousemove",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("continueUserStroke",t.V(i)))}),this.R.svg.addEventListener("touchmove",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("continueUserStroke",t.J(i)))}),i.document.addEventListener("mouseup",function(){return t.B("endUserStroke")}),i.document.addEventListener("touchend",function(){return t.B("endUserStroke")})},g.prototype.B=function(t){var i;if(this.L){for(var n=arguments.length,r=Array(n>1?n-1:0),o=1;o2&&void 0!==arguments[2]?arguments[2]:{});return n.setCharacter(i),n};var m=null,k=null;if(g.loadCharacterData=function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=void 0;return n=m&&k===i?m:new c(l({},w,i)),m=n,k=i,n.loadCharData(t)},g.getScalingTransform=function(t,i){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,r=new e({width:t,height:i,padding:n});return{x:r.getXOffset(),y:r.getYOffset(),scale:r.getScale(),transform:p("\n translate("+r.getXOffset()+", "+(r.getHeight()-r.getYOffset())+")\n scale("+r.getScale()+", "+-1*r.getScale()+")\n ").replace(/\s+/g," ")}},void 0!==i.window){var b=i.window.HanziWriter;g.noConflict=function(){return i.window.HanziWriter=b,g},i.window.HanziWriter=g}t.exports=g}).call(i,n(3))},function(t,i,n){"use strict";var r=n(8),o=n(10),s=n(0).assign,e=n(1);function u(t,i){this.I=t,this.T=i,this.Q=new r(t),this.Z=new r(t),this.K=new r(t),this.X={}}u.prototype.mount=function(t){var i=t.createSubCanvas(),n=i.svg;e.attr(n,"transform","\n translate("+this.T.getXOffset()+", "+(this.T.getHeight()-this.T.getYOffset())+")\n scale("+this.T.getScale()+", "+-1*this.T.getScale()+")\n "),this.Z.mount(i),this.Q.mount(i),this.K.mount(i),this.Y=i},u.prototype.render=function(t){var i=this;this.Z.render({opacity:t.character.outline.opacity,strokes:t.character.outline.strokes,strokeColor:t.options.outlineColor}),this.Q.render({opacity:t.character.main.opacity,strokes:t.character.main.strokes,strokeColor:t.options.strokeColor,radicalColor:t.options.radicalColor}),this.K.render({opacity:t.character.highlight.opacity,strokes:t.character.highlight.strokes,strokeColor:t.options.highlightColor});var n=t.userStrokes||{};Object.keys(this.X).forEach(function(t){n[t]||(i.X[t].destroy(),delete i.X[t])}),Object.keys(n).forEach(function(r){if(n[r]){var e=s({strokeWidth:t.options.drawingWidth,strokeColor:t.options.drawingColor},n[r]),u=i.X[r];u||((u=new o).mount(i.Y,e),i.X[r]=u),u.render(e)}})},u.prototype.destroy=function(){e.removeElm(this.Y.svg),this.Y.defs.innerHTML=""},t.exports=u},function(t,i,n){"use strict";var r=n(9);function o(t){this.tt={},this.character=t,this.strokeRenderers=this.character.strokes.map(function(t){return new r(t)})}o.prototype.mount=function(t){var i=t.createSubCanvas();this.it=i.svg,this.strokeRenderers.forEach(function(t,n){t.mount(i)})},o.prototype.render=function(t){if(t!==this.tt){t.opacity!==this.tt.opacity&&(this.it.style.opacity=t.opacity,0===t.opacity?this.it.style.display="none":0===this.tt.opacity&&(this.it.style.display="initial"));var i=!this.tt||t.strokeColor!==this.tt.strokeColor||t.radicalColor!==this.tt.radicalColor;if(i||t.strokes!==this.tt.strokes)for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{},r=t.map(function(t){return t.scope}).filter(function(t){return t});return this.cancelMutations(r),new Promise(function(o){var s={vt:!0,lt:0,F:o,dt:t,pt:n.loop,yt:r};i.ft.push(s),i.wt(s)})},e.prototype.wt=function(t){var i=this;if(t.vt){var n=t.dt;if(t.lt>=n.length){if(!t.pt)return t.vt=!1,this.ft=this.ft.filter(function(i){return i!==t}),void t.F({canceled:!1});t.lt=0}t.dt[t.lt].run(this).then(function(){t.vt&&(t.lt++,i.wt(t))})}},e.prototype.cancelMutations=function(t){var i=this;this.ft.forEach(function(n){n.yt.forEach(function(r){t.forEach(function(t){(r.indexOf(t)>=0||t.indexOf(r)>=0)&&i.gt(n)})})})},e.prototype.cancelAll=function(){this.cancelMutations([""])},e.prototype.gt=function(t){t.vt=!1;for(var i=t.lt;i=0))})},t.exports=e},function(t,i,n){"use strict";var r=n(2),o=r.subtract,s=r.distance,e=r.length;function u(t,i,n){var r=arguments.length>3&&void 0!==arguments[3]&&arguments[3];this.path=t,this.points=i,this.strokeNum=n,this.isInRadical=r}u.prototype.getStartingPoint=function(){return this.points[0]},u.prototype.getEndingPoint=function(){return this.points[this.points.length-1]},u.prototype.getLength=function(){return e(this.points)},u.prototype.getVectors=function(){var t=this.points[0];return this.points.slice(1).map(function(i){var n=o(i,t);return t=i,n})},u.prototype.getDistance=function(t){var i=this.points.map(function(i){return s(i,t)});return Math.min.apply(Math,i)},u.prototype.getAverageDistance=function(t){var i=this;return t.reduce(function(t,n){return t+i.getDistance(n)},0)/t.length},t.exports=u},function(t,i,n){"use strict";t.exports=function(t,i){this.symbol=t,this.strokes=i}},function(t,i,n){"use strict";var r=[{x:0,y:-124},{x:1024,y:900}];function o(t){this.A=t,this.mt()}o.prototype.convertExternalPoint=function(t){return{x:(t.x-this.kt)/this.bt,y:(this.getHeight()-this.Ct-t.y)/this.bt}},o.prototype.getXOffset=function(){return this.kt},o.prototype.getYOffset=function(){return this.Ct},o.prototype.getScale=function(){return this.bt},o.prototype.getHeight=function(){return this.A.height},o.prototype.mt=function(){var t=r,i=t[1].x-t[0].x,n=t[1].y-t[0].y,o=this.A.width-2*this.A.padding,s=this.A.height-2*this.A.padding,e=o/i,u=s/n;this.bt=Math.min(e,u);var h=this.A.padding+(o-this.bt*i)/2,a=this.A.padding+(s-this.bt*n)/2;this.kt=-1*t[0].x*this.bt+h,this.Ct=-1*t[0].y*this.bt+a},t.exports=o},function(t,i,n){"use strict";var r=n(17),o=n(18),s=n(0),e=s.callIfExists,u=s.counter,h=n(19),a=n(1),c=n(2),f=n(4),v=function(t){return{pathString:a.getPathString(t.externalPoints),points:t.points.map(function(t){return c.round(t)})}};function l(t,i,n){this.I=t,this.M=i,this.vt=!1,this.T=n}l.prototype.startQuiz=function(t){this.vt=!0,this.A=t,this.Mt=0,this.St=0,this.Pt=0,this.jt=[],this.M.run(h.startQuiz(this.I,t.strokeFadeDuration))},l.prototype.startUserStroke=function(t){var i=this.T.convertExternalPoint(t);if(!this.vt)return null;if(this.xt)return this.endUserStroke();var n=u();this.xt=new o(n,i,t),this.M.run(h.startUserStroke(n,i))},l.prototype.continueUserStroke=function(t){if(this.xt){var i=this.T.convertExternalPoint(t);this.xt.appendPoint(i,t);var n=this.xt.points.slice(0);this.M.run(h.updateUserStroke(this.xt.id,n))}},l.prototype.endUserStroke=function(){if(this.xt)if(this.M.run(h.removeUserStroke(this.xt.id,this.A.drawingFadeDuration)),1!==this.xt.points.length){var t=this.Ft(),i=this.M.state.character.outline.opacity>0;r(this.xt,this.I,this.Mt,{isOutlineVisible:i,leniency:this.A.leniency})?this.Ot(t):(this.Dt(),this.St>=this.A.showHintAfterMisses&&this.M.run(h.highlightStroke(t,this.A.highlightColor,this.A.strokeHighlightSpeed))),this.xt=null}else this.xt=null},l.prototype.cancel=function(){this.vt=!1,this.xt&&this.M.run(h.removeUserStroke(this.xt.id,this.A.drawingFadeDuration))},l.prototype.Ot=function(t){e(this.A.onCorrectStroke,{character:this.I.symbol,strokeNum:this.Mt,mistakesOnStroke:this.St,totalMistakes:this.Pt,strokesRemaining:this.I.strokes.length-this.Mt-1,drawnPath:v(this.xt)});var i=f.showStroke("main",this.Mt,this.A.strokeFadeDuration);this.Mt+=1,this.St=0,this.Mt===this.I.strokes.length&&(this.vt=!1,e(this.A.onComplete,{character:this.I.symbol,totalMistakes:this.Pt}),this.A.highlightOnComplete&&(i=i.concat(h.highlightCompleteChar(this.I,this.A.highlightCompleteColor,2*this.A.strokeHighlightDuration)))),this.M.run(i)},l.prototype.Dt=function(){this.St+=1,this.Pt+=1,e(this.A.onMistake,{character:this.I.symbol,strokeNum:this.Mt,mistakesOnStroke:this.St,totalMistakes:this.Pt,strokesRemaining:this.I.strokes.length-this.Mt,drawnPath:v(this.xt)})},l.prototype.Ft=function(){return this.I.strokes[this.Mt]},t.exports=l},function(t,i,n){"use strict";var r=n(0),o=r.average,s=r.assign,e=n(2),u=e.cosineSimilarity,h=e.equals,a=e.frechetDist,c=e.distance,f=e.subtract,v=e.normalizeCurve,l=e.rotate,d=e.length,p=function(t,i){var n,r,s,e=(r=[],s=(n=t)[0],n.slice(1).forEach(function(t){r.push(f(t,s)),s=t}),r),h=i.getVectors(),a=e.map(function(t){var i=h.map(function(i){return u(i,t)});return Math.max.apply(Math,i)});return o(a)>0},y=[Math.PI/16,Math.PI/32,0,-1*Math.PI/32,-1*Math.PI/16],w=function(t,i,n){var r=n.leniency,o=void 0===r?1:r,s=n.isOutlineVisible,e=void 0!==s&&s,u=i.getAverageDistance(t),h=u<=350*(e||i.strokeNum>0?.5:1)*o;if(!h)return{isMatch:!1,avgDist:u};var f,w,g,m,k,b,C,M,S,P,j,x,F=(f=t,g=o,m=c((w=i).getStartingPoint(),f[0]),k=c(w.getEndingPoint(),f[f.length-1]),m<=250*g&&k<=250*g),O=p(t,i),D=(b=t,C=i.points,M=o,S=v(b),P=v(C),j=1/0,y.forEach(function(t){var i=a(S,l(P,t));i=.35);return{isMatch:h&&F&&O&&D&&A,avgDist:u}};t.exports=function(t,i,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=function(t){if(t.length<2)return t;var i=[t[0]];return t.slice(1).forEach(function(t){h(t,i[i.length-1])||i.push(t)}),i}(t.points);if(o.length<2)return null;var e=w(o,i.strokes[n],r);if(!e.isMatch)return!1;for(var u=i.strokes.slice(n+1),a=e.avgDist,c=0;c1?n-1:0),o=1;o0&&void 0!==arguments[0]?arguments[0]:0;return new Promise(function(i,n){setTimeout(i,t)})},trim:function(t){return t.replace(/^\s+/,"").replace(/\s+$/,"")}}}).call(i,n(3))},function(t,i,n){"use strict";(function(i){var r=n(2).round;function o(t){return i.document.createElementNS("http://www.w3.org/2000/svg",t)}function s(t,i,n){t.setAttributeNS(null,i,n)}function e(t,i){Object.keys(i).forEach(function(n){return s(t,n,i[n])})}function u(t,i){this.svg=t,this.defs=i}u.prototype.createSubCanvas=function(){var t=o("g");return this.svg.appendChild(t),new u(t,this.defs)},u.init=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"100%",r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"100%",s=void 0,h=t;"string"==typeof t&&(h=i.document.getElementById(t));var a=h.nodeName.toUpperCase();"SVG"===a||"G"===a?s=h:(s=o("svg"),h.appendChild(s)),e(s,{width:n,height:r});var c=o("defs");return s.appendChild(c),new u(s,c)},t.exports={createElm:o,attrs:e,attr:s,Canvas:u,getPathString:function(t){var i=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=r(t[0]),o=t.slice(1),s="M "+n.x+" "+n.y;return o.forEach(function(t){var i=r(t);s+=" L "+i.x+" "+i.y}),i&&(s+="Z"),s},removeElm:function(t){t&&t.parentNode.removeChild(t)},urlIdRef:function(t){var n="";return i.location&&i.location.href&&(n=i.location.href.replace(/#[^#]*$/,"")),"url("+n+"#"+t+")"}}}).call(i,n(3))},function(t,i,n){"use strict";var r=n(0),o=r.average,s=r.arrLast,e=function(t,i){return{x:t.x-i.x,y:t.y-i.y}},u=function(t){return Math.sqrt(Math.pow(t.x,2)+Math.pow(t.y,2))},h=function(t,i){return u(e(t,i))},a=function(t){var i=t[0];return t.slice(1).reduce(function(t,n){var r=h(n,i);return i=n,t+r},0)},c=function(t,i,n){var r=e(i,t),o=n/u(r);return{x:i.x+o*r.x,y:i.y+o*r.y}},f=function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.05,n=t.slice(0,1);return t.slice(1).forEach(function(t){var r=n[n.length-1],o=h(t,r);if(o>i)for(var s=Math.ceil(o/i),e=o/s,u=0;u1&&void 0!==arguments[1]?arguments[1]:30,n=a(t)/(i-1),r=[t[0]],o=s(t),e=t.slice(1),u=0;u1&&void 0!==arguments[1]?arguments[1]:1);return{x:Math.round(i*t.x)/i,y:Math.round(i*t.y)/i}},equals:function(t,i){return t.x===i.x&&t.y===i.y},distance:h,frechetDist:function(t,i){for(var n=[],r=0;r-1?n[o][s]:(n[o][s]=0===o&&0===s?h(t[0],i[0]):o>0&&0===s?Math.max(r(o-1,0),h(t[o],i[0])):0===o&&s>0?Math.max(r(0,s-1),h(t[0],i[s])):o>0&&s>0?Math.max(Math.min(r(o-1,s),r(o-1,s-1),r(o,s-1)),h(t[o],i[s])):1/0,n[o][s])}(t.length-1,i.length-1)},length:a,rotate:function(t,i){return t.map(function(t){return{x:Math.cos(i)*t.x-Math.sin(i)*t.y,y:Math.sin(i)*t.x+Math.cos(i)*t.y}})},subtract:e,cosineSimilarity:function(t,i){return(t.x*i.x+t.y*i.y)/u(t)/u(i)},outlineCurve:v,extendPointOnLine:c,filterParallelPoints:function(t){if(t.length<3)return t;var i=[t[0],t[1]];return t.slice(2).forEach(function(t,n){var r=i.length,o=e(t,i[r-1]),s=e(i[r-1],i[r-2]);o.y*s.x-o.x*s.y==0&&i.pop(),i.push(t)}),i},subdivideCurve:f,normalizeCurve:function(t){var i=v(t),n={x:o(i.map(function(t){return t.x})),y:o(i.map(function(t){return t.y}))},r=i.map(function(t){return e(t,n)}),u=Math.sqrt(o([Math.pow(r[0].x,2)+Math.pow(r[0].y,2),Math.pow(s(r).x,2)+Math.pow(s(r).y,2)])),h=r.map(function(t){return{x:t.x/u,y:t.y/u}});return f(h)}}},function(t,i){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,i,n){"use strict";var r=n(5),o=n(0).objRepeat,s=function(t,i,n){return[new r("character."+t+".strokes",o({opacity:1,displayPortion:1},i.strokes.length),{duration:n,force:!0})]},e=function(t,i,n){return[new r("character."+t+".opacity",0,{duration:n,force:!0})].concat(s(t,i,0))},u=function(t,i,n){var o,s,e,u=i.strokeNum,h=(i.getLength()+600)/(3*n);return[new r("character."+t,{opacity:1,strokes:(o={},s=u,e={displayPortion:0,opacity:1},s in o?Object.defineProperty(o,s,{value:e,enumerable:!0,configurable:!0,writable:!0}):o[s]=e,o)}),new r("character."+t+".strokes."+u+".displayPortion",1,{duration:h})]},h=function(t,i,n,h,a){var c=e(t,i,n);return(c=c.concat(s(t,i,0))).push(new r("character."+t,{opacity:1,strokes:o({opacity:0},i.strokes.length)},{force:!0})),i.strokes.forEach(function(i,n){n>0&&c.push(new r.Pause(a)),c=c.concat(u(t,i,h))}),c};t.exports={showStrokes:s,showCharacter:function(t,i,n){return[new r("character."+t,{opacity:1,strokes:o({opacity:1,displayPortion:1},i.strokes.length)},{duration:n,force:!0})]},hideCharacter:e,animateCharacter:h,animateCharacterLoop:function(t,i,n,o,s,e){var u=h(t,i,n,o,s);return u.push(new r.Pause(e)),u},animateStroke:u,animateSingleStroke:function(t,i,n,o){return[new r("character."+t,function(n){for(var r=n.character[t],o={opacity:1,strokes:{}},s=0;s2&&void 0!==arguments[2]?arguments[2]:{};this.scope=t,this.u=i,this.h=n.duration||0,this.f=n.force,this.v=this.w.bind(this)}function a(t){this.h=t}h.prototype.run=function(t){var i=this;return this.k||this.C(t),0===this.h&&t.updateState(this.k),0===this.h||function t(i,n){for(var r in n)if(n.hasOwnProperty(r)){var o=n[r],s=i[r];if(o>=0){if(o!==s)return!1}else if(!t(s,o))return!1}return!0}(t.state,this.k)?Promise.resolve():(this.M=t,this.S=t.state,this.P=s(),this.j=e(this.v),new Promise(function(t){i.F=t}))},h.prototype.w=function(t){var i,n=Math.min(1,(t-this.P)/this.h);if(1===n)this.M.updateState(this.k),this.j=null,this.cancel(this.M);else{var r=(i=n,-Math.cos(i*Math.PI)/2+.5);this.M.updateState(function t(i,n,r){var o={};for(var s in n){var e=n[s],u=i[s];o[s]=e>=0?r*(e-u)+u:t(u,e,r)}return o}(this.S,this.k,r)),this.j=e(this.v)}},h.prototype.C=function(t){var i=this.u;"function"==typeof this.u&&(i=this.u(t.state)),this.k=o(this.scope,i)},h.prototype.cancel=function(t){this.F&&this.F(),this.F=null,this.j&&u(this.j),this.j=null,this.f&&(this.k||this.C(t),t.updateState(this.k))},a.prototype.run=function(){var t=this,i=new Promise(function(i){t.F=i});return this.O=setTimeout(function(){return t.cancel()},this.h),i},a.prototype.cancel=function(){clearTimeout(this.O),this.F&&this.F(),this.F=!1},h.Pause=a,t.exports=h},function(t,i,n){"use strict";(function(i){var r=n(7),o=n(11),s=n(12),e=n(15),u=n(16),h=n(1),a=n(20),c=n(21),f=n(4),v=n(0),l=v.assign,d=v.callIfExists,p=v.trim,y=v.colorStringToVals,w={charDataLoader:a,onLoadCharDataError:null,onLoadCharDataSuccess:null,showOutline:!0,showCharacter:!0,width:null,height:null,padding:20,strokeAnimationSpeed:1,strokeFadeDuration:400,strokeHighlightDuration:200,strokeHighlightSpeed:2,delayBetweenStrokes:1e3,delayBetweenLoops:2e3,strokeColor:"#555",radicalColor:null,highlightColor:"#AAF",outlineColor:"#DDD",drawingColor:"#333",leniency:1,showHintAfterMisses:3,highlightOnComplete:!0,highlightCompleteColor:null,drawingFadeDuration:300,drawingWidth:4,strokeWidth:2,outlineWidth:2};function g(){if(arguments.length>0){var t=void 0,i={},n=arguments.length<=0?void 0:arguments[0];arguments.length>1&&("string"==typeof(arguments.length<=1?void 0:arguments[1])?(console.warn("Using new HanziWriter() to set a character is deprecated. Use HanziWriter.create() instead"),t=arguments.length<=1?void 0:arguments[1],i=(arguments.length<=2?void 0:arguments[2])||{}):i=arguments.length<=1?void 0:arguments[1]),this.D(n,i),t&&this.setCharacter(t)}}g.prototype.showCharacter=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showCharacter=!0,this.U(function(){return t.M.run(f.showCharacter("main",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.hideCharacter=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showCharacter=!1,this.U(function(){return t.M.run(f.hideCharacter("main",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.animateCharacter=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.cancelQuiz(),this.U(function(){return t.M.run(f.animateCharacter("main",t.I,t.A.strokeFadeDuration,t.A.strokeAnimationSpeed,t.A.delayBetweenStrokes)).then(function(t){return d(i.onComplete,t)})})},g.prototype.animateStroke=function(t){var i=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return this.cancelQuiz(),this.U(function(){return i.M.run(f.animateSingleStroke("main",i.I,t,i.A.strokeAnimationSpeed)).then(function(t){return d(n.onComplete,t)})})},g.prototype.loopCharacterAnimation=function(){var t=this;arguments.length>0&&void 0!==arguments[0]&&arguments[0];return this.cancelQuiz(),this.U(function(){return t.M.run(f.animateCharacterLoop("main",t.I,t.A.strokeFadeDuration,t.A.strokeAnimationSpeed,t.A.delayBetweenStrokes,t.A.delayBetweenLoops),{loop:!0})})},g.prototype.showOutline=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showOutline=!0,this.U(function(){return t.M.run(f.showCharacter("outline",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.hideOutline=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.A.showOutline=!1,this.U(function(){return t.M.run(f.hideCharacter("outline",t.I,"number"==typeof i.duration?i.duration:t.A.strokeFadeDuration)).then(function(t){return d(i.onComplete,t)})})},g.prototype.updateColor=function(t,i){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return this.U(function(){var o="number"==typeof r.duration?r.duration:n.A.strokeFadeDuration,s=i;"radicalColor"!==t||i||(s=n.A.strokeColor);var e=y(s);n.A[t]=i;var u=f.updateColor(t,e,o);return"radicalColor"!==t||i||(u=u.concat(f.updateColor(t,null,0))),n.M.run(u).then(function(t){return d(r.onComplete,t)})})},g.prototype.quiz=function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.U(function(){t.cancelQuiz(),t.L=new u(t.I,t.M,t.T),t.L.startQuiz(l({},t.A,i))})},g.prototype.cancelQuiz=function(){this.L&&(this.L.cancel(),this.L=null)},g.prototype.setCharacter=function(t){var i=this;return this.cancelQuiz(),this.W=t,this._&&this._.destroy(),this.M&&this.M.cancelAll(),this._=null,this.z=this.H.loadCharData(t).then(function(n){if(!i.H.loadingFailed){var u=new s;i.I=u.generateCharacter(t,n),i.T=new e(i.A);var h=new r(i.I,i.T);i._=h,i.M=new o(i.I,i.A,function(t){h.render(t)}),i._.mount(i.R,i.M.state),i._.render(i.M.state)}}),this.z},g.prototype.D=function(t,i){return this.R=h.Canvas.init(t,i.width,i.height),this.R.svg.createSVGPoint&&(this.G=this.R.svg.createSVGPoint()),this.A=this.N(i),this.H=new c(this.A),this.$(),this.L=null,this},g.prototype.N=function(t){var i=l({},w,t);return t.strokeAnimationDuration&&!t.strokeAnimationSpeed&&(i.strokeAnimationSpeed=500/i.strokeAnimationDuration),t.strokeHighlightDuration&&!t.strokeHighlightSpeed&&(i.strokeHighlightSpeed=500/i.strokeHighlightDuration),t.highlightCompleteColor||(i.highlightCompleteColor=i.highlightColor),this.q(i)},g.prototype.q=function(t){var i=l({},t);if(i.width&&!i.height)i.height=i.width;else if(i.height&&!i.width)i.width=i.height;else if(!i.width&&!i.height){var n=this.R.svg.getBoundingClientRect(),r=n.width,o=n.height,s=Math.min(r,o);i.width=s,i.height=s}return i},g.prototype.U=function(t){var i=this;if(this.H.loadingFailed)throw Error("Failed to load character data. Call setCharacter and try again.");return this.z.then(function(){if(!i.H.loadingFailed)return t()})},g.prototype.$=function(){var t=this;this.R.svg.addEventListener("mousedown",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("startUserStroke",t.V(i)))}),this.R.svg.addEventListener("touchstart",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("startUserStroke",t.J(i)))}),this.R.svg.addEventListener("mousemove",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("continueUserStroke",t.V(i)))}),this.R.svg.addEventListener("touchmove",function(i){!t.isLoadingCharData&&t.L&&(i.preventDefault(),t.B("continueUserStroke",t.J(i)))}),i.document.addEventListener("mouseup",function(){return t.B("endUserStroke")}),i.document.addEventListener("touchend",function(){return t.B("endUserStroke")})},g.prototype.B=function(t){var i;if(this.L){for(var n=arguments.length,r=Array(n>1?n-1:0),o=1;o2&&void 0!==arguments[2]?arguments[2]:{});return n.setCharacter(i),n};var m=null,k=null;if(g.loadCharacterData=function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=void 0;return n=m&&k===i?m:new c(l({},w,i)),m=n,k=i,n.loadCharData(t)},g.getScalingTransform=function(t,i){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,r=new e({width:t,height:i,padding:n});return{x:r.getXOffset(),y:r.getYOffset(),scale:r.getScale(),transform:p("\n translate("+r.getXOffset()+", "+(r.getHeight()-r.getYOffset())+")\n scale("+r.getScale()+", "+-1*r.getScale()+")\n ").replace(/\s+/g," ")}},void 0!==i.window){var b=i.window.HanziWriter;g.noConflict=function(){return i.window.HanziWriter=b,g},i.window.HanziWriter=g}t.exports=g}).call(i,n(3))},function(t,i,n){"use strict";var r=n(8),o=n(10),s=n(0).assign,e=n(1);function u(t,i){this.I=t,this.T=i,this.Q=new r(t),this.Z=new r(t),this.K=new r(t),this.X={}}u.prototype.mount=function(t){var i=t.createSubCanvas(),n=i.svg;e.attr(n,"transform","\n translate("+this.T.getXOffset()+", "+(this.T.getHeight()-this.T.getYOffset())+")\n scale("+this.T.getScale()+", "+-1*this.T.getScale()+")\n "),this.Z.mount(i),this.Q.mount(i),this.K.mount(i),this.Y=i},u.prototype.render=function(t){var i=this;this.Z.render({opacity:t.character.outline.opacity,strokes:t.character.outline.strokes,strokeColor:t.options.outlineColor}),this.Q.render({opacity:t.character.main.opacity,strokes:t.character.main.strokes,strokeColor:t.options.strokeColor,radicalColor:t.options.radicalColor}),this.K.render({opacity:t.character.highlight.opacity,strokes:t.character.highlight.strokes,strokeColor:t.options.highlightColor});var n=t.userStrokes||{};Object.keys(this.X).forEach(function(t){n[t]||(i.X[t].destroy(),delete i.X[t])}),Object.keys(n).forEach(function(r){if(n[r]){var e=s({strokeWidth:t.options.drawingWidth,strokeColor:t.options.drawingColor},n[r]),u=i.X[r];u||((u=new o).mount(i.Y,e),i.X[r]=u),u.render(e)}})},u.prototype.destroy=function(){e.removeElm(this.Y.svg),this.Y.defs.innerHTML=""},t.exports=u},function(t,i,n){"use strict";var r=n(9);function o(t){this.tt={},this.character=t,this.strokeRenderers=this.character.strokes.map(function(t){return new r(t)})}o.prototype.mount=function(t){var i=t.createSubCanvas();this.it=i.svg,this.strokeRenderers.forEach(function(t,n){t.mount(i)})},o.prototype.render=function(t){if(t!==this.tt){t.opacity!==this.tt.opacity&&(this.it.style.opacity=t.opacity,0===t.opacity?this.it.style.display="none":0===this.tt.opacity&&(this.it.style.display="initial"));var i=!this.tt||t.strokeColor!==this.tt.strokeColor||t.radicalColor!==this.tt.radicalColor;if(i||t.strokes!==this.tt.strokes)for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{},r=t.map(function(t){return t.scope}).filter(function(t){return t});return this.cancelMutations(r),new Promise(function(o){var s={vt:!0,lt:0,F:o,dt:t,pt:n.loop,yt:r};i.ft.push(s),i.wt(s)})},e.prototype.wt=function(t){var i=this;if(t.vt){var n=t.dt;if(t.lt>=n.length){if(!t.pt)return t.vt=!1,this.ft=this.ft.filter(function(i){return i!==t}),void t.F({canceled:!1});t.lt=0}t.dt[t.lt].run(this).then(function(){t.vt&&(t.lt++,i.wt(t))})}},e.prototype.cancelMutations=function(t){var i=this;this.ft.forEach(function(n){n.yt.forEach(function(r){t.forEach(function(t){(r.indexOf(t)>=0||t.indexOf(r)>=0)&&i.gt(n)})})})},e.prototype.cancelAll=function(){this.cancelMutations([""])},e.prototype.gt=function(t){t.vt=!1;for(var i=t.lt;i=0))})},t.exports=e},function(t,i,n){"use strict";var r=n(2),o=r.subtract,s=r.distance,e=r.length;function u(t,i,n){var r=arguments.length>3&&void 0!==arguments[3]&&arguments[3];this.path=t,this.points=i,this.strokeNum=n,this.isInRadical=r}u.prototype.getStartingPoint=function(){return this.points[0]},u.prototype.getEndingPoint=function(){return this.points[this.points.length-1]},u.prototype.getLength=function(){return e(this.points)},u.prototype.getVectors=function(){var t=this.points[0];return this.points.slice(1).map(function(i){var n=o(i,t);return t=i,n})},u.prototype.getDistance=function(t){var i=this.points.map(function(i){return s(i,t)});return Math.min.apply(Math,i)},u.prototype.getAverageDistance=function(t){var i=this;return t.reduce(function(t,n){return t+i.getDistance(n)},0)/t.length},t.exports=u},function(t,i,n){"use strict";t.exports=function(t,i){this.symbol=t,this.strokes=i}},function(t,i,n){"use strict";var r=[{x:0,y:-124},{x:1024,y:900}];function o(t){this.A=t,this.mt()}o.prototype.convertExternalPoint=function(t){return{x:(t.x-this.kt)/this.bt,y:(this.getHeight()-this.Ct-t.y)/this.bt}},o.prototype.getXOffset=function(){return this.kt},o.prototype.getYOffset=function(){return this.Ct},o.prototype.getScale=function(){return this.bt},o.prototype.getHeight=function(){return this.A.height},o.prototype.mt=function(){var t=r,i=t[1].x-t[0].x,n=t[1].y-t[0].y,o=this.A.width-2*this.A.padding,s=this.A.height-2*this.A.padding,e=o/i,u=s/n;this.bt=Math.min(e,u);var h=this.A.padding+(o-this.bt*i)/2,a=this.A.padding+(s-this.bt*n)/2;this.kt=-1*t[0].x*this.bt+h,this.Ct=-1*t[0].y*this.bt+a},t.exports=o},function(t,i,n){"use strict";var r=n(17),o=n(18),s=n(0),e=s.callIfExists,u=s.counter,h=n(19),a=n(1),c=n(2),f=n(4),v=function(t){return{pathString:a.getPathString(t.externalPoints),points:t.points.map(function(t){return c.round(t)})}};function l(t,i,n){this.I=t,this.M=i,this.vt=!1,this.T=n}l.prototype.startQuiz=function(t){this.vt=!0,this.A=t,this.Mt=0,this.St=0,this.Pt=0,this.jt=[],this.M.run(h.startQuiz(this.I,t.strokeFadeDuration))},l.prototype.startUserStroke=function(t){var i=this.T.convertExternalPoint(t);if(!this.vt)return null;if(this.xt)return this.endUserStroke();var n=u();this.xt=new o(n,i,t),this.M.run(h.startUserStroke(n,i))},l.prototype.continueUserStroke=function(t){if(this.xt){var i=this.T.convertExternalPoint(t);this.xt.appendPoint(i,t);var n=this.xt.points.slice(0);this.M.run(h.updateUserStroke(this.xt.id,n))}},l.prototype.endUserStroke=function(){if(this.xt)if(this.M.run(h.removeUserStroke(this.xt.id,this.A.drawingFadeDuration)),1!==this.xt.points.length){var t=this.Ft(),i=this.M.state.character.outline.opacity>0;r(this.xt,this.I,this.Mt,{isOutlineVisible:i,leniency:this.A.leniency})?this.Ot(t):(this.Dt(),this.St>=this.A.showHintAfterMisses&&this.M.run(h.highlightStroke(t,this.A.highlightColor,this.A.strokeHighlightSpeed))),this.xt=null}else this.xt=null},l.prototype.cancel=function(){this.vt=!1,this.xt&&this.M.run(h.removeUserStroke(this.xt.id,this.A.drawingFadeDuration))},l.prototype.Ot=function(t){e(this.A.onCorrectStroke,{character:this.I.symbol,strokeNum:this.Mt,mistakesOnStroke:this.St,totalMistakes:this.Pt,strokesRemaining:this.I.strokes.length-this.Mt-1,drawnPath:v(this.xt)});var i=f.showStroke("main",this.Mt,this.A.strokeFadeDuration);this.Mt+=1,this.St=0,this.Mt===this.I.strokes.length&&(this.vt=!1,e(this.A.onComplete,{character:this.I.symbol,totalMistakes:this.Pt}),this.A.highlightOnComplete&&(i=i.concat(h.highlightCompleteChar(this.I,this.A.highlightCompleteColor,2*this.A.strokeHighlightDuration)))),this.M.run(i)},l.prototype.Dt=function(){this.St+=1,this.Pt+=1,e(this.A.onMistake,{character:this.I.symbol,strokeNum:this.Mt,mistakesOnStroke:this.St,totalMistakes:this.Pt,strokesRemaining:this.I.strokes.length-this.Mt,drawnPath:v(this.xt)})},l.prototype.Ft=function(){return this.I.strokes[this.Mt]},t.exports=l},function(t,i,n){"use strict";var r=n(0),o=r.average,s=r.assign,e=n(2),u=e.cosineSimilarity,h=e.equals,a=e.frechetDist,c=e.distance,f=e.subtract,v=e.normalizeCurve,l=e.rotate,d=e.length,p=function(t,i){var n,r,s,e=(r=[],s=(n=t)[0],n.slice(1).forEach(function(t){r.push(f(t,s)),s=t}),r),h=i.getVectors(),a=e.map(function(t){var i=h.map(function(i){return u(i,t)});return Math.max.apply(Math,i)});return o(a)>0},y=[Math.PI/16,Math.PI/32,0,-1*Math.PI/32,-1*Math.PI/16],w=function(t,i,n){var r=n.leniency,o=void 0===r?1:r,s=n.isOutlineVisible,e=void 0!==s&&s,u=i.getAverageDistance(t),h=u<=350*(e||i.strokeNum>0?.5:1)*o;if(!h)return{isMatch:!1,avgDist:u};var f,w,g,m,k,b,C,M,S,P,j,x,F=(f=t,g=o,m=c((w=i).getStartingPoint(),f[0]),k=c(w.getEndingPoint(),f[f.length-1]),m<=250*g&&k<=250*g),O=p(t,i),D=(b=t,C=i.points,M=o,S=v(b),P=v(C),j=1/0,y.forEach(function(t){var i=a(S,l(P,t));i=.35);return{isMatch:h&&F&&O&&D&&A,avgDist:u}};t.exports=function(t,i,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=function(t){if(t.length<2)return t;var i=[t[0]];return t.slice(1).forEach(function(t){h(t,i[i.length-1])||i.push(t)}),i}(t.points);if(o.length<2)return null;var e=w(o,i.strokes[n],r);if(!e.isMatch)return!1;for(var u=i.strokes.slice(n+1),a=e.avgDist,c=0;c `{x: ${point.x}, y: ${point.y}}`); 7 | console.log(`[${pointStrs.join(', ')}]`); 8 | } 9 | 10 | function updateCharacter() { 11 | document.querySelector('#target').innerHTML = ''; 12 | 13 | var character = document.querySelector('.js-char').value; 14 | window.location.hash = character; 15 | writer = HanziWriter.create('target', character, { 16 | width: 400, 17 | height: 400, 18 | radicalColor: '#1abc9c', 19 | onCorrectStroke: printStrokePoints, 20 | onMistake: printStrokePoints, 21 | }); 22 | isCharVisible = true; 23 | isOutlineVisible = true; 24 | window.writer = writer; 25 | } 26 | 27 | window.onload = function() { 28 | var char = decodeURIComponent(window.location.hash.slice(1)); 29 | if (char) { 30 | document.querySelector('.js-char').value = char; 31 | } 32 | 33 | updateCharacter(); 34 | 35 | document.querySelector('.js-char-form').addEventListener('submit', function(evt) { 36 | evt.preventDefault(); 37 | updateCharacter(); 38 | }); 39 | 40 | document.querySelector('.showCharacter').addEventListener('click', function() { 41 | writer.showCharacter() 42 | }); 43 | document.querySelector('.hideCharacter').addEventListener('click', function() { 44 | writer.hideCharacter() 45 | }); 46 | document.querySelector('.js-animate').addEventListener('click', function() { 47 | writer.animateCharacter(); 48 | }); 49 | document.querySelector('.js-quiz').addEventListener('click', function() { 50 | writer.quiz({ 51 | showOutline: true 52 | }); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /前端网页1203/js/test_data.js: -------------------------------------------------------------------------------- 1 | window.data = [ 2 | "#4PR:99,172;92,181;85,190;77,198;67,208;58,216;50,223;42,228;35,232;24,238;16,243;11,245;4,245;3,245;8,240;22,229;29,224;38,216;48,207;58,197;69,184;77,174;86,163;93,152;100,142;105,132;111,121;115,111;119,102;122,93;125,85;127,78;129,71;130,60;130,53;129,48;128,42;132,42;139,44;145,48;152,52;156,61;154,65;152,72;149,81;145,93;141,102;137,111;133,120;128,129;123,138;118,146;112,155;106,164", 3 | "#2PR:246,219;235,214;225,209;216,204;208,199;202,193;193,186;185,179;176,170;168,161;159,151;150,142;142,132;135,124;128,115;122,107;118,116;133,137;146,156;159,173;170,188;181,201;190,212;201,226;210,236;217,242;221,245;228,247;237,247;242,247;250,247;259,246;271,245;284,243;293,241;296,239;293,237;286,234;275,229;259,223" 4 | ]; -------------------------------------------------------------------------------- /前端网页1203/styles.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | background: #ffffff; 3 | margin: 0; 4 | padding: 0; 5 | text-align: center; 6 | font-family: 'Raleway', sans-serif; 7 | font-size: 14px; 8 | } 9 | body { 10 | padding-bottom: 80px; 11 | } 12 | * { 13 | box-sizing: border-box; 14 | } 15 | 16 | input, button { 17 | outline: none; 18 | } 19 | button, #target, .title { 20 | box-shadow: 0 1px 5px rgba(0,0,0,0.15); 21 | } 22 | 23 | button, #target { 24 | text-shadow: 0 1px 1px white; 25 | } 26 | 27 | .title { 28 | color: white; 29 | background: #1abc9c; 30 | padding: 15px 0; 31 | margin: 0 0 30px; 32 | } 33 | 34 | #target { 35 | border-radius: 10px; 36 | box-shadow: 0 0 8rpx 0 #bfbfbf; 37 | clear: both; 38 | width: 400px; 39 | height: 400px; 40 | margin: 80px auto; 41 | } 42 | 43 | .char-form { 44 | margin: 0 0 20px; 45 | } 46 | 47 | .char-form button { 48 | padding: 8px 5px; 49 | line-height: 14px; 50 | display: inline-block; 51 | vertical-align: top; 52 | } 53 | 54 | .char-input { 55 | font-size: 16px; 56 | padding: 5px; 57 | width: 33px; 58 | text-align: center; 59 | } 60 | 61 | .actions { 62 | width: 400px; 63 | margin: 0 auto; 64 | } 65 | 66 | .actions button { 67 | display: block; 68 | width: 97px; 69 | height: 3rem; 70 | border: 1px solid #1abc9c; 71 | color: #1abc9c; 72 | float: left; 73 | border-radius: 10px; 74 | margin-right: 4px; 75 | margin-bottom: 4px; 76 | } 77 | .actions button:last-child { 78 | margin-right: 0; 79 | } 80 | 81 | button { 82 | background: none; 83 | border: 1px solid #444; 84 | color: #444; 85 | cursor: pointer; 86 | transition: all 300ms; 87 | } 88 | .update-btn { 89 | width: 97px; 90 | border: 1px solid #e74c3c; 91 | color: #e74c3c; 92 | } 93 | 94 | button:hover { 95 | color: #1e6cd2; 96 | border: 1px solid #1e6cd2; 97 | box-shadow: none; 98 | } 99 | .char-input { 100 | width: 8rem; 101 | } -------------------------------------------------------------------------------- /微信小程序二维码.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/微信小程序二维码.jpg -------------------------------------------------------------------------------- /直书小程序源代码/App.vue: -------------------------------------------------------------------------------- 1 | 98 | 99 | 103 | -------------------------------------------------------------------------------- /直书小程序源代码/Readme.md: -------------------------------------------------------------------------------- 1 |

ColorUI简介

2 | 3 | ## 前言 4 | ColorUI是一个css库!!!在你引入样式后可以根据class来调用组件,一些含有交互的操作我也有简单写,可以为你开发提供一些思路。插件市场版本如果和更新日志不一样,请移步Github下载。有组件需求或者Bug提交也可以移步到issues。 5 | 6 | ## 交流 7 | 微信群:加入微信群请先添加开发者微信,备注UniApp插件市场。QQ群:240787041 或扫描二维码。 8 |

9 | 10 | ## 素材 11 | ColorUI在语雀有个群友共同在维护的知识库,里面有一些群友改的模板和UI素材供开发使用哦! 12 | [语雀-ColorUI群资源](https://www.yuque.com/colorui) 13 | 14 | ## 开始使用 15 | 下载源码解压,复制根目录的 `/colorui` 文件夹到你的根目录 16 | 17 | `App.vue` 引入关键Css `main.css` `icon.css` 18 | ``` 19 | 25 | ``` 26 | 27 | ------ 28 | 29 | ## 使用自定义导航栏 30 | 导航栏作为常用组件有做简单封装,当然你也可以直接复制代码结构自己修改,达到个性化目的。 31 | 32 | `App.vue` 获得系统信息 33 | ``` 34 | onLaunch: function() { 35 | uni.getSystemInfo({ 36 | success: function(e) { 37 | // #ifndef MP 38 | Vue.prototype.StatusBar = e.statusBarHeight; 39 | if (e.platform == 'android') { 40 | Vue.prototype.CustomBar = e.statusBarHeight + 50; 41 | } else { 42 | Vue.prototype.CustomBar = e.statusBarHeight + 45; 43 | }; 44 | // #endif 45 | // #ifdef MP-WEIXIN 46 | Vue.prototype.StatusBar = e.statusBarHeight; 47 | let custom = wx.getMenuButtonBoundingClientRect(); 48 | Vue.prototype.Custom = custom; 49 | Vue.prototype.CustomBar = custom.bottom + custom.top - e.statusBarHeight; 50 | // #endif 51 | // #ifdef MP-ALIPAY 52 | Vue.prototype.StatusBar = e.statusBarHeight; 53 | Vue.prototype.CustomBar = e.statusBarHeight + e.titleBarHeight; 54 | // #endif 55 | } 56 | }) 57 | }, 58 | ``` 59 | 60 | `pages.json` 配置取消系统导航栏 61 | ``` 62 | "globalStyle": { 63 | "navigationStyle": "custom" 64 | }, 65 | ``` 66 | 复制代码结构可以直接使用,注意全局变量的获取。 67 | 68 | 使用封装,在`main.js` 引入 `cu-custom` 组件。 69 | ``` 70 | import cuCustom from './colorui/components/cu-custom.vue' 71 | Vue.component('cu-custom',cuCustom) 72 | ``` 73 | 74 | `page.vue` 页面可以直接调用了 75 | ``` 76 | 77 | 返回 78 | 导航栏 79 | 80 | ``` 81 | | 参数 | 作用 |类型 | 默认值 | 82 | | -------- | -----: |-----: | :----: | 83 | | bgColor | 背景颜色类名 |String | '' | 84 | | isBack | 是否开启返回 | Boolean | false | 85 | | bgImage | 背景图片路径 | String | '' | 86 | 87 | | slot块 | 作用 | 88 | | -------- | -----: | 89 | | backText | 返回时的文字 | 90 | | content | 中间区域 | 91 | | right | 右侧区域(小程序端可使用范围很窄!) | 92 | 93 | 94 | ------ 95 | 96 | 97 | ## 使用自定义Tabbar 98 | 这部分暂时没有封装,思路可以参考下我的源码,原理是一个主页面引入多个页面,在主页面进行切换显示。这样可以解决切换时闪烁的问题。 99 | 100 | 101 | ------ 102 | 103 | 104 | ## 更新日志 105 | 106 | * 2019年4月25日 v2.1.6 107 | * 删除var变量 向下兼容安卓APP 108 | * 优化单选等表单控件 109 | 110 | * 2019年4月25日 v2.1.5 111 | * 优化图片上传 112 | * 优化一些点击区域过小 113 | * 优化图标旋转 114 | * 优化demo显示 115 | * 优化阴影 116 | * 修复支付宝小程序编译出错 117 | 118 | * 2019年4月14日 v2.1.4 119 | * 新增多种阴影 120 | * 修复一些var属性的错误 121 | * 修复轮播图控制点隐藏不了 122 | * 修改图标类名 123 | * 修复表单组件里上传图片 ios没有图片显示问题 124 | 125 | 126 | * 2019年4月01日 v2.1.3 127 | * 优化代码,支持支付宝小程序 128 | * textarea 样式还原 129 | 130 | * 2019年3月28日 v2.1.2 131 | * 修复列表组件样式 132 | * 优化主样式代码 133 | 134 | * 2019年3月27日 v2.1.1 135 | * 新增多种扩展 136 | * 优化堆叠轮播图 137 | * 优化消息列表 138 | * 优化导航栏的封装 139 | * 修复卡片评论错位(3月27日16:32:17) 140 | 141 | * 2019年3月25日 v2.1.0 142 | * 完成元素,组件移植 143 | * icon文件更改名称,避免图标冲突 144 | * 针对不同端口做了优化 -------------------------------------------------------------------------------- /直书小程序源代码/cloudfunctionTemplate/mlkit.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "机器翻译", 4 | "value": { 5 | "api": "translate", 6 | "params": "Are you ok" 7 | } 8 | }, 9 | { 10 | "name": "语音合成", 11 | "value": { 12 | "api": "tts", 13 | "params": "你" 14 | } 15 | } 16 | ] -------------------------------------------------------------------------------- /直书小程序源代码/cloudfunctions/mlkit/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "permissions": { 3 | "openapi": [ 4 | ] 5 | } 6 | } -------------------------------------------------------------------------------- /直书小程序源代码/cloudfunctions/mlkit/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | const axios = require('axios'); 4 | const uuid = require('uuid'); 5 | 6 | cloud.init() 7 | const db = cloud.database() 8 | const mlkit = axios.create({ 9 | baseURL: 'https://ml-api-drcn.ai.dbankcloud.com/v1', 10 | headers: { 11 | 'X-Request-ID': uuid.v4(), 12 | 'X-Package-Name': 'com.huawei.crj.mlkittest', 13 | 'X-Country-Code': 'cn', 14 | 'HMS-APPLICATION-ID': '105990247', 15 | 'X-Mlkit-Version': 'ml-computer-vision:1.0.2.300', 16 | 'Authorization': 'Bearer DAEDAFFOjVHEd7nfgFs3N1B6tN+V2V+kQJemzNY5w0XBp6QX6DhZAUmACdURMUgoIELB2yvaG8+PUUwIc+eWky71bIzvEpDMUv486w==', 17 | 'Content-Type': 'application/json' 18 | } 19 | }) 20 | const ocr = async (fileID) => { 21 | const res = await cloud.downloadFile({ 22 | fileID: fileID, 23 | }) 24 | const buffer = res.fileContent 25 | const imgBase64 = buffer.toString('base64') 26 | const resp = await mlkit.post('/image/recognition/ocr/text', { 27 | imgBase64, 28 | language: ["zh"] 29 | }); 30 | const ocrResult = Array.from(resp.data.texts[0].text.replace(/[^\u4e00-\u9fa5]*/g, '')); 31 | return ocrResult; 32 | } 33 | const asr = async (fileID) => { 34 | const res = await cloud.downloadFile({ 35 | fileID: fileID, 36 | }) 37 | const buffer = res.fileContent 38 | const audioBase64 = buffer.toString('base64') 39 | const resp = await mlkit.post('/asr/short', { 40 | data: audioBase64, 41 | "config": { 42 | "encoding": "aac", 43 | "sampleRate": 16000, 44 | "languageCode": "zh" 45 | } 46 | }); 47 | const asrResult = Array.from(resp.data.result.text.replace(/[^\u4e00-\u9fa5]*/g, '')); 48 | return asrResult; 49 | } 50 | const translate = async (sourceText) => { 51 | const resp = await mlkit.post('/translation/language/translate', { 52 | targetLanguage: "zh", 53 | sourceTexts: [sourceText, ] 54 | }); 55 | const translatedResult = Array.from(resp.data.data.translatedResults[0].text.replace(/[^\u4e00-\u9fa5]*/g, 56 | '')); 57 | return translatedResult; 58 | } 59 | const tts = async (text) => { 60 | const resp = await mlkit.post('/tts/text2audio', { 61 | data: { 62 | language: "zh-Hans", 63 | text, 64 | }, 65 | config: { 66 | person: "zh-Hans-st-2", 67 | codec: 3, 68 | sampleRate: 16000, 69 | speed: "5.0", 70 | pitch: "5.0", 71 | volume: "5.0", 72 | type: 0 73 | } 74 | }, { 75 | responseType: 'arraybuffer', 76 | }) 77 | const cloudPath = `hanzi-writer/tts/${text}.mp3`; 78 | const docFindRes = await db.collection('tts').where({ 79 | text, 80 | }).get(); 81 | if (docFindRes.data.length !== 0) { 82 | return docFindRes.data[0].fileID 83 | } else { 84 | const uploadRes = await cloud.uploadFile({ 85 | cloudPath, 86 | fileContent: resp.data.subarray(8) 87 | }) 88 | await db.collection('tts').add({ 89 | data: { 90 | text, 91 | fileID: uploadRes.fileID 92 | } 93 | }) 94 | return uploadRes.fileID 95 | } 96 | } 97 | // 云函数入口函数 98 | exports.main = async (event, context) => { 99 | switch (event.api) { 100 | case 'ocr': 101 | return await ocr(event.params) 102 | case 'translate': 103 | return await translate(event.params) 104 | case 'tts': 105 | return await tts(event.params) 106 | case 'asr': 107 | return await asr(event.params) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /直书小程序源代码/cloudfunctions/mlkit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ocr", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^0.27.2", 13 | "wx-server-sdk": "~2.6.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /直书小程序源代码/colorui/animation.css: -------------------------------------------------------------------------------- 1 | /* 2 | Animation 微动画 3 | 基于ColorUI组建库的动画模块 by 文晓港 2019年3月26日19:52:28 4 | */ 5 | 6 | /* css 滤镜 控制黑白底色gif的 */ 7 | .gif-black{ 8 | mix-blend-mode: screen; 9 | } 10 | .gif-white{ 11 | mix-blend-mode: multiply; 12 | } 13 | 14 | 15 | /* Animation css */ 16 | [class*=animation-] { 17 | animation-duration: .5s; 18 | animation-timing-function: ease-out; 19 | animation-fill-mode: both 20 | } 21 | 22 | .animation-fade { 23 | animation-name: fade; 24 | animation-duration: .8s; 25 | animation-timing-function: linear 26 | } 27 | 28 | .animation-scale-up { 29 | animation-name: scale-up 30 | } 31 | 32 | .animation-scale-down { 33 | animation-name: scale-down 34 | } 35 | 36 | .animation-slide-top { 37 | animation-name: slide-top 38 | } 39 | 40 | .animation-slide-bottom { 41 | animation-name: slide-bottom 42 | } 43 | 44 | .animation-slide-left { 45 | animation-name: slide-left 46 | } 47 | 48 | .animation-slide-right { 49 | animation-name: slide-right 50 | } 51 | 52 | .animation-shake { 53 | animation-name: shake 54 | } 55 | 56 | .animation-reverse { 57 | animation-direction: reverse 58 | } 59 | 60 | @keyframes fade { 61 | 0% { 62 | opacity: 0 63 | } 64 | 65 | 100% { 66 | opacity: 1 67 | } 68 | } 69 | 70 | @keyframes scale-up { 71 | 0% { 72 | opacity: 0; 73 | transform: scale(.2) 74 | } 75 | 76 | 100% { 77 | opacity: 1; 78 | transform: scale(1) 79 | } 80 | } 81 | 82 | @keyframes scale-down { 83 | 0% { 84 | opacity: 0; 85 | transform: scale(1.8) 86 | } 87 | 88 | 100% { 89 | opacity: 1; 90 | transform: scale(1) 91 | } 92 | } 93 | 94 | @keyframes slide-top { 95 | 0% { 96 | opacity: 0; 97 | transform: translateY(-100%) 98 | } 99 | 100 | 100% { 101 | opacity: 1; 102 | transform: translateY(0) 103 | } 104 | } 105 | 106 | @keyframes slide-bottom { 107 | 0% { 108 | opacity: 0; 109 | transform: translateY(100%) 110 | } 111 | 112 | 100% { 113 | opacity: 1; 114 | transform: translateY(0) 115 | } 116 | } 117 | 118 | @keyframes shake { 119 | 120 | 0%, 121 | 100% { 122 | transform: translateX(0) 123 | } 124 | 125 | 10% { 126 | transform: translateX(-9px) 127 | } 128 | 129 | 20% { 130 | transform: translateX(8px) 131 | } 132 | 133 | 30% { 134 | transform: translateX(-7px) 135 | } 136 | 137 | 40% { 138 | transform: translateX(6px) 139 | } 140 | 141 | 50% { 142 | transform: translateX(-5px) 143 | } 144 | 145 | 60% { 146 | transform: translateX(4px) 147 | } 148 | 149 | 70% { 150 | transform: translateX(-3px) 151 | } 152 | 153 | 80% { 154 | transform: translateX(2px) 155 | } 156 | 157 | 90% { 158 | transform: translateX(-1px) 159 | } 160 | } 161 | 162 | @keyframes slide-left { 163 | 0% { 164 | opacity: 0; 165 | transform: translateX(-100%) 166 | } 167 | 168 | 100% { 169 | opacity: 1; 170 | transform: translateX(0) 171 | } 172 | } 173 | 174 | @keyframes slide-right { 175 | 0% { 176 | opacity: 0; 177 | transform: translateX(100%) 178 | } 179 | 180 | 100% { 181 | opacity: 1; 182 | transform: translateX(0) 183 | } 184 | } -------------------------------------------------------------------------------- /直书小程序源代码/colorui/components/cu-custom.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 62 | 63 | 66 | -------------------------------------------------------------------------------- /直书小程序源代码/components/centerImg.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | 30 | -------------------------------------------------------------------------------- /直书小程序源代码/components/clickLink.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 34 | 35 | 44 | -------------------------------------------------------------------------------- /直书小程序源代码/components/selectWord.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 58 | 59 | 77 | -------------------------------------------------------------------------------- /直书小程序源代码/components/textTitle.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /直书小程序源代码/components/textView.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | 20 | 26 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/convertSimpleTraditionCN/index.js: -------------------------------------------------------------------------------- 1 | const charPYStr = () => { 2 | return '啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸尽劲荆兢觉决诀绝均菌钧军君峻俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座锕嗳嫒瑷暧霭谙铵鹌媪骜鳌钯呗钣鸨龅鹎贲锛荜哔滗铋筚跸苄缏笾骠飑飙镖镳鳔傧缤槟殡膑镔髌鬓禀饽钹鹁钸骖黪恻锸侪钗冁谄谶蒇忏婵骣觇禅镡伥苌怅阊鲳砗伧谌榇碜龀枨柽铖铛饬鸱铳俦帱雠刍绌蹰钏怆缍鹑辍龊鹚苁骢枞辏撺锉鹾哒鞑骀绐殚赕瘅箪谠砀裆焘镫籴诋谛绨觌镝巅钿癫铫鲷鲽铤铥岽鸫窦渎椟牍笃黩簖怼镦炖趸铎谔垩阏轭锇锷鹗颚颛鳄诶迩铒鸸鲕钫鲂绯镄鲱偾沣凫驸绂绋赙麸鲋鳆钆赅尴擀绀戆睾诰缟锆纥镉颍亘赓绠鲠诟缑觏诂毂钴锢鸪鹄鹘鸹掴诖掼鹳鳏犷匦刿妫桧鲑鳜衮绲鲧埚呙帼椁蝈铪阚绗颉灏颢诃阖蛎黉讧荭闳鲎浒鹕骅桦铧奂缳锾鲩鳇诙荟哕浍缋珲晖诨馄阍钬镬讦诘荠叽哜骥玑觊齑矶羁虿跻霁鲚鲫郏浃铗镓蛲谏缣戋戬睑鹣笕鲣鞯绛缰挢峤鹪鲛疖颌鲒卺荩馑缙赆觐刭泾迳弪胫靓阄鸠鹫讵屦榉飓钜锔窭龃锩镌隽谲珏皲剀垲忾恺铠锴龛闶钪铐骒缂轲钶锞颔龈铿喾郐哙脍狯髋诓诳邝圹纩贶匮蒉愦聩篑阃锟鲲蛴崃徕涞濑赉睐铼癞籁岚榄斓镧褴阆锒唠崂铑铹痨鳓诔缧俪郦坜苈莅蓠呖逦骊缡枥栎轹砺锂鹂疠粝跞雳鲡鳢蔹奁潋琏殓裢裣鲢魉缭钌鹩蔺廪檩辚躏绫棂蛏鲮浏骝绺镏鹨茏泷珑栊胧砻偻蒌喽嵝镂瘘耧蝼髅垆撸噜闾泸渌栌橹轳辂辘氇胪鸬鹭舻鲈脔娈栾鸾銮囵荦猡泺椤脶镙榈褛锊呒唛嬷杩劢缦镘颡鳗麽扪焖懑钔芈谧猕祢渑腼黾缈缪闵缗谟蓦馍殁镆钼铙讷铌鲵辇鲶茑袅陧蘖嗫颟蹑苎咛聍侬哝驽钕傩讴怄瓯蹒疱辔纰罴铍谝骈缥嫔钋镤镨蕲骐绮桤碛颀颃鳍佥荨悭骞缱椠钤嫱樯戗炝锖锵镪羟跄诮谯荞缲硗跷惬锲箧锓揿鲭茕蛱巯赇虮鳅诎岖阒觑鸲诠绻辁铨阕阙悫荛娆桡饪轫嵘蝾缛铷颦蚬飒毵糁缫啬铯穑铩鲨酾讪姗骟钐鳝垧殇觞厍滠畲诜谂渖谥埘莳弑轼贳铈鲥绶摅纾闩铄厮驷缌锶鸶薮馊飕锼谡稣谇荪狲唢睃闼铊鳎钛鲐昙钽锬顸傥饧铴镗韬铽缇鹈阗粜龆鲦恸钭钍抟饨箨鼍娲腽纨绾辋诿帏闱沩涠玮韪炜鲔阌莴龌邬庑怃妩骛鹉鹜饩阋玺觋硖苋莶藓岘猃娴鹇痫蚝籼跹芗饷骧缃飨哓潇骁绡枭箫亵撷绁缬陉荥馐鸺诩顼谖铉镟谑泶鳕埙浔鲟垭娅桠氩厣赝俨兖谳恹闫酽魇餍鼹炀轺鹞鳐靥谒邺晔烨诒呓峄饴怿驿缢轶贻钇镒镱瘗舣铟瘾茔莺萦蓥撄嘤滢潆璎鹦瘿颏罂镛莸铕鱿伛俣谀谕蓣嵛饫阈妪纡觎欤钰鹆鹬龉橼鸢鼋钺郓芸恽愠纭韫殒氲瓒趱錾驵赜啧帻箦谮缯谵诏钊谪辄鹧浈缜桢轸赈祯鸩诤峥钲铮筝骘栉栀轵轾贽鸷蛳絷踬踯觯锺纣绉伫槠铢啭馔颞骓缒诼镯谘缁辎赀眦锱龇鲻偬诹驺鲰镞缵躜鳟讠谫郄勐凼坂垅垴埯埝苘荬荮莜莼菰藁揸吒吣咔咝咴噘噼嚯幞岙嵴彷徼犸狍馀馇馓馕愣憷懔丬溆滟溷漤潴澹甯纟绔绱珉枧桊桉槔橥轱轷赍肷胨飚煳煅熘愍淼砜磙眍钚钷铘铞锃锍锎锏锘锝锪锫锿镅镎镢镥镩镲稆鹋鹛鹱疬疴痖癯裥襁耢颥螨麴鲅鲆鲇鲞鲴鲺鲼鳊鳋鳘鳙鞒鞴齄'; 3 | } 4 | 5 | const ftPYStr = () => { 6 | return '啊阿埃挨哎唉哀皚癌藹矮艾礙愛隘鞍氨安俺按暗岸胺案骯昂盎凹敖熬翺襖傲奧懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙壩霸罷爸白柏百擺佰敗拜稗斑班搬扳般頒板版扮拌伴瓣半辦絆邦幫梆榜膀綁棒磅蚌鎊傍謗苞胞包褒剝薄雹保堡飽寶抱報暴豹鮑爆杯碑悲卑北輩背貝鋇倍狽備憊焙被奔苯本笨崩繃甭泵蹦迸逼鼻比鄙筆彼碧蓖蔽畢斃毖幣庇痹閉敝弊必辟壁臂避陛鞭邊編貶扁便變卞辨辯辮遍標彪膘表鱉憋別癟彬斌瀕濱賓擯兵冰柄丙秉餅炳病並玻菠播撥缽波博勃搏鉑箔伯帛舶脖膊渤泊駁捕蔔哺補埠不布步簿部怖擦猜裁材才財睬踩采彩菜蔡餐參蠶殘慚慘燦蒼艙倉滄藏操糙槽曹草廁策側冊測層蹭插叉茬茶查碴搽察岔差詫拆柴豺攙摻蟬饞讒纏鏟產闡顫昌猖場嘗常長償腸廠敞暢唱倡超抄鈔朝嘲潮巢吵炒車扯撤掣徹澈郴臣辰塵晨忱沈陳趁襯撐稱城橙成呈乘程懲澄誠承逞騁秤吃癡持匙池遲弛馳恥齒侈尺赤翅斥熾充沖蟲崇寵抽酬疇躊稠愁籌仇綢瞅醜臭初出櫥廚躇鋤雛滁除楚礎儲矗搐觸處揣川穿椽傳船喘串瘡窗幢床闖創吹炊捶錘垂春椿醇唇淳純蠢戳綽疵茨磁雌辭慈瓷詞此刺賜次聰蔥囪匆從叢湊粗醋簇促躥篡竄摧崔催脆瘁粹淬翠村存寸磋撮搓措挫錯搭達答瘩打大呆歹傣戴帶殆代貸袋待逮怠耽擔丹單鄲撣膽旦氮但憚淡誕彈蛋當擋黨蕩檔刀搗蹈倒島禱導到稻悼道盜德得的蹬燈登等瞪凳鄧堤低滴迪敵笛狄滌翟嫡抵底地蒂第帝弟遞締顛掂滇碘點典靛墊電佃甸店惦奠澱殿碉叼雕雕刁掉吊釣調跌爹碟蝶叠諜疊丁盯叮釘頂鼎錠定訂丟東冬董懂動棟侗恫凍洞兜抖鬥陡豆逗痘都督毒犢獨讀堵睹賭杜鍍肚度渡妒端短鍛段斷緞堆兌隊對墩噸蹲敦頓囤鈍盾遁掇哆多奪垛躲朵跺舵剁惰墮蛾峨鵝俄額訛娥惡厄扼遏鄂餓恩而兒耳爾餌洱二貳發罰筏伐乏閥法琺藩帆番翻樊礬釩繁凡煩反返範販犯飯泛坊芳方肪房防妨仿訪紡放菲非啡飛肥匪誹吠肺廢沸費芬酚吩氛分紛墳焚汾粉奮份忿憤糞豐封楓蜂峰鋒風瘋烽逢馮縫諷奉鳳佛否夫敷膚孵扶拂輻幅氟符伏俘服浮涪福袱弗甫撫輔俯釜斧脯腑府腐赴副覆賦復傅付阜父腹負富訃附婦縛咐噶嘎該改概鈣蓋溉幹甘桿柑竿肝趕感稈敢贛岡剛鋼缸肛綱崗港杠篙臯高膏羔糕搞鎬稿告哥歌擱戈鴿胳疙割革葛格蛤閣隔鉻個各給根跟耕更庚羹埂耿梗工攻功恭龔供躬公宮弓鞏汞拱貢共鉤勾溝茍狗垢構購夠辜菇咕箍估沽孤姑鼓古蠱骨谷股故顧固雇刮瓜剮寡掛褂乖拐怪棺關官冠觀管館罐慣灌貫光廣逛瑰規圭矽歸龜閨軌鬼詭癸桂櫃跪貴劊輥滾棍鍋郭國果裹過哈骸孩海氦亥害駭酣憨邯韓含涵寒函喊罕翰撼捍旱憾悍焊汗漢夯杭航壕嚎豪毫郝好耗號浩呵喝荷菏核禾和何合盒貉閡河涸赫褐鶴賀嘿黑痕很狠恨哼亨橫衡恒轟哄烘虹鴻洪宏弘紅喉侯猴吼厚候後呼乎忽瑚壺葫胡蝴狐糊湖弧虎唬護互滬戶花嘩華猾滑畫劃化話槐徊懷淮壞歡環桓還緩換患喚瘓豢煥渙宦幻荒慌黃磺蝗簧皇凰惶煌晃幌恍謊灰揮輝徽恢蛔回毀悔慧卉惠晦賄穢會燴匯諱誨繪葷昏婚魂渾混豁活夥火獲或惑霍貨禍擊圾基機畸稽積箕肌饑跡激譏雞姬績緝吉極棘輯籍集及急疾汲即嫉級擠幾脊己薊技冀季伎祭劑悸濟寄寂計記既忌際繼紀嘉枷夾佳家加莢頰賈甲鉀假稼價架駕嫁殲監堅尖箋間煎兼肩艱奸緘繭檢柬堿鹼揀撿簡儉剪減薦檻鑒踐賤見鍵箭件健艦劍餞漸濺澗建僵姜將漿江疆蔣槳獎講匠醬降蕉椒礁焦膠交郊澆驕嬌嚼攪鉸矯僥腳狡角餃繳絞剿教酵轎較叫窖揭接皆稭街階截劫節莖睛晶鯨京驚精粳經井警景頸靜境敬鏡徑痙靖竟競凈炯窘揪究糾玖韭久灸九酒廄救舊臼舅咎就疚鞠拘狙疽居駒菊局咀矩舉沮聚拒據巨具距踞鋸俱句懼炬劇捐鵑娟倦眷卷絹撅攫抉掘倔爵桔傑捷睫竭潔結解姐戒藉芥界借介疥誡屆巾筋斤金今津襟緊錦僅謹進靳晉禁近燼浸盡勁荊兢覺決訣絕均菌鈞軍君峻俊竣浚郡駿喀咖卡咯開揩楷凱慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕顆科殼咳可渴克刻客課肯啃墾懇坑吭空恐孔控摳口扣寇枯哭窟苦酷庫褲誇垮挎跨胯塊筷儈快寬款匡筐狂框礦眶曠況虧盔巋窺葵奎魁傀饋愧潰坤昆捆困括擴廓闊垃拉喇蠟臘辣啦萊來賴藍婪欄攔籃闌蘭瀾讕攬覽懶纜爛濫瑯榔狼廊郎朗浪撈勞牢老佬姥酪烙澇勒樂雷鐳蕾磊累儡壘擂肋類淚棱楞冷厘梨犁黎籬貍離漓理李裏鯉禮莉荔吏栗麗厲勵礫歷利傈例俐痢立粒瀝隸力璃哩倆聯蓮連鐮廉憐漣簾斂臉鏈戀煉練糧涼梁粱良兩輛量晾亮諒撩聊僚療燎寥遼潦了撂鐐廖料列裂烈劣獵琳林磷霖臨鄰鱗淋凜賃吝拎玲菱零齡鈴伶羚淩靈陵嶺領另令溜琉榴硫餾留劉瘤流柳六龍聾嚨籠窿隆壟攏隴樓婁摟簍漏陋蘆盧顱廬爐擄鹵虜魯麓碌露路賂鹿潞祿錄陸戮驢呂鋁侶旅履屢縷慮氯律率濾綠巒攣孿灤卵亂掠略掄輪倫侖淪綸論蘿螺羅邏鑼籮騾裸落洛駱絡媽麻瑪碼螞馬罵嘛嗎埋買麥賣邁脈瞞饅蠻滿蔓曼慢漫謾芒茫盲氓忙莽貓茅錨毛矛鉚卯茂冒帽貌貿麽玫枚梅酶黴煤沒眉媒鎂每美昧寐妹媚門悶們萌蒙檬盟錳猛夢孟瞇醚靡糜迷謎彌米秘覓泌蜜密冪棉眠綿冕免勉娩緬面苗描瞄藐秒渺廟妙蔑滅民抿皿敏憫閩明螟鳴銘名命謬摸摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌謀牟某拇牡畝姆母墓暮幕募慕木目睦牧穆拿哪吶鈉那娜納氖乃奶耐奈南男難囊撓腦惱鬧淖呢餒內嫩能妮霓倪泥尼擬妳匿膩逆溺蔫拈年碾攆撚念娘釀鳥尿捏聶孽嚙鑷鎳涅您檸獰凝寧擰濘牛扭鈕紐膿濃農弄奴努怒女暖虐瘧挪懦糯諾哦歐鷗毆藕嘔偶漚啪趴爬帕怕琶拍排牌徘湃派攀潘盤磐盼畔判叛乓龐旁耪胖拋咆刨炮袍跑泡呸胚培裴賠陪配佩沛噴盆砰抨烹澎彭蓬棚硼篷膨朋鵬捧碰坯砒霹批披劈琵毗啤脾疲皮匹痞僻屁譬篇偏片騙飄漂瓢票撇瞥拼頻貧品聘乒坪蘋萍平憑瓶評屏坡潑頗婆破魄迫粕剖撲鋪仆莆葡菩蒲埔樸圃普浦譜曝瀑期欺棲戚妻七淒漆柒沏其棋奇歧畦崎臍齊旗祈祁騎起豈乞企啟契砌器氣迄棄汽泣訖掐洽牽扡釬鉛千遷簽仟謙乾黔錢鉗前潛遣淺譴塹嵌欠歉槍嗆腔羌墻薔強搶橇鍬敲悄橋瞧喬僑巧鞘撬翹峭俏竅切茄且怯竊欽侵親秦琴勤芹擒禽寢沁青輕氫傾卿清擎晴氰情頃請慶瓊窮秋丘邱球求囚酋泅趨區蛆曲軀屈驅渠取娶齲趣去圈顴權醛泉全痊拳犬券勸缺炔瘸卻鵲榷確雀裙群然燃冉染瓤壤攘嚷讓饒擾繞惹熱壬仁人忍韌任認刃妊紉扔仍日戎茸蓉榮融熔溶容絨冗揉柔肉茹蠕儒孺如辱乳汝入褥軟阮蕊瑞銳閏潤若弱撒灑薩腮鰓塞賽三三傘散桑嗓喪搔騷掃嫂瑟色澀森僧莎砂殺剎沙紗傻啥煞篩曬珊苫杉山刪煽衫閃陜擅贍膳善汕扇繕墑傷商賞晌上尚裳梢捎稍燒芍勺韶少哨邵紹奢賒蛇舌舍赦攝射懾涉社設砷申呻伸身深娠紳神沈審嬸甚腎慎滲聲生甥牲升繩省盛剩勝聖師失獅施濕詩屍虱十石拾時什食蝕實識史矢使屎駛始式示士世柿事拭誓逝勢是嗜噬適仕侍釋飾氏市恃室視試收手首守壽授售受瘦獸蔬樞梳殊抒輸叔舒淑疏書贖孰熟薯暑曙署蜀黍鼠屬術述樹束戍豎墅庶數漱恕刷耍摔衰甩帥栓拴霜雙爽誰水睡稅吮瞬順舜說碩朔爍斯撕嘶思私司絲死肆寺嗣四伺似飼巳松聳慫頌送宋訟誦搜艘擻嗽蘇酥俗素速粟僳塑溯宿訴肅酸蒜算雖隋隨綏髓碎歲穗遂隧祟孫損筍蓑梭唆縮瑣索鎖所塌他它她塔獺撻蹋踏胎苔擡臺泰酞太態汰坍攤貪癱灘壇檀痰潭譚談坦毯袒碳探嘆炭湯塘搪堂棠膛唐糖倘躺淌趟燙掏濤滔絳萄桃逃淘陶討套特藤騰疼謄梯剔踢銻提題蹄啼體替嚏惕涕剃屜天添填田甜恬舔腆挑條迢眺跳貼鐵帖廳聽烴汀廷停亭庭挺艇通桐酮瞳同銅彤童桶捅筒統痛偷投頭透凸禿突圖徒途塗屠土吐兔湍團推頹腿蛻褪退吞屯臀拖托脫鴕陀馱駝橢妥拓唾挖哇蛙窪娃瓦襪歪外豌彎灣玩頑丸烷完碗挽晚皖惋宛婉萬腕汪王亡枉網往旺望忘妄威巍微危韋違桅圍唯惟為濰維葦萎委偉偽尾緯未蔚味畏胃餵魏位渭謂尉慰衛瘟溫蚊文聞紋吻穩紊問嗡翁甕撾蝸渦窩我斡臥握沃巫嗚鎢烏汙誣屋無蕪梧吾吳毋武五捂午舞伍侮塢戊霧晤物勿務悟誤昔熙析西硒矽晰嘻吸錫犧稀息希悉膝夕惜熄烯溪汐犀檄襲席習媳喜銑洗系隙戲細瞎蝦匣霞轄暇峽俠狹下廈夏嚇掀鍁先仙鮮纖鹹賢銜舷閑涎弦嫌顯險現獻縣腺餡羨憲陷限線相廂鑲香箱襄湘鄉翔祥詳想響享項巷橡像向象蕭硝霄削哮囂銷消宵淆曉小孝校肖嘯笑效楔些歇蠍鞋協挾攜邪斜脅諧寫械卸蟹懈泄瀉謝屑薪芯鋅欣辛新忻心信釁星腥猩惺興刑型形邢行醒幸杏性姓兄兇胸匈洶雄熊休修羞朽嗅銹秀袖繡墟戌需虛噓須徐許蓄酗敘旭序畜恤絮婿緒續軒喧宣懸旋玄選癬眩絢靴薛學穴雪血勛熏循旬詢尋馴巡殉汛訓訊遜迅壓押鴉鴨呀丫芽牙蚜崖衙涯雅啞亞訝焉咽閹煙淹鹽嚴研蜒巖延言顏閻炎沿奄掩眼衍演艷堰燕厭硯雁唁彥焰宴諺驗殃央鴦秧楊揚佯瘍羊洋陽氧仰癢養樣漾邀腰妖瑤搖堯遙窯謠姚咬舀藥要耀椰噎耶爺野冶也頁掖業葉曳腋夜液壹壹醫揖銥依伊衣頤夷遺移儀胰疑沂宜姨彜椅蟻倚已乙矣以藝抑易邑屹億役臆逸肄疫亦裔意毅憶義益溢詣議誼譯異翼翌繹茵蔭因殷音陰姻吟銀淫寅飲尹引隱印英櫻嬰鷹應纓瑩螢營熒蠅迎贏盈影穎硬映喲擁傭臃癰庸雍踴蛹詠泳湧永恿勇用幽優悠憂尤由郵鈾猶油遊酉有友右佑釉誘又幼迂淤於盂榆虞愚輿余俞逾魚愉渝漁隅予娛雨與嶼禹宇語羽玉域芋郁籲遇喻峪禦愈欲獄育譽浴寓裕預豫馭鴛淵冤元垣袁原援轅園員圓猿源緣遠苑願怨院曰約越躍鑰嶽粵月悅閱耘雲鄖勻隕允運蘊醞暈韻孕匝砸雜栽哉災宰載再在咱攢暫贊贓臟葬遭糟鑿藻棗早澡蚤躁噪造皂竈燥責擇則澤賊怎增憎曾贈紮喳渣劄軋鍘閘眨柵榨咋乍炸詐摘齋宅窄債寨瞻氈詹粘沾盞斬輾嶄展蘸棧占戰站湛綻樟章彰漳張掌漲杖丈帳賬仗脹瘴障招昭找沼趙照罩兆肇召遮折哲蟄轍者鍺蔗這浙珍斟真甄砧臻貞針偵枕疹診震振鎮陣蒸掙睜征猙爭怔整拯正政幀癥鄭證芝枝支吱蜘知肢脂汁之織職直植殖執值侄址指止趾只旨紙誌摯擲至致置幟峙制智秩稚質炙痔滯治窒中盅忠鐘衷終種腫重仲眾舟周州洲謅粥軸肘帚咒皺宙晝驟珠株蛛朱豬諸誅逐竹燭煮拄矚囑主著柱助蛀貯鑄築住註祝駐抓爪拽專磚轉撰賺篆樁莊裝妝撞壯狀椎錐追贅墜綴諄準捉拙卓桌琢茁酌啄著灼濁茲咨資姿滋淄孜紫仔籽滓子自漬字鬃棕蹤宗綜總縱鄒走奏揍租足卒族祖詛阻組鉆纂嘴醉最罪尊遵昨左佐柞做作坐座錒噯嬡璦曖靄諳銨鵪媼驁鰲鈀唄鈑鴇齙鵯賁錛蓽嗶潷鉍篳蹕芐緶籩驃颮飆鏢鑣鰾儐繽檳殯臏鑌髕鬢稟餑鈸鵓鈽驂黲惻鍤儕釵囅諂讖蕆懺嬋驏覘禪鐔倀萇悵閶鯧硨傖諶櫬磣齔棖檉鋮鐺飭鴟銃儔幬讎芻絀躕釧愴綞鶉輟齪鶿蓯驄樅輳攛銼鹺噠韃駘紿殫賧癉簞讜碭襠燾鐙糴詆諦綈覿鏑巔鈿癲銚鯛鰈鋌銩崠鶇竇瀆櫝牘篤黷籪懟鐓燉躉鐸諤堊閼軛鋨鍔鶚顎顓鱷誒邇鉺鴯鮞鈁魴緋鐨鯡僨灃鳧駙紱紼賻麩鮒鰒釓賅尷搟紺戇睪誥縞鋯紇鎘潁亙賡綆鯁詬緱覯詁轂鈷錮鴣鵠鶻鴰摑詿摜鸛鰥獷匭劌媯檜鮭鱖袞緄鯀堝咼幗槨蟈鉿闞絎頡灝顥訶闔蠣黌訌葒閎鱟滸鶘驊樺鏵奐繯鍰鯇鰉詼薈噦澮繢琿暉諢餛閽鈥鑊訐詰薺嘰嚌驥璣覬齏磯羈蠆躋霽鱭鯽郟浹鋏鎵蟯諫縑戔戩瞼鶼筧鰹韉絳韁撟嶠鷦鮫癤頜鮚巹藎饉縉贐覲剄涇逕弳脛靚鬮鳩鷲詎屨櫸颶鉅鋦窶齟錈鐫雋譎玨皸剴塏愾愷鎧鍇龕閌鈧銬騍緙軻鈳錁頷齦鏗嚳鄶噲膾獪髖誆誑鄺壙纊貺匱蕢憒聵簣閫錕鯤蠐崍徠淶瀨賚睞錸癩籟嵐欖斕鑭襤閬鋃嘮嶗銠鐒癆鰳誄縲儷酈壢藶蒞蘺嚦邐驪縭櫪櫟轢礪鋰鸝癘糲躒靂鱺鱧蘞奩瀲璉殮褳襝鰱魎繚釕鷯藺廩檁轔躪綾欞蟶鯪瀏騮綹鎦鷚蘢瀧瓏櫳朧礱僂蔞嘍嶁鏤瘺耬螻髏壚擼嚕閭瀘淥櫨櫓轤輅轆氌臚鸕鷺艫鱸臠孌欒鸞鑾圇犖玀濼欏腡鏍櫚褸鋝嘸嘜嬤榪勱縵鏝顙鰻麼捫燜懣鍆羋謐獼禰澠靦黽緲繆閔緡謨驀饃歿鏌鉬鐃訥鈮鯢輦鯰蔦裊隉蘗囁顢躡苧嚀聹儂噥駑釹儺謳慪甌蹣皰轡紕羆鈹諞駢縹嬪釙鏷鐠蘄騏綺榿磧頎頏鰭僉蕁慳騫繾槧鈐嬙檣戧熗錆鏘鏹羥蹌誚譙蕎繰磽蹺愜鍥篋鋟撳鯖煢蛺巰賕蟣鰍詘嶇闃覷鴝詮綣輇銓闋闕愨蕘嬈橈飪軔嶸蠑縟銣顰蜆颯毿糝繅嗇銫穡鎩鯊釃訕姍騸釤鱔坰殤觴厙灄畬詵諗瀋謚塒蒔弒軾貰鈰鰣綬攄紓閂鑠廝駟緦鍶鷥藪餿颼鎪謖穌誶蓀猻嗩脧闥鉈鰨鈦鮐曇鉭錟頇儻餳鐋鏜韜鋱緹鵜闐糶齠鰷慟鈄釷摶飩籜鼉媧膃紈綰輞諉幃闈溈潿瑋韙煒鮪閿萵齷鄔廡憮嫵騖鵡鶩餼鬩璽覡硤莧薟蘚峴獫嫻鷴癇蠔秈躚薌餉驤緗饗嘵瀟驍綃梟簫褻擷紲纈陘滎饈鵂詡頊諼鉉鏇謔澩鱈塤潯鱘埡婭椏氬厴贗儼兗讞懨閆釅魘饜鼴煬軺鷂鰩靨謁鄴曄燁詒囈嶧飴懌驛縊軼貽釔鎰鐿瘞艤銦癮塋鶯縈鎣攖嚶瀅瀠瓔鸚癭頦罌鏞蕕銪魷傴俁諛諭蕷崳飫閾嫗紆覦歟鈺鵒鷸齬櫞鳶黿鉞鄆蕓惲慍紜韞殞氳瓚趲鏨駔賾嘖幘簀譖繒譫詔釗謫輒鷓湞縝楨軫賑禎鴆諍崢鉦錚箏騭櫛梔軹輊贄鷙螄縶躓躑觶鍾紂縐佇櫧銖囀饌顳騅縋諑鐲諮緇輜貲眥錙齜鯔傯諏騶鯫鏃纘躦鱒訁譾郤猛氹阪壟堖垵墊檾蕒葤蓧蒓菇槁摣咤唚哢噝噅撅劈謔襆嶴脊仿僥獁麅餘餷饊饢楞怵懍爿漵灩混濫瀦淡寧糸絝緔瑉梘棬案橰櫫軲軤賫膁腖飈糊煆溜湣渺碸滾瞘鈈鉕鋣銱鋥鋶鐦鐧鍩鍀鍃錇鎄鎇鎿鐝鑥鑹鑔穭鶓鶥鸌癧屙瘂臒襇繈耮顬蟎麯鮁鮃鮎鯗鯝鯴鱝鯿鰠鰵鱅鞽韝齇'; 7 | } 8 | 9 | const traditionalized = (cc) => { 10 | let str = ''; 11 | for (let i = 0; i < cc.length; i++) { 12 | if (charPYStr().indexOf(cc.charAt(i)) != -1) 13 | str += ftPYStr().charAt(charPYStr().indexOf(cc.charAt(i))); 14 | else 15 | str += cc.charAt(i); 16 | } 17 | return str; 18 | } 19 | 20 | const simplized = (cc) => { 21 | let str = ''; 22 | for (let i = 0; i < cc.length; i++) { 23 | if (ftPYStr().indexOf(cc.charAt(i)) != -1) 24 | str += charPYStr().charAt(ftPYStr().indexOf(cc.charAt(i))); 25 | else 26 | str += cc.charAt(i); 27 | } 28 | return str; 29 | } 30 | 31 | module.exports = { 32 | convert: function(mode, char) { 33 | if (mode == 0) // 繁体转简体 34 | return simplized(char); 35 | else // 简体转繁体 36 | return traditionalized(char); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/hanzi-writer/EventEmitter.js: -------------------------------------------------------------------------------- 1 | // lightweight partial EventEmitter, since the full node EventEmitter isn't present in wechat 2 | 3 | export default class EventEmitter { 4 | constructor() { 5 | this._listeners = {}; 6 | } 7 | 8 | addListener(name, callback) { 9 | if (!this._listeners[name]) this._listeners[name] = []; 10 | this._listeners[name].push(callback); 11 | } 12 | 13 | trigger(name, evt) { 14 | if (this._listeners[name]) { 15 | this._listeners[name].forEach(listener => listener(evt)); 16 | } 17 | } 18 | 19 | removeAllListeners() { 20 | this._listeners = {}; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/hanzi-writer/RenderTarget.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from './EventEmitter'; 2 | 3 | const polyfillCanvasCtx = (ctx) => { 4 | // need to polyfill missing setters from the wechat context... 5 | [ 6 | 'globalAlpha', 7 | 'strokeStyle', 8 | 'fillStyle', 9 | 'lineWidth', 10 | 'lineCap', 11 | 'lineJoin', 12 | ].forEach(setter => { 13 | const setterMethod = `set${setter[0].toUpperCase()}${setter.slice(1)}`; 14 | Object.defineProperty(ctx, setter, { set: ctx[setterMethod].bind(ctx) }); 15 | }); 16 | return ctx; 17 | }; 18 | 19 | const eventify = (evt, boundingRect) => { 20 | const getPoint = () => { 21 | const x = evt.touches[0].clientX - boundingRect.left; 22 | const y = evt.touches[0].clientY - boundingRect.top; 23 | return { x, y }; 24 | }; 25 | 26 | return { preventDefault: () => { }, getPoint }; 27 | }; 28 | 29 | class RenderTarget { 30 | constructor(view) { 31 | this.view = view; 32 | this.eventEmitter = new EventEmitter(); 33 | this.ctx = polyfillCanvasCtx(wx.createCanvasContext('writer-canvas', view)); 34 | this.canvas = this.view.selectComponent('#writer-canvas'); 35 | } 36 | 37 | addPointerStartListener(callback) { 38 | this.eventEmitter.addListener('pointerStart', callback); 39 | } 40 | 41 | addPointerMoveListener(callback) { 42 | this.eventEmitter.addListener('pointerMove', callback); 43 | } 44 | 45 | addPointerEndListener(callback) { 46 | this.eventEmitter.addListener('pointerEnd', callback); 47 | } 48 | 49 | trigger(eventName, evt) { 50 | this._getClientBoundingRect().then(rect => { 51 | this.eventEmitter.trigger(eventName, eventify(evt, rect)); 52 | }); 53 | } 54 | 55 | removeAllListeners() { 56 | return this.eventEmitter.removeAllListeners(); 57 | } 58 | 59 | getContext() { 60 | return this.ctx; 61 | } 62 | 63 | _getClientBoundingRect() { 64 | return new Promise(resolve => { 65 | this.view 66 | .createSelectorQuery() 67 | .select('#writer-canvas') 68 | .boundingClientRect(resolve) 69 | .exec(); 70 | }); 71 | } 72 | } 73 | 74 | RenderTarget.init = initData => new RenderTarget(initData); 75 | 76 | module.exports = RenderTarget; 77 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/hanzi-writer/defaultCharDataLoader.js: -------------------------------------------------------------------------------- 1 | const VERSION = '2.0'; 2 | const getCharDataUrl = (char) => `https://hanzi-writer.cdn.coderai.cn/package/${encodeURIComponent(char)}.json`; 3 | 4 | export default (char, onLoad, onError) => { 5 | wx.request({ 6 | url: getCharDataUrl(char), 7 | header: { 8 | 'content-type': 'application/json', 9 | }, 10 | success: (res) => { 11 | onLoad(res.data); 12 | }, 13 | fail: onError, 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/hanzi-writer/hanzi-writer-context.js: -------------------------------------------------------------------------------- 1 | import HanziWriter from 'hanzi-writer'; 2 | import RenderTarget from './RenderTarget'; 3 | import { 4 | removeEmptyKeys 5 | } from './utils'; 6 | import defaultCharDataLoader from './defaultCharDataLoader'; 7 | 8 | export default class HanziWriterContext { 9 | constructor({ 10 | ref, 11 | page, 12 | charDataLoader, 13 | character, 14 | onLoadCharDataError, 15 | onLoadCharDataSuccess, 16 | showOutline, 17 | showCharacter, 18 | 19 | // positioning options 20 | 21 | padding, 22 | 23 | // animation options 24 | 25 | strokeAnimationSpeed, 26 | strokeFadeDuration, 27 | strokeHighlightDuration, 28 | strokeHighlightSpeed, 29 | delayBetweenStrokes, 30 | delayBetweenLoops, 31 | 32 | // colors 33 | 34 | strokeColor, 35 | radicalColor, 36 | highlightColor, 37 | outlineColor, 38 | drawingColor, 39 | 40 | // quiz options 41 | 42 | leniency, 43 | showHintAfterMisses, 44 | highlightOnComplete, 45 | highlightCompleteColor, 46 | }) { 47 | if (!ref || !page) { 48 | throw new Error('parameter id, page are required'); 49 | } 50 | 51 | // this.comp = page.selectComponent('#' + id); 52 | this.comp = page.$refs[ref] 53 | if (!this.comp) { 54 | throw new Error(`hanzi-writer-view with id ${id} not found`); 55 | } 56 | 57 | this.isDestroyed = false; 58 | 59 | this.writer = new HanziWriter(this.comp, removeEmptyKeys({ 60 | width: this.comp.width, 61 | height: this.comp.height, 62 | charDataLoader: charDataLoader || defaultCharDataLoader, 63 | onLoadCharDataError, 64 | onLoadCharDataSuccess, 65 | showOutline, 66 | showCharacter, 67 | padding, 68 | strokeAnimationSpeed, 69 | strokeFadeDuration, 70 | strokeHighlightDuration, 71 | strokeHighlightSpeed, 72 | delayBetweenStrokes, 73 | delayBetweenLoops, 74 | strokeColor, 75 | radicalColor, 76 | highlightColor, 77 | outlineColor, 78 | drawingColor, 79 | leniency, 80 | showHintAfterMisses, 81 | highlightOnComplete, 82 | highlightCompleteColor, 83 | rendererOverride: { 84 | createRenderTarget: RenderTarget.init 85 | }, 86 | renderer: 'canvas', 87 | })); 88 | 89 | if (character) { 90 | this.setCharacter(character); 91 | } 92 | this.comp.connectContext(this); 93 | } 94 | 95 | _ensureNotDestroyed() { 96 | if (this.isDestroyed) throw new Error('This context has already been destroyed'); 97 | } 98 | 99 | showCharacter(options = {}) { 100 | this._ensureNotDestroyed(); 101 | return this.writer.showCharacter(options); 102 | } 103 | 104 | hideCharacter(options = {}) { 105 | this._ensureNotDestroyed(); 106 | return this.writer.hideCharacter(options); 107 | } 108 | 109 | animateCharacter(options = {}) { 110 | this._ensureNotDestroyed(); 111 | this.comp.setIsQuizzing(false); 112 | return this.writer.animateCharacter(options); 113 | } 114 | 115 | animateStroke(strokeNum, options = {}) { 116 | this._ensureNotDestroyed(); 117 | this.comp.setIsQuizzing(false); 118 | return this.writer.animateStroke(strokeNum, options); 119 | } 120 | 121 | loopCharacterAnimation(options = {}) { 122 | this._ensureNotDestroyed(); 123 | this.comp.setIsQuizzing(false); 124 | return this.writer.loopCharacterAnimation(options); 125 | } 126 | 127 | showOutline(options = {}) { 128 | this._ensureNotDestroyed(); 129 | return this.writer.showOutline(options); 130 | } 131 | 132 | hideOutline(options = {}) { 133 | this._ensureNotDestroyed(); 134 | return this.writer.hideOutline(options); 135 | } 136 | 137 | updateColor(colorName, colorVal, options = {}) { 138 | this._ensureNotDestroyed(); 139 | return this.writer.updateColor(colorName, colorVal, options); 140 | } 141 | 142 | quiz(quizOptions = {}) { 143 | this._ensureNotDestroyed(); 144 | this.comp.setIsQuizzing(true); 145 | return this.writer.quiz(quizOptions); 146 | } 147 | 148 | cancelQuiz() { 149 | this._ensureNotDestroyed(); 150 | this.comp.setIsQuizzing(false); 151 | return this.writer.cancelQuiz(); 152 | } 153 | 154 | setCharacter(character) { 155 | this._ensureNotDestroyed(); 156 | this.comp.setIsQuizzing(false); 157 | return this.writer.setCharacter(character); 158 | } 159 | 160 | trigger(evtName, evt) { 161 | this.writer.target.trigger(evtName, evt); 162 | } 163 | 164 | destroy() { 165 | if (this.isDestroyed) return; 166 | this.comp.disconnectContext(); 167 | this.writer.target.removeAllListeners(); 168 | this.writer.cancelQuiz(); 169 | this.writer.hideCharacter(); 170 | this.writer.hideOutline(); 171 | this.isDestroyed = true; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/hanzi-writer/hanzi-writer.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 70 | 71 | 86 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/hanzi-writer/index.js: -------------------------------------------------------------------------------- 1 | import HanziWriterContext from './hanzi-writer-context'; 2 | 3 | module.exports = (options) => new HanziWriterContext(options); 4 | -------------------------------------------------------------------------------- /直书小程序源代码/lib/hanzi-writer/utils.js: -------------------------------------------------------------------------------- 1 | export const removeEmptyKeys = (obj) => { 2 | const newObj = {}; 3 | Object.keys(obj).forEach((key) => { 4 | const val = obj[key]; 5 | if (val !== undefined && val !== null) { 6 | newObj[key] = val; 7 | } 8 | }); 9 | return newObj; 10 | }; 11 | -------------------------------------------------------------------------------- /直书小程序源代码/locale.json: -------------------------------------------------------------------------------- 1 | { 2 | "locale": "zh-CN", 3 | "messages": { 4 | "zh-CN": { 5 | "default": { 6 | "updateText": "更新文字", 7 | "animation": "动画", 8 | "traditional": "繁体", 9 | "simplified": "简体", 10 | "quiz": "我来写", 11 | "playAudio": "朗读", 12 | "changeSample": "点击下列图片切换示例文字", 13 | "confirm": "确定", 14 | "cancel": "取消", 15 | "uploading": "正在上传", 16 | "recognizing": "正在识别", 17 | "uploadImageOverSize": "请上传小于4MB的图片", 18 | "pageTitle": { 19 | "index": "学写汉字", 20 | "example": "示例文字", 21 | "about": "关于我们", 22 | "ocr": "拍照识字", 23 | "translate": "机器翻译", 24 | "tts": "文本转语音", 25 | "asr": "语音识别", 26 | "writer": "文字查看" 27 | }, 28 | "ocr": { 29 | "upload": "图片上传", 30 | "recognize": "识别文字", 31 | "result": "识别结果" 32 | }, 33 | "translate": { 34 | "english": "英文", 35 | "pleaseInputEnglish": "请输入英文", 36 | "translateToChinese": "翻译成中文" 37 | }, 38 | "tts": { 39 | "chinese": "中文", 40 | "pleaseInputChinese": "请输入中文" 41 | }, 42 | "asr": { 43 | "startRecord": "开始录音", 44 | "endRecord": "停止录音", 45 | "playAudio": "播放录音", 46 | "recognizeText": "识别文字" 47 | } 48 | } 49 | }, 50 | "zh-TW": { 51 | "default": { 52 | "updateText": "更新文字", 53 | "animation": "動畫", 54 | "traditional": "繁體", 55 | "simplified": "簡體", 56 | "quiz": "我來寫", 57 | "playAudio": "朗讀", 58 | "changeSample": "點擊下列圖片切換示例文字", 59 | "confirm": "確定", 60 | "cancel": "取消", 61 | "uploading": "正在上傳", 62 | "recognizing": "正在識別", 63 | "uploadImageOverSize": "請上傳小於4MB的圖片", 64 | "pageTitle": { 65 | "index": "學寫漢字", 66 | "example": "示例文字", 67 | "about": "關於我們", 68 | "ocr": "拍照識字", 69 | "translate": "機器翻譯", 70 | "tts": "文本轉語音", 71 | "asr": "語音識別", 72 | "writer": "文字查看" 73 | }, 74 | "ocr": { 75 | "upload": "圖片上傳", 76 | "recognize": "識別文字", 77 | "result": "識別結果" 78 | }, 79 | "translate": { 80 | "english": "英文", 81 | "pleaseInputEnglish": "請輸入英文", 82 | "translateToChinese": "翻譯成中文" 83 | }, 84 | "tts": { 85 | "chinese": "中文", 86 | "pleaseInputChinese": "請輸入中文" 87 | }, 88 | "asr": { 89 | "startRecord": "開始錄音", 90 | "endRecord": "停止錄音", 91 | "playAudio": "播放錄音", 92 | "recognizeText": "識別文字" 93 | } 94 | } 95 | }, 96 | "en-US": { 97 | "default": { 98 | "updateText": "Update Text", 99 | "animation": "Animation", 100 | "traditional": "Traditional", 101 | "simplified": "Simplified", 102 | "quiz": "Write Myself", 103 | "playAudio": "Read", 104 | "changeSample": "Click image to view Character", 105 | "confirm": "Confirm", 106 | "cancel": "Cancel", 107 | "uploading": "Uploading", 108 | "recognizing": "Recognizing", 109 | "uploadImageOverSize": "Please upload picture smaller than 4MB", 110 | "pageTitle": { 111 | "index": "Easy Hanzi", 112 | "example": "Example Character", 113 | "about": "About Us", 114 | "ocr": "OCR", 115 | "translate": "Translate", 116 | "tts": "Text To Speech", 117 | "asr": "Speech Recognition", 118 | "writer": "Character Viewer" 119 | }, 120 | "ocr": { 121 | "upload": "Image upload", 122 | "recognize": "Recognize Text", 123 | "result": "Result" 124 | }, 125 | "translate": { 126 | "english": "EN", 127 | "pleaseInputEnglish": "Please input English", 128 | "translateToChinese": "Translate to Chinese" 129 | }, 130 | "tts": { 131 | "chinese": "CN", 132 | "pleaseInputChinese": "Please input Chinese" 133 | }, 134 | "asr": { 135 | "startRecord": "Record", 136 | "endRecord": "Stop", 137 | "playAudio": "Play", 138 | "recognizeText": "Recognize" 139 | } 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /直书小程序源代码/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | 4 | wx.cloud.init({ 5 | traceUser: true, 6 | env: 'tommytju-ges0k' 7 | }); 8 | 9 | // 导入 hanzi-writer 10 | import hanziWriter from './lib/hanzi-writer/hanzi-writer.vue' 11 | Vue.component('hanzi-writer', hanziWriter) 12 | import clickLink from './components/clickLink.vue'; 13 | Vue.component('click-link', clickLink) 14 | import centerImg from './components/centerImg.vue'; 15 | Vue.component('center-img', centerImg) 16 | import textView from './components/textView.vue'; 17 | Vue.component('text-view', textView) 18 | import textTitle from './components/textTitle.vue'; 19 | Vue.component('text-title', textTitle) 20 | import selectWord from './components/selectWord.vue'; 21 | Vue.component('select-word', selectWord) 22 | 23 | // 导入简繁转化库 24 | import { 25 | convert 26 | } from './lib/convertSimpleTraditionCN/index.js' 27 | Vue.prototype.convert = convert; 28 | 29 | // 导入 vue-i18n多语言库 30 | import VueI18n from 'vue-i18n' 31 | import locale from 'locale.json' 32 | Vue.use(VueI18n) 33 | const i18n = new VueI18n(locale) 34 | Vue.prototype._i18n = i18n 35 | 36 | Vue.config.productionTip = false 37 | App.mpType = 'app' 38 | 39 | // 导入全局mixin方法 40 | import { globalMixins } from './mixin.js' 41 | Vue.mixin(globalMixins) 42 | 43 | const app = new Vue({ 44 | i18n, 45 | ...App 46 | }) 47 | app.$mount() 48 | -------------------------------------------------------------------------------- /直书小程序源代码/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "学写汉字", 3 | "appid" : "__UNI__C0175B1", 4 | "description" : "", 5 | "versionName" : "学写汉字 1.0.0", 6 | "versionCode" : 214, 7 | "transformPx" : false, 8 | "app-plus" : { 9 | /* 5+App特有相关 */ 10 | "modules" : {}, 11 | /* 模块配置 */ 12 | "distribute" : { 13 | /* 应用发布信息 */ 14 | "android" : { 15 | /* android打包配置 */ 16 | "permissions" : [ 17 | "", 18 | "" 19 | ] 20 | }, 21 | "ios" : {}, 22 | /* ios打包配置 */ 23 | "sdkConfigs" : {}, 24 | "icons" : { 25 | "android" : { 26 | "hdpi" : "unpackage/res/icons/72x72.png", 27 | "xhdpi" : "unpackage/res/icons/96x96.png", 28 | "xxhdpi" : "unpackage/res/icons/144x144.png", 29 | "xxxhdpi" : "unpackage/res/icons/192x192.png" 30 | }, 31 | "ios" : { 32 | "appstore" : "unpackage/res/icons/1024x1024.png", 33 | "ipad" : { 34 | "app" : "unpackage/res/icons/76x76.png", 35 | "app@2x" : "unpackage/res/icons/152x152.png", 36 | "notification" : "unpackage/res/icons/20x20.png", 37 | "notification@2x" : "unpackage/res/icons/40x40.png", 38 | "proapp@2x" : "unpackage/res/icons/167x167.png", 39 | "settings" : "unpackage/res/icons/29x29.png", 40 | "settings@2x" : "unpackage/res/icons/58x58.png", 41 | "spotlight" : "unpackage/res/icons/40x40.png", 42 | "spotlight@2x" : "unpackage/res/icons/80x80.png" 43 | }, 44 | "iphone" : { 45 | "app@2x" : "unpackage/res/icons/120x120.png", 46 | "app@3x" : "unpackage/res/icons/180x180.png", 47 | "notification@2x" : "unpackage/res/icons/40x40.png", 48 | "notification@3x" : "unpackage/res/icons/60x60.png", 49 | "settings@2x" : "unpackage/res/icons/58x58.png", 50 | "settings@3x" : "unpackage/res/icons/87x87.png", 51 | "spotlight@2x" : "unpackage/res/icons/80x80.png", 52 | "spotlight@3x" : "unpackage/res/icons/120x120.png" 53 | } 54 | } 55 | }, 56 | "splashscreen" : { 57 | "android" : { 58 | "hdpi" : "/Users/maxoyed/Downloads/秉笔直书/480x762 – 学写汉字.png", 59 | "xhdpi" : "/Users/maxoyed/Downloads/秉笔直书/720x1242 – 学写汉字.png", 60 | "xxhdpi" : "/Users/maxoyed/Downloads/秉笔直书/1080x1882 – 学写汉字.png" 61 | } 62 | } 63 | } 64 | }, 65 | /* SDK配置 */ 66 | "quickapp" : {}, 67 | /* 快应用特有相关 */ 68 | "mp-weixin" : { 69 | "appid" : "wx7929379521b078d3", 70 | "cloudfunctionRoot" : "./cloudfunctions/", 71 | "setting" : { 72 | "urlCheck" : true, 73 | "es6" : false, 74 | "minified" : true 75 | } 76 | }, 77 | "h5" : { 78 | "title" : "ColorUi for UniApp", 79 | "domain" : "demo.color-ui.com" 80 | }, 81 | "mp-qq" : { 82 | "appid" : "1109649302", 83 | "setting" : { 84 | "urlCheck" : false, 85 | "es6" : true, 86 | "minified" : true 87 | } 88 | }, 89 | "quickapp-webview" : { 90 | "icon" : "C:/Users/maxoy/Downloads/学写汉字logo.png", 91 | "package" : "com.hanzi-writer.zzh", 92 | "versionName" : "1.0.0", 93 | "versionCode" : 1 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /直书小程序源代码/mixin.js: -------------------------------------------------------------------------------- 1 | const globalMixins = { 2 | onLoad() { 3 | const pageName = getCurrentPages().pop().route.split('/').pop(); 4 | uni.setNavigationBarTitle({ 5 | title: this.i18n.pageTitle[pageName] 6 | }); 7 | }, 8 | computed: { 9 | i18n() { 10 | return this.$t('default'); 11 | } 12 | }, 13 | methods: { 14 | navTo(url){ 15 | uni.navigateTo({ 16 | url 17 | }) 18 | } 19 | } 20 | } 21 | 22 | export { 23 | globalMixins 24 | } 25 | -------------------------------------------------------------------------------- /直书小程序源代码/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hanzi-writer-uni-app", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "hanzi-writer": { 8 | "version": "2.1.0", 9 | "resolved": "https://registry.npm.taobao.org/hanzi-writer/download/hanzi-writer-2.1.0.tgz", 10 | "integrity": "sha1-jl6CREZPRXjeeqVBORANJEM181g=" 11 | }, 12 | "prettier": { 13 | "version": "1.12.1", 14 | "resolved": "http://registry.npm.taobao.org/prettier/download/prettier-1.12.1.tgz", 15 | "integrity": "sha1-wa0g6APndJ+vkFpAnSNn4Gu+cyU=" 16 | }, 17 | "vue-i18n": { 18 | "version": "8.15.1", 19 | "resolved": "https://registry.npm.taobao.org/vue-i18n/download/vue-i18n-8.15.1.tgz?cache=0&sync_timestamp=1574846332347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-i18n%2Fdownload%2Fvue-i18n-8.15.1.tgz", 20 | "integrity": "sha1-kAl6CKHpMvZFxrnEBMeA0k9tYiQ=" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /直书小程序源代码/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hanzi-writer-uni-app", 3 | "version": "1.0.0", 4 | "description": "

\"ColorUI简介\"

", 5 | "main": "main.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "dependencies": { 10 | "copy-webpack-plugin": "5.1.1", 11 | "hanzi-writer": "2.3.0", 12 | "prettier": "^1.12.1", 13 | "vue-i18n": "^8.15.1" 14 | }, 15 | "devDependencies": {}, 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "author": "maxoyed ", 20 | "license": "ISC" 21 | } 22 | -------------------------------------------------------------------------------- /直书小程序源代码/pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [{ 3 | "path": "pages/index/index", 4 | "style": { 5 | "navigationBarTitleText": "学写汉字", 6 | "enablePullDownRefresh": false 7 | } 8 | 9 | }, { 10 | "path": "pages/index/ocr", 11 | "style": { 12 | "navigationBarTitleText": "拍照识字", 13 | "enablePullDownRefresh": false 14 | } 15 | }, { 16 | "path": "pages/index/translate", 17 | "style": { 18 | "navigationBarTitleText": "机器翻译", 19 | "enablePullDownRefresh": false 20 | } 21 | 22 | }, { 23 | "path": "pages/index/tts", 24 | "style": { 25 | "navigationBarTitleText": "文字转语音", 26 | "enablePullDownRefresh": false 27 | } 28 | 29 | }, { 30 | "path": "pages/index/asr", 31 | "style": { 32 | "navigationBarTitleText": "语音识别", 33 | "enablePullDownRefresh": false 34 | } 35 | 36 | }, { 37 | "path": "pages/index/example", 38 | "style": { 39 | "navigationBarTitleText": "示例文字", 40 | "enablePullDownRefresh": false 41 | } 42 | 43 | }, { 44 | "path": "pages/index/writer", 45 | "style": { 46 | "enablePullDownRefresh": false 47 | } 48 | 49 | }, { 50 | "path": "pages/about/about", 51 | "style": {} 52 | }], 53 | "globalStyle": { 54 | "mp-alipay": { 55 | /* 支付宝小程序特有相关 */ 56 | "transparentTitle": "always", 57 | "allowsBounceVertical": "NO" 58 | }, 59 | "navigationBarBackgroundColor": "#0081ff", 60 | "navigationBarTitleText": "学写汉字", 61 | "navigationBarTextStyle": "white" 62 | }, 63 | "usingComponts": true, 64 | "condition": { //模式配置,仅开发期间生效 65 | "current": 3, //当前激活的模式(list 的索引项) 66 | "list": [{ 67 | "name": "拍照识字", //模式名称 68 | "path": "pages/index/ocr", //启动页面 69 | "query": "" //启动参数 70 | }, { 71 | "name": "关于我们", //模式名称 72 | "path": "pages/about/about", //启动页面 73 | "query": "" //启动参数 74 | }, { 75 | "name": "学写汉字", //模式名称 76 | "path": "pages/index/index", //启动页面 77 | "query": "" //启动参数 78 | }] 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/about/about.vue: -------------------------------------------------------------------------------- 1 | 89 | 90 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/index/asr.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 129 | 130 | 133 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/index/example.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 59 | 60 | 65 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 117 | 118 | 121 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/index/ocr.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 184 | 185 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/index/translate.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 60 | 61 | 63 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/index/tts.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 73 | 74 | -------------------------------------------------------------------------------- /直书小程序源代码/pages/index/writer.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 98 | 99 | 104 | -------------------------------------------------------------------------------- /直书小程序源代码/static/characterBg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /直书小程序源代码/vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const CopyWebpackPlugin = require('copy-webpack-plugin') 3 | 4 | module.exports = { 5 | configureWebpack: { 6 | plugins: [ 7 | new CopyWebpackPlugin([{ 8 | from: path.join(__dirname, 'cloudfunctions'), 9 | to: path.join(__dirname, 'unpackage/dist', process.env.NODE_ENV === 'production' ? 10 | 'build' : 'dev', process.env.UNI_PLATFORM, 'cloudfunctions') 11 | },{ 12 | from: path.join(__dirname, 'cloudfunctionTemplate'), 13 | to: path.join(__dirname, 'unpackage/dist', process.env.NODE_ENV === 'production' ? 14 | 'build' : 'dev', process.env.UNI_PLATFORM, 'cloudfunctionTemplate') 15 | }]) 16 | ] 17 | }, 18 | chainWebpack: (config) => { 19 | // 发行或运行时启用了压缩时会生效 20 | config.optimization.minimizer('terser').tap((args) => { 21 | const compress = args[0].terserOptions.compress 22 | // 非 App 平台移除 console 代码(包含所有 console 方法,如 log,debug,info...) 23 | compress.drop_console = true 24 | compress.pure_funcs = [ 25 | '__f__', // App 平台 vue 移除日志代码 26 | // 'console.debug' // 可移除指定的 console 方法 27 | ] 28 | return args 29 | }) 30 | } 31 | } -------------------------------------------------------------------------------- /直书小程序源代码/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ajv-errors@^1.0.0: 6 | version "1.0.1" 7 | resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" 8 | integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== 9 | 10 | ajv-keywords@^3.1.0: 11 | version "3.5.2" 12 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" 13 | integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== 14 | 15 | ajv@^6.1.0: 16 | version "6.12.6" 17 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 18 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 19 | dependencies: 20 | fast-deep-equal "^3.1.1" 21 | fast-json-stable-stringify "^2.0.0" 22 | json-schema-traverse "^0.4.1" 23 | uri-js "^4.2.2" 24 | 25 | ansi-colors@^3.0.0: 26 | version "3.2.4" 27 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" 28 | integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== 29 | 30 | aproba@^1.1.1: 31 | version "1.2.0" 32 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 33 | integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== 34 | 35 | array-union@^1.0.1: 36 | version "1.0.2" 37 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 38 | integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= 39 | dependencies: 40 | array-uniq "^1.0.1" 41 | 42 | array-uniq@^1.0.1: 43 | version "1.0.3" 44 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 45 | integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= 46 | 47 | balanced-match@^1.0.0: 48 | version "1.0.2" 49 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 50 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 51 | 52 | big.js@^5.2.2: 53 | version "5.2.2" 54 | resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" 55 | integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== 56 | 57 | bluebird@^3.5.5: 58 | version "3.7.2" 59 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" 60 | integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== 61 | 62 | brace-expansion@^1.1.7: 63 | version "1.1.11" 64 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 65 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 66 | dependencies: 67 | balanced-match "^1.0.0" 68 | concat-map "0.0.1" 69 | 70 | buffer-from@^1.0.0: 71 | version "1.1.2" 72 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 73 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 74 | 75 | cacache@^12.0.3: 76 | version "12.0.4" 77 | resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" 78 | integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== 79 | dependencies: 80 | bluebird "^3.5.5" 81 | chownr "^1.1.1" 82 | figgy-pudding "^3.5.1" 83 | glob "^7.1.4" 84 | graceful-fs "^4.1.15" 85 | infer-owner "^1.0.3" 86 | lru-cache "^5.1.1" 87 | mississippi "^3.0.0" 88 | mkdirp "^0.5.1" 89 | move-concurrently "^1.0.1" 90 | promise-inflight "^1.0.1" 91 | rimraf "^2.6.3" 92 | ssri "^6.0.1" 93 | unique-filename "^1.1.1" 94 | y18n "^4.0.0" 95 | 96 | chownr@^1.1.1: 97 | version "1.1.4" 98 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" 99 | integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== 100 | 101 | commondir@^1.0.1: 102 | version "1.0.1" 103 | resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" 104 | integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= 105 | 106 | concat-map@0.0.1: 107 | version "0.0.1" 108 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 109 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 110 | 111 | concat-stream@^1.5.0: 112 | version "1.6.2" 113 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 114 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== 115 | dependencies: 116 | buffer-from "^1.0.0" 117 | inherits "^2.0.3" 118 | readable-stream "^2.2.2" 119 | typedarray "^0.0.6" 120 | 121 | copy-concurrently@^1.0.0: 122 | version "1.0.5" 123 | resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" 124 | integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== 125 | dependencies: 126 | aproba "^1.1.1" 127 | fs-write-stream-atomic "^1.0.8" 128 | iferr "^0.1.5" 129 | mkdirp "^0.5.1" 130 | rimraf "^2.5.4" 131 | run-queue "^1.0.0" 132 | 133 | copy-webpack-plugin@5.1.1: 134 | version "5.1.1" 135 | resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88" 136 | integrity sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg== 137 | dependencies: 138 | cacache "^12.0.3" 139 | find-cache-dir "^2.1.0" 140 | glob-parent "^3.1.0" 141 | globby "^7.1.1" 142 | is-glob "^4.0.1" 143 | loader-utils "^1.2.3" 144 | minimatch "^3.0.4" 145 | normalize-path "^3.0.0" 146 | p-limit "^2.2.1" 147 | schema-utils "^1.0.0" 148 | serialize-javascript "^2.1.2" 149 | webpack-log "^2.0.0" 150 | 151 | core-util-is@~1.0.0: 152 | version "1.0.3" 153 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 154 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 155 | 156 | cyclist@^1.0.1: 157 | version "1.0.1" 158 | resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" 159 | integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= 160 | 161 | dir-glob@^2.0.0: 162 | version "2.2.2" 163 | resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" 164 | integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== 165 | dependencies: 166 | path-type "^3.0.0" 167 | 168 | duplexify@^3.4.2, duplexify@^3.6.0: 169 | version "3.7.1" 170 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" 171 | integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== 172 | dependencies: 173 | end-of-stream "^1.0.0" 174 | inherits "^2.0.1" 175 | readable-stream "^2.0.0" 176 | stream-shift "^1.0.0" 177 | 178 | emojis-list@^3.0.0: 179 | version "3.0.0" 180 | resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" 181 | integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== 182 | 183 | end-of-stream@^1.0.0, end-of-stream@^1.1.0: 184 | version "1.4.4" 185 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 186 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 187 | dependencies: 188 | once "^1.4.0" 189 | 190 | fast-deep-equal@^3.1.1: 191 | version "3.1.3" 192 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 193 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 194 | 195 | fast-json-stable-stringify@^2.0.0: 196 | version "2.1.0" 197 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 198 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 199 | 200 | figgy-pudding@^3.5.1: 201 | version "3.5.2" 202 | resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" 203 | integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== 204 | 205 | find-cache-dir@^2.1.0: 206 | version "2.1.0" 207 | resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" 208 | integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== 209 | dependencies: 210 | commondir "^1.0.1" 211 | make-dir "^2.0.0" 212 | pkg-dir "^3.0.0" 213 | 214 | find-up@^3.0.0: 215 | version "3.0.0" 216 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 217 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 218 | dependencies: 219 | locate-path "^3.0.0" 220 | 221 | flush-write-stream@^1.0.0: 222 | version "1.1.1" 223 | resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" 224 | integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== 225 | dependencies: 226 | inherits "^2.0.3" 227 | readable-stream "^2.3.6" 228 | 229 | from2@^2.1.0: 230 | version "2.3.0" 231 | resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" 232 | integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= 233 | dependencies: 234 | inherits "^2.0.1" 235 | readable-stream "^2.0.0" 236 | 237 | fs-write-stream-atomic@^1.0.8: 238 | version "1.0.10" 239 | resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" 240 | integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= 241 | dependencies: 242 | graceful-fs "^4.1.2" 243 | iferr "^0.1.5" 244 | imurmurhash "^0.1.4" 245 | readable-stream "1 || 2" 246 | 247 | fs.realpath@^1.0.0: 248 | version "1.0.0" 249 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 250 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 251 | 252 | glob-parent@^3.1.0: 253 | version "3.1.0" 254 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" 255 | integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= 256 | dependencies: 257 | is-glob "^3.1.0" 258 | path-dirname "^1.0.0" 259 | 260 | glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: 261 | version "7.2.0" 262 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" 263 | integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== 264 | dependencies: 265 | fs.realpath "^1.0.0" 266 | inflight "^1.0.4" 267 | inherits "2" 268 | minimatch "^3.0.4" 269 | once "^1.3.0" 270 | path-is-absolute "^1.0.0" 271 | 272 | globby@^7.1.1: 273 | version "7.1.1" 274 | resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" 275 | integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= 276 | dependencies: 277 | array-union "^1.0.1" 278 | dir-glob "^2.0.0" 279 | glob "^7.1.2" 280 | ignore "^3.3.5" 281 | pify "^3.0.0" 282 | slash "^1.0.0" 283 | 284 | graceful-fs@^4.1.15, graceful-fs@^4.1.2: 285 | version "4.2.10" 286 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" 287 | integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== 288 | 289 | hanzi-writer@2.3.0: 290 | version "2.3.0" 291 | resolved "https://registry.yarnpkg.com/hanzi-writer/-/hanzi-writer-2.3.0.tgz#06586eb37486226c51057674e2fed7da3362555c" 292 | integrity sha512-2tKjsUrTW1lBxwpSVhGZ+lTlAycZPeJuov0og9Qbw0ETAS6y7+KxxjHhAtPDNAuLKS3FJeh80s9jxLA/e8jF0w== 293 | 294 | iferr@^0.1.5: 295 | version "0.1.5" 296 | resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" 297 | integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= 298 | 299 | ignore@^3.3.5: 300 | version "3.3.10" 301 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" 302 | integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== 303 | 304 | imurmurhash@^0.1.4: 305 | version "0.1.4" 306 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 307 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 308 | 309 | infer-owner@^1.0.3: 310 | version "1.0.4" 311 | resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" 312 | integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== 313 | 314 | inflight@^1.0.4: 315 | version "1.0.6" 316 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 317 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 318 | dependencies: 319 | once "^1.3.0" 320 | wrappy "1" 321 | 322 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: 323 | version "2.0.4" 324 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 325 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 326 | 327 | is-extglob@^2.1.0, is-extglob@^2.1.1: 328 | version "2.1.1" 329 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 330 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 331 | 332 | is-glob@^3.1.0: 333 | version "3.1.0" 334 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" 335 | integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= 336 | dependencies: 337 | is-extglob "^2.1.0" 338 | 339 | is-glob@^4.0.1: 340 | version "4.0.3" 341 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 342 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 343 | dependencies: 344 | is-extglob "^2.1.1" 345 | 346 | isarray@~1.0.0: 347 | version "1.0.0" 348 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 349 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 350 | 351 | json-schema-traverse@^0.4.1: 352 | version "0.4.1" 353 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 354 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 355 | 356 | json5@^1.0.1: 357 | version "1.0.1" 358 | resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" 359 | integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== 360 | dependencies: 361 | minimist "^1.2.0" 362 | 363 | loader-utils@^1.2.3: 364 | version "1.4.0" 365 | resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" 366 | integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== 367 | dependencies: 368 | big.js "^5.2.2" 369 | emojis-list "^3.0.0" 370 | json5 "^1.0.1" 371 | 372 | locate-path@^3.0.0: 373 | version "3.0.0" 374 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 375 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 376 | dependencies: 377 | p-locate "^3.0.0" 378 | path-exists "^3.0.0" 379 | 380 | lru-cache@^5.1.1: 381 | version "5.1.1" 382 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" 383 | integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== 384 | dependencies: 385 | yallist "^3.0.2" 386 | 387 | make-dir@^2.0.0: 388 | version "2.1.0" 389 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" 390 | integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== 391 | dependencies: 392 | pify "^4.0.1" 393 | semver "^5.6.0" 394 | 395 | minimatch@^3.0.4: 396 | version "3.1.2" 397 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 398 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 399 | dependencies: 400 | brace-expansion "^1.1.7" 401 | 402 | minimist@^1.2.0, minimist@^1.2.6: 403 | version "1.2.6" 404 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" 405 | integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== 406 | 407 | mississippi@^3.0.0: 408 | version "3.0.0" 409 | resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" 410 | integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== 411 | dependencies: 412 | concat-stream "^1.5.0" 413 | duplexify "^3.4.2" 414 | end-of-stream "^1.1.0" 415 | flush-write-stream "^1.0.0" 416 | from2 "^2.1.0" 417 | parallel-transform "^1.1.0" 418 | pump "^3.0.0" 419 | pumpify "^1.3.3" 420 | stream-each "^1.1.0" 421 | through2 "^2.0.0" 422 | 423 | mkdirp@^0.5.1: 424 | version "0.5.6" 425 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" 426 | integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== 427 | dependencies: 428 | minimist "^1.2.6" 429 | 430 | move-concurrently@^1.0.1: 431 | version "1.0.1" 432 | resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" 433 | integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= 434 | dependencies: 435 | aproba "^1.1.1" 436 | copy-concurrently "^1.0.0" 437 | fs-write-stream-atomic "^1.0.8" 438 | mkdirp "^0.5.1" 439 | rimraf "^2.5.4" 440 | run-queue "^1.0.3" 441 | 442 | normalize-path@^3.0.0: 443 | version "3.0.0" 444 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 445 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 446 | 447 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 448 | version "1.4.0" 449 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 450 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 451 | dependencies: 452 | wrappy "1" 453 | 454 | p-limit@^2.0.0, p-limit@^2.2.1: 455 | version "2.3.0" 456 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 457 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 458 | dependencies: 459 | p-try "^2.0.0" 460 | 461 | p-locate@^3.0.0: 462 | version "3.0.0" 463 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 464 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 465 | dependencies: 466 | p-limit "^2.0.0" 467 | 468 | p-try@^2.0.0: 469 | version "2.2.0" 470 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 471 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 472 | 473 | parallel-transform@^1.1.0: 474 | version "1.2.0" 475 | resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" 476 | integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== 477 | dependencies: 478 | cyclist "^1.0.1" 479 | inherits "^2.0.3" 480 | readable-stream "^2.1.5" 481 | 482 | path-dirname@^1.0.0: 483 | version "1.0.2" 484 | resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" 485 | integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= 486 | 487 | path-exists@^3.0.0: 488 | version "3.0.0" 489 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 490 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 491 | 492 | path-is-absolute@^1.0.0: 493 | version "1.0.1" 494 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 495 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 496 | 497 | path-type@^3.0.0: 498 | version "3.0.0" 499 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" 500 | integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== 501 | dependencies: 502 | pify "^3.0.0" 503 | 504 | pify@^3.0.0: 505 | version "3.0.0" 506 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" 507 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= 508 | 509 | pify@^4.0.1: 510 | version "4.0.1" 511 | resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" 512 | integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== 513 | 514 | pkg-dir@^3.0.0: 515 | version "3.0.0" 516 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" 517 | integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== 518 | dependencies: 519 | find-up "^3.0.0" 520 | 521 | prettier@^1.12.1: 522 | version "1.19.1" 523 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" 524 | integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== 525 | 526 | process-nextick-args@~2.0.0: 527 | version "2.0.1" 528 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 529 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 530 | 531 | promise-inflight@^1.0.1: 532 | version "1.0.1" 533 | resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" 534 | integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= 535 | 536 | pump@^2.0.0: 537 | version "2.0.1" 538 | resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" 539 | integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== 540 | dependencies: 541 | end-of-stream "^1.1.0" 542 | once "^1.3.1" 543 | 544 | pump@^3.0.0: 545 | version "3.0.0" 546 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 547 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 548 | dependencies: 549 | end-of-stream "^1.1.0" 550 | once "^1.3.1" 551 | 552 | pumpify@^1.3.3: 553 | version "1.5.1" 554 | resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" 555 | integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== 556 | dependencies: 557 | duplexify "^3.6.0" 558 | inherits "^2.0.3" 559 | pump "^2.0.0" 560 | 561 | punycode@^2.1.0: 562 | version "2.1.1" 563 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 564 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 565 | 566 | "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@~2.3.6: 567 | version "2.3.7" 568 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 569 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 570 | dependencies: 571 | core-util-is "~1.0.0" 572 | inherits "~2.0.3" 573 | isarray "~1.0.0" 574 | process-nextick-args "~2.0.0" 575 | safe-buffer "~5.1.1" 576 | string_decoder "~1.1.1" 577 | util-deprecate "~1.0.1" 578 | 579 | rimraf@^2.5.4, rimraf@^2.6.3: 580 | version "2.7.1" 581 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 582 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== 583 | dependencies: 584 | glob "^7.1.3" 585 | 586 | run-queue@^1.0.0, run-queue@^1.0.3: 587 | version "1.0.3" 588 | resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" 589 | integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= 590 | dependencies: 591 | aproba "^1.1.1" 592 | 593 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 594 | version "5.1.2" 595 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 596 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 597 | 598 | schema-utils@^1.0.0: 599 | version "1.0.0" 600 | resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" 601 | integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== 602 | dependencies: 603 | ajv "^6.1.0" 604 | ajv-errors "^1.0.0" 605 | ajv-keywords "^3.1.0" 606 | 607 | semver@^5.6.0: 608 | version "5.7.1" 609 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 610 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 611 | 612 | serialize-javascript@^2.1.2: 613 | version "2.1.2" 614 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" 615 | integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== 616 | 617 | slash@^1.0.0: 618 | version "1.0.0" 619 | resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" 620 | integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= 621 | 622 | ssri@^6.0.1: 623 | version "6.0.2" 624 | resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" 625 | integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== 626 | dependencies: 627 | figgy-pudding "^3.5.1" 628 | 629 | stream-each@^1.1.0: 630 | version "1.2.3" 631 | resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" 632 | integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== 633 | dependencies: 634 | end-of-stream "^1.1.0" 635 | stream-shift "^1.0.0" 636 | 637 | stream-shift@^1.0.0: 638 | version "1.0.1" 639 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" 640 | integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== 641 | 642 | string_decoder@~1.1.1: 643 | version "1.1.1" 644 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 645 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 646 | dependencies: 647 | safe-buffer "~5.1.0" 648 | 649 | through2@^2.0.0: 650 | version "2.0.5" 651 | resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" 652 | integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== 653 | dependencies: 654 | readable-stream "~2.3.6" 655 | xtend "~4.0.1" 656 | 657 | typedarray@^0.0.6: 658 | version "0.0.6" 659 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 660 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= 661 | 662 | unique-filename@^1.1.1: 663 | version "1.1.1" 664 | resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" 665 | integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== 666 | dependencies: 667 | unique-slug "^2.0.0" 668 | 669 | unique-slug@^2.0.0: 670 | version "2.0.2" 671 | resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" 672 | integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== 673 | dependencies: 674 | imurmurhash "^0.1.4" 675 | 676 | uri-js@^4.2.2: 677 | version "4.4.1" 678 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 679 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 680 | dependencies: 681 | punycode "^2.1.0" 682 | 683 | util-deprecate@~1.0.1: 684 | version "1.0.2" 685 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 686 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 687 | 688 | uuid@^3.3.2: 689 | version "3.4.0" 690 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" 691 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== 692 | 693 | vue-i18n@^8.15.1: 694 | version "8.27.1" 695 | resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.27.1.tgz#fe660f6c14793ae404d6a715875d772594a3324f" 696 | integrity sha512-lWrGm4F25qReJ7XxSnFVb2h3PfW54ldnM4C+YLBGGJ75+Myt/kj4hHSTKqsyDLamvNYpvINMicSOdW+7yuqgIQ== 697 | 698 | webpack-log@^2.0.0: 699 | version "2.0.0" 700 | resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" 701 | integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== 702 | dependencies: 703 | ansi-colors "^3.0.0" 704 | uuid "^3.3.2" 705 | 706 | wrappy@1: 707 | version "1.0.2" 708 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 709 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 710 | 711 | xtend@~4.0.1: 712 | version "4.0.2" 713 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 714 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 715 | 716 | y18n@^4.0.0: 717 | version "4.0.3" 718 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" 719 | integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== 720 | 721 | yallist@^3.0.2: 722 | version "3.1.1" 723 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 724 | integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== 725 | -------------------------------------------------------------------------------- /秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182410.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182410.jpg -------------------------------------------------------------------------------- /秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182435.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182435.jpg -------------------------------------------------------------------------------- /秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182439.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182439.jpg -------------------------------------------------------------------------------- /秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182642.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/秉笔直书——汉字笔画学习小程序.assets/微信图片_20191216182642.jpg -------------------------------------------------------------------------------- /秉笔直书——汉字笔画学习小程序.assets/微信小程序二维码.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/秉笔直书——汉字笔画学习小程序.assets/微信小程序二维码.jpg -------------------------------------------------------------------------------- /秉笔直书——汉字笔画学习小程序.assets/微信截图_20191216182729.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/秉笔直书——汉字笔画学习小程序.assets/微信截图_20191216182729.png -------------------------------------------------------------------------------- /秉笔直书——汉字笔画学习小程序.assets/汉字笔画.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TommyZihao/EasyHanzi/97a6225c36e8652cec34061d4c4b6bb1f5c01bdd/秉笔直书——汉字笔画学习小程序.assets/汉字笔画.jpg --------------------------------------------------------------------------------