封装了tesseract的识别，部署在阿里云上，服务端源码地址为： https://github.com/shidenggui/yh_verify_code_docker
163088
def detect_yh_client_result(image_path):
    """"""
    api = "http://yh.ez.shidenggui.com:5000/yh_client"
    with open(image_path, "rb") as f:
        rep = requests.post(api, files={"image": f})
    if rep.status_code != 201:
        error = rep.json()["message"]
        raise exceptions.TradeError("request {} error: {}".format(api, error))
    return rep.json()["result"]
775639
function AstParser(tokens, doc){

	// ------------ 变量 ------------
	syntaxCheck(tokens); // 删除空白文本
	let reader = new TokenReader(tokens);
	let ast = [];
	let file = doc.file;

	// ------------ 接口方法 ------------
	// 解析
	this.parse = function() {
		let ast = parseChildren();
//console.info(MODULE, JSON.stringify(ast,null,2));
		return ast;
	}

	// ------------ 内部方法 ------------
	// HTML子节点
	function parseChildren() {

		let ary = [], node;

		// 循环直到遇见标签闭合Token
		while ( !reader.eof() && reader.getCurrentToken().type != options.TypeTagClose ) {
			node = parseTag();
			node && ary.push(node);

			node = parseComment();
			node && ary.push(node);

			node = parseCodeBlock();
			node && ary.push(node);

			node = parseText();
			node && ary.push(node);

			node = parseExpression();
			node && ary.push(node);
		}

		return ary;
	}

	// HTML节点
	function parseTag() {
		let curToken = reader.getCurrentToken();
		if ( reader.eof() || (curToken.type != options.TypeTagOpen && curToken.type != options.TypeTagSelfClose) ) {
			return null;
		}

		let attrs, children, node = {tag: curToken.text};
		let isClose = (curToken.type == options.TypeTagSelfClose);
		reader.skip(1); // 跳过标签名

		// 收集属性
		attrs = parseAttr();

		if ( !isClose ) {
			children = parseChildren();
			if ( reader.getCurrentToken().type == options.TypeTagClose ) {
				if ( reader.getCurrentToken().text == node.tag ) {
					reader.skip(1); // 跳过闭合标签
				}else{

					let token = reader.getCurrentToken();
					!token.pos && (token = reader.getPreToken());

					let text = File.read(file);
					let rs = /^\[view\][\s\S]*?\n|\n\[view\][\s\S]*?\n/i.exec(text);
					let offset = rs.index + rs[0].length;
					let start = offset + curToken.pos.start+1;
					let end = offset + token.pos.end;
					let msg = 'close tag unmatch: ' + node.tag + ' / ' + token.text;
					throw Err.cat(msg, 'file=' + file, new Err( {text, start, end} )); // 标签没有闭合
				}
			}else{
				
				let token = reader.getCurrentToken();
				!token.pos && (token = reader.getPreToken());

				let text = File.read(file);
				let rs = /^\[view\][\s\S]*?\n|\n\[view\][\s\S]*?\n/i.exec(text);
				let offset = rs.index + rs[0].length;
				let start = offset + curToken.pos.start+1;
				let end = offset + token.pos.end;
				let msg = 'tag not close: ' + node.tag;
				throw Err.cat(msg, 'file=' + file, new Err( {text, start, end} )); // 标签没有闭合
			}
		}

		attrs && (node.attrs = attrs);
		children && children.length && (node.children = children);

		return node;
	}

	// HTML节点属性
	function parseAttr() {
		if ( reader.eof() || reader.getCurrentToken().type != options.TypeAttributeName ) {
			return null;
		}

		let attr = {};
		while ( !reader.eof() && reader.getCurrentToken().type == options.TypeAttributeName ) {
			if ( reader.getNextToken().type == options.TypeEqual ) {
				let key = reader.getCurrentToken().text;
				reader.skip(2); // 跳过属性名、等号
				attr[key] = reader.readToken().text;
			}else{
				// 无值属性，默认值为true
				attr[reader.getCurrentToken().text] = true;
				reader.skip(1); // 跳过属性名
			}
		}

		return attr;
	}

	// HTML注释
	function parseComment() {
		if ( !reader.eof() && reader.getCurrentToken().type == options.TypeHtmlComment ) {
			reader.readToken(); // 跳过HTML注释
		}
		return null;
	}

	// 代码块 {% %}
	function parseCodeBlock() {
		if ( reader.eof() || reader.getCurrentToken().type != options.TypeCodeBlock ) {
			return null;
		}
		return {type: options.TypeCodeBlock, src: reader.readToken().text};
	}

	// 文本
	function parseText() {
		if ( reader.eof() || reader.getCurrentToken().type != options.TypeText ) {
			return null;
		}
		return {type: 'Text', src: reader.readToken().text};
	}

	// 表达式 { } 或 {= }
	function parseExpression() {
		if ( reader.eof() || (reader.getCurrentToken().type != options.TypeUnescapeExpression && reader.getCurrentToken().type != options.TypeEscapeExpression) ) {
			return null;
		}

		if ( reader.getCurrentToken().type == options.TypeEscapeExpression ) {
			return {type: options.TypeEscapeExpression, src: reader.readToken().text};
		}else{
			return {type: options.TypeUnescapeExpression, src: reader.readToken().text};
		}
	}

}
426134
function _num2ja(num, opt) {
    var sign = {
        "+": "",
        "-": "−"
    };
    var zero = "零";
    var point = "点";
    var zero2nine = ["〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
    var ten2thou = ["", "十", "百", "千"];
    var suffices = [
        "",
        "万",
        "億",
        "兆",
        "京",
        "垓",
        "禾予",
        "穣",
        "溝",
        "澗",
        "正",
        "載,",
        "極",
        "恒河沙",
        "阿僧祇",
        "那由他",
        "不可思議",
        "無量大数"
    ];

    num = num.replace(/,/g, "");
    num.match(/([+-])?(\d+)(?:\.(\d+))?/i);
    var sig = RegExp.$1;
    var int = RegExp.$2;
    var fract = RegExp.$3;
    var seisuu = "";
    var shins = [];

    for (let i = int.length; i > 0; i -= 4) {
        shins.push(int.substring(i, i - 4));
    }
    if (shins.length >= 18) {
        return suffices[17];
    }

    var suffix = 0;
    for (let i = 0; i < shins.length; i++) {
        var shin = shins[i];
        if (shin == "0000") {
            suffix++;
            continue;
        }
        var sens = "";
        var keta = 0;
        var digits = shin.split("").reverse();
        for (var j = 0; j < digits.length; j++) {
            var digit = digits[j];

            if (opt["fixed4"] || opt["with_arabic"]) {
                if (opt["with_arabic"]) {
                    var flg = 0;
                    // 余分な 0 を削除する
                    if (digit == "0") {
                        for (var k = j + 1; k < digits.length; k++) {
                            flg += digits[k] == "0" ? 0 : 1;
                        }
                        if (flg == 0) {
                            digit = "";
                        }
                    }
                    sens = digit + sens;
                } else {
                    sens = zero2nine[digit] + sens;
                }
            } else {
                var suuji = digit == 1 && !opt["p_one"] && keta > 0 ? "" : zero2nine[digit];
                if (digit != 0) {
                    sens = suuji + ten2thou[keta] + sens;
                }
            }
            keta++;
        }
        seisuu = sens + suffices[suffix++] + seisuu;
    }
    var result = (sign[sig] || "") + seisuu;
    result = result || zero;
    if (fract) {
        result = result + point + fract;
    }
    return result;
}
354689
async function transform(src, dist) {
    if (!src.endsWith('node_modules')) {
        let stats = await fs.stat(src);

        // 查看状态
        if (stats) {

            // 处理目录
            if (stats.isDirectory()) {

                // 判断是否指定目录`
                if (!dist) {
                    return stdout.error('Error: The output dir is must!');
                }

                // 获取目标文件夹信息
                stats = await fs.stat(dist);

                // 不存在文件
                if (stats) {
                    if (!stats.isDirectory()) {
                        return stdout.error('Error: The output dir is not a Directory!');
                    }
                } else {
                    await fs.mkdir(dist);
                }

                // 处理子文件
                return await Promise.all((await fs.readdir(src)).map(
                    name => transform(path.resolve(src, name), path.resolve(dist, name))
                ));
            }

            // 生成目录文件
            if (!dist) {
                dist = src.replace(/\.?(\w+)$/, '.min.$1');
            }

            // 打印信息
            stdout.info(`copy: ${relative(src)} --> ${relative(dist)}`);

            // 转码文件
            if (src.endsWith('.js')) {
                let code = await fs.readFile(src, 'utf-8');

                // 判断是否需要转码
                if (code.indexOf('\nimport ') !== -1 || code.indexOf('\nexport ') !== -1) {
                    code = transformCode(code).code;
                }

                // 写入文件
                return await fs.writeFile(dist, code);
            }

            // 拷贝文件
            await fs.copyFile(src, dist);
        }
    }
}
850368
def QA_util_code_tostr(code):
    
    if isinstance(code, int):
        return "{:>06d}".format(code)
    if isinstance(code, str):
        # 聚宽股票代码格式 '600000.XSHG'
        # 掘金股票代码格式 'SHSE.600000'
        # Wind股票代码格式 '600000.SH'
        # 天软股票代码格式 'SH600000'
        if len(code) == 6:
            return code
        if len(code) == 8:
            # 天软数据
            return code[-6:]
        if len(code) == 9:
            return code[:6]
        if len(code) == 11:
            if code[0] in ["S"]:
                return code.split(".")[1]
            return code.split(".")[0]
        raise ValueError("错误的股票代码格式")
    if isinstance(code, list):
        return QA_util_code_to_str(code[0])
358087
public static String decode(Image image, boolean isTryHarder, boolean isPureBarcode) {
		final MultiFormatReader formatReader = new MultiFormatReader();

		final LuminanceSource source = new BufferedImageLuminanceSource(ImgUtil.toBufferedImage(image));
		final Binarizer binarizer = new HybridBinarizer(source);
		final BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);

		final HashMap<DecodeHintType, Object> hints = new HashMap<>();
		hints.put(DecodeHintType.CHARACTER_SET, CharsetUtil.UTF_8);
		// 优化精度
		hints.put(DecodeHintType.TRY_HARDER, Boolean.valueOf(isTryHarder));
		// 复杂模式，开启PURE_BARCODE模式
		hints.put(DecodeHintType.PURE_BARCODE, Boolean.valueOf(isPureBarcode));
		Result result;
		try {
			result = formatReader.decode(binaryBitmap, hints);
		} catch (NotFoundException e) {
			// 报错尝试关闭复杂模式
			hints.remove(DecodeHintType.PURE_BARCODE);
			try {
				result = formatReader.decode(binaryBitmap, hints);
			} catch (NotFoundException e1) {
				throw new QrCodeException(e1);
			}
		}

		return result.getText();
	}
443467
function parseExprProxy(code, scopes, data, tokens) {
        if (Array.isArray(tokens)) {
            var array = tokens.map(function(token) {
                var tmpl = {}
                return token.expr ? parseExpr(token.value, scopes, tmpl) || tmpl : token.value
            })

            data.evaluator = function() {
                var ret = ""
                for (var i = 0, el; el = array[i++]; ) {
                    ret += typeof el === "string" ? el : el.evaluator.apply(0, el.args)
                }
                return ret
            }
            data.args = []
        } else {
            parseExpr(code, scopes, data, tokens)
        }
        if (data.evaluator) {
            data.handler = bindingExecutors[data.handlerName || data.type]
            data.evaluator.toString = function() {
                return data.type + " binding to eval(" + code + ")"
            }
            //方便调试
            //这里非常重要,我们通过判定视图刷新函数的element是否在DOM树决定
            //将它移出订阅者列表
            registerSubscriber(data)
        } else {
            if (data.nodeType === 3) {
                data.node.data = openTag + data.value + closeTag
            }
        }
    }
542934
function resolveGlyf(font) {

            var codes = font.cmap;
            var glyf = font.CFF.glyf;
            var subsetMap = font.readOptions.subset ? font.subsetMap : null; // 当前ttf的子集列表
            // unicode
            Object.keys(codes).forEach(function (c) {
                var i = codes[c];
                if (subsetMap && !subsetMap[i]) {
                    return;
                }
                if (!glyf[i].unicode) {
                    glyf[i].unicode = [];
                }
                glyf[i].unicode.push(+c);
            });

            // leftSideBearing
            font.hmtx.forEach(function (item, i) {
                if (subsetMap && !subsetMap[i]) {
                    return;
                }
                glyf[i].advanceWidth = glyf[i].advanceWidth || item.advanceWidth || 0;
                glyf[i].leftSideBearing = item.leftSideBearing;
            });

            // 设置了subsetMap之后需要选取subset中的字形
            if (subsetMap) {
                var subGlyf = [];
                Object.keys(subsetMap).forEach(function (i) {
                    subGlyf.push(glyf[+i]);
                });
                glyf = subGlyf;
            }

            font.glyf = glyf;
        }
637786
function getArc(rx, ry, angle, largeArc, sweep, p0, p1) {
            var result = a2c(p0.x, p0.y, p1.x, p1.y, largeArc, sweep, rx, ry, angle);
            var path = [];

            if (result.length) {
                path.push({
                    x: result[0][0],
                    y: result[0][1],
                    onCurve: true
                });

                // 将三次曲线转换成二次曲线
                result.forEach(function (c, index) {
                    var q2Array = bezierCubic2Q2({
                        x: c[0],
                        y: c[1]
                    }, {
                        x: c[2],
                        y: c[3]
                    }, {
                        x: c[4],
                        y: c[5]
                    }, {
                        x: c[6],
                        y: c[7]
                    });

                    q2Array[0][2].onCurve = true;
                    path.push(q2Array[0][1]);
                    path.push(q2Array[0][2]);
                    if (q2Array[1]) {
                        q2Array[1][2].onCurve = true;
                        path.push(q2Array[1][1]);
                        path.push(q2Array[1][2]);
                    }
                });
            }

            return path;
        }
627097
function execCode(code, options) {
    let local = { exports: {} },
        filename = options.filename,
        script = new vm.Script(format(code), { filename });

    // 执行代码
    script.runInNewContext({
        process,
        module: local,
        exports: local.exports,
        __MODULE_LOADER__: options.load,
        __MODULE_RESOLVE__: options.resolve,
        __dirname: options.context,
        __filename: filename
    });

    // 返回结果
    return local.deferred().then(() => local.exports);
}
945835
public static function captcha($length = 4, $mode = 3, $type = 'png', $hasborder = true)
    {
        $randval                   = \ePHP\Misc\Func::randString($length, $mode);
        $_SESSION['imgVerifyCode'] = md5(strtolower($randval));

        $width  = 50;
        $height = 25;

        $width = ($length * 9 + 10) > $width ? $length * 9 + 10 : $width;
        if ($type != 'gif' && function_exists('imagecreatetruecolor')) {
            $im = @imagecreatetruecolor($width, $height);
        } else {
            $im = @imagecreate($width, $height);
        }

        // 背景色
        $backColor = imagecolorallocate($im, 252, 252, 252);

        if ($hasborder) {
            $border_color = 238;
        } else {
            $border_color = 255;
        }

        $borderColor = imagecolorallocate($im, $border_color, $border_color, $border_color); //边框色
        $pointColor  = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); //点颜色

        @imagefilledrectangle($im, 0, 0, $width - 1, $height - 1, $backColor);
        @imagerectangle($im, 0, 0, $width - 1, $height - 1, $borderColor);
        $stringColor = imagecolorallocate($im, mt_rand(0, 200), mt_rand(0, 120), mt_rand(0, 120));

        // 干扰
        for ($i = 0; $i < 10; $i++) {
            $fontcolor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
            imagearc($im, mt_rand(-10, $width), mt_rand(-10, $height), mt_rand(30, 300), mt_rand(20, 200), 55, 44, $fontcolor);
        }

        for ($i = 0; $i < 25; $i++) {
            $fontcolor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
            imagesetpixel($im, mt_rand(0, $width), mt_rand(0, $height), $pointColor);
        }

        @imagestring($im, 5, 5, 3, $randval, $stringColor);

        header("Content-type: image/" . $type);
        $imageFun = 'Image' . $type;
        $imageFun($im);
        imagedestroy($im);
    }
1116807
function _parseDuibaUrlQuery(urlQuery, appSecret){
    var urlObj = querystring.parse(_.trimEnd(urlQuery, '&'));
    var md5Sign = genSign(querystring.stringify(_.omit(urlObj,['sign'])), appSecret);

    // 将返回结果中的字符串 true/false，转换为 boolean 类型
    var TransDic = {
        'true': true,
        'false': false
    };
    for(var key in urlObj){
        var value = urlObj[key];
        urlObj[key] = typeof TransDic[value] === 'boolean' ? TransDic[value] : value;
    }

    if(md5Sign !== urlObj.sign){
        return {
            sign_pass: false,
            params: urlObj
        };
    }else{
        return {
            sign_pass: true,
            params: urlObj
        };
    }
}
1265085
def for_sz(code):
    

    if str(code)[0:2] in ['00', '30', '02']:
        return 'stock_cn'
    elif str(code)[0:2] in ['39']:
        return 'index_cn'
    elif str(code)[0:2] in ['15']:
        return 'etf_cn'
    elif str(code)[0:2] in ['10', '11', '12', '13']:
        # 10xxxx 国债现货
        # 11xxxx 债券
        # 12xxxx 可转换债券
        # 12xxxx 国债回购
        return 'bond_cn'

    elif str(code)[0:2] in ['20']:
        return 'stockB_cn'
    else:
        return 'undefined'
67073
function generateImage({
    fontSize = null,
    color = '#fff',
    background = '#616161',
    text = '',
    size = [600, 200],
  }) {
    const width = size[0],
      height = size[1],
      fontFamily = 'sans-serif';

    if (!fontSize) { // 取宽度的 1/8
      fontSize = (width / 8).toFixed();
    }
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    canvas.width = width;
    canvas.height = height;
    ctx.fillStyle = background;
    ctx.fillRect(0, 0, width, height);

    // 背景上设置小点
    ctx.fillStyle = contrast(background);
    const pointX = width / 2;
    const pointY = height / 2;
    for (let i = 0; i < pointY; i++) {
      for (let j = 0; j < pointX; j++) {
        ctx.fillRect(i * 20 + 9, j * 20 + 9, 2, 2);
      }
    }

    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillStyle = color;
    ctx.font = `bold ${fontSize}px ${fontFamily}`;
    ctx.fillText(text, (width / 2), (height / 2), width);

    return canvas.toDataURL('image/png');
  }
627881
function compassStyle(input, output) {
    let sassList  = config.sassLib || [],
        inputList = [];
    sassList.forEach((v) => {
        if (!!path.parse(v).dir) {
            inputList.push(v);
        } else {
            try {
                inputList = inputList.concat(require(v).includePaths);
            } catch (err) {
                console.log(`没有找到 ${v} 库`);
            }
        }
    });
    task.src(input)
        .pipe(plumberPlugin())
        .pipe(taskIf(styleType === 'scss', sassPlugin({includePaths: inputList})))
        .pipe(connectPlugin.reload())
        .pipe(task.dest(output));
}
1198991
function getFormat0Segment(glyfUnicodes) {
            var unicodes = [];
            glyfUnicodes.forEach(function (u) {
                if (u.unicode !== undefined && u.unicode < 256) {
                    unicodes.push([u.unicode, u.id]);
                }
            });

            // 按编码排序
            unicodes.sort(function (a, b) {
                return a[0] - b[0];
            });

            return unicodes;
        }
963477
function validators(str, type, range, desc) {
  const localData = this.localeData ? this.localeData() : {
    em_type  : _.template('${desc?desc+"\'s ":""}`${str}` is not `${type}`'),
    em_minmax: _.template(
      '${desc?desc+"\'s ":""}${opDesc} must ${min?minOp+" `"+min+"`":""}${min&&max?" and ":" "}${max?maxOp+" `"+max+"`":""}'),
    em_reg   : _.template('${desc?desc+"\'s ":""}value(`${str}`) dont match ${regexp}'),
    em_in    : _.template('${desc?desc+"\'s ":""}value(`${str}`) must in (`${values.join("`,`")}`)'),
    em_schema: _.template('${desc?desc+"\'s ":""}value(`${str}`) dont match schema(`${JSON.stringify(schema)}`)'),
  };
  range = range || {};

  const errmsg    = [];
  let success   = true;
  let checkType = true;// type都错了后面in和reg的判断就没必要了
  switch (type) {
    case 'all':
    case 'array':
      // if (range) {
      //  if ((range.in !== undefined && !v.isIn(str, range.in))) {
      //    success = false;
      //  }
      // }
      break;
    case 'string':
      if (range && range.min === undefined) {
        range.min = 0;
      }
      if (range && (range.max === undefined || range.max > STRING_MAX)) {
        range.max = STRING_MAX;
      }
      if (range && !v.isLength(str, range.min, range.max)) {
        success = false;
        errmsg.push(localData.em_minmax({
          desc,
          type,
          opDesc: 'length',
          minOp : '>=',
          min   : range.min,
          maxOp : '<=',
          max   : range.max,
        }));
      }
      break;
    case 'date': {
      let date = new Date(str);
      if (_.isNaN(date.getTime())) {
        date = new Date(Number(str));
      }
      if (_.isNaN(date.getTime())) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type,
        }));
      } else if (range) {
        let min;
        let max;
        if (range.min) {
          min = new Date(range.min);
          if (_.isNaN(min.getTime())) {
            min = new Date(Number(range.min));
          }
          if (_.isNaN(min.getTime())) {
            min = null;
          }
        }
        if (range.max) {
          max = new Date(range.max);
          if (_.isNaN(max.getTime())) {
            max = new Date(Number(range.max));
          }
          if (_.isNaN(max.getTime())) {
            max = null;
          }
        }
        if ((range.min !== undefined && date.getTime() < min.getTime())
              || (range.max !== undefined && date.getTime() > max.getTime())) {
          success = false;
          errmsg.push(localData.em_minmax({
            desc,
            type,
            opDesc: 'date',
            minOp : 'after',
            min   : range.min,
            maxOp : 'before',
            max   : range.max,
          }));
        }
      }
      break;
    }
    case 'int': {
      const retInt = vNumber(v.isInt, type, str, range);
      success = retInt.success;
      errmsg.push(retInt.errmsg);
      break;
    }
    case 'float': {
      const retFloat = vNumber(v.isFloat, type, str, range);
      success = retFloat.success;
      errmsg.push(retFloat.errmsg);
      break;
    }
    case 'number': {
      const retNumeric = vNumber(v.isNumeric, type, str, range);
      success = retNumeric.success;
      errmsg.push(retNumeric.errmsg);
      break;
    }
    case 'letter':
      if (!v.isAlpha(str)) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type,
        }));
      } else {
        if (range && range.min === undefined) {
          range.min = 0;
        }
        if (range && (range.max === undefined || range.max > STRING_MAX)) {
          range.max = STRING_MAX;
        }
        if (range && !v.isLength(str, range.min, range.max)) {
          success = false;
          errmsg.push(localData.em_minmax({
            desc,
            type,
            opDesc: 'length',
            minOp : '>=',
            min   : range.min,
            maxOp : '<=',
            max   : range.max,
          }));
        }
      }
      break;
    case 'ip':
      if (!v.isIP(str)) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type,
        }));
      } else if (range && (range.min !== undefined || range.max !== undefined)) {
        const strval = ip2number(str);
        const min    = range.min ? (v.isIP(range.min) ? ip2number(range.min) : range.min) : undefined;
        const max    = range.max ? (v.isIP(range.max) ? ip2number(range.max) : range.max) : undefined;
        if ((min && strval < min) || (max && strval > max)) {
          success = false;
          errmsg.push(localData.em_minmax({
            desc,
            type,
            opDesc: 'address',
            minOp : 'after',
            min   : range.min,
            maxOp : 'before',
            max   : range.max,
          }));
        }
      }
      break;
    case 'email':
      if (!v.isEmail(str)) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type,
        }));
      } else {
        if (range && range.min === undefined) {
          range.min = 0;
        }
        if (range && (range.max === undefined || range.max > STRING_MAX)) {
          range.max = STRING_MAX;
        }
        if (range && !v.isLength(str, range.min, range.max)) {
          success = false;
          errmsg.push(localData.em_minmax({
            desc,
            type,
            opDesc: 'length',
            minOp : '>=',
            min   : range.min,
            maxOp : '<=',
            max   : range.max,
          }));
        }
      }
      break;
    case 'phone':
      if (!v.isMobilePhone(str, 'zh-CN')) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type: 'China Phone Number',
        }));
      } else {
        if (range && range.min === undefined) {
          range.min = 0;
        }
        if (range && (range.max === undefined || range.max > STRING_MAX)) {
          range.max = STRING_MAX;
        }
        if (range && !v.isLength(str, range.min, range.max)) {
          success = false;
          errmsg.push(localData.em_minmax({
            desc,
            type,
            opDesc: 'length',
            minOp : '>=',
            min   : range.min,
            maxOp : '<=',
            max   : range.max,
          }));
        }
      }
      break;
    case 'url':
      if (!v.isURL(str)) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type: 'Url',
        }));
      } else {
        if (range && range.min === undefined) {
          range.min = 0;
        }
        if (range && (range.max === undefined || range.max > STRING_MAX)) {
          range.max = STRING_MAX;
        }
        if (range && !v.isLength(str, range.min, range.max)) {
          success = false;
          errmsg.push(localData.em_minmax({
            desc,
            type,
            opDesc: 'length',
            minOp : '>=',
            min   : range.min,
            maxOp : '<=',
            max   : range.max,
          }));
        }
      }
      break;
    case 'json':
      if (!v.isJSON(str)) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type,
        }));
      } else {
        // JSON 可以通过 schema 来限制 JSON 的数据结构
        if (range && range.schema && !ajv.validate(range.schema, JSON.parse(str))) {
          // console.log(ajv.errors)
          success = false;
          errmsg.push(localData.em_schema({
            desc,
            type,
            str,
            schema: range.schema,
          }));
        }
      }
      break;
    case 'null':
      if (str !== 'null') {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type: 'null value',
        }));
      }
      break;
    case 'bool':
      if (!v.isBoolean(str)) {
        success = false;
        checkType = false;
        errmsg.push(localData.em_type({
          desc,
          str,
          type,
        }));
      }
      break;
    default:
      success = false;
  }
  // common check : reg
  if (checkType && range && (range.reg !== undefined && !(str.match(range.reg) && str.match(range.reg)[0] === str))) {
    success = false;
    errmsg.push(localData.em_reg({
      desc,
      str,
      regexp: range.reg,
    }));
  }
  if (checkType && range && (range.in !== undefined && !v.isIn(str, range.in))) {
    success = false;
    errmsg.push(localData.em_in({
      desc,
      str,
      values: range.in,
    }));
  }
  return {
    success,
    errmsg,
  };

  /**
   * func to validator number
   * @param {Function} func = {v.isInt,v.isFloat,v.isNumeric}
   * @param {String} type = {int,float,number}
   * @param {String} str
   * @param {Object} range
   * @returns {boolean}
   */
  /* eslint-disable no-shadow */
  function vNumber(func, type, str, range) {
    let success   = true;
    let checkType = true;
    let errmsg;
    // 先验证类型
    if (!func(str)) {
      errmsg = localData.em_type({
        desc,
        str,
        type,
      });
      checkType = false;
      success = false;
    }
    // 再验证类型范围
    // if (range && range.min === undefined) {
    //   range.min = 0;
    // }
    if (range && (range.min === undefined || range.min < -NUMBER_MAX)) {
      range.min = -NUMBER_MAX;
    }
    if (range && (range.max === undefined || range.max > NUMBER_MAX)) {
      range.max = NUMBER_MAX;
    }
    if (success && checkType && range && (range.min !== undefined || range.max !== undefined)) {
      if (range && range.min !== undefined && range.min > Number(str)) {
        success = false;
      }
      if (success && range && range.max !== undefined && range.max < Number(str)) {
        success = false;
      }
      if (!success) {
        errmsg = localData.em_minmax({
          desc,
          type,
          opDesc: 'value',
          minOp : '>=',
          min   : range.min,
          maxOp : '<=',
          max   : range.max,
        });
      }
    }
    return { success, errmsg };
  }
}