├── .babelrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── browser ├── moha.js └── moha.min.js ├── es5 ├── browser.js ├── index.js ├── modules │ └── pangu.js ├── stores │ └── exps-dict.js ├── things │ ├── big-news.js │ ├── elder.js │ └── life-exp.js └── utils │ ├── extend.js │ └── upper-case-first.js ├── gulpfile.babel.js ├── package.json ├── src └── scripts │ ├── browser.js │ ├── index.js │ ├── modules │ └── pangu.js │ ├── stores │ └── exps-dict.js │ ├── things │ ├── big-news.js │ ├── elder.js │ └── life-exp.js │ └── utils │ ├── extend.js │ └── upper-case-first.js └── test └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": [ 4 | "add-module-exports" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules 3 | 4 | gh-pages 5 | .publish 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /test 2 | /src/gh-pages 3 | 4 | .babelrc 5 | 6 | gulpfile.babel.js 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 IFELog 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## MoHa: First mo and then hahhhhhhhhhh [WIP] 2 | 3 | 4 | 5 | > `风声雨声读书声,谈笑风生` 6 | > `The sound of Wind, Rain and Reading, just talk and laugh` 7 | > `家事国事天下事,三件小事` 8 | > `The affairs of Family, Country and World, just 3 little things` 9 | 10 | ## Installtion 11 | ``` 12 | npm i moha --save 13 | ``` 14 | 15 | ## Features & Usage 16 | 17 | ### 1. Improving Life Experiences (Converter) 18 | ``` javascript 19 | import {lifeExp} from 'moha' 20 | 21 | let talks = '我是最好的。Great!' 22 | let exps = lifeExp(talks) 23 | 24 | console.log(exps) // Echo: 我是坠吼滴。Excited! 25 | ``` 26 | > Here is the [Exps Dict](https://github.com/IFELog/MoHa/blob/master/src/scripts/stores/exps-dict.js) which would make you say `Wow, MoHa is excited!`. 27 | 28 | ### 2. Making Big News with HK Journalists (Page Translator) 29 | ``` javascript 30 | import {bigNews} from 'moha' 31 | 32 | bigNews() // Current page will be halangify 33 | ``` 34 | ### 3. Talking with the Elder (Generator) 35 | - Todo: Imitate the elder and create an elder (Generator). 36 | 37 | ## How to Contribute? 38 | **The first and the most important thing** is to create a puppet account on GitHub to keep yourself safe in the real world. When someone knocks on your door and says "Open the door, check the water meter!", please don't trust the guy and directly reply "Water meter is outside the door!". 39 | 40 | ## Dependencies 41 | - [pangu.js](https://github.com/vinta/pangu.js) - 為什麼你們就是不能加個空格呢? 42 | 43 | ## References 44 | - [蛤蛤体生成器](http://dkwingsmt.github.io/haha/) 45 | - [把长者语言写进电脑](https://github.com/xiaq/halang/issues/1) 46 | - [恶俗古风自动生成器](http://www.jianshu.com/p/f893291674ca) 47 | 48 | ## License 49 | This work is licensed under the MIT license. 50 | -------------------------------------------------------------------------------- /browser/moha.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> 跟 Go 版差了一個 ' 68 | // quote_cjk >> 跟 Go 版差了一個 ' 69 | // fix_quote 70 | // fix_single_quote 71 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])(["])/g, '$1 $2'); 72 | newText = newText.replace(/(["])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2'); 73 | newText = newText.replace(/(["'\(\[\{<\u201c]+)(\s*)(.+?)(\s*)(["'\)\]\}>\u201d]+)/g, '$1$3$5'); 74 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])( )(')([A-Za-z])/g, '$1$3$4'); 75 | 76 | // cjk_hash 77 | // hash_cjk 78 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])(#(\S+))/g, '$1 $2'); 79 | newText = newText.replace(/((\S+)#)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $3'); 80 | 81 | // cjk_operator_ans 82 | // ans_operator_cjk 83 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\+\-\*\/=&\\|<>])([A-Za-z0-9])/g, '$1 $2 $3'); 84 | newText = newText.replace(/([A-Za-z0-9])([\+\-\*\/=&\\|<>])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2 $3'); 85 | 86 | // cjk_bracket_cjk 87 | // cjk_bracket 88 | // bracket_cjk 89 | // fix_bracket 90 | var oldText = newText; 91 | var tmpText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c]+(.*?)[\)\]\}>\u201d]+)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2 $4'); 92 | newText = tmpText; 93 | if (oldText === tmpText) { 94 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c>])/g, '$1 $2'); 95 | newText = newText.replace(/([\)\]\}>\u201d<])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2'); 96 | } 97 | newText = newText.replace(/([\(\[\{<\u201c]+)(\s*)(.+?)(\s*)([\)\]\}>\u201d]+)/g, '$1$3$5'); 98 | 99 | // fix_symbol 100 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([~!:,\.\?\u2026])([A-Za-z0-9])/g, '$1$2 $3'); 101 | 102 | // cjk_ans 103 | // ans_cjk 104 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([A-Za-z0-9`\$%\^&\*\-=\+\\\|/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])/g, '$1 $2'); 105 | newText = newText.replace(/([A-Za-z0-9`~\$%\^&\*\-=\+\\\|/!;:,\.\?\u00a1-\u00ff\u2022\u2026\u2027\u2150-\u218f])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2'); 106 | 107 | return newText; 108 | }; 109 | 110 | module.exports = exports['default']; 111 | 112 | },{}],4:[function(require,module,exports){ 113 | 'use strict'; 114 | 115 | Object.defineProperty(exports, "__esModule", { 116 | value: true 117 | }); 118 | var expsDict = { 119 | // Chinese => Chinese 120 | '最': '坠', 121 | '好的': '吼滴', 122 | '好啊': '吼哇', 123 | '着急': '拙计', 124 | '粉丝': '膜法师', 125 | '支持|赞同': '兹瓷', 126 | '批评|指责|责备': '批判', 127 | '招惹|冒犯|挑衅': '得罪', 128 | '差错|错误|过失': '偏差', 129 | '赚钱|获利': '闷声发大财', 130 | '印点|内定[^钦点]': '钦点', 131 | '经验(丰富|多)': '身经百战', 132 | '(过来|老)(司机|人)': '长者', 133 | '人生(哲学|哲理)': '人生经验', 134 | '(绝对|肯定)(啦|呀)': '当然啦', 135 | '知不知道|晓不晓得': '识得唔识得', 136 | '谈话|闲聊|聊天|交流': '谈笑风生', 137 | '(见识|阅历)(丰富|多|广)': '见得多了', 138 | '不予置评|拒绝(回答|评论)': '无可奉告', 139 | '(坠|很|相当|非常)快': '比香港记者还快', 140 | '(按|讲)(原则|准则|规则|道理)': '讲基本法', 141 | '胡说|乱说|信口胡言|瞎扯|瞎说|胡扯': '一派胡言', 142 | '制造舆论|哗众取宠|一本道|故弄玄虚|夸大其词': '搞个大新闻', 143 | '(到|去|游览)过(许|很)多(地方|城市|国家)': '哪一个国家我没有去过', 144 | '233(3*)': function _(find, $1) { 145 | var multiH = $1.replace(/3/g, 'h'); 146 | return 'hhh' + multiH; 147 | }, 148 | '(呵|哈|嘻*)': function _(find, $1) { 149 | var multiH = $1.replace(/./g, '蛤'); 150 | return '' + multiH; 151 | }, 152 | 153 | // Chinese => English 154 | '我很生气': 'I\'m angry', 155 | '天真(的^|了?)': ' naive', 156 | '(太|很|非常?)年轻(的^|了?)': 'too young', 157 | '(太|很|非常?)简单(的^|了?)': 'too simple', 158 | '有(些|的?)时(候?)': 'sometimes', 159 | 160 | // English => English 161 | "great": 'excited' 162 | }; 163 | 164 | exports.default = expsDict; 165 | module.exports = exports['default']; 166 | 167 | },{}],5:[function(require,module,exports){ 168 | 'use strict'; 169 | 170 | Object.defineProperty(exports, "__esModule", { 171 | value: true 172 | }); 173 | 174 | var _lifeExp = require('./life-exp'); 175 | 176 | var _lifeExp2 = _interopRequireDefault(_lifeExp); 177 | 178 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 179 | 180 | // Working only in browsers :( 181 | var bigNews = function bigNews() { 182 | var $root = arguments.length <= 0 || arguments[0] === undefined ? document.querySelector('body') : arguments[0]; 183 | var isIncludeTitle = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1]; 184 | 185 | 186 | // Replace title 187 | if (isIncludeTitle) { 188 | document.title = (0, _lifeExp2.default)(document.title); 189 | } 190 | 191 | // Replace body or other DOM 192 | if ($root !== null) { 193 | DOMTraversal($root, function (node) { 194 | if (node.nodeType === 1) { 195 | // Element 196 | tranAttr(node, ['title', 'alt', 'placeholder']); 197 | } else if (node.nodeType === 3) { 198 | // Text 199 | // FIXME: Disable converting code to halang 200 | node.data = (0, _lifeExp2.default)(node.data, { isTrim: false }); 201 | } 202 | }); 203 | } 204 | 205 | return $root; 206 | }; 207 | 208 | /* ==== Private Functions ==== */ 209 | var DOMTraversal = function DOMTraversal(node, callback) { 210 | callback(node); 211 | node = node.firstChild; 212 | while (node) { 213 | DOMTraversal(node, callback); 214 | node = node.nextSibling; 215 | } 216 | }; 217 | 218 | var tranAttr = function tranAttr(node, attr) { 219 | if (Array.isArray(attr)) { 220 | for (var i = 0; i < attr.length; i++) { 221 | tranAttr(node, attr[i]); 222 | } 223 | } else { 224 | var attrValue = node.getAttribute(attr); 225 | if (attrValue !== "" && attrValue !== null) { 226 | node.setAttribute(attr, (0, _lifeExp2.default)(attrValue, { isTrim: false })); 227 | } 228 | } 229 | }; 230 | 231 | exports.default = bigNews; 232 | module.exports = exports['default']; 233 | 234 | },{"./life-exp":7}],6:[function(require,module,exports){ 235 | "use strict"; 236 | 237 | Object.defineProperty(exports, "__esModule", { 238 | value: true 239 | }); 240 | var elder = function elder() {}; 241 | 242 | exports.default = elder; 243 | module.exports = exports['default']; 244 | 245 | },{}],7:[function(require,module,exports){ 246 | 'use strict'; 247 | 248 | Object.defineProperty(exports, "__esModule", { 249 | value: true 250 | }); 251 | 252 | var _pangu = require('../modules/pangu'); 253 | 254 | var _pangu2 = _interopRequireDefault(_pangu); 255 | 256 | var _extend = require('../utils/extend'); 257 | 258 | var _extend2 = _interopRequireDefault(_extend); 259 | 260 | var _upperCaseFirst = require('../utils/upper-case-first'); 261 | 262 | var _upperCaseFirst2 = _interopRequireDefault(_upperCaseFirst); 263 | 264 | var _expsDict = require('../stores/exps-dict'); 265 | 266 | var _expsDict2 = _interopRequireDefault(_expsDict); 267 | 268 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 269 | 270 | var lifeExp = function lifeExp(talks) { 271 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 272 | 273 | // Init exps 274 | var exps = talks; 275 | 276 | // Init options 277 | var defaultOptions = { 278 | isTrim: true, 279 | isWearGlasses: false 280 | }; 281 | options = (0, _extend2.default)({}, defaultOptions, options); 282 | 283 | /* ==== Teaching ==== */ 284 | 285 | // Replace text according to expsDict 286 | for (var pattern in _expsDict2.default) { 287 | exps = exps.replace(new RegExp(pattern, 'ig'), _expsDict2.default[pattern]); 288 | } 289 | 290 | // TODO: Wear glasses 291 | if (options.isWearGlasses) {} 292 | 293 | // Add space between Chinese and English characters 294 | exps = (0, _pangu2.default)(exps); 295 | 296 | // Remove leading and trailing excess spaces 297 | if (options.isTrim) { 298 | exps.trim(); 299 | } 300 | 301 | // Upper case the first character of each sentence 302 | var endPunctuation = ['。', '!', '?', // Fullwidth 303 | '. ', '! ', '? ' // Halfwidth 304 | ]; 305 | endPunctuation.forEach(function (mark) { 306 | exps = exps.split(mark).map(_upperCaseFirst2.default).join(mark); 307 | }); 308 | 309 | return exps; 310 | }; 311 | 312 | exports.default = lifeExp; 313 | module.exports = exports['default']; 314 | 315 | },{"../modules/pangu":3,"../stores/exps-dict":4,"../utils/extend":8,"../utils/upper-case-first":9}],8:[function(require,module,exports){ 316 | "use strict"; 317 | 318 | Object.defineProperty(exports, "__esModule", { 319 | value: true 320 | }); 321 | var _arguments = arguments; 322 | var extend = function extend(dest) { 323 | var objs = [].slice.call(_arguments, 1); 324 | 325 | for (var i = 0, len = objs.length; i < len; i++) { 326 | var obj = objs[i]; 327 | for (var prop in obj) { 328 | dest[prop] = obj[prop]; 329 | } 330 | } 331 | 332 | return dest; 333 | }; 334 | 335 | exports.default = extend; 336 | module.exports = exports['default']; 337 | 338 | },{}],9:[function(require,module,exports){ 339 | 'use strict'; 340 | 341 | Object.defineProperty(exports, "__esModule", { 342 | value: true 343 | }); 344 | 345 | exports.default = function (str) { 346 | if (str == null) { 347 | return ''; 348 | } 349 | return str.charAt(0).toUpperCase() + str.substr(1); 350 | }; 351 | 352 | module.exports = exports['default']; 353 | 354 | },{}]},{},[1]) 355 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvc2NyaXB0cy9icm93c2VyLmpzIiwic3JjL3NjcmlwdHMvaW5kZXguanMiLCJzcmMvc2NyaXB0cy9tb2R1bGVzL3Bhbmd1LmpzIiwic3JjL3NjcmlwdHMvc3RvcmVzL2V4cHMtZGljdC5qcyIsInNyYy9zY3JpcHRzL3RoaW5ncy9iaWctbmV3cy5qcyIsInNyYy9zY3JpcHRzL3RoaW5ncy9lbGRlci5qcyIsInNyYy9zY3JpcHRzL3RoaW5ncy9saWZlLWV4cC5qcyIsInNyYy9zY3JpcHRzL3V0aWxzL2V4dGVuZC5qcyIsInNyYy9zY3JpcHRzL3V0aWxzL3VwcGVyLWNhc2UtZmlyc3QuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7QUNBQTs7Ozs7O0FBRUEsT0FBTyxJQUFQOzs7Ozs7Ozs7OztBQ0ZBOzs7O0FBQ0E7Ozs7QUFDQTs7Ozs7O2tCQUVlO0FBQ2IsNEJBRGE7QUFFYiw0QkFGYTtBQUdiLHdCQUhhOzs7Ozs7Ozs7OztrQkNKQSxVQUFDLElBQUQsRUFBVTtBQUN2QixNQUFJLFVBQVUsSUFBVjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFEbUIsU0FzQnZCLEdBQVUsUUFBUSxPQUFSLENBQWdCLGlJQUFoQixFQUFtSixPQUFuSixDQUFWLENBdEJ1QjtBQXVCdkIsWUFBVSxRQUFRLE9BQVIsQ0FBZ0IsaUlBQWhCLEVBQW1KLE9BQW5KLENBQVYsQ0F2QnVCO0FBd0J2QixZQUFVLFFBQVEsT0FBUixDQUFnQiwwREFBaEIsRUFBNEUsUUFBNUUsQ0FBVixDQXhCdUI7QUF5QnZCLFlBQVUsUUFBUSxPQUFSLENBQWdCLDRJQUFoQixFQUE4SixRQUE5SixDQUFWOzs7O0FBekJ1QixTQTZCdkIsR0FBVSxRQUFRLE9BQVIsQ0FBZ0Isb0lBQWhCLEVBQXNKLE9BQXRKLENBQVYsQ0E3QnVCO0FBOEJ2QixZQUFVLFFBQVEsT0FBUixDQUFnQixvSUFBaEIsRUFBc0osT0FBdEosQ0FB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QVMsR0FBNUMsRUFBaUQ7QUFDL0MsUUFBSSxNQUFNLEtBQUssQ0FBTCxDQUFOLENBRDJDO0FBRS9DLFNBQUssSUFBSSxJQUFKLElBQVksR0FBakIsRUFBc0I7QUFDcEIsV0FBSyxJQUFMLElBQWEsSUFBSSxJQUFKLENBQWIsQ0FEb0I7S0FBdEI7R0FGRjs7QUFPQSxTQUFPLElBQVAsQ0FWcUI7Q0FBVjs7a0JBYUU7Ozs7Ozs7Ozs7a0JDYkEsVUFBQyxHQUFELEVBQVM7QUFDdEIsTUFBSSxPQUFPLElBQVAsRUFBYTtBQUNmLFdBQU8sRUFBUCxDQURlO0dBQWpCO0FBR0EsU0FBTyxJQUFJLE1BQUosQ0FBVyxDQUFYLEVBQWMsV0FBZCxLQUE4QixJQUFJLE1BQUosQ0FBVyxDQUFYLENBQTlCLENBSmU7Q0FBVCIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJpbXBvcnQgbW9oYSBmcm9tICcuL2luZGV4J1xuXG5nbG9iYWwubW9oYSA9IG1vaGFcbiIsImltcG9ydCBsaWZlRXhwIGZyb20gJy4vdGhpbmdzL2xpZmUtZXhwJ1xuaW1wb3J0IGJpZ05ld3MgZnJvbSAnLi90aGluZ3MvYmlnLW5ld3MnXG5pbXBvcnQgZWxkZXIgZnJvbSAnLi90aGluZ3MvZWxkZXInXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbGlmZUV4cCxcbiAgYmlnTmV3cyxcbiAgZWxkZXJcbn1cbiIsImV4cG9ydCBkZWZhdWx0ICh0ZXh0KSA9PiB7XG4gIGxldCBuZXdUZXh0ID0gdGV4dFxuXG4gIC8qXG4gIFxcdTJlODAtXFx1MmVmZiBDSksgUmFkaWNhbHMgU3VwcGxlbWVudFxuICBcXHUyZjAwLVxcdTJmZGYgS2FuZ3hpIFJhZGljYWxzXG4gIFxcdTMwNDAtXFx1MzA5ZiBIaXJhZ2FuYVxuICBcXHUzMGEwLVxcdTMwZmYgS2F0YWthbmFcbiAgXFx1MzEwMC1cXHUzMTJmIEJvcG9tb2ZvXG4gIFxcdTMyMDAtXFx1MzJmZiBFbmNsb3NlZCBDSksgTGV0dGVycyBhbmQgTW9udGhzXG4gIFxcdTM0MDAtXFx1NGRiZiBDSksgVW5pZmllZCBJZGVvZ3JhcGhzIEV4dGVuc2lvbiBBXG4gIFxcdTRlMDAtXFx1OWZmZiBDSksgVW5pZmllZCBJZGVvZ3JhcGhzXG4gIFxcdWY5MDAtXFx1ZmFmZiBDSksgQ29tcGF0aWJpbGl0eSBJZGVvZ3JhcGhzXG5cbiAgaHR0cDovL3VuaWNvZGUtdGFibGUuY29tL2VuL1xuICBodHRwczovL2dpdGh1Yi5jb20vdmludGEvcGFuZ3VcbiAgKi9cblxuICAvLyBjamtfcXVvdGUgPj4g6LefIEdvIOeJiOW3ruS6huS4gOWAiyAnXG4gIC8vIHF1b3RlX2NqayA+PiDot58gR28g54mI5beu5LqG5LiA5YCLICdcbiAgLy8gZml4X3F1b3RlXG4gIC8vIGZpeF9zaW5nbGVfcXVvdGVcbiAgbmV3VGV4dCA9IG5ld1RleHQucmVwbGFjZSgvKFtcXHUyZTgwLVxcdTJlZmZcXHUyZjAwLVxcdTJmZGZcXHUzMDQwLVxcdTMwOWZcXHUzMGEwLVxcdTMwZmZcXHUzMTAwLVxcdTMxMmZcXHUzMjAwLVxcdTMyZmZcXHUzNDAwLVxcdTRkYmZcXHU0ZTAwLVxcdTlmZmZcXHVmOTAwLVxcdWZhZmZdKShbXCJdKS9nLCAnJDEgJDInKVxuICBuZXdUZXh0ID0gbmV3VGV4dC5yZXBsYWNlKC8oW1wiXSkoW1xcdTJlODAtXFx1MmVmZlxcdTJmMDAtXFx1MmZkZlxcdTMwNDAtXFx1MzA5ZlxcdTMwYTAtXFx1MzBmZlxcdTMxMDAtXFx1MzEyZlxcdTMyMDAtXFx1MzJmZlxcdTM0MDAtXFx1NGRiZlxcdTRlMDAtXFx1OWZmZlxcdWY5MDAtXFx1ZmFmZl0pL2csICckMSAkMicpXG4gIG5ld1RleHQgPSBuZXdUZXh0LnJlcGxhY2UoLyhbXCInXFwoXFxbXFx7PFxcdTIwMWNdKykoXFxzKikoLis/KShcXHMqKShbXCInXFwpXFxdXFx9PlxcdTIwMWRdKykvZywgJyQxJDMkNScpXG4gIG5ld1RleHQgPSBuZXdUZXh0LnJlcGxhY2UoLyhbXFx1MmU4MC1cXHUyZWZmXFx1MmYwMC1cXHUyZmRmXFx1MzA0MC1cXHUzMDlmXFx1MzBhMC1cXHUzMGZmXFx1MzEwMC1cXHUzMTJmXFx1MzIwMC1cXHUzMmZmXFx1MzQwMC1cXHU0ZGJmXFx1NGUwMC1cXHU5ZmZmXFx1ZjkwMC1cXHVmYWZmXSkoICkoJykoW0EtWmEtel0pL2csICckMSQzJDQnKVxuXG4gIC8vIGNqa19oYXNoXG4gIC8vIGhhc2hfY2prXG4gIG5ld1RleHQgPSBuZXdUZXh0LnJlcGxhY2UoLyhbXFx1MmU4MC1cXHUyZWZmXFx1MmYwMC1cXHUyZmRmXFx1MzA0MC1cXHUzMDlmXFx1MzBhMC1cXHUzMGZmXFx1MzEwMC1cXHUzMTJmXFx1MzIwMC1cXHUzMmZmXFx1MzQwMC1cXHU0ZGJmXFx1NGUwMC1cXHU5ZmZmXFx1ZjkwMC1cXHVmYWZmXSkoIyhcXFMrKSkvZywgJyQxICQyJylcbiAgbmV3VGV4dCA9IG5ld1RleHQucmVwbGFjZSgvKChcXFMrKSMpKFtcXHUyZTgwLVxcdTJlZmZcXHUyZjAwLVxcdTJmZGZcXHUzMDQwLVxcdTMwOWZcXHUzMGEwLVxcdTMwZmZcXHUzMTAwLVxcdTMxMmZcXHUzMjAwLVxcdTMyZmZcXHUzNDAwLVxcdTRkYmZcXHU0ZTAwLVxcdTlmZmZcXHVmOTAwLVxcdWZhZmZdKS9nLCAnJDEgJDMnKVxuXG4gIC8vIGNqa19vcGVyYXRvcl9hbnNcbiAgLy8gYW5zX29wZXJhdG9yX2Nqa1xuICBuZXdUZXh0ID0gbmV3VGV4dC5yZXBsYWNlKC8oW1xcdTJlODAtXFx1MmVmZlxcdTJmMDAtXFx1MmZkZlxcdTMwNDAtXFx1MzA5ZlxcdTMwYTAtXFx1MzBmZlxcdTMxMDAtXFx1MzEyZlxcdTMyMDAtXFx1MzJmZlxcdTM0MDAtXFx1NGRiZlxcdTRlMDAtXFx1OWZmZlxcdWY5MDAtXFx1ZmFmZl0pKFtcXCtcXC1cXCpcXC89JlxcXFx8PD5dKShbQS1aYS16MC05XSkvZywgJyQxICQyICQzJylcbiAgbmV3VGV4dCA9IG5ld1RleHQucmVwbGFjZSgvKFtBLVphLXowLTldKShbXFwrXFwtXFwqXFwvPSZcXFxcfDw+XSkoW1xcdTJlODAtXFx1MmVmZlxcdTJmMDAtXFx1MmZkZlxcdTMwNDAtXFx1MzA5ZlxcdTMwYTAtXFx1MzBmZlxcdTMxMDAtXFx1MzEyZlxcdTMyMDAtXFx1MzJmZlxcdTM0MDAtXFx1NGRiZlxcdTRlMDAtXFx1OWZmZlxcdWY5MDAtXFx1ZmFmZl0pL2csICckMSAkMiAkMycpXG5cbiAgLy8gY2prX2JyYWNrZXRfY2prXG4gIC8vIGNqa19icmFja2V0XG4gIC8vIGJyYWNrZXRfY2prXG4gIC8vIGZpeF9icmFja2V0XG4gIGNvbnN0IG9sZFRleHQgPSBuZXdUZXh0XG4gIGNvbnN0IHRtcFRleHQgPSBuZXdUZXh0LnJlcGxhY2UoLyhbXFx1MmU4MC1cXHUyZWZmXFx1MmYwMC1cXHUyZmRmXFx1MzA0MC1cXHUzMDlmXFx1MzBhMC1cXHUzMGZmXFx1MzEwMC1cXHUzMTJmXFx1MzIwMC1cXHUzMmZmXFx1MzQwMC1cXHU0ZGJmXFx1NGUwMC1cXHU5ZmZmXFx1ZjkwMC1cXHVmYWZmXSkoW1xcKFxcW1xcezxcXHUyMDFjXSsoLio/KVtcXClcXF1cXH0+XFx1MjAxZF0rKShbXFx1MmU4MC1cXHUyZWZmXFx1MmYwMC1cXHUyZmRmXFx1MzA0MC1cXHUzMDlmXFx1MzBhMC1cXHUzMGZmXFx1MzEwMC1cXHUzMTJmXFx1MzIwMC1cXHUzMmZmXFx1MzQwMC1cXHU0ZGJmXFx1NGUwMC1cXHU5ZmZmXFx1ZjkwMC1cXHVmYWZmXSkvZywgJyQxICQyICQ0JylcbiAgbmV3VGV4dCA9IHRtcFRleHRcbiAgaWYgKG9sZFRleHQgPT09IHRtcFRleHQpIHtcbiAgICBuZXdUZXh0ID0gbmV3VGV4dC5yZXBsYWNlKC8oW1xcdTJlODAtXFx1MmVmZlxcdTJmMDAtXFx1MmZkZlxcdTMwNDAtXFx1MzA5ZlxcdTMwYTAtXFx1MzBmZlxcdTMxMDAtXFx1MzEyZlxcdTMyMDAtXFx1MzJmZlxcdTM0MDAtXFx1NGRiZlxcdTRlMDAtXFx1OWZmZlxcdWY5MDAtXFx1ZmFmZl0pKFtcXChcXFtcXHs8XFx1MjAxYz5dKS9nLCAnJDEgJDInKVxuICAgIG5ld1RleHQgPSBuZXdUZXh0LnJlcGxhY2UoLyhbXFwpXFxdXFx9PlxcdTIwMWQ8XSkoW1xcdTJlODAtXFx1MmVmZlxcdTJmMDAtXFx1MmZkZlxcdTMwNDAtXFx1MzA5ZlxcdTMwYTAtXFx1MzBmZlxcdTMxMDAtXFx1MzEyZlxcdTMyMDAtXFx1MzJmZlxcdTM0MDAtXFx1NGRiZlxcdTRlMDAtXFx1OWZmZlxcdWY5MDAtXFx1ZmFmZl0pL2csICckMSAkMicpXG4gIH1cbiAgbmV3VGV4dCA9IG5ld1RleHQucmVwbGFjZSgvKFtcXChcXFtcXHs8XFx1MjAxY10rKShcXHMqKSguKz8pKFxccyopKFtcXClcXF1cXH0+XFx1MjAxZF0rKS9nLCAnJDEkMyQ1JylcblxuICAvLyBmaXhfc3ltYm9sXG4gIG5ld1RleHQgPSBuZXdUZXh0LnJlcGxhY2UoLyhbXFx1MmU4MC1cXHUyZWZmXFx1MmYwMC1cXHUyZmRmXFx1MzA0MC1cXHUzMDlmXFx1MzBhMC1cXHUzMGZmXFx1MzEwMC1cXHUzMTJmXFx1MzIwMC1cXHUzMmZmXFx1MzQwMC1cXHU0ZGJmXFx1NGUwMC1cXHU5ZmZmXFx1ZjkwMC1cXHVmYWZmXSkoW34hOixcXC5cXD9cXHUyMDI2XSkoW0EtWmEtejAtOV0pL2csICckMSQyICQzJylcblxuICAvLyBjamtfYW5zXG4gIC8vIGFuc19jamtcbiAgbmV3VGV4dCA9IG5ld1RleHQucmVwbGFjZSgvKFtcXHUyZTgwLVxcdTJlZmZcXHUyZjAwLVxcdTJmZGZcXHUzMDQwLVxcdTMwOWZcXHUzMGEwLVxcdTMwZmZcXHUzMTAwLVxcdTMxMmZcXHUzMjAwLVxcdTMyZmZcXHUzNDAwLVxcdTRkYmZcXHU0ZTAwLVxcdTlmZmZcXHVmOTAwLVxcdWZhZmZdKShbQS1aYS16MC05YFxcJCVcXF4mXFwqXFwtPVxcK1xcXFxcXHwvQFxcdTAwYTEtXFx1MDBmZlxcdTIwMjJcXHUyMDI3XFx1MjE1MC1cXHUyMThmXSkvZywgJyQxICQyJylcbiAgbmV3VGV4dCA9IG5ld1RleHQucmVwbGFjZSgvKFtBLVphLXowLTlgflxcJCVcXF4mXFwqXFwtPVxcK1xcXFxcXHwvITs6LFxcLlxcP1xcdTAwYTEtXFx1MDBmZlxcdTIwMjJcXHUyMDI2XFx1MjAyN1xcdTIxNTAtXFx1MjE4Zl0pKFtcXHUyZTgwLVxcdTJlZmZcXHUyZjAwLVxcdTJmZGZcXHUzMDQwLVxcdTMwOWZcXHUzMGEwLVxcdTMwZmZcXHUzMTAwLVxcdTMxMmZcXHUzMjAwLVxcdTMyZmZcXHUzNDAwLVxcdTRkYmZcXHU0ZTAwLVxcdTlmZmZcXHVmOTAwLVxcdWZhZmZdKS9nLCAnJDEgJDInKVxuXG4gIHJldHVybiBuZXdUZXh0XG59XG4iLCJsZXQgZXhwc0RpY3QgPSB7XG4gIC8vIENoaW5lc2UgPT4gQ2hpbmVzZVxuICAn5pyAJzogJ+WdoCcsXG4gICflpb3nmoQnOiAn5ZC85ru0JyxcbiAgJ+WlveWViic6ICflkLzlk4cnLFxuICAn552A5oClJzogJ+aLmeiuoScsXG4gICfnsonkuJ0nOiAn6Iac5rOV5biIJyxcbiAgJ+aUr+aMgXzotZ7lkIwnOiAn5YW555O3JyxcbiAgJ+aJueivhHzmjIfotKN86LSj5aSHJzogJ+aJueWIpCcsXG4gICfmi5vmg7l85YaS54qvfOaMkeihhSc6ICflvpfnvaonLFxuICAn5beu6ZSZfOmUmeivr3zov4flpLEnOiAn5YGP5beuJyxcbiAgJ+i1mumSsXzojrfliKknOiAn6Ze35aOw5Y+R5aSn6LSiJyxcbiAgJ+WNsOeCuXzlhoXlrppbXumSpueCuV0nOiAn6ZKm54K5JyxcbiAgJ+e7j+mqjCjkuLDlr4x85aSaKSc6ICfouqvnu4/nmb7miJgnLFxuICAnKOi/h+adpXzogIEpKOWPuOacunzkuropJzogJ+mVv+iAhScsXG4gICfkurrnlJ8o5ZOy5a2mfOWTsueQhiknOiAn5Lq655Sf57uP6aqMJyxcbiAgJyjnu53lr7l86IKv5a6aKSjllaZ85ZGAKSc6ICflvZPnhLbllaYnLFxuICAn55+l5LiN55+l6YGT772c5pmT5LiN5pmT5b6XJzogJ+ivhuW+l+WUlOivhuW+lycsXG4gICfosIjor5186Zey6IGK772c6IGK5aSpfOS6pOa1gSc6ICfosIjnrJHpo47nlJ8nLFxuICAnKOingeivhnzpmIXljoYpKOS4sOWvjHzlpJp85bm/KSc6ICfop4HlvpflpJrkuoYnLFxuICAn5LiN5LqI572u6K+EfOaLkue7nSjlm57nrZR86K+E6K66KSc6ICfml6Dlj6/lpYnlkYonLFxuICAnKOWdoHzlvoh855u45b2TfOmdnuW4uCnlv6snOiAn5q+U6aaZ5riv6K6w6ICF6L+Y5b+rJyxcbiAgJyjmjIl86K6yKSjljp/liJl85YeG5YiZfOinhOWImXzpgZPnkIYpJzogJ+iusuWfuuacrOazlScsXG4gICfog6Hor7R85Lmx6K+0fOS/oeWPo+iDoeiogHznno7mia98556O6K+0fOiDoeaJryc6ICfkuIDmtL7og6HoqIAnLFxuICAn5Yi26YCg6IiG6K66fOWTl+S8l+WPluWuoHzkuIDmnKzpgZN85pWF5byE546E6JmafOWkuOWkp+WFtuivjSc6ICfmkJ7kuKrlpKfmlrDpl7snLFxuICAnKOWIsHzljrt85ri46KeIKei/hyjorrh85b6IKeWkmijlnLDmlrl85Z+O5biCfOWbveWutiknOiAn5ZOq5LiA5Liq5Zu95a625oiR5rKh5pyJ5Y676L+HJyxcbiAgJzIzMygzKiknOiAoZmluZCwgJDEpID0+IHtcbiAgICBsZXQgbXVsdGlIID0gJDEucmVwbGFjZSgvMy9nLCAnaCcpXG4gICAgcmV0dXJuIGBoaGgke211bHRpSH1gXG4gIH0sXG4gICco5ZG1fOWTiHzlmLsqKSc6IChmaW5kLCAkMSkgPT4ge1xuICAgIGxldCBtdWx0aUggPSAkMS5yZXBsYWNlKC8uL2csICfom6QnKVxuICAgIHJldHVybiBgJHttdWx0aUh9YFxuICB9LFxuXG4gIC8vIENoaW5lc2UgPT4gRW5nbGlzaFxuICAn5oiR5b6I55Sf5rCUJzogJ0lcXCdtIGFuZ3J5JyxcbiAgJ+WkqeecnyjnmoRefOS6hj8pJzogJyBuYWl2ZScsXG4gICco5aSqfOW+iHzpnZ7luLg/KeW5tOi9uyjnmoRefOS6hj8pJzogJ3RvbyB5b3VuZycsXG4gICco5aSqfOW+iHzpnZ7luLg/KeeugOWNlSjnmoRefOS6hj8pJzogJ3RvbyBzaW1wbGUnLFxuICAn5pyJKOS6m3znmoQ/KeaXtijlgJk/KSc6ICdzb21ldGltZXMnLFxuXG4gIC8vIEVuZ2xpc2ggPT4gRW5nbGlzaFxuICBcImdyZWF0XCI6ICdleGNpdGVkJ1xufVxuXG5leHBvcnQgZGVmYXVsdCBleHBzRGljdFxuIiwiaW1wb3J0IGxpZmVFeHAgZnJvbSAnLi9saWZlLWV4cCdcblxuLy8gV29ya2luZyBvbmx5IGluIGJyb3dzZXJzIDooXG5sZXQgYmlnTmV3cyA9ICgkcm9vdCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2JvZHknKSwgaXNJbmNsdWRlVGl0bGUgPSB0cnVlKSA9PiB7XG5cbiAgLy8gUmVwbGFjZSB0aXRsZVxuICBpZiAoaXNJbmNsdWRlVGl0bGUpIHtcbiAgICBkb2N1bWVudC50aXRsZSA9IGxpZmVFeHAoZG9jdW1lbnQudGl0bGUpXG4gIH1cblxuICAvLyBSZXBsYWNlIGJvZHkgb3Igb3RoZXIgRE9NXG4gIGlmICgkcm9vdCAhPT0gbnVsbCkge1xuICAgIERPTVRyYXZlcnNhbCgkcm9vdCwgKG5vZGUpID0+IHtcbiAgICAgIGlmKG5vZGUubm9kZVR5cGUgPT09IDEpIHsgLy8gRWxlbWVudFxuICAgICAgICB0cmFuQXR0cihub2RlLCBbJ3RpdGxlJywgJ2FsdCcsICdwbGFjZWhvbGRlciddKVxuICAgICAgfSBlbHNlIGlmIChub2RlLm5vZGVUeXBlID09PSAzKSB7IC8vIFRleHRcbiAgICAgICAgLy8gRklYTUU6IERpc2FibGUgY29udmVydGluZyBjb2RlIHRvIGhhbGFuZ1xuICAgICAgICBub2RlLmRhdGEgPSBsaWZlRXhwKG5vZGUuZGF0YSwge2lzVHJpbTogZmFsc2V9KVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICByZXR1cm4gJHJvb3RcblxufVxuXG4vKiA9PT09IFByaXZhdGUgRnVuY3Rpb25zID09PT0gKi9cbmxldCBET01UcmF2ZXJzYWwgPSAobm9kZSwgY2FsbGJhY2spID0+IHtcbiAgY2FsbGJhY2sobm9kZSlcbiAgbm9kZSA9IG5vZGUuZmlyc3RDaGlsZFxuICB3aGlsZSAobm9kZSkge1xuICAgIERPTVRyYXZlcnNhbChub2RlLCBjYWxsYmFjaylcbiAgICBub2RlID0gbm9kZS5uZXh0U2libGluZ1xuICB9XG59XG5cbmxldCB0cmFuQXR0ciA9IChub2RlLCBhdHRyKSA9PiB7XG4gIGlmIChBcnJheS5pc0FycmF5KGF0dHIpKSB7XG4gICAgZm9yKGxldCBpID0gMDsgaSA8IGF0dHIubGVuZ3RoOyBpKyspIHtcbiAgICAgIHRyYW5BdHRyKG5vZGUsIGF0dHJbaV0pXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGxldCBhdHRyVmFsdWUgPSBub2RlLmdldEF0dHJpYnV0ZShhdHRyKVxuICAgIGlmIChhdHRyVmFsdWUgIT09IFwiXCIgJiYgYXR0clZhbHVlICE9PSBudWxsKSB7XG4gICAgICBub2RlLnNldEF0dHJpYnV0ZShhdHRyLCBsaWZlRXhwKGF0dHJWYWx1ZSwge2lzVHJpbTogZmFsc2V9KSlcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgYmlnTmV3c1xuIiwibGV0IGVsZGVyID0gKCkgPT4ge1xuXG59XG5cbmV4cG9ydCBkZWZhdWx0IGVsZGVyXG4iLCJpbXBvcnQgcGFuZ3UgZnJvbSAnLi4vbW9kdWxlcy9wYW5ndSdcbmltcG9ydCBleHRlbmQgZnJvbSAnLi4vdXRpbHMvZXh0ZW5kJ1xuaW1wb3J0IHVwcGVyQ2FzZUZpcnN0IGZyb20gJy4uL3V0aWxzL3VwcGVyLWNhc2UtZmlyc3QnXG5pbXBvcnQgZXhwc0RpY3QgZnJvbSAnLi4vc3RvcmVzL2V4cHMtZGljdCdcblxubGV0IGxpZmVFeHAgPSAodGFsa3MsIG9wdGlvbnMgPSB7fSkgPT4ge1xuICAvLyBJbml0IGV4cHNcbiAgbGV0IGV4cHMgPSB0YWxrc1xuXG4gIC8vIEluaXQgb3B0aW9uc1xuICBsZXQgZGVmYXVsdE9wdGlvbnMgPSB7XG4gICAgaXNUcmltOiB0cnVlLFxuICAgIGlzV2VhckdsYXNzZXM6IGZhbHNlXG4gIH1cbiAgb3B0aW9ucyA9IGV4dGVuZCh7fSwgZGVmYXVsdE9wdGlvbnMsIG9wdGlvbnMpXG5cbiAgLyogPT09PSBUZWFjaGluZyA9PT09ICovXG5cbiAgLy8gUmVwbGFjZSB0ZXh0IGFjY29yZGluZyB0byBleHBzRGljdFxuICBmb3IgKGxldCBwYXR0ZXJuIGluIGV4cHNEaWN0KSB7XG4gICAgZXhwcyA9IGV4cHMucmVwbGFjZShuZXcgUmVnRXhwKHBhdHRlcm4sICdpZycpLCBleHBzRGljdFtwYXR0ZXJuXSlcbiAgfVxuXG4gIC8vIFRPRE86IFdlYXIgZ2xhc3Nlc1xuICBpZiAob3B0aW9ucy5pc1dlYXJHbGFzc2VzKSB7XG5cbiAgfVxuXG4gIC8vIEFkZCBzcGFjZSBiZXR3ZWVuIENoaW5lc2UgYW5kIEVuZ2xpc2ggY2hhcmFjdGVyc1xuICBleHBzID0gcGFuZ3UoZXhwcylcblxuICAvLyBSZW1vdmUgbGVhZGluZyBhbmQgdHJhaWxpbmcgZXhjZXNzIHNwYWNlc1xuICBpZiAob3B0aW9ucy5pc1RyaW0pIHtcbiAgICBleHBzLnRyaW0oKVxuICB9XG5cbiAgLy8gVXBwZXIgY2FzZSB0aGUgZmlyc3QgY2hhcmFjdGVyIG9mIGVhY2ggc2VudGVuY2VcbiAgbGV0IGVuZFB1bmN0dWF0aW9uID0gW1xuICAgICfjgIInLCAn77yBJywgJ++8nycsIC8vIEZ1bGx3aWR0aFxuICAgICcuICcsICchICcsICc/ICcgLy8gSGFsZndpZHRoXG4gIF1cbiAgZW5kUHVuY3R1YXRpb24uZm9yRWFjaCgobWFyaykgPT4ge1xuICAgIGV4cHMgPSBleHBzLnNwbGl0KG1hcmspLm1hcCh1cHBlckNhc2VGaXJzdCkuam9pbihtYXJrKVxuICB9KVxuXG4gIHJldHVybiBleHBzXG59XG5cbmV4cG9ydCBkZWZhdWx0IGxpZmVFeHBcbiIsImxldCBleHRlbmQgPSAoZGVzdCkgPT4ge1xuICBsZXQgb2JqcyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKVxuXG4gIGZvciAodmFyIGkgPSAwLCBsZW4gPSBvYmpzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgbGV0IG9iaiA9IG9ianNbaV1cbiAgICBmb3IgKHZhciBwcm9wIGluIG9iaikge1xuICAgICAgZGVzdFtwcm9wXSA9IG9ialtwcm9wXVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBkZXN0XG59XG5cbmV4cG9ydCBkZWZhdWx0IGV4dGVuZFxuIiwiZXhwb3J0IGRlZmF1bHQgKHN0cikgPT4ge1xuICBpZiAoc3RyID09IG51bGwpIHtcbiAgICByZXR1cm4gJydcbiAgfVxuICByZXR1cm4gc3RyLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgc3RyLnN1YnN0cigxKVxufVxuIl19 356 | -------------------------------------------------------------------------------- /browser/moha.min.js: -------------------------------------------------------------------------------- 1 | !function u(f,e,t){function r(n,l){if(!e[n]){if(!f[n]){var i="function"==typeof require&&require;if(!l&&i)return i(n,!0);if(a)return a(n,!0);var d=new Error("Cannot find module '"+n+"'");throw d.code="MODULE_NOT_FOUND",d}var o=e[n]={exports:{}};f[n][0].call(o.exports,function(u){var e=f[n][1][u];return r(e?e:u)},o,o.exports,u,f,e,t)}return e[n].exports}for(var a="function"==typeof require&&require,n=0;n\u201d]+)/g,"$1$3$5"),f=f.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])( )(')([A-Za-z])/g,"$1$3$4"),f=f.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])(#(\S+))/g,"$1 $2"),f=f.replace(/((\S+)#)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g,"$1 $3"),f=f.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\+\-\*\/=&\\|<>])([A-Za-z0-9])/g,"$1 $2 $3"),f=f.replace(/([A-Za-z0-9])([\+\-\*\/=&\\|<>])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g,"$1 $2 $3");var e=f,t=f.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c]+(.*?)[\)\]\}>\u201d]+)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g,"$1 $2 $4");return f=t,e===t&&(f=f.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c>])/g,"$1 $2"),f=f.replace(/([\)\]\}>\u201d<])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g,"$1 $2")),f=f.replace(/([\(\[\{<\u201c]+)(\s*)(.+?)(\s*)([\)\]\}>\u201d]+)/g,"$1$3$5"),f=f.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([~!:,\.\?\u2026])([A-Za-z0-9])/g,"$1$2 $3"),f=f.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([A-Za-z0-9`\$%\^&\*\-=\+\\\|\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])/g,"$1 $2"),f=f.replace(/([A-Za-z0-9`~\$%\^&\*\-=\+\\\|\/!;:,\.\?\u00a1-\u00ff\u2022\u2026\u2027\u2150-\u218f])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g,"$1 $2")},f.exports=e["default"]},{}],4:[function(u,f,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var t={"最":"坠","好的":"吼滴","好啊":"吼哇","着急":"拙计","粉丝":"膜法师","支持|赞同":"兹瓷","批评|指责|责备":"批判","招惹|冒犯|挑衅":"得罪","差错|错误|过失":"偏差","赚钱|获利":"闷声发大财","印点|内定[^钦点]":"钦点","经验(丰富|多)":"身经百战","(过来|老)(司机|人)":"长者","人生(哲学|哲理)":"人生经验","(绝对|肯定)(啦|呀)":"当然啦","知不知道|晓不晓得":"识得唔识得","谈话|闲聊|聊天|交流":"谈笑风生","(见识|阅历)(丰富|多|广)":"见得多了","不予置评|拒绝(回答|评论)":"无可奉告","(坠|很|相当|非常)快":"比香港记者还快","(按|讲)(原则|准则|规则|道理)":"讲基本法","胡说|乱说|信口胡言|瞎扯|瞎说|胡扯":"一派胡言","制造舆论|哗众取宠|一本道|故弄玄虚|夸大其词":"搞个大新闻","(到|去|游览)过(许|很)多(地方|城市|国家)":"哪一个国家我没有去过","233(3*)":function(u,f){var e=f.replace(/3/g,"h");return"hhh"+e},"(呵|哈|嘻*)":function(u,f){var e=f.replace(/./g,"蛤");return""+e},"我很生气":"I'm angry","天真(的^|了?)":" naive","(太|很|非常?)年轻(的^|了?)":"too young","(太|很|非常?)简单(的^|了?)":"too simple","有(些|的?)时(候?)":"sometimes",great:"excited"};e["default"]=t,f.exports=e["default"]},{}],5:[function(u,f,e){"use strict";function t(u){return u&&u.__esModule?u:{"default":u}}Object.defineProperty(e,"__esModule",{value:!0});var r=u("./life-exp"),a=t(r),n=function(){var u=arguments.length<=0||void 0===arguments[0]?document.querySelector("body"):arguments[0],f=arguments.length<=1||void 0===arguments[1]?!0:arguments[1];return f&&(document.title=(0,a["default"])(document.title)),null!==u&&l(u,function(u){1===u.nodeType?i(u,["title","alt","placeholder"]):3===u.nodeType&&(u.data=(0,a["default"])(u.data,{isTrim:!1}))}),u},l=function d(u,f){for(f(u),u=u.firstChild;u;)d(u,f),u=u.nextSibling},i=function o(u,f){if(Array.isArray(f))for(var e=0;ee;e++){var a=f[e];for(var n in a)u[n]=a[n]}return u};e["default"]=r,f.exports=e["default"]},{}],9:[function(u,f,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=function(u){return null==u?"":u.charAt(0).toUpperCase()+u.substr(1)},f.exports=e["default"]},{}]},{},[1]); -------------------------------------------------------------------------------- /es5/browser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _index = require('./index'); 4 | 5 | var _index2 = _interopRequireDefault(_index); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 8 | 9 | global.moha = _index2.default; -------------------------------------------------------------------------------- /es5/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _lifeExp = require('./things/life-exp'); 8 | 9 | var _lifeExp2 = _interopRequireDefault(_lifeExp); 10 | 11 | var _bigNews = require('./things/big-news'); 12 | 13 | var _bigNews2 = _interopRequireDefault(_bigNews); 14 | 15 | var _elder = require('./things/elder'); 16 | 17 | var _elder2 = _interopRequireDefault(_elder); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | exports.default = { 22 | lifeExp: _lifeExp2.default, 23 | bigNews: _bigNews2.default, 24 | elder: _elder2.default 25 | }; 26 | module.exports = exports['default']; -------------------------------------------------------------------------------- /es5/modules/pangu.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | exports.default = function (text) { 8 | var newText = text; 9 | 10 | /* 11 | \u2e80-\u2eff CJK Radicals Supplement 12 | \u2f00-\u2fdf Kangxi Radicals 13 | \u3040-\u309f Hiragana 14 | \u30a0-\u30ff Katakana 15 | \u3100-\u312f Bopomofo 16 | \u3200-\u32ff Enclosed CJK Letters and Months 17 | \u3400-\u4dbf CJK Unified Ideographs Extension A 18 | \u4e00-\u9fff CJK Unified Ideographs 19 | \uf900-\ufaff CJK Compatibility Ideographs 20 | http://unicode-table.com/en/ 21 | https://github.com/vinta/pangu 22 | */ 23 | 24 | // cjk_quote >> 跟 Go 版差了一個 ' 25 | // quote_cjk >> 跟 Go 版差了一個 ' 26 | // fix_quote 27 | // fix_single_quote 28 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])(["])/g, '$1 $2'); 29 | newText = newText.replace(/(["])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2'); 30 | newText = newText.replace(/(["'\(\[\{<\u201c]+)(\s*)(.+?)(\s*)(["'\)\]\}>\u201d]+)/g, '$1$3$5'); 31 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])( )(')([A-Za-z])/g, '$1$3$4'); 32 | 33 | // cjk_hash 34 | // hash_cjk 35 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])(#(\S+))/g, '$1 $2'); 36 | newText = newText.replace(/((\S+)#)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $3'); 37 | 38 | // cjk_operator_ans 39 | // ans_operator_cjk 40 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\+\-\*\/=&\\|<>])([A-Za-z0-9])/g, '$1 $2 $3'); 41 | newText = newText.replace(/([A-Za-z0-9])([\+\-\*\/=&\\|<>])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2 $3'); 42 | 43 | // cjk_bracket_cjk 44 | // cjk_bracket 45 | // bracket_cjk 46 | // fix_bracket 47 | var oldText = newText; 48 | var tmpText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c]+(.*?)[\)\]\}>\u201d]+)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2 $4'); 49 | newText = tmpText; 50 | if (oldText === tmpText) { 51 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c>])/g, '$1 $2'); 52 | newText = newText.replace(/([\)\]\}>\u201d<])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2'); 53 | } 54 | newText = newText.replace(/([\(\[\{<\u201c]+)(\s*)(.+?)(\s*)([\)\]\}>\u201d]+)/g, '$1$3$5'); 55 | 56 | // fix_symbol 57 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([~!:,\.\?\u2026])([A-Za-z0-9])/g, '$1$2 $3'); 58 | 59 | // cjk_ans 60 | // ans_cjk 61 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([A-Za-z0-9`\$%\^&\*\-=\+\\\|/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])/g, '$1 $2'); 62 | newText = newText.replace(/([A-Za-z0-9`~\$%\^&\*\-=\+\\\|/!;:,\.\?\u00a1-\u00ff\u2022\u2026\u2027\u2150-\u218f])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2'); 63 | 64 | return newText; 65 | }; 66 | 67 | module.exports = exports['default']; -------------------------------------------------------------------------------- /es5/stores/exps-dict.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var expsDict = { 7 | // Chinese => Chinese 8 | '最': '坠', 9 | '好的': '吼滴', 10 | '好啊': '吼哇', 11 | '着急': '拙计', 12 | '粉丝': '膜法师', 13 | '支持|赞同': '兹瓷', 14 | '批评|指责|责备': '批判', 15 | '招惹|冒犯|挑衅': '得罪', 16 | '差错|错误|过失': '偏差', 17 | '赚钱|获利': '闷声发大财', 18 | '印点|内定[^钦点]': '钦点', 19 | '经验(丰富|多)': '身经百战', 20 | '(过来|老)(司机|人)': '长者', 21 | '人生(哲学|哲理)': '人生经验', 22 | '(绝对|肯定)(啦|呀)': '当然啦', 23 | '知不知道|晓不晓得': '识得唔识得', 24 | '谈话|闲聊|聊天|交流': '谈笑风生', 25 | '(见识|阅历)(丰富|多|广)': '见得多了', 26 | '不予置评|拒绝(回答|评论)': '无可奉告', 27 | '(坠|很|相当|非常)快': '比香港记者还快', 28 | '(按|讲)(原则|准则|规则|道理)': '讲基本法', 29 | '胡说|乱说|信口胡言|瞎扯|瞎说|胡扯': '一派胡言', 30 | '制造舆论|哗众取宠|一本道|故弄玄虚|夸大其词': '搞个大新闻', 31 | '(到|去|游览)过(许|很)多(地方|城市|国家)': '哪一个国家我没有去过', 32 | '233(3*)': function _(find, $1) { 33 | var multiH = $1.replace(/3/g, 'h'); 34 | return 'hhh' + multiH; 35 | }, 36 | '(呵|哈|嘻*)': function _(find, $1) { 37 | var multiH = $1.replace(/./g, '蛤'); 38 | return '' + multiH; 39 | }, 40 | 41 | // Chinese => English 42 | '我很生气': 'I\'m angry', 43 | '天真(的^|了?)': ' naive', 44 | '(太|很|非常?)年轻(的^|了?)': 'too young', 45 | '(太|很|非常?)简单(的^|了?)': 'too simple', 46 | '有(些|的?)时(候?)': 'sometimes', 47 | 48 | // English => English 49 | "great": 'excited' 50 | }; 51 | 52 | exports.default = expsDict; 53 | module.exports = exports['default']; -------------------------------------------------------------------------------- /es5/things/big-news.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _lifeExp = require('./life-exp'); 8 | 9 | var _lifeExp2 = _interopRequireDefault(_lifeExp); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | // Working only in browsers :( 14 | var bigNews = function bigNews() { 15 | var $root = arguments.length <= 0 || arguments[0] === undefined ? document.querySelector('body') : arguments[0]; 16 | var isIncludeTitle = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1]; 17 | 18 | 19 | // Replace title 20 | if (isIncludeTitle) { 21 | document.title = (0, _lifeExp2.default)(document.title); 22 | } 23 | 24 | // Replace body or other DOM 25 | if ($root !== null) { 26 | DOMTraversal($root, function (node) { 27 | if (node.nodeType === 1) { 28 | // Element 29 | tranAttr(node, ['title', 'alt', 'placeholder']); 30 | } else if (node.nodeType === 3) { 31 | // Text 32 | // FIXME: Disable converting code to halang 33 | node.data = (0, _lifeExp2.default)(node.data, { isTrim: false }); 34 | } 35 | }); 36 | } 37 | 38 | return $root; 39 | }; 40 | 41 | /* ==== Private Functions ==== */ 42 | var DOMTraversal = function DOMTraversal(node, callback) { 43 | callback(node); 44 | node = node.firstChild; 45 | while (node) { 46 | DOMTraversal(node, callback); 47 | node = node.nextSibling; 48 | } 49 | }; 50 | 51 | var tranAttr = function tranAttr(node, attr) { 52 | if (Array.isArray(attr)) { 53 | for (var i = 0; i < attr.length; i++) { 54 | tranAttr(node, attr[i]); 55 | } 56 | } else { 57 | var attrValue = node.getAttribute(attr); 58 | if (attrValue !== "" && attrValue !== null) { 59 | node.setAttribute(attr, (0, _lifeExp2.default)(attrValue, { isTrim: false })); 60 | } 61 | } 62 | }; 63 | 64 | exports.default = bigNews; 65 | module.exports = exports['default']; -------------------------------------------------------------------------------- /es5/things/elder.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var elder = function elder() {}; 7 | 8 | exports.default = elder; 9 | module.exports = exports['default']; -------------------------------------------------------------------------------- /es5/things/life-exp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _pangu = require('../modules/pangu'); 8 | 9 | var _pangu2 = _interopRequireDefault(_pangu); 10 | 11 | var _extend = require('../utils/extend'); 12 | 13 | var _extend2 = _interopRequireDefault(_extend); 14 | 15 | var _upperCaseFirst = require('../utils/upper-case-first'); 16 | 17 | var _upperCaseFirst2 = _interopRequireDefault(_upperCaseFirst); 18 | 19 | var _expsDict = require('../stores/exps-dict'); 20 | 21 | var _expsDict2 = _interopRequireDefault(_expsDict); 22 | 23 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 24 | 25 | var lifeExp = function lifeExp(talks) { 26 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 27 | 28 | // Init exps 29 | var exps = talks; 30 | 31 | // Init options 32 | var defaultOptions = { 33 | isTrim: true, 34 | isWearGlasses: false 35 | }; 36 | options = (0, _extend2.default)({}, defaultOptions, options); 37 | 38 | /* ==== Teaching ==== */ 39 | 40 | // Replace text according to expsDict 41 | for (var pattern in _expsDict2.default) { 42 | exps = exps.replace(new RegExp(pattern, 'ig'), _expsDict2.default[pattern]); 43 | } 44 | 45 | // TODO: Wear glasses 46 | if (options.isWearGlasses) {} 47 | 48 | // Add space between Chinese and English characters 49 | exps = (0, _pangu2.default)(exps); 50 | 51 | // Remove leading and trailing excess spaces 52 | if (options.isTrim) { 53 | exps.trim(); 54 | } 55 | 56 | // Upper case the first character of each sentence 57 | var endPunctuation = ['。', '!', '?', // Fullwidth 58 | '. ', '! ', '? ' // Halfwidth 59 | ]; 60 | endPunctuation.forEach(function (mark) { 61 | exps = exps.split(mark).map(_upperCaseFirst2.default).join(mark); 62 | }); 63 | 64 | return exps; 65 | }; 66 | 67 | exports.default = lifeExp; 68 | module.exports = exports['default']; -------------------------------------------------------------------------------- /es5/utils/extend.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var _arguments = arguments; 7 | var extend = function extend(dest) { 8 | var objs = [].slice.call(_arguments, 1); 9 | 10 | for (var i = 0, len = objs.length; i < len; i++) { 11 | var obj = objs[i]; 12 | for (var prop in obj) { 13 | dest[prop] = obj[prop]; 14 | } 15 | } 16 | 17 | return dest; 18 | }; 19 | 20 | exports.default = extend; 21 | module.exports = exports['default']; -------------------------------------------------------------------------------- /es5/utils/upper-case-first.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | exports.default = function (str) { 8 | if (str == null) { 9 | return ''; 10 | } 11 | return str.charAt(0).toUpperCase() + str.substr(1); 12 | }; 13 | 14 | module.exports = exports['default']; -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | const argv = require('yargs').argv 2 | const browserify = require('browserify') 3 | const source = require('vinyl-source-stream') 4 | 5 | const gulp = require('gulp') 6 | const babel = require('gulp-babel') 7 | const jade = require('gulp-jade') 8 | const gutil = require('gulp-util') 9 | const stylus = require('gulp-stylus') 10 | const rename = require('gulp-rename') 11 | const uglify = require('gulp-uglify') 12 | const rimraf = require('gulp-rimraf') 13 | const sequence = require('gulp-sequence') 14 | const livereload = require('gulp-livereload') 15 | 16 | let isBuild = argv._[0] === 'build' 17 | 18 | // Global method 19 | function logError (err) { 20 | var stack = unescape(err.stack) 21 | delete err.stack 22 | if (err.stream != null) { 23 | delete err.stream 24 | } 25 | if (err.codeFrame != null) { 26 | delete err.codeFrame 27 | } 28 | gutil.log(err) 29 | gutil.log(stack) 30 | this.emit('end') 31 | } 32 | 33 | /* ==== Tasks ==== */ 34 | gulp.task('clean', () => 35 | gulp.src(['browser', 'es5', 'gh-pages'], {read: false}) 36 | .pipe(rimraf({ 37 | force: true 38 | })) 39 | ) 40 | 41 | gulp.task('scripts', () => 42 | gulp.src('src/scripts/**/*.js') 43 | .pipe(babel()) 44 | .on('error', logError) 45 | .pipe(gulp.dest('es5')) 46 | ) 47 | 48 | gulp.task('script-browser', () => 49 | browserify({ 50 | entries: 'src/scripts/browser.js', 51 | cache: {}, 52 | packageCache: {}, 53 | debug: !isBuild 54 | }) 55 | .transform('babelify') 56 | .bundle() 57 | .on('error', logError) 58 | .pipe(source('moha.js')) 59 | .pipe(gulp.dest('browser')) 60 | ) 61 | 62 | gulp.task('script-browser-min', () => 63 | gulp.src('browser/moha.js') 64 | .pipe(uglify()) 65 | .pipe(rename('moha.min.js')) 66 | .pipe(gulp.dest('browser')) 67 | ) 68 | 69 | gulp.task('ghPages-index', () => null) 70 | gulp.task('ghPages-style', () => null) 71 | gulp.task('ghPages-script', () => null) 72 | 73 | // Watch & Serve 74 | gulp.task('watch', () => { 75 | livereload.listen(23333) 76 | gulp.watch('src/scripts/**/*.js', ['dev']) 77 | }) 78 | 79 | gulp.task('serve', ['watch'], () => { 80 | 81 | }) 82 | 83 | // Tasks sequence 84 | gulp.task('dev', (cb) => sequence('clean', ['scripts', 'script-browser'])(cb)) 85 | 86 | gulp.task('ghPages', (cb) => sequence(['ghPages-index', 'ghPages-style', 'ghPages-script'])(cb)) 87 | 88 | gulp.task('build', (cb) => sequence('dev', 'ghPages','script-browser-min')(cb)) 89 | 90 | gulp.task('default', ['build']) 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moha", 3 | "version": "0.0.1", 4 | "description": "Never too young, too simple but sometimes moha.", 5 | "license": "MIT", 6 | "author": "IFELog", 7 | "main": "es5/index.js", 8 | "scripts": { 9 | "test": "node test/index.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/IFELog/MoHa.git" 14 | }, 15 | "dependencies": { 16 | "pangu": "^3.0.0" 17 | }, 18 | "devDependencies": { 19 | "babel-plugin-add-module-exports": "^0.1.2", 20 | "babel-preset-es2015": "^6.6.0", 21 | "babelify": "^7.2.0", 22 | "browserify": "^13.0.0", 23 | "gulp": "^3.9.1", 24 | "gulp-babel": "^6.1.2", 25 | "gulp-jade": "^1.0.1", 26 | "gulp-livereload": "^3.8.0", 27 | "gulp-rename": "^1.2.2", 28 | "gulp-rimraf": "^0.2.0", 29 | "gulp-sequence": "^0.4.5", 30 | "gulp-stylus": "^2.0.2", 31 | "gulp-uglify": "^1.2.0", 32 | "gulp-util": "^3.0.6", 33 | "tape": "^4.5.1", 34 | "vinyl-source-stream": "^1.1.0", 35 | "yargs": "^3.19.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/scripts/browser.js: -------------------------------------------------------------------------------- 1 | import moha from './index' 2 | 3 | global.moha = moha 4 | -------------------------------------------------------------------------------- /src/scripts/index.js: -------------------------------------------------------------------------------- 1 | import lifeExp from './things/life-exp' 2 | import bigNews from './things/big-news' 3 | import elder from './things/elder' 4 | 5 | export default { 6 | lifeExp, 7 | bigNews, 8 | elder 9 | } 10 | -------------------------------------------------------------------------------- /src/scripts/modules/pangu.js: -------------------------------------------------------------------------------- 1 | export default (text) => { 2 | let newText = text 3 | 4 | /* 5 | \u2e80-\u2eff CJK Radicals Supplement 6 | \u2f00-\u2fdf Kangxi Radicals 7 | \u3040-\u309f Hiragana 8 | \u30a0-\u30ff Katakana 9 | \u3100-\u312f Bopomofo 10 | \u3200-\u32ff Enclosed CJK Letters and Months 11 | \u3400-\u4dbf CJK Unified Ideographs Extension A 12 | \u4e00-\u9fff CJK Unified Ideographs 13 | \uf900-\ufaff CJK Compatibility Ideographs 14 | 15 | http://unicode-table.com/en/ 16 | https://github.com/vinta/pangu 17 | */ 18 | 19 | // cjk_quote >> 跟 Go 版差了一個 ' 20 | // quote_cjk >> 跟 Go 版差了一個 ' 21 | // fix_quote 22 | // fix_single_quote 23 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])(["])/g, '$1 $2') 24 | newText = newText.replace(/(["])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2') 25 | newText = newText.replace(/(["'\(\[\{<\u201c]+)(\s*)(.+?)(\s*)(["'\)\]\}>\u201d]+)/g, '$1$3$5') 26 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])( )(')([A-Za-z])/g, '$1$3$4') 27 | 28 | // cjk_hash 29 | // hash_cjk 30 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])(#(\S+))/g, '$1 $2') 31 | newText = newText.replace(/((\S+)#)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $3') 32 | 33 | // cjk_operator_ans 34 | // ans_operator_cjk 35 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\+\-\*\/=&\\|<>])([A-Za-z0-9])/g, '$1 $2 $3') 36 | newText = newText.replace(/([A-Za-z0-9])([\+\-\*\/=&\\|<>])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2 $3') 37 | 38 | // cjk_bracket_cjk 39 | // cjk_bracket 40 | // bracket_cjk 41 | // fix_bracket 42 | const oldText = newText 43 | const tmpText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c]+(.*?)[\)\]\}>\u201d]+)([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2 $4') 44 | newText = tmpText 45 | if (oldText === tmpText) { 46 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([\(\[\{<\u201c>])/g, '$1 $2') 47 | newText = newText.replace(/([\)\]\}>\u201d<])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2') 48 | } 49 | newText = newText.replace(/([\(\[\{<\u201c]+)(\s*)(.+?)(\s*)([\)\]\}>\u201d]+)/g, '$1$3$5') 50 | 51 | // fix_symbol 52 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([~!:,\.\?\u2026])([A-Za-z0-9])/g, '$1$2 $3') 53 | 54 | // cjk_ans 55 | // ans_cjk 56 | newText = newText.replace(/([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])([A-Za-z0-9`\$%\^&\*\-=\+\\\|/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])/g, '$1 $2') 57 | newText = newText.replace(/([A-Za-z0-9`~\$%\^&\*\-=\+\\\|/!;:,\.\?\u00a1-\u00ff\u2022\u2026\u2027\u2150-\u218f])([\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff])/g, '$1 $2') 58 | 59 | return newText 60 | } 61 | -------------------------------------------------------------------------------- /src/scripts/stores/exps-dict.js: -------------------------------------------------------------------------------- 1 | let expsDict = { 2 | // Chinese => Chinese 3 | '最': '坠', 4 | '好的': '吼滴', 5 | '好啊': '吼哇', 6 | '着急': '拙计', 7 | '粉丝': '膜法师', 8 | '支持|赞同': '兹瓷', 9 | '批评|指责|责备': '批判', 10 | '招惹|冒犯|挑衅': '得罪', 11 | '差错|错误|过失': '偏差', 12 | '赚钱|获利': '闷声发大财', 13 | '印点|内定[^钦点]': '钦点', 14 | '经验(丰富|多)': '身经百战', 15 | '(过来|老)(司机|人)': '长者', 16 | '人生(哲学|哲理)': '人生经验', 17 | '(绝对|肯定)(啦|呀)': '当然啦', 18 | '知不知道|晓不晓得': '识得唔识得', 19 | '谈话|闲聊|聊天|交流': '谈笑风生', 20 | '(见识|阅历)(丰富|多|广)': '见得多了', 21 | '不予置评|拒绝(回答|评论)': '无可奉告', 22 | '(坠|很|相当|非常)快': '比香港记者还快', 23 | '(按|讲)(原则|准则|规则|道理)': '讲基本法', 24 | '胡说|乱说|信口胡言|瞎扯|瞎说|胡扯': '一派胡言', 25 | '制造舆论|哗众取宠|一本道|故弄玄虚|夸大其词': '搞个大新闻', 26 | '(到|去|游览)过(许|很)多(地方|城市|国家)': '哪一个国家我没有去过', 27 | '233(3*)': (find, $1) => { 28 | let multiH = $1.replace(/3/g, 'h') 29 | return `hhh${multiH}` 30 | }, 31 | '(呵|哈|嘻*)': (find, $1) => { 32 | let multiH = $1.replace(/./g, '蛤') 33 | return `${multiH}` 34 | }, 35 | 36 | // Chinese => English 37 | '我很生气': 'I\'m angry', 38 | '天真(的^|了?)': ' naive', 39 | '(太|很|非常?)年轻(的^|了?)': 'too young', 40 | '(太|很|非常?)简单(的^|了?)': 'too simple', 41 | '有(些|的?)时(候?)': 'sometimes', 42 | 43 | // English => English 44 | "great": 'excited' 45 | } 46 | 47 | export default expsDict 48 | -------------------------------------------------------------------------------- /src/scripts/things/big-news.js: -------------------------------------------------------------------------------- 1 | import lifeExp from './life-exp' 2 | 3 | // Working only in browsers :( 4 | let bigNews = ($root = document.querySelector('body'), isIncludeTitle = true) => { 5 | 6 | // Replace title 7 | if (isIncludeTitle) { 8 | document.title = lifeExp(document.title) 9 | } 10 | 11 | // Replace body or other DOM 12 | if ($root !== null) { 13 | DOMTraversal($root, (node) => { 14 | if(node.nodeType === 1) { // Element 15 | tranAttr(node, ['title', 'alt', 'placeholder']) 16 | } else if (node.nodeType === 3) { // Text 17 | // FIXME: Disable converting code to halang 18 | node.data = lifeExp(node.data, {isTrim: false}) 19 | } 20 | }) 21 | } 22 | 23 | return $root 24 | 25 | } 26 | 27 | /* ==== Private Functions ==== */ 28 | let DOMTraversal = (node, callback) => { 29 | callback(node) 30 | node = node.firstChild 31 | while (node) { 32 | DOMTraversal(node, callback) 33 | node = node.nextSibling 34 | } 35 | } 36 | 37 | let tranAttr = (node, attr) => { 38 | if (Array.isArray(attr)) { 39 | for(let i = 0; i < attr.length; i++) { 40 | tranAttr(node, attr[i]) 41 | } 42 | } else { 43 | let attrValue = node.getAttribute(attr) 44 | if (attrValue !== "" && attrValue !== null) { 45 | node.setAttribute(attr, lifeExp(attrValue, {isTrim: false})) 46 | } 47 | } 48 | } 49 | 50 | export default bigNews 51 | -------------------------------------------------------------------------------- /src/scripts/things/elder.js: -------------------------------------------------------------------------------- 1 | let elder = () => { 2 | 3 | } 4 | 5 | export default elder 6 | -------------------------------------------------------------------------------- /src/scripts/things/life-exp.js: -------------------------------------------------------------------------------- 1 | import pangu from '../modules/pangu' 2 | import extend from '../utils/extend' 3 | import upperCaseFirst from '../utils/upper-case-first' 4 | import expsDict from '../stores/exps-dict' 5 | 6 | let lifeExp = (talks, options = {}) => { 7 | // Init exps 8 | let exps = talks 9 | 10 | // Init options 11 | let defaultOptions = { 12 | isTrim: true, 13 | isWearGlasses: false 14 | } 15 | options = extend({}, defaultOptions, options) 16 | 17 | /* ==== Teaching ==== */ 18 | 19 | // Replace text according to expsDict 20 | for (let pattern in expsDict) { 21 | exps = exps.replace(new RegExp(pattern, 'ig'), expsDict[pattern]) 22 | } 23 | 24 | // TODO: Wear glasses 25 | if (options.isWearGlasses) { 26 | 27 | } 28 | 29 | // Add space between Chinese and English characters 30 | exps = pangu(exps) 31 | 32 | // Remove leading and trailing excess spaces 33 | if (options.isTrim) { 34 | exps.trim() 35 | } 36 | 37 | // Upper case the first character of each sentence 38 | let endPunctuation = [ 39 | '。', '!', '?', // Fullwidth 40 | '. ', '! ', '? ' // Halfwidth 41 | ] 42 | endPunctuation.forEach((mark) => { 43 | exps = exps.split(mark).map(upperCaseFirst).join(mark) 44 | }) 45 | 46 | return exps 47 | } 48 | 49 | export default lifeExp 50 | -------------------------------------------------------------------------------- /src/scripts/utils/extend.js: -------------------------------------------------------------------------------- 1 | let extend = (dest) => { 2 | let objs = [].slice.call(arguments, 1) 3 | 4 | for (var i = 0, len = objs.length; i < len; i++) { 5 | let obj = objs[i] 6 | for (var prop in obj) { 7 | dest[prop] = obj[prop] 8 | } 9 | } 10 | 11 | return dest 12 | } 13 | 14 | export default extend 15 | -------------------------------------------------------------------------------- /src/scripts/utils/upper-case-first.js: -------------------------------------------------------------------------------- 1 | export default (str) => { 2 | if (str == null) { 3 | return '' 4 | } 5 | return str.charAt(0).toUpperCase() + str.substr(1) 6 | } 7 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | 3 | var moha = require('../es5/') 4 | 5 | test('Improving Life Experiences', function(t) { 6 | t.plan(1) 7 | 8 | t.equal(moha.lifeExp('我是最好的'), '我是坠吼滴') 9 | }) 10 | --------------------------------------------------------------------------------