Commit 1b96a8ac authored by 姜登's avatar 姜登

zmop_alipay正式服

parents
{
// 启动端口
"httpPort": 10031,
// 域名配置
"host": "http://t.51gjj.com",
"tj1": "http://tj1.51gjj.com:5118/",
// 正式服地址
"tj2": "http://tj2.51gjj.com:5118/",
// 测试服地址
"tj3": "http://tj3.51gjj.com:5118/",
"mongoUrl": "http://tv.51gjj.com",
"zhukeUrl": "http://tv.51gjj.com",
"hexinUrl": "http://td.51gjj.com",
"wlnUrl": "http://t.51gjj.com",
// 定时任务配置
"timeInterval": "00 00 00 * * *",
// log4js配置
"log4jsName": "zmop",
"log4jsConfig": {
"appenders": [
{
"type": "console"
},
{
"category": [
"console"
],
"type": "dateFile",
"filename": "./logs/",
"alwaysIncludePattern": true,
"pattern": "-yyyyMMdd.log"
}
],
"replaceConsole": true,
"levels": {
"console": "ALL"
}
},
"dbConfig": {
"connectionLimit": 50,
"host": "rm-bp1272001633qc0x9.mysql.rds.aliyuncs.com",
"user": "hexin",
"password": "gYUHszn9#q",
"database": "node_zm"
},
"dbConfigOcr": {
"connectionLimit": 50,
"host": "rm-bp1272001633qc0x9.mysql.rds.aliyuncs.com",
"user": "query",
"password": "5gqR2EQK",
"database": "ocr"
},
"dbConfigBG": {
"connectionLimit": 50,
"host": "rm-bp1272001633qc0x9.mysql.rds.aliyuncs.com",
"user": "query",
"password": "5gqR2EQK",
"database": "background"
},
"zmop_app_id":"300002663",
//"zmop_app_id": "300002565",
//"zmop_app_id": "300002796",
"entities": {
"300002565": "杭州巨业企业管理咨询有限公司",
"300002663": "杭州巨业企业管理咨询有限公司",
"300002796": "浙江容泽网络科技有限公司",
"2018051160085345": "",
"2018042460057138": "杭州盆钵信息技术有限公司",
"2018051560161652": "杭州靖乾网络科技有限公司"
}
}
[
{
"eventId": 5,
"desc": "每日登录",
"max_times": 1,
"times": 0,
"total": "0",
"complete": false
},
{
"eventId": 7,
"desc": "邀请好友",
"max_times": 0,
"times": 0,
"total": "0",
"complete": false
},
{
"eventId": 8,
"desc": "购买卡券",
"max_times": 3,
"times": 5,
"total": "100",
"complete": true
},
{
"eventId": 10,
"desc": "出售卡券",
"max_times": 5,
"times": 11,
"total": "220",
"complete": true
},
{
"date": "",
"delta": 0,
"complete": false,
"eventId": 3,
"desc": "社保认证"
},
{
"date": "2018-03-01",
"delta": -13,
"complete": false,
"eventId": 1,
"desc": "公积金认证"
}
]
const rp = require('request-promise'),
moment = require('moment'),
fs = require('fs'),
rsa = require('./rsa'),
orm = require('../orm'),
extend = require('extend'),
log = console.log.bind(console),
error = console.error.bind(console)
function build_transaction_id() {
let t = moment().format('YYYYMMDDHHmmssSSS')
let str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
while (t.length < 32) {
t += str[Math.round(Math.random() * (str.length - 1))]
}
return t
}
// 芝麻分
async function score(app_id, auth_token, user_id) {
let transaction_id = build_transaction_id()
let data = {
app_id: app_id,
method: 'zhima.credit.score.get',
format: 'JSON',
charset: 'utf-8',
sign_type: 'RSA2',
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
version: '1.0',
auth_token: auth_token,
biz_content: JSON.stringify({transaction_id: transaction_id, product_code: 'w1010100100000000001'}),
}
data.sign = rsa.sign(data, app_id)
let resp = await rp.post({
url: 'https://openapi.alipay.com/gateway.do',
json: true,
form: data
})
let row = {
transaction_id: transaction_id,
resp: JSON.stringify(resp),
open_id: user_id,
platform: 'alipay',
method: 'watch_list'
}
log('zmop_score resp: ', resp)
await orm.create_api_task(row)
if (rsa.verify(resp.sign, JSON.stringify(resp.zhima_credit_score_get_response), app_id)) {
return resp.zhima_credit_score_get_response
} else {
error('API-[ alipay/score ] 验签失败| app_id: ', app_id)
throw new Error('验签失败')
}
}
// 行业关注名单
async function watch_list(app_id, auth_token, user_id) {
let transaction_id = build_transaction_id()
let data = {
app_id: app_id,
method: 'zhima.credit.watchlistii.get',
format: 'JSON',
charset: 'utf-8',
sign_type: 'RSA2',
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
version: '1.0',
auth_token: auth_token,
biz_content: JSON.stringify({transaction_id: transaction_id, product_code: 'w1010100100000000022'}),
}
data.sign = rsa.sign(data, app_id)
let resp = await rp.post({
url: 'https://openapi.alipay.com/gateway.do',
json: true,
form: data
})
let row = {
transaction_id: transaction_id,
resp: JSON.stringify(resp),
open_id: user_id,
platform: 'alipay',
method: 'watch_list'
}
log('zmop_score resp: ', resp)
await orm.create_api_task(row)
if (rsa.verify(resp.sign, JSON.stringify(resp.zhima_credit_watchlistii_get_response), app_id)) {
return resp.zhima_credit_watchlistii_get_response
} else {
error('API-[ alipay/score ] 验签失败| app_id: ', app_id)
throw new Error('验签失败')
}
}
async function access_token(app_id, auth_code,) {
let data = {
app_id: app_id,
method: 'alipay.system.oauth.token',
charset: 'utf-8',
sign_type: 'RSA2',
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
version: '1.0',
grant_type: 'authorization_code',
code: auth_code
}
data.sign = rsa.sign(data, app_id)
let resp = await rp.post({
url: 'https://openapi.alipay.com/gateway.do',
json: true,
form: data
})
console.log('##### Access_token #####\n', resp)
if (resp.error_response) {
return resp.error_response
}
if (rsa.verify(resp.sign, JSON.stringify(resp.alipay_system_oauth_token_response), app_id)) {
console.log('access_token: ', resp)
return resp.alipay_system_oauth_token_response
} else {
error('API-[ alipay/access_token ] 验签失败| app_id: ', app_id)
throw new Error('验签失败')
}
}
// 支付用户账户
async function pay_forName(open_id,parter_name,appKey,cert_name) {
let transaction_id = build_transaction_id()
let data = {
app_id: '2018030502317524',
method: 'alipay.fund.trans.toaccount.transfer',
format: 'JSON',
charset: 'utf-8',
sign_type: 'RSA2',
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
version: '1.0',
biz_content: JSON.stringify({
out_biz_no: transaction_id,
payee_type: 'ALIPAY_USERID',
payee_account: open_id,
amount: '0.1',
payer_show_name: parter_name,
payee_real_name: cert_name
}),
}
await orm.insert_pay_task(transaction_id,appKey,open_id,cert_name);
data.sign = rsa.signpay(data, "2018030502317524")
let p = formatUrl(data)
let resp = await rp.post({
url: p.url,
form: p.execParams,
json: true
})
let row = {
transaction_id: transaction_id,
resp: JSON.stringify(resp),
open_id: open_id,
platform: 'alipay',
method: 'pay'
}
log('pay_forName resp: ', resp)
await orm.create_api_task(row)
return resp.alipay_fund_trans_toaccount_transfer_response;
}
module.exports = {
build_transaction_id,
access_token,
score,
pay_forName
}
function formatUrl(params) {
let requestUrl = 'https://openapi.alipay.com/gateway.do';
// 需要放在 url 中的参数列表
const urlArgs = [
'app_id', 'method', 'format', 'charset',
'sign_type', 'sign', 'timestamp', 'version',
'notify_url', 'return_url', 'auth_token', 'app_auth_token',
];
for (const key in params) {
if (urlArgs.includes(key)) {
const val = encodeURIComponent(params[key]);
requestUrl = `${requestUrl}${requestUrl.includes('?') ? '&' : '?'}${key}=${val}`;
// 删除 postData 中对应的数据
delete params[key];
}
}
return {execParams: params, url: requestUrl};
}
// access_token('2018042460057138','e58ed29be5664ef9b174f9b02776UX48').then(r=>{log(r)}).catch(e=>{log(e)})
\ No newline at end of file
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnv0wNm0RDlJFeOfYO2Ed
IOF1snkiUSqp5pvwX8z6+3kc/kOdhDfwrPUk4LWx+PmCiuSUyEsojBKDCwtK8kzH
4OrA3B4yG+NrjJ1060fRJsaxX+m95+2q0a7LIz2gXuAS4glWrx3i5rSDpOF9R9qw
hNjg3pExn7NZ2n/ro3cUT+Lauzqu0A9GzJ1TwbXt97XN4mx33sfbrT+NaS6UBCMS
3KUgA1kl/AUB34eWEyDbwAei/czMUfa73eeMFGqacXESEJl/qKdulB6XPEDV0Msk
tcqbL+qx8l0jFJyh9OW829l7Pu2lBqFLk/owp9HztuHSX7N9kvO1wPu+dHk/Mgdj
FQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA0y38Y65ulJhzPm4BZLZ0UK98Qcmz6munK7kZTLW7il2MvErc
DgmJ2faajxDyMDKh7fDQTcj2ZlvuwrKK9UpLfnSg5444LYSZpFTkySydQe+VPBC/
/MB9bZ/JSVotM4bEjoVdbCrs4bk3A+CjTMkq8V8WlWOBOX7HwLd6kIyfR2QrUO5q
b7v8C1Jl0B81IRkCHNTZ91rpVDzcpJkbTzVTDeC/Ydsc0KQL3FAFe+nl0+pkLyEs
H/Wr1LV0d5v63wE1Dn10CYRQ9n6tsTceNPcd2NRrWTyrczKULxtf8ylds116UCDo
bxDFUx4xr44z4qyjz4omc3zUTe5vZ7lCFSKpsQIDAQABAoIBABk+U/8uaLWGi7AY
wj3huYGzmGzcyY7qE2+cjrOmvaZKjHotkKR062+MlOkpI2ozgzvIH35M2Xde4emQ
IiA0I1YYZuuHCpwWT69fHoIVvS6WjwZBElIKSHQEN7F3ABQ6teA7fPFjKDHLTBJA
lgSlv2Ze8XomDNpsl0AoLpR82sVTsmr3wjCOPxrF/b6waXZKf7GU7wo3erziJ8gr
2qLZzxgjNaMWYIAeqFiaSp0orTLDMR06oPqOlp/vxMvIUpOlPFnvfnha2FGWAmJj
QRrENSagKO2/lLo+mvZM8GG7yuLSfH4+obMf5805j2EKdTGBHSkgAhS1J6nLIJVe
Gy4axIECgYEA6kBzkGenbCXHgeB1+PpHcgwjZsMFqDBgV6bRH2J+msGTgLviBwhj
n6qMuYJdsv2eOSHUEAtcZNVn9fsZrbg8giaGF65cFmpQZKuDE1AqfdvHePM0W8Nn
uaUzz1UjGSqhMl2N/GHoKfBMCrljnvwwJ4lbphwhzMl4yiJaWmE5U8kCgYEA5skr
quZG5b3FK85CS0qR10z/EqLElxJRF9X9vuyiQ+aIRMg4GhRajMQTDo7YIXh/rD9O
myjO1KwXa62vhB3zjy7ytQyfFuoWPDMSf6860W+Tuc2a9HSJQxQzjUMbv+gLlJYf
orrSoiVoMK4VdsW7mQXl+2IqEMRaHktcZ1YgiqkCgYEA38WT37V09NWeIQ5YA/Cq
AWNhChBwvfsAfZrImE+Rm6ohis9wGsHD0UmtxqSnd43Y8MDFAFKp/1TxS8SEAjRF
8Rp16/dO1sbWZ2SEARYKkVI62eqR8LrYwjnzJTMyJR9Y/3DpatfoXO/E5FW2ubA1
G/+WAjdLfoJTldx9LWtExSkCgYA3RAlu/YIQ1ib3XIdHnG3cTxXuEohdXQeKW7ZO
GECrXfNX9VJp/GHKv9GIdPCQ41g/mVFrmpQdHbDmGkujqcB/k1CPxpv6UshMVjah
2QaOzNdlcTUgQR/1rkrCE0X76MeNJ34f6/kw1yBiN+3v6V4JQP5X+qP0K/EgvA8+
t8NHMQKBgAcoUbBKOa5njQ9tppJK3zML2Z/miJIaXwaX/9A7Wtpdqwa/0tSa7sBQ
2lYRqMV54t1/L0DqSeYzN59yOUwmX6DBsThiwx0Vg5z8WI5aVYT+690MnL0VtHLj
jlhcBNqMxRXjH7M1Fyq+i3NjBkRutthMGO66ZEjH+BKJJ7CU2DyC
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv3FVEfUyu1O1th+9JeYO
6zvuxl0OVscCi9Rx9QiPYyJAugCzQYBguk+tqkNgYI00NIz/y99NsulyjCGkLnlZ
lSolKrefjKVSSWxiNcy3yA0loLDUturIxg2kR13uSzm46fPIX3fxRc37n3Y7hIio
pE+3NCUAJGnIkQFStlvVKUoh65zkf7+sygS8l6u338THsLEcq0WBABx36NrGqxP9
Olus12Jvc9MGhrgPo4Dj0OUd8IbamHDUYPDPF2oc0a5huMKNjeTeJuJEK42k5DUj
Gdn4ZLS2AQowimKt5qwKjMC2sFcqRH1hTZD9mthuNE0PXfj61Nw5KKItob5Que53
EQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsw0WUygOnvIYW6bIJaK4
WzNBwF7NhIqTTk7dew/Of2PQto+iEmv2o1Tyc53gLjvMXSbG46nxsEvyXH19OPb+
A74j4LCnQl4Mg8yph2689rJnHWmdmqvw+8A6/XcCq7rjN2LlQhu5ibya3Gi41+uy
PPUPuc2B1tL0JTydxIt8bGg3wCLXmdpHxJJ8aegBRd1+3NkfEy+53/maBujmjni/
HqJ/nsFoqJ2CjRv0Oo6hSKHi50k5wc85u4+Mp0PY0FHP8PJ6qw6vUjakiWBs16vH
0uA+/JEgAftMbpvFOuM70/5blUFg6KnMPnynbD4jIwMYpsNVJSCJOmjUERZZF2n3
ewIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA0y38Y65ulJhzPm4BZLZ0UK98Qcmz6munK7kZTLW7il2MvErc
DgmJ2faajxDyMDKh7fDQTcj2ZlvuwrKK9UpLfnSg5444LYSZpFTkySydQe+VPBC/
/MB9bZ/JSVotM4bEjoVdbCrs4bk3A+CjTMkq8V8WlWOBOX7HwLd6kIyfR2QrUO5q
b7v8C1Jl0B81IRkCHNTZ91rpVDzcpJkbTzVTDeC/Ydsc0KQL3FAFe+nl0+pkLyEs
H/Wr1LV0d5v63wE1Dn10CYRQ9n6tsTceNPcd2NRrWTyrczKULxtf8ylds116UCDo
bxDFUx4xr44z4qyjz4omc3zUTe5vZ7lCFSKpsQIDAQABAoIBABk+U/8uaLWGi7AY
wj3huYGzmGzcyY7qE2+cjrOmvaZKjHotkKR062+MlOkpI2ozgzvIH35M2Xde4emQ
IiA0I1YYZuuHCpwWT69fHoIVvS6WjwZBElIKSHQEN7F3ABQ6teA7fPFjKDHLTBJA
lgSlv2Ze8XomDNpsl0AoLpR82sVTsmr3wjCOPxrF/b6waXZKf7GU7wo3erziJ8gr
2qLZzxgjNaMWYIAeqFiaSp0orTLDMR06oPqOlp/vxMvIUpOlPFnvfnha2FGWAmJj
QRrENSagKO2/lLo+mvZM8GG7yuLSfH4+obMf5805j2EKdTGBHSkgAhS1J6nLIJVe
Gy4axIECgYEA6kBzkGenbCXHgeB1+PpHcgwjZsMFqDBgV6bRH2J+msGTgLviBwhj
n6qMuYJdsv2eOSHUEAtcZNVn9fsZrbg8giaGF65cFmpQZKuDE1AqfdvHePM0W8Nn
uaUzz1UjGSqhMl2N/GHoKfBMCrljnvwwJ4lbphwhzMl4yiJaWmE5U8kCgYEA5skr
quZG5b3FK85CS0qR10z/EqLElxJRF9X9vuyiQ+aIRMg4GhRajMQTDo7YIXh/rD9O
myjO1KwXa62vhB3zjy7ytQyfFuoWPDMSf6860W+Tuc2a9HSJQxQzjUMbv+gLlJYf
orrSoiVoMK4VdsW7mQXl+2IqEMRaHktcZ1YgiqkCgYEA38WT37V09NWeIQ5YA/Cq
AWNhChBwvfsAfZrImE+Rm6ohis9wGsHD0UmtxqSnd43Y8MDFAFKp/1TxS8SEAjRF
8Rp16/dO1sbWZ2SEARYKkVI62eqR8LrYwjnzJTMyJR9Y/3DpatfoXO/E5FW2ubA1
G/+WAjdLfoJTldx9LWtExSkCgYA3RAlu/YIQ1ib3XIdHnG3cTxXuEohdXQeKW7ZO
GECrXfNX9VJp/GHKv9GIdPCQ41g/mVFrmpQdHbDmGkujqcB/k1CPxpv6UshMVjah
2QaOzNdlcTUgQR/1rkrCE0X76MeNJ34f6/kw1yBiN+3v6V4JQP5X+qP0K/EgvA8+
t8NHMQKBgAcoUbBKOa5njQ9tppJK3zML2Z/miJIaXwaX/9A7Wtpdqwa/0tSa7sBQ
2lYRqMV54t1/L0DqSeYzN59yOUwmX6DBsThiwx0Vg5z8WI5aVYT+690MnL0VtHLj
jlhcBNqMxRXjH7M1Fyq+i3NjBkRutthMGO66ZEjH+BKJJ7CU2DyC
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAuV742wnO6btJsiQ53AF1rY8HMDaUPhpoTpjGIyKvPbE3PF1c
rYsjmFyQCrdLePcXSS9YCIXi9QDElvkNsIF7+YB7MHcS1ejlw8k3/PeewRzRQGPG
I4rda86cWB1qNj6g9Eq/GnHnKSMc7rEoB1LHdeBCO+XtR0YmkYZYoXVJ5T+iLgR3
zfLhXuICZaodSuTdSFA9R623OnSxoanYc/yQR7sVEXHJRI7gkMIlKU1IYzUDvIUM
BUB+1nY/gPApowxWe7Yq5ARz27UxtaJ3WWlPWSnLbgv2Hlg/0Zs1MaNxptHxL4fw
1aV8vm9RX0zaCgPQsoDdTo8fO2/7yYvBnT9tqwIDAQABAoIBAF9dkMF/RkfQ5pUT
NgENbzEfCB+xtIpOo6LrzeN9kJI4faY8kdVmY6Wa2S/qJJXS6NPp22xnFN/eyUSy
VGyd8N3nT3kbiUErVClpd7hY2/+Vh8GMkv7uDgPMg3qBh4boqX2EhtRgDQCI4/WY
hnNeDueBvBF8tJmaaXUsnKRT5vRc7C9aF6lJVTAcdZ+ZtNtPPMwyugLp9XFdcaTR
wBoz1ma+1BkYnheV0WWru0S+YQJGquZ1DHKV+VAVPVWZZg/y5wBQmv3nD4eU+grx
V2pLQnesWhLvWdZvoBSqxc+LvknOcccIZLYjF9GKkJYiSh6YO9jJ45VgbhGcDVtD
+g+aOYECgYEA3gqSOIrt/ZXahbukoUr2WnX+hIo0fZrIWslYuhBPR7nWcfA9Yo5i
fpd9VwzIePghkmhs0bRYIyK+3RII4rxvIUJsq7YkMlGa14/aIMV9FJQq22brOAjB
/tW5qiUNjx/jk7pmMy2EVOC0iaIuoEzkDzCmQEiKGn6Kz1YsxjuCGbECgYEA1bis
eflr+0/lVh9Z2jv5oEk6A+WQXYccek0wvGGkeJzLzWB2dwzDQpLZGeomjf5RktHN
T128gLWE7Uy+y2aXcgC1Uf97vxMS5hltFbUZLGGwx2V7F2SSWOJJZPImj1vMWjJU
KMHbA3IybVksriz+gtfpxA5m6NdsdJZ4XMFoOBsCgYB7PjLa34IpdrvL7tL6E7mZ
jFSxDGUGMptyiL+Oxu66SRQWOdpYkd9plHwljRrYyiEYOo3r98XT+r0lx5TXBPBJ
7ayTwo1kwJbJfzb7aaJ7gaIoFYAJohLLd6WOIvLbtj+DB7siPOlukyqiGjr3Dran
F8GvfJPrEMHLQ3GmtfEIgQKBgQDBk+OlFyWXG2a9+ueHo4sWgzzpCqUYEajZndDm
0AoItPxjqVujuQui4R+DOXJyake4lA9CM8TpT4B272xhDytdNwcEnkOXbc9QWvdT
EhUa/eEAugojxhRILa4MoMgMUTlm+O8Be5TEKktCf+LYYCimmqpBykmr3HN/pkqe
uQ+MwQKBgQDa0xQX7Db7ndmwQDpGrFK5p1IN29H8m/c/TDsI7e/4ruOeaLHaKifa
fL6v/axQnLvIW8ksUw45mBONaHsdAkaka5bF25zTIx9baHnfrcMr8Fy030vs/1Td
uMisDrGmxEbDlZnFeUUDW7VM9/zIEc/D5vZAZQnRXdFbQA4ta0zRHQ==
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnv0wNm0RDlJFeOfYO2Ed
IOF1snkiUSqp5pvwX8z6+3kc/kOdhDfwrPUk4LWx+PmCiuSUyEsojBKDCwtK8kzH
4OrA3B4yG+NrjJ1060fRJsaxX+m95+2q0a7LIz2gXuAS4glWrx3i5rSDpOF9R9qw
hNjg3pExn7NZ2n/ro3cUT+Lauzqu0A9GzJ1TwbXt97XN4mx33sfbrT+NaS6UBCMS
3KUgA1kl/AUB34eWEyDbwAei/czMUfa73eeMFGqacXESEJl/qKdulB6XPEDV0Msk
tcqbL+qx8l0jFJyh9OW829l7Pu2lBqFLk/owp9HztuHSX7N9kvO1wPu+dHk/Mgdj
FQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0y38Y65ulJhzPm4BZLZ0
UK98Qcmz6munK7kZTLW7il2MvErcDgmJ2faajxDyMDKh7fDQTcj2ZlvuwrKK9UpL
fnSg5444LYSZpFTkySydQe+VPBC//MB9bZ/JSVotM4bEjoVdbCrs4bk3A+CjTMkq
8V8WlWOBOX7HwLd6kIyfR2QrUO5qb7v8C1Jl0B81IRkCHNTZ91rpVDzcpJkbTzVT
DeC/Ydsc0KQL3FAFe+nl0+pkLyEsH/Wr1LV0d5v63wE1Dn10CYRQ9n6tsTceNPcd
2NRrWTyrczKULxtf8ylds116UCDobxDFUx4xr44z4qyjz4omc3zUTe5vZ7lCFSKp
sQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA0y38Y65ulJhzPm4BZLZ0UK98Qcmz6munK7kZTLW7il2MvErc
DgmJ2faajxDyMDKh7fDQTcj2ZlvuwrKK9UpLfnSg5444LYSZpFTkySydQe+VPBC/
/MB9bZ/JSVotM4bEjoVdbCrs4bk3A+CjTMkq8V8WlWOBOX7HwLd6kIyfR2QrUO5q
b7v8C1Jl0B81IRkCHNTZ91rpVDzcpJkbTzVTDeC/Ydsc0KQL3FAFe+nl0+pkLyEs
H/Wr1LV0d5v63wE1Dn10CYRQ9n6tsTceNPcd2NRrWTyrczKULxtf8ylds116UCDo
bxDFUx4xr44z4qyjz4omc3zUTe5vZ7lCFSKpsQIDAQABAoIBABk+U/8uaLWGi7AY
wj3huYGzmGzcyY7qE2+cjrOmvaZKjHotkKR062+MlOkpI2ozgzvIH35M2Xde4emQ
IiA0I1YYZuuHCpwWT69fHoIVvS6WjwZBElIKSHQEN7F3ABQ6teA7fPFjKDHLTBJA
lgSlv2Ze8XomDNpsl0AoLpR82sVTsmr3wjCOPxrF/b6waXZKf7GU7wo3erziJ8gr
2qLZzxgjNaMWYIAeqFiaSp0orTLDMR06oPqOlp/vxMvIUpOlPFnvfnha2FGWAmJj
QRrENSagKO2/lLo+mvZM8GG7yuLSfH4+obMf5805j2EKdTGBHSkgAhS1J6nLIJVe
Gy4axIECgYEA6kBzkGenbCXHgeB1+PpHcgwjZsMFqDBgV6bRH2J+msGTgLviBwhj
n6qMuYJdsv2eOSHUEAtcZNVn9fsZrbg8giaGF65cFmpQZKuDE1AqfdvHePM0W8Nn
uaUzz1UjGSqhMl2N/GHoKfBMCrljnvwwJ4lbphwhzMl4yiJaWmE5U8kCgYEA5skr
quZG5b3FK85CS0qR10z/EqLElxJRF9X9vuyiQ+aIRMg4GhRajMQTDo7YIXh/rD9O
myjO1KwXa62vhB3zjy7ytQyfFuoWPDMSf6860W+Tuc2a9HSJQxQzjUMbv+gLlJYf
orrSoiVoMK4VdsW7mQXl+2IqEMRaHktcZ1YgiqkCgYEA38WT37V09NWeIQ5YA/Cq
AWNhChBwvfsAfZrImE+Rm6ohis9wGsHD0UmtxqSnd43Y8MDFAFKp/1TxS8SEAjRF
8Rp16/dO1sbWZ2SEARYKkVI62eqR8LrYwjnzJTMyJR9Y/3DpatfoXO/E5FW2ubA1
G/+WAjdLfoJTldx9LWtExSkCgYA3RAlu/YIQ1ib3XIdHnG3cTxXuEohdXQeKW7ZO
GECrXfNX9VJp/GHKv9GIdPCQ41g/mVFrmpQdHbDmGkujqcB/k1CPxpv6UshMVjah
2QaOzNdlcTUgQR/1rkrCE0X76MeNJ34f6/kw1yBiN+3v6V4JQP5X+qP0K/EgvA8+
t8NHMQKBgAcoUbBKOa5njQ9tppJK3zML2Z/miJIaXwaX/9A7Wtpdqwa/0tSa7sBQ
2lYRqMV54t1/L0DqSeYzN59yOUwmX6DBsThiwx0Vg5z8WI5aVYT+690MnL0VtHLj
jlhcBNqMxRXjH7M1Fyq+i3NjBkRutthMGO66ZEjH+BKJJ7CU2DyC
-----END RSA PRIVATE KEY-----
const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const NodeRSA = require('node-rsa');
// def sign(privatekey, data):
// '''
// 加签
// :param privatekey:私钥文件路径
// :param data:要加签的数据
// :return string:签名
// '''
// signEVP = EVP.load_key(privatekey)
// signEVP.sign_init()
// signEVP.sign_update(data)
// result = signEVP.sign_final()
// return base64.b64encode(result)
const private_key = fs.readFileSync(path.join(__dirname, 'keys/private_key.pem')).toString()
const private_pay_key = fs.readFileSync(path.join(__dirname, 'keys/private_pay_key.pem')).toString()
const ant_public_key = {}
ant_public_key['2018042460057138'] = fs.readFileSync(path.join(__dirname, 'keys/2018042460057138_ant_public_key.pem')).toString()
ant_public_key['2018051160085345'] = fs.readFileSync(path.join(__dirname, 'keys/2018051160085345_ant_public_key.pem')).toString()
ant_public_key['2018051560161652'] = fs.readFileSync(path.join(__dirname, 'keys/2018051560161652_ant_public_key.pem')).toString()
//params= URLEncode(Base64(RSAEncrypt(param1=URLEncode(param1value)&param2=URLEncode(param2value))))
// 加签
// :param privatekey:私钥文件路径
// :param data:要加签的数据
// :return string:签名
function RSAEncrypt(data) {
let str = params2str(data)
let key = new NodeRSA(private_key)
key.setOptions({encryptionScheme: 'pkcs1'});
let encrypted = key.encrypt(str, 'base64')
return encrypted
}
function RSADecrypt(str) {
let key = new NodeRSA(private_key)
key.setOptions({encryptionScheme: 'pkcs1'});
let encrypted = key.decrypt(str, 'utf8')
return encrypted
}
// 转换业务参数为str
function params2str(data) {
let str = ''
for (let k of Object.keys(data).sort()) {
let v = data[k]
if (Object.prototype.toString.call(v) === '[object Object]') {
v = JSON.stringify(v)
}
str += k + '=' + v + '&'
}
return str.slice(0, str.length - 1)
}
// str 转为 json
function str2params(str) {
let ret = {}
let arr = str.split('&')
for (let item of arr) {
let index = item.indexOf('=')
ret[item.slice(0, index)] = decodeURIComponent(item.slice(index + 1))
}
return ret
}
// 加签
function sign(data) {
let str = params2str(data)
let sign = crypto.createSign('RSA-SHA256')
sign.update(str)
return sign.sign(private_key, 'base64')
}
// 加签
function signpay(data) {
let str = params2str(data)
let sign = crypto.createSign('RSA-SHA256')
sign.update(str)
return sign.sign(private_pay_key, 'base64')
}
// 验签
// sign_value: 签名,
// str: 待验签的数据
function verify(sign_value, str, app_id) {
var verify = crypto.createVerify('RSA-SHA256');
verify.update(str);
return verify.verify(ant_public_key[app_id], sign_value, 'base64')
}
// let resp = { alipay_system_oauth_token_response:
// { access_token: 'authzmaBd3a9fe8c041843cdbd01cb6ba1c4fX48',
// alipay_user_id: '20881049053508330572421081610248',
// expires_in: 31536000,
// re_expires_in: 31622400,
// refresh_token: 'authzmaB6991f8567e38405c85803d5023550X48',
// user_id: '2088802182470482' },
// sign: 'LriQN3gcY177GL1SPqGqsnD1YuJdR9qKg4fSaS8V3KNXF/Fi2I0eDSK0t8o0lAHB3AgHF6YyD7+VwtO/pKc9yZpbTIVSrCm2kFaEJGaJgG7F7sh+CNEZnNE69usW50Y7LQUGPy8olr2+LnE6eyM4xR9KlYDTCP4RA+K0OlFSKz8V0ylwgC0H9nij+le3pyQZdESarLGMuZk24+a49lYgZfjsnI6rf2DkrCN1/0RNNuIGqS2XtXBuQCY15gzBIyY9ux65YIvEoc+LUKTyNOpXvBeQYP9JzkQqc7Nkh1f6lozcrNtoxdP8ltZU/dW3/2TpIQ4oQ1J2ztezmamZvTxjDg==' }
// if (verify(resp.sign, JSON.stringify(resp.alipay_system_oauth_token_response), '2018051560161652')) {
// console.log('success')
// } else {
// console.log('error')
// }
// let a = {
// apiname: 'com.alipay.account.auth',
// method: 'alipay.open.auth.sdk.code.get',
// app_id: 2018042460057138,
// app_name: 'mc',
// biz_type: 'openservice',
// pid: 2088031974398640,
// product_id: 'APP_FAST_LOGIN',
// scope: 'kuaijie',
// target_id: 'kkkkk091125',
// auth_type: 'AUTHACCOUNT',
// sign_type: 'RSA2',
// }
// a.sign = encodeURIComponent(sign(a))
// console.log(sign('app_id=2018042460057138&amp;charset=utf-8&amp;code=1558df8e1bd2409dafeb9f428075SX48&amp;format=JSON&amp;grant_type=authorization_code&amp;method=alipay.system.oauth.token&amp;sign_type=RSA2&amp;timestamp=2018-05-03 16:40:45&amp;version=1.0'));
module.exports = {
signpay,
sign,
verify,
RSAEncrypt,
RSADecrypt,
params2str,
str2params
}
const ZmopClient = require('./zmop_client/zmop_client'),
utils = require('./utils'),
Alipay = require('./alipay/alipay'),
orm = require('./orm'),
moment = require('moment'),
rp = require('request-promise'),
request = require('request'),
http = require('http'),
https = require('https'),
URL = require('url'),
Zmop = new ZmopClient()
// async function is_authed(cert_no, cert_name) {
// try {
// let auth_info = JSON.parse(await Zmop.authed(cert_no, cert_name))
// if (auth_info.success && auth_info.authorized) {
// // 获取芝麻分, 通知任务成功
// // auth_info: {"success":true,"authorized":true,"open_id":"268806822853700342467205358"}
// return auth_info.open_id
// }
// return false
// } catch (e) {
// return false
// }
// }
// setTimeout(async () => {
// let p = {
// platform: 'alipay',
// app_id: '2018051160085345',
// access_token: 'authzmaB81ec3d1b20034e78bc5d343e3944aB48',
// open_id: '2088802182470482'
// }
// try {
// let d = await save_brief_score(p, 650)
// console.log(d)
// } catch (e) {
// console.log(e)
// }
// }, 0)
async function save_watch_list(task) {
try {
let list = ''
if (task.platform == 'alipay') {
list = await Alipay.watch_list(task.app_id, task.access_token, task.open_id)
if (list.code == '20001') {
console.log('[ alipay-api ]- watch_list error: ', list)
throw new Error('鉴权失败')
}
if (list.code != '10000') {
console.log('[ alipay-api ]- watch_list error: ', list)
throw new Error('系统错误, 请稍后再试')
}
} else {
list = await Zmop.watch_list(task.app_id, task.open_id)
if (!list.success) {
if (list.error_message == '鉴权失败') {
throw new Error('鉴权失败')
}
throw new Error('获取行业关注名单失败')
}
}
let row = {
id: list.biz_no,
open_id: task.open_id,
platform: task.platform,
is_matched: list.is_matched ? 1 : 0,
details: JSON.stringify(list.details || []),
create_time: moment().format('YYYY-MM-DD HH:mm:ss')
}
await orm.create_watch_list(row, 'zmop_watch_list')
delete row.id
delete row.platform
delete row.open_id
return {is_matched: list.is_matched, details: list.details || []}
} catch (e) {
if (e.message != '鉴权失败') {
// sendWarnMsg('13107706693', '获取行业关注失败')
}
throw e
}
}
async function save_score(task) {
try {
let score = ''
if (task.platform == 'alipay') {
score = await Alipay.score(task.app_id, task.access_token, task.open_id)
if (score.code == '20001') {
console.log('[ alipay-api ]- score error: ', score)
throw new Error('鉴权失败')
}
if (score.code != '10000') {
throw new Error(score.sub_msg)
}
} else {
score = await Zmop.score(task.app_id, task.open_id)
if (!score.success) {
if (score.error_message == '鉴权失败') {
throw new Error('鉴权失败')
}
throw new Error('获取芝麻分失败')
}
}
let row = {
id: score.biz_no,
open_id: task.open_id,
platform: task.platform,
score: score.zm_score,
which_month: utils.which_month(),
create_time: moment().format('YYYY-MM-DD HH:mm:ss')
}
await orm.create(row, 'zmop_score')
delete row.id
delete row.platform
delete row.open_id
return row
} catch (e) {
if (e.message != '鉴权失败') {
// sendWarnMsg('13107706693', '获取芝麻分失败')
}
throw e
}
}
// 芝麻分普惠版
async function save_brief_score(task, admit_score) {
try {
let score = ''
if (task.platform == 'alipay') {
score = await Alipay.brief_score(task.app_id, task.open_id, admit_score)
if (score.code == '20001') {
console.log('[ alipay-api ]- brief_score error: ', score)
throw new Error('鉴权失败')
}
if (score.code != '10000') {
throw new Error(score.sub_msg)
}
} else {
throw new Error('请选择通过支付宝APP授权')
}
return {
is_admittance: score.is_admittance,
admit_score: admit_score,
create_time: moment().format('YYYY-MM-DD HH:mm:ss'),
}
} catch (e) {
if (e.message != '请选择通过支付宝APP授权') {
// sendWarnMsg('13107706693', '获取芝麻分普惠版失败')
}
throw e
}
}
// 行业关注名单普惠版
async function save_brief_watch_list(task) {
try {
let list = ''
if (task.platform == 'alipay') {
list = await Alipay.brief_watch_list(task.app_id, task.open_id)
if (list.code == '20001') {
console.log('[ alipay-api ]- brief_watch_list error: ', list)
throw new Error('鉴权失败')
}
if (list.code != '10000') {
throw new Error(list.sub_msg)
}
} else {
throw new Error('请选择通过支付宝APP授权')
}
return {
level: list.level,
create_time: moment().format('YYYY-MM-DD HH:mm:ss'),
}
} catch (e) {
if (e.message != '请选择通过支付宝APP授权') {
// sendWarnMsg('13107706693', '获取芝麻分普惠版失败')
}
throw e
}
}
async function notify_result(state, status, error_message) {
try {
if (status == 'true') {
status = 'success'
} else {
status = 'fail'
}
let body = {
order_id: state.order_id,
status: status,
msg: error_message
}
if (state.extras) {
body.extras = state.extras
}
let len = Buffer.byteLength(JSON.stringify(body), 'utf8')
let url = decodeURIComponent(state.redirect)
let content = URL.parse(url);
content.method = 'POST'
content.headers = {
'content-type': 'application/json',
'content-length': len,
'encoding': 'UTF-8'
}
console.log(content);
if (content.protocol == 'https:') {
request_https(content, body)
} else {
request_http(content, body)
}
} catch (e) {
console.error('## ERROR ## notify_result ######\n ', state, '\n', e.message)
}
}
function request_http(options, data) {
var req = http.request(options, function (res) {
//console.log('STATUS: ' + res.statusCode);
//console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('UTF-8');
res.on('data', function (chunk) {
console.log('###### NOTIFY SUCCESS #### :BODY: ' + chunk, JSON.stringify(data));
});
res.on('end', function () {
console.log('###### NOTIFY SUCCESS #### :END: ', options.href);
});
});
req.on('error', function (chunk) {
console.log('###### NOTIFY SUCCESS #### :ERROR: ' + chunk, JSON.stringify(data));
});
req.write(JSON.stringify(data));
req.end();
}
function request_https(options, data) {
var req = https.request(options, function (res) {
//console.log('STATUS: ' + res.statusCode);
//console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('UTF-8');
res.on('data', function (chunk) {
console.log('###### NOTIFY SUCCESS #### :BODY: ' + chunk, JSON.stringify(data));
});
res.on('end', function () {
console.log('###### NOTIFY END #### :END: ', options.href);
});
});
req.on('error', function (chunk) {
console.log('###### NOTIFY SUCCESS #### :ERROR: ' + chunk, JSON.stringify(data));
});
req.write(JSON.stringify(data));
req.end();
}
// let state = {
// appKey: '6911223ABDBF4A0588E3A0B64E18ED3A',
// order_id: '20180524100241444pJOmyJAcarpfguU',
// channel: 'H5',
// redirect: 'https://ti.51gjj.com/zmop/auth'
// }
//
// let p = {
// open_id: '268806822853700383571348420',
// error_message: '操作成功',
// state: 'eyJhcHBLZXkiOiI2OTExMjIzQUJEQkY0QTA1ODhFM0EwQjY0RTE4RUQzQSIsIm9yZGVyX2lkIjoiMjAxODA1MjQxMDAyNDE0NDRwSk9teUpBY2FycGZndVUiLCJjaGFubmVsIjoiSDUiLCJyZWRpcmVjdCI6Imh0dHA6Ly90dC41MWdqai5jb206MTAwMzAvZGVtb2g1L2NiUmVzdWx0In0=',
// error_code: 'SUCCESS',
// app_id: '300002663',
// success: 'true'
// }
/**
*
* @param {*} phone String 通知的电话号码 eg: '18857785871,17774010868'
* @param {*} msg String 短信内容 eg: [征信] 验签失败 / 征信重启了 + 时间
* @param {*} type Number (不填)
* eg: send_msg('17774010868,13685747781', '你喜欢黄炜吗?') 第一个参数,`,`后不能有空格
*/
function sendWarnMsg(phone, msg, type = 0) {
return new Promise(function (resolve, reject) {
let url = 'http://cf.51welink.com/submitdata/Service.asmx/g_Submit'
let sprdid = '1012808'
switch (type) {
case 0:
sprdid = '1012808' // 行业通知短信
break
case 1:
sprdid = '1012812' // 会员营销短信
break
case 2:
sprdid = '1012828' // 语音行业短信
break
case 3:
sprdid = '1012888' // 行业触发短信
break
}
let body = {
'sname': 'jbwl51kqyx', // 账号
'spwd': 'zKtdTO9x', // 密码
'scorpid': '', // 企业代码
'sprdid': sprdid, // 产品编号
'sdst': phone, // 手机号码
'smsg': msg
} // 短信内容
let options = {
url: url,
method: "POST",
form: body,
headers: {"Content-Type": "application/x-www-form-urlencoded"}
}
request(options, (e, r, vb) => {
if (e) {
console.log('[ 发送短信失败 ]', body.sdst, body.smsg)
reject({code: -1, msg: '发送短信失败'})
}
else {
try {
let state = vb.match(/\<State\>(\d)+?<\/State>/)[1]
if (state == 0) {
console.log('[ 发送短信成功 ]', body.sdst, body.smsg)
resolve({code: 0, msg: '发送短信成功'})
} else {
console.log('[ 发送短信失败 ]', body.sdst, body.smsg)
reject({code: -1, msg: '发送短信失败'})
}
} catch (e) {
console.log('[ 发送短信失败 ]', body.sdst, body.smsg)
reject({code: -1, msg: '发送短信失败'})
}
}
})
})
}
// 选择app_id
async function get_app_id(cert_no) {
try {
let rows = await orm.authed(cert_no)
if (rows.length == 0) {
return await orm.payload_app_id()
} else {
return rows[0].app_id
}
} catch (e) {
throw e
}
}
//检测姓名是否匹配
async function checkName(appKey, open_id, order_id) {
try {
let ret = await orm.get_checkName(appKey);
if (ret.check_name == '1') {
let cert_name = await orm.get_certName(order_id)
let checkopen_id = await orm.get_openId(open_id);
if (checkopen_id.length < 1) {
let result = await Alipay.pay_forName(open_id, ret.name, appKey, cert_name);
if (result.sub_code == 'PAYEE_USER_INFO_ERROR') {
await orm.update_pay_task(-1, result.sub_msg, result.out_biz_no);
return {code: -1, msg: result.sub_msg};
}
await orm.update_pay_task(1, result.sub_msg || '支付成功', result.out_biz_no);
return {code: 0, msg: 'success'};
} else {
if (checkopen_id[0].cert_name == cert_name) {
return {code: 0, msg: 'success'};
} else {
let result = await Alipay.pay_forName(open_id, ret.name, appKey, cert_name);
if (result.sub_code == 'PAYEE_USER_INFO_ERROR') {
await orm.update_pay_task(-1, result.sub_msg, result.out_biz_no);
return {code: -1, msg: result.sub_msg};
}
await orm.update_pay_task(1, result.sub_msg || '支付成功', result.out_biz_no);
return {code: 0, msg: 'success'};
}
}
} else {
return {code: 0, msg: 'success'};
}
}catch (e){
throw e
}
}
module.exports = {
//is_authed,
save_score,
save_watch_list,
save_brief_score,
save_brief_watch_list,
notify_result,
checkName,
}
\ No newline at end of file
const Seq = require('sequelize')
var mysql = require('mysql2'),
extend = require('extend'),
moment = require('moment'),
rp = require('request-promise'),
log = console.log.bind(console),
error = console.error.bind(console),
config = require('config'),
utils = require('./utils'),
dbConfig = config.get('dbConfig')
const sequelize = new Seq({
database: dbConfig.database,
username: dbConfig.user,
password: dbConfig.password,
host: dbConfig.host,
dialect: 'mysql',
pool: {
max: 20,
min: 2,
acquire: 30000,
idle: 10000
},
define: {
timestamps: false // 默认为 true
},
dialectOptions: {
dateStrings: 'DATETIME',
},
isParse: false,
timezone: '+08:00'
});
const Task = sequelize.define('zmop_task', {
app_id: {type: Seq.STRING,},
app_key: {type: Seq.STRING},
order_id: {type: Seq.STRING},
success: {type: Seq.INTEGER},
error_msg: {type: Seq.STRING},
open_id: {type: Seq.STRING},
cert_no: {type: Seq.STRING},
cert_name: {type: Seq.STRING},
cert_phone: {type: Seq.STRING},
access_token: {type: Seq.STRING},
platform: {type: Seq.STRING},
redirect: {type: Seq.STRING},
create_time: {type: Seq.DATE},
finish_time: {type: Seq.DATE},
}, {
freezeTableName: true
})
Task.removeAttribute('id')
async function create(params, table) {
try {
params.create_time = moment().format('YYYY-MM-DD HH:mm:ss')
let keys = Object.keys(params).join('`,`')
let values = Object.values(params).join('","')
let sql = 'INSERT INTO ' + table + ' (`' + keys + '`) VALUES("' + values + '")'
let ret = await sequelize.query(sql, {replacements: [keys, values]})
console.log(ret)
} catch (e) {
throw e
}
}
async function create_watch_list(row) {
try {
let sql = 'INSERT INTO zmop_watch_list (`id`,`open_id`,`platform`,`is_matched`,`details`,`create_time`) VALUES(?,?,?,?,?,?)'
let ret = await sequelize.query(sql,
{replacements: [row.id, row.open_id, row.platform, row.is_matched, row.details, row.create_time]})
console.log(ret)
} catch (e) {
throw e
}
}
async function bill_record(app_key, order_id, cert_no, data1, data2, method = 'score') {
try {
return await sequelize.transaction(async function (t) {
let sql = 'SELECT `score_price` as price, `balance` FROM `zmop_partner` WHERE `app_key` = ? AND `using` = 1'
let bill = 'INSERT INTO zmop_bill_score (`app_key`, `order_id`, `create_time`, `cert_no`, `score`, `which_month`) VALUES(?,?,?,?,?,?)'
if (method == 'watch_list') {
sql = 'SELECT `watch_list_price` as price, `balance` FROM `zmop_partner` WHERE `app_key` = ? AND `using` = 1'
bill = 'INSERT INTO zmop_bill_watch_list (`app_key`, `order_id`, `create_time`, `cert_no`, `details`, `is_matched`) VALUES(?,?,?,?,?,?)'
}
let ret = await sequelize.query(sql, {replacements: [app_key], type: sequelize.QueryTypes.SELECT})
if (ret.length != 1) {
throw new Error('无效的appKey')
}
log(ret[0])
let price = Number(ret[0].price)
if (price > Number(ret[0].balance)) {
throw new Error('您的余额不足, 请充值')
}
sql = 'UPDATE zmop_partner SET balance = balance - ? where `app_key` = ?'
await sequelize.query(sql, {replacements: [price, app_key], transaction: t})
return await sequelize.query(bill, {
replacements: [app_key, order_id, new Date().toLocaleString(), cert_no, data1, data2],
transaction: t
})
})
} catch (e) {
throw e
}
}
async function brief_bill_record(app_key, order_id, cert_no, data1, data2, app_id, method = 'score') {
try {
return await sequelize.transaction(async function (t) {
let sql = 'SELECT `score_price` as price, `balance` FROM `zmop_partner` WHERE `app_key` = ? AND `using` = 1'
let bill = 'INSERT INTO zmop_bill_brief_score (`app_key`, `order_id`, `create_time`, `cert_no`, `admit_score`, `is_admittance`, `app_id`) VALUES(?,?,?,?,?,?,?)'
if (method == 'watch_list') {
sql = 'SELECT `score_price` as price, `balance` FROM `zmop_partner` WHERE `app_key` = ? AND `using` = 1'
bill = 'INSERT INTO zmop_bill_brief_watch_list (`app_key`, `order_id`, `create_time`, `cert_no`, `level`, `var1`, `app_id`) VALUES(?,?,?,?,?,?,?)'
}
let ret = await sequelize.query(sql, {replacements: [app_key], type: sequelize.QueryTypes.SELECT})
if (ret.length != 1) {
throw new Error('无效的appKey')
}
log(ret[0])
let price = Number(ret[0].price)
if (price > Number(ret[0].balance)) {
throw new Error('已达到接口调用限制次数')
}
sql = 'UPDATE zmop_partner SET balance = balance - ? where `app_key` = ?'
await sequelize.query(sql, {replacements: [price, app_key], transaction: t})
return await sequelize.query(bill, {
replacements: [app_key, order_id, new Date().toLocaleString(), cert_no, data1, data2, app_id],
transaction: t
})
})
} catch (e) {
throw e
}
}
async function get_auth(app_key) {
try {
let sql = 'SELECT `app_key`, `get_score`, `get_watch_list`,`get_brief_score`, `get_brief_watch_list`, ' +
'`balance`, `score_price` FROM zmop_partner WHERE app_key = ? AND `using` = 1'
let row = await sequelize.query(sql, {replacements: [app_key], type: sequelize.QueryTypes.SELECT})
if (row.length != 1) {
throw new Error('无效的appKey')
}
return row[0]
} catch (e) {
error(e)
throw e
}
}
// 最新的任务
async function task(order_id) {
try {
let sql = 'SELECT open_id, platform, create_time, app_id, cert_no, access_token FROM zmop_task WHERE success = 1 and order_id = ?'
let ret = await sequelize.query(sql, {
replacements: [order_id,],
type: sequelize.QueryTypes.SELECT
})
if (ret.length == 0) {
log('API-[ last_task ]: 无此订单号', order_id)
throw new Error('无此订单号')
}
return ret[0]
} catch (e) {
error(e)
throw e
}
}
// 最新的任务
async function bill(order_id, data_type = 'score') {
try {
let sql = 'SELECT order_id, cert_no, create_time, score, which_month FROM zmop_bill_score WHERE order_id = ? order by create_time DESC'
if (data_type == 'watch_list') {
sql = 'SELECT order_id, cert_no, create_time, details, is_matched FROM zmop_bill_watch_list WHERE order_id = ? order by create_time DESC'
}
let ret = await sequelize.query(sql, {
replacements: [order_id,],
type: sequelize.QueryTypes.SELECT
})
if (ret.length == 0) {
log('API-[ last_task ]: 无此订单号', order_id)
return false
}
return ret[0]
} catch (e) {
error(e)
throw e
}
}
// 最新的普惠版账单
async function brief_bill(order_id, data_type = 'score') {
try {
let sql = 'SELECT order_id, cert_no, create_time, admit_score, is_admittance FROM zmop_bill_brief_score WHERE order_id = ? order by create_time DESC'
if (data_type == 'watch_list') {
sql = 'SELECT order_id, cert_no, create_time, level FROM zmop_bill_brief_watch_list WHERE order_id = ? order by create_time DESC'
}
let ret = await sequelize.query(sql, {
replacements: [order_id,],
type: sequelize.QueryTypes.SELECT
})
if (ret.length == 0) {
log('API-[ last_task ]: 无此订单号', order_id)
return false
}
return ret[0]
} catch (e) {
error(e)
throw e
}
}
// setTimeout(async function () {
// try {
// log(await payload_brief('650', ''))
// } catch (e) {
// log(e)
// }
// })
async function create_api_task(params) {
try {
let sql = 'INSERT INTO zmop_api_task (`transaction_id`, `resp`, `open_id`, `create_time`, `method`, `platform`) VALUES (?,?,?,?,?,?)'
await sequelize.query(sql, {
replacements: [params.transaction_id, params.resp, params.open_id, new Date().toLocaleString(), params.method, params.platform]
})
} catch (e) {
throw e
}
}
async function get_score(task) {
try {
let sql = 'SELECT score, which_month, create_time FROM zmop_score WHERE platform = ? and open_id = ?' +
' ORDER BY create_time DESC'
let rows = await sequelize.query(sql, {
replacements: [task.platform, task.open_id],
type: sequelize.QueryTypes.SELECT
})
if (rows.length > 0 && utils.test_month(rows[0].create_time)) {
// 直接通知任务成功
return rows[0]
}
return false
} catch (e) {
error('orm-get_score error : ', e)
return false
}
}
async function cert_info(order_id) {
try {
let sql = 'SELECT cert_no, cert_name FROM zmop_task WHERE success = 1 and order_id = ?'
let ret = await sequelize.query(sql, {replacements: [order_id], type: sequelize.QueryTypes.SELECT})
if (ret.length > 0) {
return ret[0]
}
throw new Error('无效的order_id')
} catch (e) {
error(e)
throw e
}
}
async function check_order_id(order_id) {
try {
let sql = 'SELECT order_id FROM zmop_task WHERE order_id = ?'
let ret = await sequelize.query(sql, {replacements: [order_id], type: sequelize.QueryTypes.SELECT})
if (ret.length > 0) {
throw new Error('重复的订单号')
}
return true
} catch (e) {
throw e
}
}
async function check_app_key(app_key) {
try {
let sql = 'SELECT app_key FROM java_open_platform.customer_product WHERE goods_sn = "012008212235" and app_key = ? and state = 1'
let ret = await sequelize.query(sql, {replacements: [app_key], type: sequelize.QueryTypes.SELECT})
if (ret.length == 0) {
throw new Error('无效的appKey')
}
} catch (e) {
throw e
}
}
// 该订单号最近一次计费的时间之后24小时不会计费
async function counted(order_id, app_key) {
try {
let sql = 'SELECT create_time FROM zmop_bill WHERE app_key = ? and order_id = ? and count = 1 order by create_time DESC LIMIT 1'
let ret = await sequelize.query(sql, {replacements: [app_key, order_id], type: sequelize.QueryTypes.SELECT})
if (ret.length > 0) {
let delta = moment().diff(moment(ret[0].create_time), 'minutes')
if (delta <= 60 * 24) {
return ret[0].create_time
}
}
return false
} catch (e) {
throw e
}
}
async function create_task(row) {
row.create_time = new Date().toLocaleString()
let ret = await Task.create(row)
return ret.toJSON()
}
async function update_task(row, order_id) {
row.finish_time = new Date().toLocaleString()
if (row.success == 'true') {
row.success = 1
} else {
row.success = -1
}
let ret = await Task.update(row, {where: {order_id: order_id, success: 0}})
if (ret[0] == 0) {
console.warn('###### 更新任务状态失败 #####\n order_id: ', order_id)
}
}
async function payload_app_id(platform = 'alipay') {
try {
let sql = 'SELECT `app_id`, `platform`, `weight` FROM zmop_alipay_payload WHERE `using`=1 and platform = ?'
let ret = await sequelize.query(sql, {replacements: [platform], type: sequelize.QueryTypes.SELECT})
if (ret.length == 0) {
sql = 'SELECT `app_id`, `platform`, `weight` FROM zmop_alipay_payload WHERE `using`=1'
return await sequelize.query(sql, {type: sequelize.QueryTypes.SELECT})
}
return ret
} catch (e) {
error(e)
throw e
}
}
// 选择有普惠版权限的app_id
async function payload_brief(method = 'score', admit_score) {
try {
let sql = 'SELECT `app_id`, `weight` FROM zmop_brief_payload WHERE `using`=1 and admit_score = ?'
if (method != 'score') {
sql = 'SELECT `app_id`, `weight` FROM zmop_brief_payload WHERE `using`=1'
}
let ret = await sequelize.query(sql, {replacements: [admit_score], type: sequelize.QueryTypes.SELECT})
if (ret.length == 0) {
throw new Error('请选择正确的准入分')
}
return ret
} catch (e) {
error(e)
throw e
}
}
async function update_payload(app_id) {
try {
let sql = 'UPDATE zmop_alipay_payload SET `count` = `count` + 1 WHERE `app_id`= ?'
return await sequelize.query(sql, {
replacements: [app_id],
type: sequelize.QueryTypes.UPDATE
})
} catch (e) {
error(e)
throw e
}
}
async function company_info(app_key) {
try {
let sql = 'SELECT `name`, `company`,`partya` FROM zmop_partner WHERE `app_key`= ?'
return await sequelize.query(sql, {
replacements: [app_key],
type: sequelize.QueryTypes.SELECT
})
} catch (e) {
error(e)
throw e
}
}
// 是否已授权
async function authed(cert_no, platform) {
try {
let sql = 'select a.app_id, a.app_key, b.entity, b.platform from zmop_task a join ' +
'(SELECT `app_id`, `entity`, `platform` FROM zmop_alipay_payload where `using` = 1 and platform = ?)' +
' b on a.app_id = b.app_id where a.cert_no = ? group by a.app_id order by create_time'
return await sequelize.query(sql, {
replacements: [platform, cert_no],
type: sequelize.QueryTypes.SELECT
})
} catch (e) {
error(e)
throw e
}
}
//插入zmop_open_id表
async function insert_openId(open_id,access_token,app_id,platform) {
try{
let sql = 'INSERT INTO `zmop_open_id` (`open_id`,`access_token`, `app_id`,`platform`,`create_time`) VALUES (?,?,?,?,?)';
await sequelize.query(sql, {
replacements: [open_id,access_token,app_id,platform,new Date().toLocaleString()]
})
}catch (e){
error(e)
throw e
}
}
//获取合作方是否需要判断
async function get_checkName(appKey) {
try{
let sql = 'SELECT `check_name`,`name` from zmop_partner where `app_key` = ? ';
let ret = await sequelize.query(sql, {
replacements:[appKey],
type: sequelize.QueryTypes.SELECT
})
return ret[0]
}catch (e){
throw e
}
}
//获取用户姓名
async function get_certName(order_id) {
try{
let sql = 'SELECT `cert_name` from zmop_task where order_id = ? ';
let ret = await sequelize.query(sql,{
replacements:[order_id],
type: sequelize.QueryTypes.SELECT
})
return ret[0].cert_name
}catch (e){
throw e
}
}
//插入zmop_pay_task
async function insert_pay_task(transaction_id, appKey, open_id,cert_name) {
try {
let sql = 'INSERT INTO `zmop_pay_task` (`transaction_id`,`app_key`, `status`,`create_time`,`open_id`,`cert_name`) VALUES (?,?,?,?,?,?)';
await sequelize.query(sql, {
replacements: [transaction_id, appKey, 0, new Date().toLocaleString(), open_id,cert_name]
})
} catch (e) {
throw e
}
}
//更新zmop_pay_task
async function update_pay_task(status, msg, transaction_id) {
try {
let sql = 'UPDATE `zmop_pay_task` SET status = ? , msg = ?, finished_time = ? WHERE transaction_id = ?';
await sequelize.query(sql, {
replacements: [status, msg, new Date().toLocaleString(), transaction_id],
type: sequelize.QueryTypes.UPDATE
})
} catch (e) {
error (e)
throw e
}
}
async function get_openId(open_id) {
try {
let sql = 'SELECT `cert_name`,`open_id` from zmop_pay_task where open_id = ? and status = 1 order by `finished_time` desc';
let ret = await sequelize.query(sql, {
replacements: [open_id],
type: sequelize.QueryTypes.SELECT
})
return ret
} catch (e) {
throw e
}
}
module.exports.create = create
module.exports.check_order_id = check_order_id
module.exports.check_app_key = check_app_key
module.exports.get_score = get_score
module.exports.cert_info = cert_info
module.exports.create_api_task = create_api_task
module.exports.task = task
module.exports.counted = counted
module.exports.bill_record = bill_record
module.exports.get_auth = get_auth
module.exports.update_task = update_task
module.exports.create_task = create_task
module.exports.payload_app_id = payload_app_id
module.exports.update_payload = update_payload
module.exports.company_info = company_info
module.exports.authed = authed
module.exports.bill = bill
module.exports.create_watch_list = create_watch_list
module.exports.payload_brief = payload_brief
module.exports.brief_bill = brief_bill
module.exports.brief_bill_record = brief_bill_record
module.exports.insert_openId = insert_openId
module.exports.get_checkName = get_checkName
module.exports.get_certName = get_certName
module.exports.insert_pay_task = insert_pay_task
module.exports.update_pay_task = update_pay_task
module.exports.get_openId = get_openId
const OSS = require('ali-oss')
const co = require('co')
const crypto = require('crypto')
const fs = require('fs')
const config = require('config')
const client = new OSS({
bucket: '51query',
accessKeyId: 'LTAI6Glaum6TDzKf',
accessKeySecret: 'zmNjWhmOD1nIClZ3hoDmGrdNNiBJBi',
secure: true,
region: "oss-cn-hangzhou"
})
function upload_image(key, data) {
return co(function*() {
// use 'chunked encoding'
//var stream = fs.createReadStream('./exp.js');
data = data.replace(/^data:image\/\S+?;base64,/,"");
var result = yield client.put(key, new Buffer(data, 'base64'));
console.log('upload_image: ', result);
return result
}).catch(function (err) {
console.log('upload_image error: ', err);
});
}
function upload(key, data) {
return co(function*() {
// use 'chunked encoding'
//var stream = fs.createReadStream('./exp.js');
var result = yield client.put(key, new Buffer(data));
console.log('upload: ', result);
return result
}).catch(function (err) {
console.log('upload error: ', err);
});
}
const getUploadSign = (dirPath, fileName) => {
const {AccessKeyId, Host, AccessKeySecret} = config.oss
let callback = {
"callbackUrl": `${config.host}/kqyx/oss/callback`,
"callbackBody": "filename=${object}&size=${size}&mimeType=${mimeType}",
"callbackBodyType": "application/x-www-form-urlencoded"
}
callback = JSON.stringify(callback)
const callbackbody = new Buffer(callback).toString('base64')
const end = new Date().getTime() + 300000
const expiration = new Date(end).toISOString()
let policyString = {
expiration,
conditions: [
// 1024*1024 1mb限制
['content-length-range', 0, 1048576],
['starts-with', '$key', 'kqyx']
]
}
policyString = JSON.stringify(policyString)
const policy = new Buffer(policyString).toString('base64')
const signature = crypto.createHmac('sha1', AccessKeySecret).update(policy).digest('base64')
return {
AccessKeyId,
host: Host,
policy,
signature,
fileName,
dirPath,
callbackbody
}
}
const signed_url = (name) => {
return client.signatureUrl(name)
}
const deleteFile = (key) => {
co(function*() {
return yield client.delete(key)
}).catch(function (err) {
console.log(err)
throw err
})
}
module.exports = {
upload_image,
signed_url,
deleteFile,
upload
}
\ No newline at end of file
/**
* Created by xaj on 2017/5/26.
*/
var rp = require('request-promise');
var request = require('request');
var config = require('config')
var tj1 = config.get('tj1');
var tj2 = config.get('tj2');
/*************************************************************************************
* Description: getToken
* Author: xaj
* Date: 2017/6/05
* Parameter: body Obeject 传进来的参数
* Callback: promise
* Return: N/A
* Caution:
*************************************************************************************/
function getToken(body) {
return new Promise((resolve, reject) => {
let form_data = body
let reqUrl = tj2 + "access/getToken";
let options= {
url: reqUrl,
method: "POST",
json: true,
body: form_data,
headers: {
'content-type': 'application/json'
}
}
request(options,(e,r,b)=>{
if(e){
console.error('[getToken] error: ' + JSON.stringify(e));
reject(e);
}else{
console.log('[getToken] success result: ' + JSON.stringify(b));
resolve(b);
}
})
})
}
/*************************************************************************************
* Description: getOrderSn
* Author: xaj
* Date: 2017/6/05
* Parameter: body Object 传进来的参数
* Callback: promise
* Return: N/A
* Caution:
*************************************************************************************/
function getOrderSn(body) {
return new Promise((resolve, reject) => {
let form_data = body;
let reqUrl = tj2 + "order/getOrderSn";
let options= {
url: reqUrl,
method: "POST",
json: true,
body: form_data,
headers: {
'content-type': 'application/json'
}
}
request(options,(e,r,b)=>{
if(e){
console.error('[getOrderSn] error: ' + JSON.stringify(e));
reject(e);
}else{
console.log('[getOrderSn] success result: ' + JSON.stringify(b));
resolve(b);
}
})
})
}
/*************************************************************************************
* Description: 检查签名是否失效
* Author: xaj
* Date: 2017/5/27
* Parameter: body, Object 传进来的参数
* Callback: promise
* Return: N/A
* Caution:
*************************************************************************************/
function signValidityCheck(body) {
return new Promise((resolve, reject) => {
let form_data = body;
let url = tj2 + "access/signValidityCheck";
let options= {
url: url,
method: "POST",
json: true,
body: form_data,
headers: {
'content-type': 'application/json'
}
}
request(options,(e,r,vb)=>{
if(e) {
console.error('[signValidityCheck] signValidityCheck error: ' + JSON.stringify(e));
reject("服务器维护")
}
else {
console.log('[signValidityCheck] signValidityCheck success: ' + JSON.stringify(vb));
resolve(vb);
}
})
})
}
async function app_key_info(app_key) {
try {
let resp = await rp.get({
url: tj2 + 'customer/query/?appKey=' + app_key,
json: true
})
if (resp.code == 0) {
if (resp.data.customerList.length > 0) {
return resp.data.customerList[0]
} else {
throw new Error('无效的appKey')
}
} else {
throw new Error('API-[app_key_info] error ', resp)
}
} catch (e) {
throw e
}
}
// app_key_info('122818D0E79CCEB3B8D3D6BB51BF615E').then(r=>{console.log(r)}).catch(e=>{console.log(e)})
exports.getToken = getToken;
exports.app_key_info = app_key_info;
exports.getOrderSn = getOrderSn;
exports.signValidityCheck = signValidityCheck;
/**
* Created by xaj on 2017/6/6.
*/
const schedule = require('node-schedule');
const fs = require('fs');
const path = require('path');
const moment = require('moment');
const config = require('config');
const basic = require('../middlewares/_pub').basic;
const process = require('child_process');
/*每分钟的第30秒触发: '30 * * * * *'
每小时的1分30秒触发 :'30 1 * * * *'
每天的凌晨1点1分30秒触发 :'30 1 1 * * *'
每月的1日1点1分30秒触发 :'30 1 1 1 * *'
2016年的1月1日1点1分30秒触发 :'30 1 1 1 1 2016'
每周1的1点1分30秒触发 :'30 1 1 * * 1'*/
function BeginCleanLogWork(timeInterval){
schedule.scheduleJob(timeInterval, cleanLogJob);
}
function BeginCleanPm2LogWork(){
schedule.scheduleJob('00 00 00 1 * *', cleanPm2LogJob);
}
function cleanLogJob() {
console.log('[cleanLogJob] BeginDayWork:' + new Date());
let servicName = config.get('log4jsName');
let dateMoment = moment(new Date()).subtract(3, 'days').format('YYYYMMDD');
let fileName = basic.getLocalIP('eth', 'IPv4') + '-' + servicName + '-' + dateMoment + '.log';
let filePath = path.join('./logs/' + fileName);
console.log(fileName)
console.log(filePath)
if (fs.existsSync(filePath)) {
fs.unlink(filePath, function (err) {
if (err) {
console.error('[cleanLogJob] 清除3天前日志失败,原因:' + JSON.stringify(err));
}
else {
console.log('[cleanLogJob] 清除3天前日志成功,被清除日志:' + fileName);
}
})
}
else {
console.error('[cleanLogJob] 日志文件: %s 不存在', filePath);
}
}
function cleanPm2LogJob() {
process.exec('pm2 flush', function (error, stdout, stderr) {
if (error) {
console.log('[cleanPm2LogJob] exec error: ' + error);
}
else {
console.log(stdout);
console.log(stderr);
}
});
}
// BeginCleanLogWork();
module.exports = {
"BeginCleanLogWork": BeginCleanLogWork,
"BeginCleanPm2LogWork": BeginCleanPm2LogWork
};
const moment = require('moment')
const orm = require('./orm')
function test_month(str) {
let a = which_month()
let b = which_month(str)
if (a == b) {
return true
} else {
return false
}
}
function which_month(str = null) {
let today = moment()
if (str) {
today = moment(str)
}
let day = today.get('date')
if (day > 6) {
return today.format('YYYY-MM')
} else {
return today.subtract(1, 'month').format('YYYY-MM')
}
}
async function test_order_id(order_id) {
try {
if (!order_id) {
throw new Error('无效的订单号')
}
let ret = true
let t = order_id.slice(0, 17)
let append = order_id.slice(17)
if (/[^0-9a-zA-Z_-]/.test(append) || order_id.length != 32 || /[^\d]/.test(t)) {
throw new Error('无效的订单号')
}
return await orm.check_order_id(order_id)
} catch (e) {
throw e
}
}
function to_base64(str) {
return new Buffer(str).toString('base64')
}
function from_base64(base64) {
return new Buffer(base64, 'base64').toString()
}
// 加权随机
function load_balance(items) {
let list = []
for (let item of items) {
for (let i = 0; i < item.weight; i++) {
list.push(item.app_id)
}
}
let randint = getRandomInt(0, list.length)
return list[randint]
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
}
module.exports = {
test_order_id,
test_month,
which_month,
to_base64,
from_base64,
load_balance
}
\ No newline at end of file
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCir0A1PyJ+v56i21m/hjECVtM43oq7Uj8SC1lDhJqeOWMCZEQc
ChHYpnRkhyrypVRhNKXq7edq5Cp1f5/q4mPrw5GcyX68VPBTeRml7wtp/0oYoW1c
9wEqbgPWsHelVdb+2VN3V6Hryot7ovz01jkndPK+T4R2LdwbaK2hUnKdFwIDAQAB
AoGAJlbw5duUMJTOOQlC1G02nZuCufNQdKcEcCc2iT/2BHX3zHd+ybDh1dIcuhhU
2cx231W+CGi60ikljH1gXcWu0GAbGMSyvC4sTs+sDNpzp2peYtZ67bSNp7rd6sNA
v8zZgC66zpNQVuD0WQNxHAISQNUNNaxDGz+AYRIBM4VKy7kCQQDOnWsEHKdr12f5
1GgiownfoC53U+oRiyuoxFx+YS7iR9QCAPRHx8822LgThMA1qvINKfDwtocpK+UO
imi2MyHNAkEAyZHGRPO+ij9XRIw5IfFNpGpt40MQv4PQYpmI/of7zbBVUaEFvJ0y
DZ6s9KhU7cHblKsruUHu6KZS/Lu37k4mcwJAQNf2thuoD5hS8X1QEU7J0n0bGCgl
1cuvsA+wV5l4dVvFlbtm7wAucDAj1Txcdntn6+m1zFX8pVc5VA7sPgJeIQJAG1SO
o47BCRGpjXvNy1JiiqZ7m9LeFHmU6amTr59UfwEnsFe65WYTAVHAdbPVQB+G3FOR
LB9Ke3UBz47MU515DQJAMeAIdlp71W1TKNhLv5pLQtfSmFzMQWvhXZuLnysvqFfg
IJpsio6hJcr9sJI72s6kBPaVyVvwCYOlreXq2SM2uw==
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyDAB5cXvXum9x9z3S6akLTxnZ
curc0hpldpWdlB315gOUbKvjJKvpaocWiVMHMcv6UZ2Ml7TVXXmEd/7e7iG1wIJm
ocNaC86wpOyLqlsg7P22weuy3dq8SyOcZ8PQkn346VahJ7OUoPNc/8Y23tNJXdO/
+lpl98nzOe0ABdanIQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyDAB5cXvXum9x9z3S6akLTxnZ
curc0hpldpWdlB315gOUbKvjJKvpaocWiVMHMcv6UZ2Ml7TVXXmEd/7e7iG1wIJm
ocNaC86wpOyLqlsg7P22weuy3dq8SyOcZ8PQkn346VahJ7OUoPNc/8Y23tNJXdO/
+lpl98nzOe0ABdanIQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCir0A1PyJ+v56i21m/hjECVtM43oq7Uj8SC1lDhJqeOWMCZEQc
ChHYpnRkhyrypVRhNKXq7edq5Cp1f5/q4mPrw5GcyX68VPBTeRml7wtp/0oYoW1c
9wEqbgPWsHelVdb+2VN3V6Hryot7ovz01jkndPK+T4R2LdwbaK2hUnKdFwIDAQAB
AoGAJlbw5duUMJTOOQlC1G02nZuCufNQdKcEcCc2iT/2BHX3zHd+ybDh1dIcuhhU
2cx231W+CGi60ikljH1gXcWu0GAbGMSyvC4sTs+sDNpzp2peYtZ67bSNp7rd6sNA
v8zZgC66zpNQVuD0WQNxHAISQNUNNaxDGz+AYRIBM4VKy7kCQQDOnWsEHKdr12f5
1GgiownfoC53U+oRiyuoxFx+YS7iR9QCAPRHx8822LgThMA1qvINKfDwtocpK+UO
imi2MyHNAkEAyZHGRPO+ij9XRIw5IfFNpGpt40MQv4PQYpmI/of7zbBVUaEFvJ0y
DZ6s9KhU7cHblKsruUHu6KZS/Lu37k4mcwJAQNf2thuoD5hS8X1QEU7J0n0bGCgl
1cuvsA+wV5l4dVvFlbtm7wAucDAj1Txcdntn6+m1zFX8pVc5VA7sPgJeIQJAG1SO
o47BCRGpjXvNy1JiiqZ7m9LeFHmU6amTr59UfwEnsFe65WYTAVHAdbPVQB+G3FOR
LB9Ke3UBz47MU515DQJAMeAIdlp71W1TKNhLv5pLQtfSmFzMQWvhXZuLnysvqFfg
IJpsio6hJcr9sJI72s6kBPaVyVvwCYOlreXq2SM2uw==
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCir0A1PyJ+v56i21m/hjECVtM4
3oq7Uj8SC1lDhJqeOWMCZEQcChHYpnRkhyrypVRhNKXq7edq5Cp1f5/q4mPrw5Gc
yX68VPBTeRml7wtp/0oYoW1c9wEqbgPWsHelVdb+2VN3V6Hryot7ovz01jkndPK+
T4R2LdwbaK2hUnKdFwIDAQAB
-----END PUBLIC KEY-----
tt.51gjj.com:5000/redirect?params=JevbQqScHiM1Qoryf1%2FD4MIrl7mvWRtt8neRUzLelEdru%2FRUt8N%2FQOs3qWgdOqUXVNXZnUL87Bc0uFFm4dxAwRRNxr0ek4kFPBoDwuk063AS3vFz%2Bsm0wy808hX6s63MnXfCbGqq1tpvkVb4mFp1jDFXJJgZjOoJ%2FBhTLfQWI%2BSE4YjWcvm3%2BV9enCv8TrYZ3jPhmf%2F3KeX%2BuZB3HhWmnqQHv6nu9Wbh%2Fqf2sevtvWzV08F6eT8JcDhF%2FK%2F1aZvSVgr83%2BuzRbO%2BCUa7KY0GWNc5moFfhT45TeR2PslcTDde36sUumlLdEQxR2qXXf7TPL2z0Y0bWKE7JMpbx%2BqnPg%3D%3D&sign=HOg8UcgLT4zFTq5J7sTy9N7XHjS%2Fg8NfMnYoR4ip9UdPPScHXiqnuIDZ44zQT9NU5X6z3XoeGt04YFfeDS3DXGaD1YhyTvWwCigAMPnu7YlSG1ZeAputY0xD8sCkN7Dv20GQE42%2BU%2BSOQk8wzcsHJ87KwQUkXF9oTQviaIS0fk0%3D
\ No newline at end of file
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyDAB5cXvXum9x9z3S6akLTxnZ
curc0hpldpWdlB315gOUbKvjJKvpaocWiVMHMcv6UZ2Ml7TVXXmEd/7e7iG1wIJm
ocNaC86wpOyLqlsg7P22weuy3dq8SyOcZ8PQkn346VahJ7OUoPNc/8Y23tNJXdO/
+lpl98nzOe0ABdanIQIDAQAB
-----END PUBLIC KEY-----
const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const NodeRSA = require('node-rsa');
// def sign(privatekey, data):
// '''
// 加签
// :param privatekey:私钥文件路径
// :param data:要加签的数据
// :return string:签名
// '''
// signEVP = EVP.load_key(privatekey)
// signEVP.sign_init()
// signEVP.sign_update(data)
// result = signEVP.sign_final()
// return base64.b64encode(result)
const private_key = fs.readFileSync(path.join(__dirname, 'keys/rsa_private_key.pem')).toString()
const zmop_public_key = fs.readFileSync(path.join(__dirname, 'keys/zmop_public_key.pem')).toString()
//params= URLEncode(Base64(RSAEncrypt(param1=URLEncode(param1value)&param2=URLEncode(param2value))))
// 加签
// :param privatekey:私钥文件路径
// :param data:要加签的数据
// :return string:签名
function RSAEncrypt(data) {
let str = params2str(data)
let key = new NodeRSA(zmop_public_key)
key.setOptions({encryptionScheme: 'pkcs1'});
let encrypted = key.encrypt(str, 'base64')
return encrypted
}
function RSADecrypt(str) {
let key = new NodeRSA(private_key)
key.setOptions({encryptionScheme: 'pkcs1'});
let encrypted = key.decrypt(str, 'utf8')
return encrypted
}
// 转换业务参数为str
function params2str(data) {
let str = ''
for (let k of Object.keys(data)) {
let v = data[k]
if (Object.prototype.toString.call(v) === '[object Object]') {
v = JSON.stringify(v)
}
str += k + '=' + encodeURIComponent(v) + '&'
}
return str.slice(0, str.length - 1)
}
// str 转为 json
function str2params(str) {
let ret = {}
let arr = str.split('&')
for (let item of arr) {
let index = item.indexOf('=')
ret[item.slice(0, index)] = decodeURIComponent(item.slice(index + 1))
}
return ret
}
// 加签
function sign(data) {
// 签名采用sha1withRsa算法
let str = params2str(data)
let sign = crypto.createSign('RSA-SHA1')
sign.update(str)
return sign.sign(private_key, 'base64')
}
// 验签
// sign_value: 签名,
// str: 待验签的数据
function verify(sign_value, str) {
var verify = crypto.createVerify('RSA-SHA1');
verify.update(str);
return verify.verify(zmop_public_key, sign_value, 'base64')
}
// let resp = {
// "encrypted": true,
// "sign": {
// "signSource": "zhima_sign_value",
// "signResult": "OKICqUJzHMn9ee5p0xIlJE7L5FZ5nOmjtdDYCqHD3FsQCM5RLJ2U3kFCpXf4sWnSW5J/DRsCmYRffofZapP7wH//xrJq5n9rVDg+CHQ3i5E5Mrtv4/X3wsURaDXpX1wJr+mGd2RL8zTwDi9FW1N7bHK28I3sNgwaoWLeS15iJ4s="
// },
// "biz_response_sign": "cEHP5udepFpo6Ow/ejWwLR0Q1MPaxUZA17zt7Ezd73DVNUl8RqDf/mNzap79aOucOc53n0GXwY1HIQMLLNKI9w2va62SajFhrLFYMy+QtWN3w6EsnuWNOz0xQLKpKCw3HbloD2S6nYk1dg3fBWMhC2pyZ8xXES4l6nZXWzTsOnc=",
// "biz_response": "gG4WYaHXetiko/9nqvGPGDVIyY055WgIDQ3RxVEmX9xVRAO9m8rzO33G0lO8S3iQkfHnkjZhbiQhWP7Fm8x9LtEwm8GjnSl+6egPgORUazOAdKdbvRWr9ri18znCJLu5JBr9QH6J7NoPU5YV231fN4bCPRnpD603p96TPQ/Zw/k="
// }
// if (resp.encrypted) {
// let decrypted_res = RSADecrypt(resp.biz_response)
// console.log(JSON.parse(decrypted_res))
// if (verify(resp.biz_response_sign, decrypted_res)) {
// console.log('success')
// } else {
// console.log('error')
// }
// }
module.exports = {
sign,
verify,
RSAEncrypt,
RSADecrypt,
params2str,
str2params
}
const rp = require('request-promise'),
moment = require('moment'),
fs = require('fs'),
rsa = require('./rsa'),
orm = require('../orm'),
extend = require('extend'),
config = require('config'),
log = console.log.bind(console),
error = console.error.bind(console)
// const api_host = "https://zmopenapi.zmxy.com.cn/openapi.do" // 芝麻信用网关地址
// const private_key_file = "d:\\keys\\private_key.pem" // 商户私钥文件路径
// const zmPublic_key_file = "d:\\keys\\public_key.pem" // 芝麻公钥文件路径
// const app_id = "1000***" // 芝麻分配给商户的 appId
// params= URLEncode(Base64(RSAEncrypt(param1=URLEncode(param1value)&param2=URLEncode(param2value))))
class ZmopClient {
constructor() {
this.zmop_host = 'https://zmopenapi.zmxy.com.cn/openapi.do'
this.data = {
app_id: config.get("zmop_app_id"),
charset: 'UTF-8',
version: '1.0',
platform: 'zmop',
}
}
prepare(method, params) {
this.data.method = method
let extended = {
method: method,
params: rsa.RSAEncrypt(params),
sign: rsa.sign(params)
}
return extend(extended, this.data)
}
build_url(certNo, name, extras) {
try {
log(certNo)
log(extras)
let params = {
identity_type: 2,
identity_param: {"certNo": certNo.toString().toUpperCase(), "name": name, "certType": "IDENTITY_CARD"},
biz_params: {"auth_code": "M_H5", "channelType": "app", "state": extras}
}
let method = 'zhima.auth.info.authorize'
return this.zmop_host + '?' + rsa.params2str(this.prepare(method, params))
} catch (e) {
error(e)
throw e
}
}
// 查看是否授权
async authed(certNo, name) {
try {
let method = 'zhima.auth.info.authquery'
// let params = {
// auth_category: 'C2B',
// identity_type: '0',
// identity_param: {"openId": "268801234567890123456"}
// }
//使用身份证和姓名
let params = {
auth_category: 'C2B',
identity_type: '2',
identity_param: {"certNo": certNo.toString().toUpperCase(), "name": name, "certType": "IDENTITY_CARD"}
}
let resp = await rp.post({
url: this.zmop_host,
json: true,
form: this.prepare(method, params)
})
if (resp.encrypted) {
let decrypted_res = rsa.RSADecrypt(resp.biz_response)
if (rsa.verify(resp.biz_response_sign, decrypted_res)) {
return decrypted_res
} else {
throw new Error('api-authed 验签失败 resp')
}
} else {
return resp
}
} catch (e) {
throw e
}
}
async watch_list(open_id) {
let retry = 0
let self = this
async function get(transaction_id) {
try {
let method = 'zhima.credit.watchlistii.get'
let params = {
transaction_id: transaction_id,
product_code: 'w1010100100000000022',
open_id: open_id
}
let resp = await rp.post({
url: self.zmop_host,
json: true,
form: self.prepare(method, params)
})
let row = {
transaction_id: transaction_id,
resp: JSON.stringify(resp),
open_id: open_id,
platform: 'zhima',
method: 'watch_list'
}
log('zmop_score resp: ', resp)
await orm.create_api_task(row)
if (resp.encrypted) {
let decrypted_res = rsa.RSADecrypt(resp.biz_response)
if (rsa.verify(resp.biz_response_sign, decrypted_res)) {
return JSON.parse(decrypted_res)
} else {
error('api-score 验签失败: ', decrypted_res)
throw new Error('api-score 验签失败')
}
} else {
let biz_response = JSON.parse(resp.biz_response)
//{ encrypted: false, biz_response: '{"success":false,"error_code":"ZMCSP.zm_account_not_existed","error_message":"芝麻账户不存在"}' }
if (biz_response.error_code == 'ZMCREDIT.transaction_id_repeat' && retry < 3) {
retry++
let transaction_id = ZmopClient.build_transaction_id()
return await get(open_id, transaction_id)
} else {
return biz_response
}
}
} catch (e) {
throw e
}
}
let transaction_id = ZmopClient.build_transaction_id()
return await get(transaction_id)
}
// 查询芝麻分接口
async score(open_id) {
let retry = 0
let self = this
async function get(transaction_id) {
try {
let method = 'zhima.credit.score.get'
let params = {
transaction_id: transaction_id,
product_code: 'w1010100100000000001',
open_id: open_id
}
let resp = await rp.post({
url: self.zmop_host,
json: true,
form: self.prepare(method, params)
})
let row = {
transaction_id: transaction_id,
resp: JSON.stringify(resp),
open_id: open_id,
platform: 'zhima',
method: 'score'
}
log('zmop_score resp: ', resp)
await orm.create_api_task(row)
if (resp.encrypted) {
let decrypted_res = rsa.RSADecrypt(resp.biz_response)
if (rsa.verify(resp.biz_response_sign, decrypted_res)) {
return JSON.parse(decrypted_res)
} else {
error('api-score 验签失败: ', decrypted_res)
throw new Error('api-score 验签失败')
}
} else {
let biz_response = JSON.parse(resp.biz_response)
//{ encrypted: false, biz_response: '{"success":false,"error_code":"ZMCSP.zm_account_not_existed","error_message":"芝麻账户不存在"}' }
if (biz_response.error_code == 'ZMCREDIT.transaction_id_repeat' && retry < 3) {
retry++
let transaction_id = ZmopClient.build_transaction_id()
return await get(open_id, transaction_id)
} else {
return biz_response
}
}
} catch (e) {
throw e
}
}
let transaction_id = ZmopClient.build_transaction_id()
return await get(transaction_id)
}
static
build_transaction_id() {
let t = moment().format('YYYYMMDDHHmmssSSS')
let str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
while (t.length < 32) {
t += str[Math.round(Math.random() * (str.length - 1))]
}
return t
}
}
// let t = ZmopClient.build_transaction_id()
// let open_id = '268806822853700342467205358'
// let zmop = new ZmopClient()
// setTimeout(async () => {
// console.log(await zmop.authed('421224199107090029', '吴莹'))
// })
module.exports = ZmopClient
/**
* Created by xaj on 2017/1/11.
*/
"use strict";
var config = require('config'),
log4js = require('log4js'),
log4jsConfig = require('./logger'),
basic = require('./basic');
module.exports = {
"config" : config,
"log4js" : log4js,
"log4jsConfig" : log4jsConfig,
"basic" : basic
};
\ No newline at end of file
var jwt = require('jsonwebtoken'),
moment = require('moment'),
extend = require('extend'),
fs = require('fs');
module.exports = function (options) {
var opts = extend({}, {
pub_cert_file: './rsa_public_key.pem',
pri_cert_file: './rsa_private_key.pem',
query_name: 'token',
data_name: 'phone',
//指定过期时间
expiresIn: moment().add(1, 'years').unix(),
//用于从请求信息中获取登录凭证,用户名、密码...
getCredentials: function () {
return {};
},
//用于登录验证,根据用户名密码验证用户是否有效
verifyIdentity: function () {
return true;
}
}, options);
//公钥
var pub_cert = fs.readFileSync(opts.pub_cert_file);
//私钥
var pri_cert = fs.readFileSync(opts.pri_cert_file);
return {
_create: function (data) {
var payload = {};
payload[opts.data_name] = data;
return jwt.sign(payload, pri_cert, {
expiresIn: opts.expiresIn,
algorithm: 'RS256',
noTimestamp: true
});
},
//第一次生成token
generateToken: function (req) {
var data = opts.verifyIdentity(opts.getCredentials(req));
if (!data) return '';
return this._create(data);
},
// 销毁token, 过期时间改为当前时间
destory: function () {
var payload = this.verify(req);
opts.expiresIn = moment().unix()
if (payload) return this._create(payload[opts.data_name]);
return '';
},
//刷新token
refreshToken: function (req) {
var payload = this.verify(req);
if (payload) return this._create(payload[opts.data_name]);
return '';
},
//从请求中获取token的字符串
_getReqToken: function (req) {
var token = '';
//获取token
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
token = req.headers.authorization.split(' ')[1];
} else if (req.query && req.query[opts.query_name]) {
token = req.query[opts.query_name];
}
return token;
},
//验证token并得到其中的payload
verify: function (req) {
var token = this._getReqToken(req);
if (!token) return false;
var payload = null;
try {
//验证token是否有效
payload = jwt.verify(token, pub_cert, {algorithms: 'RS256'});
} catch (err) {
console.log(err);
}
return payload;
},
//token解码
decode: function (token) {
var decoded = null;
try {
decoded = jwt.decode(token, {complete: true, json: true});
} catch (err) {
console.log(err);
}
return decoded;
},
//获得身份信息
getIdentity: function (req) {
var payload = this.verify(req);
return payload && payload[opts.data_name];
}
}
};
\ No newline at end of file
/**
* Created by xaj on 2017/1/11.
*
* Description: common methods such as get local ip, make muti-level directory, string format, and so on;
* common data&check methods which need to disclosure from constants.js.
*
*/
"use strict";
var path = require('path'),
os = require('os'),
fs = require('fs');
module.exports = {
/*
* iftype: 网卡类型 eth, lo, tunl
* family: IPv4 or IPv6
* default return: '127.0.0.1'
*
* Description: get ipv4 or ipv6 address of assigned interface
* eg: getLocalIP(eth, IPv4)
* */
"getLocalIP" : function (iftype, family) {
var ip = '127.0.0.1';
var ifs = os.networkInterfaces();
for (var dev in ifs) {
if (dev.toLowerCase().match(iftype.toLowerCase())) {
var devinfo = ifs[dev];
for (var i=0; i<devinfo.length; i++) {
if (devinfo[i].family.toLowerCase() === family.toLowerCase()) {
ip = devinfo[i].address;
break;
}
}
break;
}
}
return ip;
},
/*
* dirpath: absolute directory path
*
* Description: asynchronous make directory
* */
"mkdirs" : function mkdirs(dirpath, mode, callback) {
fs.exists(dirpath, function(exists){
if (exists) {
callback(dirpath);
} else {
mkdirs(path.dirname(dirpath), mode, function(){
fs.mkdir(dirpath, mode, callback);
});
}
});
},
/*
* dirpath: absolute directory path
*
* Description: synchronous make directory
* */
"mkdirsSync" : function mkdirsSync(dirpath, mode) {
if (fs.existsSync(dirpath))
{
return;
} else {
mkdirsSync(path.dirname(dirpath), mode);
fs.mkdirSync(dirpath, mode);
}
},
/*
* s: string
*
* Description: string format, change multi spaces to one space
* eg: tmp = trim(stdout).split(' '), then tmp is an array obj
* */
"trimSpaces" : function (s) {
return s.replace(/(^\s*)|(\s*$)/g, '').replace(/\s+/g,' ');
},
};
var config = require('config');
var fs = require('fs');
var log4js = require('log4js');
var basic = require('./basic');
var log4jsConfig;
if (config.has('log4jsConfig')) {
log4jsConfig = config.get('log4jsConfig');
}
if(log4jsConfig) {
let name = config.get('log4jsName');
log4jsConfig.appenders[1].category.unshift(name);
/* log日志的配置 */
var logDir = log4jsConfig.appenders[1].filename;
if(logDir) {
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}
}
/* 给日志文件名加上IP地址 */
var IpAdress = basic.getLocalIP('eth', 'IPv4');
if(log4jsConfig.appenders) {
for (var i = 0; i < log4jsConfig.appenders.length; i++) {
if (log4jsConfig.appenders[i].pattern) {
/* 把IP和微服务名移到filename字符串前面 */
var serviceName = log4jsConfig.appenders[i].pattern.split("-", 1);
log4jsConfig.appenders[i].pattern = log4jsConfig.appenders[i].pattern.slice(serviceName[0].length);
log4jsConfig.appenders[i].filename = log4jsConfig.appenders[i].filename + IpAdress + '-' + name + serviceName[0];
}
}
}
log4js.configure(log4jsConfig);
/* 将uncaughtException异常截获打印到log */
process.on('uncaughtException',function(err){
console.error(err.stack);
process.emit('exit',1);
});
}
module.exports = log4jsConfig;
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "zmop",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"lib": "lib"
},
"scripts": {
"start": "cross-env NODE_ENV=production&&node kqyx.js",
"dev": "supervisor index"
},
"author": "xaj",
"license": "MIT",
"dependencies": {
"ali-oss": "^5.2.0",
"body-parser": "^1.17.2",
"co": "^4.6.0",
"config": "^1.28.1",
"connect-multiparty": "^2.1.0",
"cookie-parser": "^1.4.3",
"crypto": "0.0.3",
"express": "^4.16.2",
"express-ws": "^3.0.0",
"extend": "^3.0.1",
"hbs": "^4.0.1",
"https": "^1.0.0",
"iconv-lite": "^0.4.17",
"log4js": "0.6.27",
"moment": "^2.18.1",
"mysql": "^2.15.0",
"mysql2": "^1.5.3",
"node-rsa": "^0.4.2",
"node-schedule": "^1.2.3",
"nunjucks": "^3.1.2",
"request": "^2.83.0",
"request-promise": "^4.2.2",
"sequelize": "^4.37.6"
},
"devDependencies": {
"cross-env": "^5.1.4"
}
}
# **1** 温馨提示
!>欢迎你成为煎饼数据服务的合作方,在开始接口调用之前请先确保完成以下事项:
>1. 完成 `合作方入驻` 流程,并已经完成本产品`签约`;
2. 你需要获取一个 `appKey``appSecret`
3. 通信协议只支持 `HTTPS`, 网关为 `https://t.51gjj.com/`
4. 整个流程可以分为`用户授权``获取数据`, `用户授权`支持`H5``API`, `获取数据`只支持`API`
5. `订单号(order_id)`是合作方与煎饼数据服务系统产生业务交互的唯一凭证,生成规则参考 `4.2`
6. `授权有效期`: 授权成功的用户,芝麻会为其开通芝麻信用账户并建立授权关系。用户若不主动取消授权,该授权为永久有效。在授权有效期内,合作方可以查询用户的信用信息。
7. `取消授权功能`: 用户可在芝麻信用客户端(即支付宝客户端 -> 芝麻信用 -> 信用管理 -> 授权管理)内取消授权。取消后,将不能查询该用户的信用信息。用户取消授权后,再查询该用户信息时芝麻会返回授权已失效的异常,此时需要引导用户重新发起授权过程。
# **2** 开始接入
## **2.1** H5接入
!> 访问之前需要生成订单号,生成过程见附录。
<table>
<tr>
<td>DOMAIN</td>
<td colspan=4>网关</td>
</tr>
<tr>
<td>PATH</td>
<td colspan=4>zmop/index</td>
</tr>
<tr>
<td>METHOD</td>
<td colspan=4>GET</td>
</tr>
<tr>
<td rowspan=9>GET参数</td>
<td>参数名</td>
<td>参数类型</td>
<td>参数描述</td>
<td>可空</td>
</tr>
<tr>
<td>appKey</td>
<td>string</td>
<td>平台发放给开发者的标识开发者身份的标识符</td>
<td>NO</td>
</tr>
<tr>
<td>order_id</td>
<td>string</td>
<td>订单号</td>
<td>NO</td>
</tr>
<tr>
<td>redirect</td>
<td>string</td>
<td>用户授权结束之后, 接收授权结果的异步回调地址, 须urlEncode,</td>
<td>NO</td>
</tr>
<tr>
<td>extras</td>
<td>string</td>
<td>合作方自定义数据, 会作为异步回调地址的参数返回给合作方</td>
<td>YES</td>
</tr>
<tr>
<td>channel</td>
<td>string</td>
<td>传入`H5`将只跳转到支付宝的H5页面进行授权</td>
<td>YES</td>
</tr>
</table>
## **2.2** 用户授权结束通知
**通知说明**
>当用户授权结束之后, 采用异步通知到合作方, `只通知一次, 需返回状态码为200的http响应`
**请求方式:**
- Method: POST
- Content-type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|status |是 |string |订单号对应状态(success/failed) |
|msg |是 |string | 任务结果的描述|
|order_id |是 |string | 任务订单号 |
|extras |否 |string | 合作方自定义数据|
**请求示例**
```json
{
"status": "success",
"msg": "操作成功",
"order_id": "20180************tfLVD232",
"extras": "esljdsd"
}
```
# **3** 获取用户数据
**简要描述:**
- 根据订单号获取用户数据
- 需要签名, 签名算法见`附录4.1`
## **3.1** 获取访问令牌token
>**请求URL:**
- ` zmop/getToken `
------------
>**请求方式:**
>- Method: POST
- Content-Type: application/json
- Charset: UTF-8
------------
> **参数:**
>
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|sign |是 |String |签名 |
|appKey |是 |String |公钥 |
|timestamp |是 |String | 时间戳 (单位:ms) |
------------
>**请求示例**
``` json
{
"sign":"SDSKKL5KJJKLL6JK1L",
"params":{
"appKey":"3FD179425381644F95424B66BE06E3E4",
"timestamp":"1494828184314"
}
}
```
>**返回示例1**
``` json
{
"code": 0,
"data": {
"token": "cd4283827366490eb037bf1b4b28dadc"
}
}
```
>**返回示例2**
``` json
{
"code": -1,
"msg": "参数错误"
}
```
>**返回参数说明**
>|参数名|类型|说明|
|:----- |:-----|----- |
|token |String |访问令牌(Token的有效期为2小时,当Token未失效时调用该接口,则返回新的Token,有效期重新计算,老的Token同时失效) |
|code |String |状态码 |
|msg |String |错误信息 |
------------
## **3.2** 获取芝麻分数据
**请求URL:**
- `zmop/data/score `
**请求方式:**
- Method: POST
- Content-type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|appKey |是 |string |公钥 |
|timestamp |是 |string | 时间戳 (单位:ms) |
|sign |是 |string | 签名 |
|token |是 |string | 访问令牌 |
|order_id |是 |string | 任务订单号 |
**请求示例**
``` json
{
"sign":"89D89A1D07E875C649D6A2D03F8E650A",
"params":{
"appKey": "88A03809137291F333BF2689AB85850E",
"timestamp":"3412xxxxxx01234567",
"token":"xx",
"order_id":"20180408121212555qwe23qwe1232sde"
}
}
```
**返回示例1**
``` json
{
"code": "0",
"data": {
//此处参考附录 4.3
...
}
}
```
**返回示例2**
``` json
{
"code": -1,
"msg": "无此订单数据"
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|data |String |数据结构参照芝麻分数据结构 |
|code |String |状态码 |
|msg |String |错误信息 |
## **3.3** 获取行业关注名单数据
**请求URL:**
- `zmop/data/watch_list `
**请求方式:**
- Method: POST
- Content-type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|appKey |是 |string |公钥 |
|timestamp |是 |string | 时间戳 (单位:ms) |
|sign |是 |string | 签名 |
|token |是 |string | 访问令牌 |
|order_id |是 |string | 任务订单号 |
**请求示例**
``` json
{
"sign":"89D89A1D07E875C649D6A2D03F8E650A",
"params":{
"appKey": "88A03809137291F333BF2689AB85850E",
"timestamp":"3412xxxxxx01234567",
"token":"xx",
"order_id":"20180408121212555qwe23qwe1232sde"
}
}
```
**返回示例1**
``` json
{
"code": "0",
"data": {
//此处参考附录 4.4
...
}
}
```
**返回示例2**
``` json
{
"code": -1,
"msg": "无此订单数据"
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|data |String |数据结构参照4.4 |
|code |String |状态码 |
|msg |String |错误信息 |
# **4** 附录
## **4.1** 签名算法
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
- 参数名ASCII码从小到大排序(字典序);
- 如果参数的值为空不参与签名;
- 参数名区分大小写;
第二步,在stringA最后拼接上appSecret得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
举例:
假设传送的参数如下:
``` json
appKey : 88A03809137291F333BF2689AB85850E,
order_id : 426ea0df-7f1b-4491-8989-5c130291e892,
phone : 18572387576,
timestamp : 1494649888152
token : 0eaeb00afcc4448da724d9179a50abe7
nonce_str:ibuaiVcKdpRxkhJA
```
第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:
``` javascript
stringA="appKey=092217B6B52ED02D46EFFFA7CFA20940&nonce_str=8224891888270884&order_id=3e993890-ff08-4af5-bb9b-04fda6dd2b78&phone=15658117723&timestamp=1494669826683&token=8731de2cd2604f4a856f210703541326";
```
第二步:拼接API密钥:
``` javascript
stringSignTemp=stringA+"&appSecret=192006250b4c09247ec02edce69f6a2d"
sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7"
```
## **4.2** 订单号
释义
>`订单号(order_id)`是合作方(或机构)与煎饼数据服务系统产生业务交互的唯一凭证,具体表现为一个长度为 `32` 位的字符串,仅能包含 `0-9A-Za-z_-` 等字符。每一个订单号(order_id)表明了合作方(或机构)与煎饼数据服务系统产生了一次确定的业务交互,煎饼数据服务系统给出了一个确定的返回结果,并以此作为与煎饼数据服务系统明细对账的唯一依据
生成规则
>订单号(order_id)推荐生成方式是,前 `17` 位为精确到`毫秒`的时间值(yyyyMMddHHmmssSSS)作为前缀,以合作方(或机构)自行生成的不重复字符串作为后缀,组成 `32` 位的字符串。
## **4.3** 芝麻分数据结构
**数据字典**
|参数名|类型|说明|
|:----- |:-----|----- |
|order_id |String |订单号 |
|create_time |String |从芝麻信用获取芝麻分的时间 |
|which_month |String |最新芝麻分所属月|
|score |String |芝麻分 |
### 数据样例
```json
{
"score": "746",
"which_month": "2018-04",
"create_time": "2018-04-28 11:26:02",
"order_id": "2018042710535*****QcPMRFLn8b7qYb"
}
```
## **4.4** 行业关注名单数据结构
**数据字典**
|名称|类型|描述|
|:---- |:--- |----- |
|order_id |String |订单号 |
|create_time |String |从芝麻信用获取数据的时间 |
|details |Array | 行业关注名单信息列表,由芝麻信用进行维护和升级 |
|isMatched |Boolean | true=命中 在关注名单中 false=未命中 |
**行业关注名单详细(details)信息详情:**
|名称|类型|描述|
|:---- |:---- |:----- |
|biz_code |String | 风险信息行业编码 |
|level |string | 风险等级 |
|type |String | 行业名单风险类型 |
|code |String | 风险编码 |
|refresh_time |Date | 数据刷新时间 |
|settlement |Boolean | 结清状态 |
|status |String | 用户本人对该条负面记录有异议时,表示该异议处理流程的状态 |
|statement |String | 当用户进行异议处理,并核查完毕之后,仍有异议时,给出的声明|
|extend_info |Array | 扩展信息 |
**扩展信息(extend_info)信息详情:**
|名称|类型|描述|
|:---- |:--- |----- |
|key |String | 补充信息字段的英文编码 |
|value |String | 补充信息字段的信息内容 |
|description |String | 补充信息字段的中文描述 |
### 数据样例
```json
{
"create_time": "2018-04-28 11:26:02",
"order_id": "2018042710535*****QcPMRFLn8b7qYb",
"details": [{ //行业关注名单信息列表,由芝麻信用进行维护和升级
"biz_code": "AH", //风险信息行业编码
"code": "AH001002", //风险编码
"extend_info": [{ //扩展信息
"description": "编号", //补充信息字段的中文描述
"key": "id", // 补充信息字段的英文编码
"value": "testlwztestlwz0d090d794bd563ba6053244b35fb2ccc" //补充信息字段的信息内容
}],
"level": 0, //风险等级
"refresh_time": 1465488000000, // 数据刷新时间
"settlement": true, //结清状态
"type": "AH001" //行业名单风险类型
}],
"is_matched": true //true=命中 在关注名单中 false=未命中
}
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>芝麻分接口文档</title>
<meta name="description" content="Description">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="vendor/themes/vue.css">
<style>
.markdown-section {
margin-left: 20px;
}
.field-support {
background: content-box;
font-size: 15px;
border: 1px solid #ddd;
padding: 6px 20px;
}
</style>
</head>
<body>
<div id="app"></div>
</body>
<script>
window.$docsify = {
name: '芝麻分接口文档',
repo: '', themeColor: '#3F51B5'
}
</script>
<script src="vendor/docsify.js"></script>
<script src="vendor/themes/bash.js"></script>
<script src="vendor/themes/json_base.js"></script>
</html>
const express = require('express');
const http = require('http');
const path = require('path');
const config = require('config');
// middlewares
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const timeInterval = config.get('timeInterval');
const scheduleproc = require('./lib/scheduleproc');
var app = express();
var login = require('./routers/login');
var pay = require('./routers/pay');
var tools = require('./routers/tools');
var main = require('./routers/main');
var data_service = require('./routers/data_service');
//X-Frame-Options: Allow-From http://www.growingio.com
app.use('*', function (req, res, next) {
res.setHeader('X-Frame-Options', 'ALLOW-FROM https://www.growingio.com');
next();
})
// 给app配置bodyParser中间件
// 通过如下配置再路由种处理request时,可以直接获得post请求的body部分
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
const aes = require('./lib/aes');
const token = require('./lib/token')
app.use(function (req, res, next) {
if (req.body.data) {
try {
req.body = aes.aesDecrypt(req.body.data)
if (!req.body) {
return res.send({code: 199, msg: '系统错误'})
}
req.body = JSON.parse(req.body)
} catch (e) {
console.log(e)
return res.send({code: 199, msg: '系统错误'})
}
}
// if (!/login/.test(req.path)) {
// try {
// let test = token.decode(req.headers.authorization)
// if (test) {
// req.body.userId = test.userId
// }
// }catch(e) {
// return res.send({code: -1, msg: '无效的authorization token'})
// }
// }
console.log(req.path, ': ', req.body)
next()
})
// 注册路由
app.use('/login', login);
app.use('/tools', tools);
app.use('/data', main);
app.use('/pay', pay);
app.use('/dataService', data_service);
const httpPort = config.get('httpPort')
var Server = http.createServer(app);
Server.listen(httpPort, function () {
console.log((new Date()) + ' server start http server and listen on: ' + JSON.stringify(Server.address()));
});
// 定时清理日志任务
scheduleproc.BeginCleanLogWork(timeInterval);
\ No newline at end of file
!function(){"use strict";function e(e){var t=Object.create(null);return function(n){var r=t[n];return r||(t[n]=e(n))}}function t(e){return"string"==typeof e||"number"==typeof e}function n(){}function r(e){return"function"==typeof e}function i(e){var t=["init","mounted","beforeEach","afterEach","doneEach","ready"];e._hooks={},e._lifecycle={},t.forEach(function(t){var n=e._hooks[t]=[];e._lifecycle[t]=function(e){return n.push(e)}})}function a(e,t,r,i){void 0===i&&(i=n);var a=r,o=e._hooks[t],s=function(e){var t=o[e];if(e>=o.length)i(a);else if("function"==typeof t)if(2===t.length)t(r,function(t){a=t,s(e+1)});else{var n=t(r);a=void 0!==n?n:a,s(e+1)}else s(e+1)};s(0)}function o(e,t){if(void 0===t&&(t=!1),"string"==typeof e){if("undefined"!=typeof window.Vue)return s(e);e=t?s(e):be[e]||(be[e]=s(e))}return e}function s(e,t){return t?e.querySelector(t):ye.querySelector(e)}function l(e,t){return[].slice.call(t?e.querySelectorAll(t):ye.querySelectorAll(e))}function c(e,t){return e=ye.createElement(e),t&&(e.innerHTML=t),e}function u(e,t){return e.appendChild(t)}function p(e,t){return e.insertBefore(t,e.children[0])}function h(e,t,n){r(t)?window.addEventListener(e,t):e.addEventListener(t,n)}function d(e,t,n){r(t)?window.removeEventListener(e,t):e.removeEventListener(t,n)}function g(e,t,n){e&&e.classList[n?t:"toggle"](n||t)}function f(e){var t={};return(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach(function(e){var n=e.replace(/\+/g," ").split("=");t[n[0]]=Ce(n[1])}),t):t}function m(e){var t=[];for(var n in e)t.push(($e(n)+"="+$e(e[n])).toLowerCase());return t.length?"?"+t.join("&"):""}function v(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return je(e.join("/"))}function b(e){var t=window.location.href.indexOf("#");window.location.replace(window.location.href.slice(0,t>=0?t:0)+"#"+e)}function y(){var e=k();return e=Oe(e),"/"===e.charAt(0)?b(e):void b("/"+e)}function k(){var e=window.location.href,t=e.indexOf("#");return t===-1?"":e.slice(t+1)}function w(e){void 0===e&&(e=window.location.href);var t="",n=e.indexOf("?");n>=0&&(t=e.slice(n+1),e=e.slice(0,n));var r=e.indexOf("#");return r&&(e=e.slice(r+1)),{path:e,query:f(t)}}function x(e,t,n){var r=n&&"#"===e[0],i=w(Oe(e));return i.query=pe({},i.query,t),e=i.path+m(i.query),e=e.replace(/\.md(\?)|\.md$/,"$1"),r&&(e=n+e),je("#/"+e)}function _(e){var t=function(e){return ke.classList.toggle("close")};e=o(e),h(e,"click",function(e){e.stopPropagation(),t()});var n=o(".sidebar");Le&&h(ke,"click",function(e){return ke.classList.contains("close")&&t()}),h(n,"click",function(e){return setTimeout(0)})}function S(){var e=o("section.cover");if(e){var t=e.getBoundingClientRect().height;window.pageYOffset>=t||e.classList.contains("hidden")?g(ke,"add","sticky"):g(ke,"remove","sticky")}}function L(e,t,n){e=o(e);var r,i=l(e,"a"),a="#"+k();return i.sort(function(e,t){return t.href.length-e.href.length}).forEach(function(e){var n=e.getAttribute("href"),i=t?e.parentNode:e;0!==a.indexOf(n)||r?g(i,"remove","active"):(r=e,g(i,"add","active"))}),n&&(ye.title=r?r.innerText+" - "+Pe:Pe),r}function C(){for(var e,t=o(".sidebar"),n=l(".anchor"),r=s(t,".sidebar-nav"),i=s(t,"li.active"),a=ke.scrollTop,c=0,u=n.length;c<u;c+=1){var p=n[c];if(p.offsetTop>a){e||(e=p);break}e=p}if(e){var h=qe[e.getAttribute("data-id")];if(h&&h!==i&&(i&&i.classList.remove("active"),h.classList.add("active"),i=h,!Ne&&ke.classList.contains("sticky"))){var d=t.clientHeight,g=0,f=i.offsetTop+i.clientHeight+40,m=i.offsetTop>=r.scrollTop&&f<=r.scrollTop+d,v=f-g<d,b=m?r.scrollTop:v?g:f-d;t.scrollTop=b}}}function $(){if(!Le){for(var e=o(".sidebar"),t=l(e,"li"),n=0,r=t.length;n<r;n+=1){var i=t[n],a=i.querySelector("a");if(a){var s=a.getAttribute("href");"/"!==s&&(s=w(s).query.id),qe[decodeURIComponent(s)]=i}}d("scroll",C),h("scroll",C),h(e,"mouseover",function(){Ne=!0}),h(e,"mouseleave",function(){Ne=!1})}}function E(e){var t=s("#"+e);t&&t.scrollIntoView()}function T(e){void 0===e&&(e=0),Fe.scrollTop=e===!0?0:Number(e)}function A(){var e=c("div");e.classList.add("progress"),u(ke,e),me=e}function j(e,t){void 0===t&&(t=!1);var r=new XMLHttpRequest,i=function(){r.addEventListener.apply(r,arguments)};return Ie[e]?{then:function(t){return t(Ie[e])},abort:n}:(r.open("GET",e),r.send(),{then:function(r,a){if(void 0===a&&(a=n),t){var o=setInterval(function(e){return He({step:Math.floor(5*Math.random()+1)})},500);i("progress",He),i("loadend",function(e){He(e),clearInterval(o)})}i("error",a),i("load",function(t){var n=t.target;n.status>=400?a(n):(Ie[e]=n.response,r(n.response))})},abort:function(e){return 4!==r.readyState&&r.abort()}})}function O(e,t){e.innerHTML=e.innerHTML.replace(/var\(\s*--theme-color.*?\)/g,t)}function M(e){return e?(/\/\//.test(e)||(e="https://github.com/"+e),e=e.replace(/^git\+/,""),'<a href="'+e+'" class="github-corner" aria-label="View source on Github"><svg viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>'):""}function P(e){var t='<button class="sidebar-toggle"><div class="sidebar-toggle-button"><span></span><span></span><span></span></div></button><aside class="sidebar">'+(e.name?'<h1><a class="app-name-link" data-nosearch>'+e.name+"</a></h1>":"")+'<div class="sidebar-nav"></div></aside>';return(Le?t+"<main>":"<main>"+t)+'<section class="content"><article class="markdown-section" id="main"></article></section></main>'}function q(){var e=", 100%, 85%",t="linear-gradient(to left bottom, hsl("+(Math.floor(255*Math.random())+e)+") 0%,hsl("+(Math.floor(255*Math.random())+e)+") 100%)";return'<section class="cover" style="background: '+t+'"><div class="cover-main"></div><div class="mask"></div></section>'}function N(e,t){return void 0===t&&(t=""),e&&e.length?(e.forEach(function(e){t+='<li><a class="section-link" href="'+e.slug+'">'+e.title+"</a></li>",e.children&&(t+='<li><ul class="children">'+N(e.children)+"</li></ul>")}),t):""}function F(e,t){return'<p class="'+e+'">'+t.slice(5).trim()+"</p>"}function H(e){return"<style>:root{--theme-color: "+e+";}</style>"}function I(e,t){return t={exports:{}},e(t,t.exports),t.exports}function z(e,t){var n=[],r={};return e.forEach(function(e){var i=e.level||1,a=i-1;i>t||(r[a]?r[a].children=(r[a].children||[]).concat(e):n.push(e),r[i]=e)}),n}function R(e){if("string"!=typeof e)return"";var t=e.toLowerCase().trim().replace(/<[^>\d]+>/g,"").replace(Ue,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),n=De[t];return n=De.hasOwnProperty(t)?n+1:0,De[t]=n,n&&(t=t+"-"+n),t}function W(e,t){return'<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/'+t+'.png" alt="'+t+'" />'}function B(e){return $docsify.noEmoji?e:e.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/:(\w+?):/gi,window.emojify||W).replace(/__colon__/g,":")}function D(e,t){var n="";if(e)n=Qe(e),n=n.match(/<ul[^>]*>([\s\S]+)<\/ul>/g)[0];else{var r=Ye[Xe]||z(Je,t);n=N(r,"<ul>"),Ye[Xe]=r}return n}function U(e,t){if(e){Je[0]&&Je[0].ignoreAllSubs&&(Je=[]),Je[0]&&1===Je[0].level&&Je.shift(),Je.forEach(function(e,t){e.ignoreSubHeading&&Je.splice(t,1)});var n=Ye[Xe]||z(Je,t);e.parentNode.innerHTML+=N(n,'<ul class="app-sub-sidebar">'),Ye[Xe]=n}Je=[]}function G(e){var t=Je.slice(),n=Qe(e);return Je=t.slice(),n}function V(){var e=l(".markdown-section>script").filter(function(e){return!/template/.test(e.type)})[0];if(!e)return!1;var t=e.innerText.trim();return!!t&&void setTimeout(function(e){window.__EXECUTE_RESULT__=new Function(t)()},0)}function X(e){e||(e="not found"),this._renderTo(".markdown-section",e),!this.config.loadSidebar&&this._renderSidebar(),this.config.executeScript===!1||"undefined"==typeof window.Vue||V()?this.config.executeScript&&V():setTimeout(function(e){var t=window.__EXECUTE_RESULT__;t&&t.$destroy&&t.$destroy(),window.__EXECUTE_RESULT__=(new window.Vue).$mount("#main")},0),this.config.auto2top&&T(this.config.auto2top)}function Z(e){var n=o(".app-name-link"),r=e.config.nameLink,i=e.route.path;if(n)if(t(e.config.nameLink))n.setAttribute("href",r);else if("object"==typeof r){var a=Object.keys(r).find(function(e){return i.indexOf(e)>-1});n.setAttribute("href",r[a])}}function Y(e){e._renderTo=function(e,t,n){var r=o(e);r&&(r[n?"outerHTML":"innerHTML"]=t)},e._renderSidebar=function(e){var t=this.config,n=t.maxLevel,r=t.subMaxLevel,i=t.autoHeader,a=t.loadSidebar;this._renderTo(".sidebar-nav",D(e,n));var s=L(".sidebar-nav",!0,!0);if(U(a?s:"",r),this.activeLink=s,$(),i&&s){var l=o("#main"),u=l.children[0];if(u&&"H1"!==u.tagName){var h=c("h1");h.innerText=s.innerText,p(l,h)}}},e._renderNav=function(e){e&&this._renderTo("nav",Qe(e)),L("nav")},e._renderMain=function(e){var t=this;a(this,"beforeEach",e,function(e){var n=t.isHTML?e:Qe(e);a(t,"afterEach",n,function(e){return X.call(t,e)})})},e._renderCover=function(e){var t=o(".cover");if(!e)return void g(t,"remove","show");g(t,"add","show");var n=this.coverIsHTML?e:G(e),r=n.trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$');if(r){if("color"===r[2])t.style.background=r[1]+(r[3]||"");else{var i=r[1];g(t,"add","has-mask"),Te(r[1])||(i=v(Ee(this.config.basePath),r[1])),t.style.backgroundImage="url("+i+")",t.style.backgroundSize="cover",t.style.backgroundPosition="center center"}n=n.replace(r[0],"")}this._renderTo(".cover-main",n),S()},e._updateRender=function(){Qe.update(),Z(this)}}function J(e){var t=e.config;Qe.init(t.markdown,t.basePath);var n=t.el||"#app",r=s("nav")||c("nav"),i=s(n),a="",o=ke;i||(i=c(n),u(ke,i)),t.repo&&(a+=M(t.repo)),t.coverpage&&(a+=q()),a+=P(t),e._renderTo(i,a,!0),t.mergeNavbar&&Le?o=s(".sidebar"):(r.classList.add("app-nav"),t.repo||r.classList.add("no-badge")),p(o,r),t.themeColor&&(ye.head.innerHTML+=H(t.themeColor),ze(t.themeColor)),g(ke,"ready")}function Q(e,t){return t[e]?Q(t[e],t):e}function K(e){return/\.(md|html)$/g.test(e)?e:/\/$/g.test(e)?e+"README.md":e+".md"}function ee(e){e.route={},e.$getFile=function(e){var t=this,n=t.config,r=Ee(n.basePath);return e=n.alias?Q(e,n.alias):e,e=K(e),e="/README.md"===e?n.homepage||e:e,e=Te(e)?e:v(r,e)}}function te(e){y(),et=e.route=w(),e._updateRender(),h("hashchange",function(t){return y(),e.route=w(),e._updateRender(),et.path===e.route.path?void e.$resetEvents():(e.$fetch(),void(et=e.route))})}function ne(e){e.$resetEvents=function(){E(this.route.query.id),L("nav")}}function re(e){_("button.sidebar-toggle"),e.config.coverpage?!Le&&h("scroll",S):ke.classList.add("sticky")}function ie(e,t,n,r,i){e=i?e:e.replace(/\/$/,""),e=Ae(e),e&&j(r.$getFile(e+t)).then(n,function(i){return ie(e,t,n,r)})}function ae(e){var t;e._fetch=function(e){var r=this;void 0===e&&(e=n);var i=this.route,a=i.path,o=this.config,s=o.loadNavbar,l=o.loadSidebar;t&&t.abort&&t.abort(),t=j(this.$getFile(a),!0),this.isHTML=/\.html$/g.test(a),t.then(function(t){if(r._renderMain(t),!l)return e();var n=function(t){r._renderSidebar(t),e()};ie(a,l,n,r,!0)},function(e){return r._renderMain(null)}),s&&ie(a,s,function(e){return r._renderNav(e)},this,!0)},e._fetchCover=function(){var e=this,t=this.config,n=t.coverpage,r=Ae(this.route.path),i=this.$getFile(r+n);return"/"===this.route.path&&n?(this.coverIsHTML=/\.html$/g.test(i),void j(i).then(function(t){return e._renderCover(t)})):void this._renderCover()},e.$fetch=function(e){var t=this;void 0===e&&(e=n),this._fetchCover(),this._fetch(function(n){t.$resetEvents(),a(t,"doneEach"),e()})}}function oe(e){e.$fetch(function(t){return a(e,"ready")})}function se(e){e._init=function(){var e=this;e.config=he||{},i(e),le(e),a(e,"init"),J(e),re(e),te(e),oe(e),a(e,"mounted")}}function le(e){[].concat(e.config.plugins).forEach(function(t){return r(t)&&t(e._lifecycle,e)})}function ce(){this._init()}var ue=e(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),pe=Object.assign||function(e){for(var t=arguments,n=Object.prototype.hasOwnProperty,r=1;r<arguments.length;r++){var i=Object(t[r]);for(var a in i)n.call(i,a)&&(e[a]=i[a])}return e},he=pe({el:"#app",repo:"",maxLevel:6,subMaxLevel:0,loadSidebar:null,loadNavbar:null,homepage:"README.md",coverpage:"",basePath:"",auto2top:!1,name:"",themeColor:"",nameLink:window.location.pathname,autoHeader:!1,executeScript:null,noEmoji:!1,ga:"",mergeNavbar:!1},window.$docsify),de=document.currentScript||[].slice.call(document.getElementsByTagName("script")).filter(function(e){return/docsify\./.test(e.src)})[0];if(de){for(var ge in he){var fe=de.getAttribute("data-"+ue(ge));t(fe)&&(he[ge]=""===fe||fe)}he.loadSidebar===!0&&(he.loadSidebar="_sidebar.md"),he.loadNavbar===!0&&(he.loadNavbar="_navbar.md"),he.coverpage===!0&&(he.coverpage="_coverpage.md"),he.repo===!0&&(he.repo=""),he.name===!0&&(he.name="")}window.$docsify=he;var me,ve,be={},ye=document,ke=ye.body,we=ye.head,xe=Object.freeze({getNode:o,$:ye,body:ke,head:we,find:s,findAll:l,create:c,appendTo:u,before:p,on:h,off:d,toggleClass:g}),_e=window.navigator.userAgent.toLowerCase(),Se=_e&&/msie|trident/.test(_e),Le=document.body.clientWidth<=600,Ce=decodeURIComponent,$e=encodeURIComponent,Ee=e(function(e){return/^(\/|https?:)/g.test(e)?e:je(window.location.pathname+"/"+e)}),Te=e(function(e){return/(:|(\/{2}))/.test(e)}),Ae=e(function(e){return/\/$/g.test(e)?e:(e=e.match(/(\S*\/)[^\/]+$/))?e[1]:""}),je=e(function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")}),Oe=e(function(e){return e.replace("#","?id=")}),Me=Object.freeze({normalize:y,getHash:k,parse:w,toURL:x,parseQuery:f,stringifyQuery:m,getBasePath:Ee,getPath:v,isAbsolutePath:Te,getParentPath:Ae,cleanPath:je}),Pe=ye.title,qe={},Ne=!1,Fe=ye.scrollingElement||ye.documentElement,He=function(e){var t,n=e.loaded,r=e.total,i=e.step;!me&&A(),i?(t=parseInt(me.style.width||0,10)+i,t=t>80?80:t):t=Math.floor(n/r*100),me.style.opacity=1,me.style.width=t>=95?"100%":t+"%",t>=95&&(clearTimeout(ve),ve=setTimeout(function(e){me.style.opacity=0,me.style.width="0%"},200))},Ie={},ze=function(e){if(!(window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)"))){var t=l("style:not(.inserted),link");[].forEach.call(t,function(t){if("STYLE"===t.nodeName)O(t,e);else if("LINK"===t.nodeName){var n=t.getAttribute("href");if(!/\.css$/.test(n))return;j(n).then(function(t){var n=c("style",t);we.appendChild(n),O(n,e)})}})}},Re="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},We=I(function(e,t){(function(){function t(e){this.tokens=[],this.tokens.links={},this.options=e||u.defaults,this.rules=p.normal,this.options.gfm&&(this.options.tables?this.rules=p.tables:this.rules=p.gfm)}function n(e,t){if(this.options=t||u.defaults,this.links=e,this.rules=h.normal,this.renderer=this.options.renderer||new r,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.gfm?this.options.breaks?this.rules=h.breaks:this.rules=h.gfm:this.options.pedantic&&(this.rules=h.pedantic)}function r(e){this.options=e||{}}function i(e){this.tokens=[],this.token=null,this.options=e||u.defaults,this.options.renderer=this.options.renderer||new r,this.renderer=this.options.renderer,this.renderer.options=this.options}function a(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function o(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g,function(e,t){return t=t.toLowerCase(),"colon"===t?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function s(e,t){return e=e.source,t=t||"",function n(r,i){return r?(i=i.source||i,i=i.replace(/(^|[^\[])\^/g,"$1"),e=e.replace(r,i),n):new RegExp(e,t)}}function l(){}function c(e){for(var t,n,r=arguments,i=1;i<arguments.length;i++){t=r[i];for(n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e}function u(e,n,r){if(r||"function"==typeof n){r||(r=n,n=null),n=c({},u.defaults,n||{});var o,s,l=n.highlight,p=0;try{o=t.lex(e,n)}catch(e){return r(e)}s=o.length;var h=function(e){if(e)return n.highlight=l,r(e);var t;try{t=i.parse(o,n)}catch(t){e=t}return n.highlight=l,e?r(e):r(null,t)};if(!l||l.length<3)return h();if(delete n.highlight,!s)return h();for(;p<o.length;p++)!function(e){return"code"!==e.type?--s||h():l(e.text,e.lang,function(t,n){return t?h(t):null==n||n===e.text?--s||h():(e.text=n,e.escaped=!0,void(--s||h()))})}(o[p])}else try{return n&&(n=c({},u.defaults,n)),i.parse(t.lex(e,n),n)}catch(e){if(e.message+="\nPlease report this to https://github.com/chjj/marked.",(n||u.defaults).silent)return"<p>An error occured:</p><pre>"+a(e.message+"",!0)+"</pre>";throw e}}var p={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:l,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:l,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:l,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};p.bullet=/(?:[*+-]|\d+\.)/,p.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,p.item=s(p.item,"gm")(/bull/g,p.bullet)(),p.list=s(p.list)(/bull/g,p.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+p.def.source+")")(),p.blockquote=s(p.blockquote)("def",p.def)(),p._tag="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b",p.html=s(p.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,p._tag)(),p.paragraph=s(p.paragraph)("hr",p.hr)("heading",p.heading)("lheading",p.lheading)("blockquote",p.blockquote)("tag","<"+p._tag)("def",p.def)(),p.normal=c({},p),p.gfm=c({},p.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),p.gfm.paragraph=s(p.paragraph)("(?!","(?!"+p.gfm.fences.source.replace("\\1","\\2")+"|"+p.list.source.replace("\\1","\\3")+"|")(),p.tables=c({},p.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),t.rules=p,t.lex=function(e,n){var r=new t(n);return r.lex(e)},t.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},t.prototype.token=function(e,t,n){for(var r,i,a,o,s,l,c,u,h,d=this,e=e.replace(/^ +$/gm,"");e;)if((a=d.rules.newline.exec(e))&&(e=e.substring(a[0].length),a[0].length>1&&d.tokens.push({type:"space"})),a=d.rules.code.exec(e))e=e.substring(a[0].length),a=a[0].replace(/^ {4}/gm,""),d.tokens.push({type:"code",text:d.options.pedantic?a:a.replace(/\n+$/,"")});else if(a=d.rules.fences.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"code",lang:a[2],text:a[3]||""});else if(a=d.rules.heading.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"heading",depth:a[1].length,text:a[2]});else if(t&&(a=d.rules.nptable.exec(e))){for(e=e.substring(a[0].length),l={type:"table",header:a[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:a[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:a[3].replace(/\n$/,"").split("\n")},u=0;u<l.align.length;u++)/^ *-+: *$/.test(l.align[u])?l.align[u]="right":/^ *:-+: *$/.test(l.align[u])?l.align[u]="center":/^ *:-+ *$/.test(l.align[u])?l.align[u]="left":l.align[u]=null;for(u=0;u<l.cells.length;u++)l.cells[u]=l.cells[u].split(/ *\| */);d.tokens.push(l)}else if(a=d.rules.lheading.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"heading",depth:"="===a[2]?1:2,text:a[1]});else if(a=d.rules.hr.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"hr"});else if(a=d.rules.blockquote.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"blockquote_start"}),a=a[0].replace(/^ *> ?/gm,""),d.token(a,t,!0),d.tokens.push({type:"blockquote_end"});else if(a=d.rules.list.exec(e)){for(e=e.substring(a[0].length),o=a[2],d.tokens.push({type:"list_start",ordered:o.length>1}),a=a[0].match(d.rules.item),r=!1,h=a.length,u=0;u<h;u++)l=a[u],c=l.length,l=l.replace(/^ *([*+-]|\d+\.) +/,""),~l.indexOf("\n ")&&(c-=l.length,l=d.options.pedantic?l.replace(/^ {1,4}/gm,""):l.replace(new RegExp("^ {1,"+c+"}","gm"),"")),d.options.smartLists&&u!==h-1&&(s=p.bullet.exec(a[u+1])[0],o===s||o.length>1&&s.length>1||(e=a.slice(u+1).join("\n")+e,u=h-1)),i=r||/\n\n(?!\s*$)/.test(l),u!==h-1&&(r="\n"===l.charAt(l.length-1),i||(i=r)),d.tokens.push({type:i?"loose_item_start":"list_item_start"}),d.token(l,!1,n),d.tokens.push({type:"list_item_end"});d.tokens.push({type:"list_end"})}else if(a=d.rules.html.exec(e))e=e.substring(a[0].length),d.tokens.push({type:d.options.sanitize?"paragraph":"html",pre:!d.options.sanitizer&&("pre"===a[1]||"script"===a[1]||"style"===a[1]),text:a[0]});else if(!n&&t&&(a=d.rules.def.exec(e)))e=e.substring(a[0].length),d.tokens.links[a[1].toLowerCase()]={href:a[2],title:a[3]};else if(t&&(a=d.rules.table.exec(e))){for(e=e.substring(a[0].length),l={type:"table",header:a[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:a[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:a[3].replace(/(?: *\| *)?\n$/,"").split("\n")},u=0;u<l.align.length;u++)/^ *-+: *$/.test(l.align[u])?l.align[u]="right":/^ *:-+: *$/.test(l.align[u])?l.align[u]="center":/^ *:-+ *$/.test(l.align[u])?l.align[u]="left":l.align[u]=null;for(u=0;u<l.cells.length;u++)l.cells[u]=l.cells[u].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */);d.tokens.push(l)}else if(t&&(a=d.rules.paragraph.exec(e)))e=e.substring(a[0].length),d.tokens.push({type:"paragraph",text:"\n"===a[1].charAt(a[1].length-1)?a[1].slice(0,-1):a[1]});else if(a=d.rules.text.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"text",text:a[0]});else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0));return this.tokens};var h={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:l,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:l,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};h._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/,h._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/,h.link=s(h.link)("inside",h._inside)("href",h._href)(),h.reflink=s(h.reflink)("inside",h._inside)(),h.normal=c({},h),h.pedantic=c({},h.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),h.gfm=c({},h.normal,{escape:s(h.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:s(h.text)("]|","~]|")("|","|https?://|")()}),h.breaks=c({},h.gfm,{br:s(h.br)("{2,}","*")(),text:s(h.gfm.text)("{2,}","*")()}),n.rules=h,n.output=function(e,t,r){var i=new n(t,r);return i.output(e)},n.prototype.output=function(e){for(var t,n,r,i,o=this,s="";e;)if(i=o.rules.escape.exec(e))e=e.substring(i[0].length),s+=i[1];else if(i=o.rules.autolink.exec(e))e=e.substring(i[0].length),"@"===i[2]?(n=":"===i[1].charAt(6)?o.mangle(i[1].substring(7)):o.mangle(i[1]),r=o.mangle("mailto:")+n):(n=a(i[1]),r=n),s+=o.renderer.link(r,null,n);else if(o.inLink||!(i=o.rules.url.exec(e))){if(i=o.rules.tag.exec(e))!o.inLink&&/^<a /i.test(i[0])?o.inLink=!0:o.inLink&&/^<\/a>/i.test(i[0])&&(o.inLink=!1),e=e.substring(i[0].length),s+=o.options.sanitize?o.options.sanitizer?o.options.sanitizer(i[0]):a(i[0]):i[0];else if(i=o.rules.link.exec(e))e=e.substring(i[0].length),o.inLink=!0,s+=o.outputLink(i,{href:i[2],title:i[3]}),o.inLink=!1;else if((i=o.rules.reflink.exec(e))||(i=o.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),t=o.links[t.toLowerCase()],!t||!t.href){s+=i[0].charAt(0),e=i[0].substring(1)+e;continue}o.inLink=!0,s+=o.outputLink(i,t),o.inLink=!1}else if(i=o.rules.strong.exec(e))e=e.substring(i[0].length),s+=o.renderer.strong(o.output(i[2]||i[1]));else if(i=o.rules.em.exec(e))e=e.substring(i[0].length),s+=o.renderer.em(o.output(i[2]||i[1]));else if(i=o.rules.code.exec(e))e=e.substring(i[0].length),s+=o.renderer.codespan(a(i[2],!0));else if(i=o.rules.br.exec(e))e=e.substring(i[0].length),s+=o.renderer.br();else if(i=o.rules.del.exec(e))e=e.substring(i[0].length),s+=o.renderer.del(o.output(i[1]));else if(i=o.rules.text.exec(e))e=e.substring(i[0].length),s+=o.renderer.text(a(o.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else e=e.substring(i[0].length),n=a(i[1]),r=n,s+=o.renderer.link(r,null,n);return s},n.prototype.outputLink=function(e,t){var n=a(t.href),r=t.title?a(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,a(e[1]))},n.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014\/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014\/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},n.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,i=0;i<r;i++)t=e.charCodeAt(i),Math.random()>.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},r.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'<pre><code class="'+this.options.langPrefix+a(t,!0)+'">'+(n?e:a(e,!0))+"\n</code></pre>\n":"<pre><code>"+(n?e:a(e,!0))+"\n</code></pre>"},r.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n){return"<h"+t+' id="'+this.options.headerPrefix+n.toLowerCase().replace(/[^\w]+/g,"-")+'">'+e+"</h"+t+">\n"},r.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},r.prototype.list=function(e,t){var n=t?"ol":"ul";return"<"+n+">\n"+e+"</"+n+">\n"},r.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},r.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},r.prototype.table=function(e,t){return"<table>\n<thead>\n"+e+"</thead>\n<tbody>\n"+t+"</tbody>\n</table>\n"},r.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td",r=t.align?"<"+n+' style="text-align:'+t.align+'">':"<"+n+">";return r+e+"</"+n+">\n"},r.prototype.strong=function(e){return"<strong>"+e+"</strong>"},r.prototype.em=function(e){return"<em>"+e+"</em>"},r.prototype.codespan=function(e){return"<code>"+e+"</code>"},r.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},r.prototype.del=function(e){return"<del>"+e+"</del>"},r.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(o(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:"))return""}var i='<a href="'+e+'"';return t&&(i+=' title="'+t+'"'),i+=">"+n+"</a>"},r.prototype.image=function(e,t,n){var r='<img src="'+e+'" alt="'+n+'"';return t&&(r+=' title="'+t+'"'),r+=this.options.xhtml?"/>":">"},r.prototype.text=function(e){return e},i.parse=function(e,t,n){var r=new i(t,n);return r.parse(e)},i.prototype.parse=function(e){var t=this;this.inline=new n(e.links,this.options,this.renderer),this.tokens=e.reverse();for(var r="";this.next();)r+=t.tok();return r},i.prototype.next=function(){return this.token=this.tokens.pop()},i.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},i.prototype.parseText=function(){for(var e=this,t=this.token.text;"text"===this.peek().type;)t+="\n"+e.next().text;return this.inline.output(t)},i.prototype.tok=function(){var e=this;switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var t,n,r,i,a,o="",s="";for(r="",t=0;t<this.token.header.length;t++)i={header:!0,align:e.token.align[t]},r+=e.renderer.tablecell(e.inline.output(e.token.header[t]),{header:!0,align:e.token.align[t]});for(o+=this.renderer.tablerow(r),t=0;t<this.token.cells.length;t++){for(n=e.token.cells[t],r="",a=0;a<n.length;a++)r+=e.renderer.tablecell(e.inline.output(n[a]),{header:!1,align:e.token.align[a]});s+=e.renderer.tablerow(r)}return this.renderer.table(o,s);case"blockquote_start":for(var s="";"blockquote_end"!==this.next().type;)s+=e.tok();return this.renderer.blockquote(s);case"list_start":for(var s="",l=this.token.ordered;"list_end"!==this.next().type;)s+=e.tok();return this.renderer.list(s,l);case"list_item_start":for(var s="";"list_item_end"!==this.next().type;)s+="text"===e.token.type?e.parseText():e.tok();return this.renderer.listitem(s);case"loose_item_start":for(var s="";"list_item_end"!==this.next().type;)s+=e.tok();return this.renderer.listitem(s);case"html":var c=this.token.pre||this.options.pedantic?this.token.text:this.inline.output(this.token.text);return this.renderer.html(c);case"paragraph":return this.renderer.paragraph(this.inline.output(this.token.text));case"text":return this.renderer.paragraph(this.parseText())}},l.exec=l,u.options=u.setOptions=function(e){return c(u.defaults,e),u},u.defaults={gfm:!0,tables:!0,breaks:!1,pedantic:!1,sanitize:!1,sanitizer:null,mangle:!0,smartLists:!1,silent:!1,highlight:null,langPrefix:"lang-",smartypants:!1,headerPrefix:"",renderer:new r,xhtml:!1},u.Parser=i,u.parser=i.parse,u.Renderer=r,u.Lexer=t,u.lexer=t.lex,u.InlineLexer=n,u.inlineLexer=n.output,u.parse=u,e.exports=u}).call(function(){return this||("undefined"!=typeof window?window:Re)}())}),Be=I(function(e){var t="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},n=function(){var e=/\blang(?:uage)?-(\w+)\b/i,n=0,r=t.Prism={util:{encode:function(e){return e instanceof i?new i(e.type,r.util.encode(e.content),e.alias):"Array"===r.util.type(e)?e.map(r.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++n}),e.__id},clone:function(e){var t=r.util.type(e);switch(t){case"Object":var n={};for(var i in e)e.hasOwnProperty(i)&&(n[i]=r.util.clone(e[i]));return n;case"Array":return e.map&&e.map(function(e){return r.util.clone(e)})}return e}},languages:{extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var i in t)n[i]=t[i];return n},insertBefore:function(e,t,n,i){i=i||r.languages;var a=i[e];if(2==arguments.length){n=arguments[1];for(var o in n)n.hasOwnProperty(o)&&(a[o]=n[o]);return a}var s={};for(var l in a)if(a.hasOwnProperty(l)){if(l==t)for(var o in n)n.hasOwnProperty(o)&&(s[o]=n[o]);
s[l]=a[l]}return r.languages.DFS(r.languages,function(t,n){n===i[e]&&t!=e&&(this[t]=s)}),i[e]=s},DFS:function(e,t,n,i){i=i||{};for(var a in e)e.hasOwnProperty(a)&&(t.call(e,a,e[a],n||a),"Object"!==r.util.type(e[a])||i[r.util.objId(e[a])]?"Array"!==r.util.type(e[a])||i[r.util.objId(e[a])]||(i[r.util.objId(e[a])]=!0,r.languages.DFS(e[a],t,a,i)):(i[r.util.objId(e[a])]=!0,r.languages.DFS(e[a],t,null,i)))}},plugins:{},highlightAll:function(e,t){var n={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};r.hooks.run("before-highlightall",n);for(var i,a=n.elements||document.querySelectorAll(n.selector),o=0;i=a[o++];)r.highlightElement(i,e===!0,n.callback)},highlightElement:function(n,i,a){for(var o,s,l=n;l&&!e.test(l.className);)l=l.parentNode;l&&(o=(l.className.match(e)||[,""])[1].toLowerCase(),s=r.languages[o]),n.className=n.className.replace(e,"").replace(/\s+/g," ")+" language-"+o,l=n.parentNode,/pre/i.test(l.nodeName)&&(l.className=l.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var c=n.textContent,u={element:n,language:o,grammar:s,code:c};if(r.hooks.run("before-sanity-check",u),!u.code||!u.grammar)return u.code&&(u.element.textContent=u.code),void r.hooks.run("complete",u);if(r.hooks.run("before-highlight",u),i&&t.Worker){var p=new Worker(r.filename);p.onmessage=function(e){u.highlightedCode=e.data,r.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(u.element),r.hooks.run("after-highlight",u),r.hooks.run("complete",u)},p.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=r.highlight(u.code,u.grammar,u.language),r.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(n),r.hooks.run("after-highlight",u),r.hooks.run("complete",u)},highlight:function(e,t,n){var a=r.tokenize(e,t);return i.stringify(r.util.encode(a),n)},tokenize:function(e,t,n){var i=r.Token,a=[e],o=t.rest;if(o){for(var s in o)t[s]=o[s];delete t.rest}e:for(var s in t)if(t.hasOwnProperty(s)&&t[s]){var l=t[s];l="Array"===r.util.type(l)?l:[l];for(var c=0;c<l.length;++c){var u=l[c],p=u.inside,h=!!u.lookbehind,d=!!u.greedy,g=0,f=u.alias;if(d&&!u.pattern.global){var m=u.pattern.toString().match(/[imuy]*$/)[0];u.pattern=RegExp(u.pattern.source,m+"g")}u=u.pattern||u;for(var v=0,b=0;v<a.length;b+=a[v].length,++v){var y=a[v];if(a.length>e.length)break e;if(!(y instanceof i)){u.lastIndex=0;var k=u.exec(y),w=1;if(!k&&d&&v!=a.length-1){if(u.lastIndex=b,k=u.exec(e),!k)break;for(var x=k.index+(h?k[1].length:0),_=k.index+k[0].length,S=v,L=b,C=a.length;S<C&&L<_;++S)L+=a[S].length,x>=L&&(++v,b=L);if(a[v]instanceof i||a[S-1].greedy)continue;w=S-v,y=e.slice(b,L),k.index-=b}if(k){h&&(g=k[1].length);var x=k.index+g,k=k[0].slice(g),_=x+k.length,$=y.slice(0,x),E=y.slice(_),T=[v,w];$&&T.push($);var A=new i(s,p?r.tokenize(k,p):k,f,k,d);T.push(A),E&&T.push(E),Array.prototype.splice.apply(a,T)}}}}}return a},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var i,a=0;i=n[a++];)i(t)}}},i=r.Token=function(e,t,n,r,i){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!i};if(i.stringify=function(e,t,n){if("string"==typeof e)return e;if("Array"===r.util.type(e))return e.map(function(n){return i.stringify(n,t,e)}).join("");var a={type:e.type,content:i.stringify(e.content,t,n),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:n};if("comment"==a.type&&(a.attributes.spellcheck="true"),e.alias){var o="Array"===r.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(a.classes,o)}r.hooks.run("wrap",a);var s=Object.keys(a.attributes).map(function(e){return e+'="'+(a.attributes[e]||"").replace(/"/g,"&quot;")+'"'}).join(" ");return"<"+a.tag+' class="'+a.classes.join(" ")+'"'+(s?" "+s:"")+">"+a.content+"</"+a.tag+">"},!t.document)return t.addEventListener?(t.addEventListener("message",function(e){var n=JSON.parse(e.data),i=n.language,a=n.code,o=n.immediateClose;t.postMessage(r.highlight(a,r.languages[i],i)),o&&t.close()},!1),t.Prism):t.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(r.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(r.highlightAll):window.setTimeout(r.highlightAll,16):document.addEventListener("DOMContentLoaded",r.highlightAll))),t.Prism}();e.exports&&(e.exports=n),"undefined"!=typeof Re&&(Re.Prism=n),n.languages.markup={comment:/<!--[\w\W]*?-->/,prolog:/<\?[\w\W]+?\?>/,doctype:/<!DOCTYPE[\w\W]+?>/i,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},n.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&amp;/,"&"))}),n.languages.xml=n.languages.markup,n.languages.html=n.languages.markup,n.languages.mathml=n.languages.markup,n.languages.svg=n.languages.markup,n.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},n.languages.css.atrule.inside.rest=n.util.clone(n.languages.css),n.languages.markup&&(n.languages.insertBefore("markup","tag",{style:{pattern:/(<style[\w\W]*?>)[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:n.languages.css,alias:"language-css"}}),n.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:n.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:n.languages.css}},alias:"language-css"}},n.languages.markup.tag)),n.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(true|false)\b/,function:/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},n.languages.javascript=n.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,function:/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*\*?|\/|~|\^|%|\.{3}/}),n.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}}),n.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\\\|\\?[^\\])*?`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:n.languages.javascript}},string:/[\s\S]+/}}}),n.languages.markup&&n.languages.insertBefore("markup","tag",{script:{pattern:/(<script[\w\W]*?>)[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:n.languages.javascript,alias:"language-javascript"}}),n.languages.js=n.languages.javascript,function(){"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(){var e={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"};Array.prototype.forEach&&Array.prototype.slice.call(document.querySelectorAll("pre[data-src]")).forEach(function(t){for(var r,i=t.getAttribute("data-src"),a=t,o=/\blang(?:uage)?-(?!\*)(\w+)\b/i;a&&!o.test(a.className);)a=a.parentNode;if(a&&(r=(t.className.match(o)||[,""])[1]),!r){var s=(i.match(/\.(\w+)$/)||[,""])[1];r=e[s]||s}var l=document.createElement("code");l.className="language-"+r,t.textContent="",l.textContent="Loading…",t.appendChild(l);var c=new XMLHttpRequest;c.open("GET",i,!0),c.onreadystatechange=function(){4==c.readyState&&(c.status<400&&c.responseText?(l.textContent=c.responseText,n.highlightElement(l)):c.status>=400?l.textContent="✖ Error "+c.status+" while fetching file: "+c.statusText:l.textContent="✖ Error: File does not exist or is empty")},c.send(null)})},document.addEventListener("DOMContentLoaded",self.Prism.fileHighlight))}()}),De={},Ue=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g;R.clear=function(){De={}};var Ge=We,Ve="",Xe="",Ze=new We.Renderer,Ye={},Je=[],Qe=e(function(e){var t="";return e?(t=Ge(e),t=B(t),R.clear(),t):e});Qe.renderer=Ze,Qe.init=function(e,t){void 0===e&&(e={}),void 0===t&&(t=window.location.pathname),Ve=Ee(t),r(e)?Ge=e(We,Ze):(Ze=pe(Ze,e.renderer),We.setOptions(pe(e,{renderer:Ze})))},Qe.update=function(){Xe=w().path},Ze.heading=function(e,t){var n={level:t,title:e};/{docsify-ignore}/g.test(e)&&(e=e.replace("{docsify-ignore}",""),n.title=e,n.ignoreSubHeading=!0),/{docsify-ignore-all}/g.test(e)&&(e=e.replace("{docsify-ignore-all}",""),n.title=e,n.ignoreAllSubs=!0);var r=R(e),i=x(Xe,{id:r});return n.slug=i,Je.push(n),"<h"+t+' id="'+r+'"><a href="'+i+'" data-id="'+r+'" class="anchor"><span>'+e+"</span></a></h"+t+">"},Ze.code=function(e,t){void 0===t&&(t="");var n=Be.highlight(e,Be.languages[t]||Be.languages.markup);return'<pre v-pre data-lang="'+t+'"><code class="lang-'+t+'">'+n+"</code></pre>"},Ze.link=function(e,t,n){var r="";return/:|(\/{2})/.test(e)?r=' target="_blank"':e=x(e,null,Xe),t&&(t=' title="'+t+'"'),'<a href="'+e+'"'+(t||"")+r+">"+n+"</a>"},Ze.paragraph=function(e){return/^!&gt;/.test(e)?F("tip",e):/^\?&gt;/.test(e)?F("warn",e):"<p>"+e+"</p>"},Ze.image=function(e,t,n){var r=e,i=t?' title="'+t+'"':"";return Te(e)||(r=v(Ve,e)),'<img src="'+r+'" data-origin="'+e+'" alt="'+n+'"'+i+">"};var Ke=Object.freeze({markdown:Qe,sidebar:D,subSidebar:U,cover:G}),et={},tt=Object.freeze({cached:e,hyphenate:ue,merge:pe,isPrimitive:t,noop:n,isFn:r,UA:_e,isIE:Se,isMobile:Le}),nt=function(){window.Docsify={util:tt,dom:xe,render:Ke,route:Me,get:j,slugify:R},window.marked=We,window.Prism=Be},rt=ce.prototype;se(rt),ee(rt),Y(rt),ae(rt),ne(rt),nt(),setTimeout(function(e){return new ce},0)}();
(function(Prism) {
var insideString = {
variable: [
// Arithmetic Environment
{
pattern: /\$?\(\([\s\S]+?\)\)/,
inside: {
// If there is a $ sign at the beginning highlight $(( and )) as variable
variable: [{
pattern: /(^\$\(\([\s\S]+)\)\)/,
lookbehind: true
},
/^\$\(\(/,
],
number: /\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee]-?\d+)?)\b/,
// Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,
// If there is no $ sign at the beginning highlight (( and )) as punctuation
punctuation: /\(\(?|\)\)?|,|;/
}
},
// Command Substitution
{
pattern: /\$\([^)]+\)|`[^`]+`/,
inside: {
variable: /^\$\(|^`|\)$|`$/
}
},
/\$(?:[a-z0-9_#\?\*!@]+|\{[^}]+\})/i
],
};
Prism.languages.bash = {
'shebang': {
pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,
alias: 'important'
},
'comment': {
pattern: /(^|[^"{\\])#.*/,
lookbehind: true
},
'string': [
//Support for Here-Documents https://en.wikipedia.org/wiki/Here_document
{
pattern: /((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,
lookbehind: true,
greedy: true,
inside: insideString
},
{
pattern: /(["'])(?:\\\\|\\?[^\\])*?\1/g,
greedy: true,
inside: insideString
}
],
'variable': insideString.variable,
// Originally based on http://ss64.com/bash/
'function': {
pattern: /(^|\s|;|\||&)(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\s|;|\||&)/,
lookbehind: true
},
'keyword': {
pattern: /(^|\s|;|\||&)(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\s|;|\||&)/,
lookbehind: true
},
'boolean': {
pattern: /(^|\s|;|\||&)(?:true|false)(?=$|\s|;|\||&)/,
lookbehind: true
},
'operator': /&&?|\|\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,
'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];]/
};
var inside = insideString.variable[1].inside;
inside['function'] = Prism.languages.bash['function'];
inside.keyword = Prism.languages.bash.keyword;
inside.boolean = Prism.languages.bash.boolean;
inside.operator = Prism.languages.bash.operator;
inside.punctuation = Prism.languages.bash.punctuation;
})(Prism);
Prism.languages.json = {
'property': /"(?:\\.|[^\\"])*"(?=\s*:)/ig,
'string': /"(?!:)(?:\\.|[^\\"])*"(?!:)/g,
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?)\b/g,
'punctuation': /[{}[\]);,]/g,
'operator': /:/g,
'boolean': /\b(true|false)\b/gi,
'null': /\bnull\b/gi
};
Prism.languages.jsonp = Prism.languages.json;
@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}.emoji{height:19.2px;height:1.2rem;vertical-align:middle}.progress{background-color:#42b983;background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;-webkit-transition:width .2s,opacity .4s;transition:width .2s,opacity .4s;width:0;z-index:5}.search .search-keyword,.search a:hover{color:#42b983;color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}.app-nav{left:0;margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:2}.app-nav p{margin:0}.app-nav>a{margin:0 16px;margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;-webkit-transition:color .3s;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:#42b983;color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 16px;margin:0 1rem;padding:5px 0;position:relative}.app-nav li ul{background-color:#fff;border:1px solid #ddd;border-bottom-color:#ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:scroll;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:16px;line-height:1rem;margin:0;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.app-nav.no-badge{margin-right:25px}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner svg{color:#fff;fill:#42b983;fill:var(--theme-color,#42b983);height:80px;width:80px}.github-corner:hover .octo-arm{-webkit-animation:a .56s ease-in-out;animation:a .56s ease-in-out}main{display:block;position:relative;width:100vw;height:100%}.anchor{display:inline-block;text-decoration:none;-webkit-transition:all .3s;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0;top:0;bottom:0;left:0;position:absolute;-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out;width:300px;z-index:3}.sidebar>h1{margin:0 auto 16px;margin:0 auto 1rem;font-size:24px;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar ul{margin:0;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;bottom:0;left:0;position:absolute;text-align:center;-webkit-transition:opacity .3s;transition:opacity .3s;width:30px;width:284px;z-index:4}.sidebar-toggle .sidebar-toggle-button:hover{opacity:.4}.sidebar-toggle span{background-color:#42b983;background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:20px;top:0;right:0;bottom:0;left:300px;position:absolute;-webkit-transition:left .25s ease;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:800px;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:16px;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;width:20px;height:20px;text-align:center;top:14px}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:16px;padding:1rem}body.close .sidebar{-webkit-transform:translateX(-300px);transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;overflow-x:hidden}.sidebar{left:-300px;-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.content{left:0;max-width:100vw;position:static;-webkit-transition:-webkit-transform .25s ease;transition:-webkit-transform .25s ease;transition:transform .25s ease;transition:transform .25s ease,-webkit-transform .25s ease}.app-nav,.github-corner{-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto}body.close .sidebar{-webkit-transform:translateX(300px);transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);-webkit-transition:background-color 1s;transition:background-color 1s;width:284px}body.close .content{-webkit-transform:translateX(300px);transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner .octo-arm{-webkit-animation:a .56s ease-in-out;animation:a .56s ease-in-out}.github-corner:hover .octo-arm{-webkit-animation:none;animation:none}}@-webkit-keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}section.cover{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;display:none}section.cover .cover-main{-webkit-box-flex:1;-ms-flex:1;flex:1;margin:-20px 16px 0;text-align:center;z-index:1}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:24px;line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:40px;font-size:2.5rem;font-weight:300;margin:10px 0 40px;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-7px;bottom:-.4375rem;font-size:16px;font-size:1rem;position:absolute}section.cover blockquote{font-size:24px;font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-color:#42b983;border:1px solid var(--theme-color,#42b983);border-radius:2rem;box-sizing:border-box;color:#42b983;color:var(--theme-color,#42b983);display:inline-block;font-size:16.8px;font-size:1.05rem;letter-spacing:1.6px;letter-spacing:.1rem;margin-right:16px;margin-right:1rem;padding:.75em 32px;padding:.75em 2rem;text-decoration:none;-webkit-transition:all .15s ease;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:#42b983;background-color:var(--theme-color,#42b983);color:#fff;margin-right:0}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983);-webkit-transition:color .3s;transition:color .3s}section.cover blockquote>p>a:hover{color:#42b983;color:var(--theme-color,#42b983)}section.cover.show{display:-webkit-box;display:-ms-flexbox;display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;width:100%;height:100%}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0 6px 15px}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar .section-link:before{content:"-";padding-right:4px}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:32px;font-size:2rem;margin:0 0 16px;margin:0 0 1rem}.markdown-section h2{font-size:28px;font-size:1.75rem;margin:45px 0 12.8px;margin:45px 0 .8rem}.markdown-section h3{font-size:24px;font-size:1.5rem;margin:40px 0 9.6px;margin:40px 0 .6rem}.markdown-section h4{font-size:20px;font-size:1.25rem}.markdown-section h5,.markdown-section h6{font-size:16px;font-size:1rem}.markdown-section h6{color:#777}.markdown-section figure,.markdown-section ol,.markdown-section p,.markdown-section ul{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:25.6px;line-height:1.6rem;word-spacing:.8px;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:24px;padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid #42b983;border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code{border-radius:2px;color:#e96900;font-size:12.8px;font-size:.8rem;margin:0 2px;padding:3px 5px;white-space:nowrap}.markdown-section code,.markdown-section pre{background-color:#f8f8f8;font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section pre{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;line-height:24px;line-height:1.5rem;margin:1.2em 0;overflow:auto;padding:0 22.4px;padding:0 1.4rem;position:relative;word-wrap:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:#42b983;color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:#42b983;color:var(--theme-color,#42b983)}.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;background-color:#f8f8f8;border-radius:2px;color:#525252;display:block;font-family:Roboto Mono,Monaco,courier,monospace;font-size:12.8px;font-size:.8rem;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;padding:2.2em 5px;white-space:inherit}.markdown-section code:after,.markdown-section code:before{letter-spacing:.8px;letter-spacing:.05rem}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:24px;min-height:1.5rem}pre:after{color:#ccc;content:attr(data-lang);font-size:9.6px;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0}
\ No newline at end of file
# **1** 温馨提示
!>欢迎你成为煎饼数据服务的合作方,在开始接口调用之前请先确保完成以下事项:
>1. 完成 `合作方入驻` 流程,并已经完成本产品`签约`;
2. 你需要获取一个 `appKey``appSecret`
3. 通信协议只支持 `HTTPS`, 网关为 `https://t.51gjj.com/`
4. 整个流程可以分为`用户授权``获取数据`, `用户授权`支持`H5``API`, `获取数据`只支持`API`
5. `订单号(order_id)`是合作方与煎饼数据服务系统产生业务交互的唯一凭证,生成规则参考 `4.2`
6. `授权有效期`: 授权成功的用户,芝麻会为其开通芝麻信用账户并建立授权关系。用户若不主动取消授权,该授权为永久有效。在授权有效期内,合作方可以查询用户的信用信息。
7. `取消授权功能`: 用户可在芝麻信用客户端(即支付宝客户端 -> 芝麻信用 -> 信用管理 -> 授权管理)内取消授权。取消后,将不能查询该用户的信用信息。用户取消授权后,再查询该用户信息时芝麻会返回授权已失效的异常,此时需要引导用户重新发起授权过程。
# **2** 开始接入
## **2.1** API接入
!> 访问之前需要生成订单号,生成过程见附录。
**请求URL:**
- `zmop/auth `
!> 如需要H5授权链接, 请求URL为`zmop/auth/?channel=H5`
**请求方式:**
- Method: POST
- Content-type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|cert_no |是 |string |授权用户的身份证 |
|cert_name |是 |string | 授权用户的姓名 |
|cert_phone |是 |string | 授权用户的手机号 |
|redirect |是 |string | 用户授权结束之后, 接收授权结果的异步回调地址, 须urlEncode, |
|order_id |是 |string | 任务订单号 |
|appKey |是 |string | 平台发放给开发者的标识开发者身份的标识符 |
|extras |否 |string | 合作方自定义数据, 会作为异步回调地址的参数返回给合作方 |
**请求示例**
```json
{
"cert_no": "*******************",
"cert_name": "王二",
"cert_phone": "1*********3",
"appKey": "3*******************6",
"order_id": "20180************tfLVD232",
"redirect": "https://www.baidu.com",
"extras": "esljdsd"
}
```
**返回示例1**
``` json
{
"code": 0,
"auth_url": "alipayqr://platformapi/startapp?saId=10000007&qrcode=https%3A%2F%2Fopenauth.alipay.com%2Foauth2%2FpublicAppAuthorize.htm%3Fapp_id%3D20180420057138%26scope%3Dauth_zhima%26redirect_uri%3D...",
"channel": "APP"
}
```
**返回示例2**
``` json
{
"code": 0,
"auth_url": "https://zmopenapi.zmxy.com.cn/openapi.do?method=zhima.auth.info.authorize...",
"channel": "H5"
}
```
**返回示例3**
``` json
{
"code": "-1",
"msg": "重复的订单号"
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|auth_url |String |授权链接 |
|channel |String |值为`APP``H5`, `APP`授权链接通过唤醒支付宝进行授权, `H5`授权链接可以通过浏览器打开|
|code |String |状态码 |
|msg |String |错误信息 |
## **2.2** 用户授权结束通知
**通知说明**
>当用户授权结束之后, 采用异步通知到合作方, `只通知一次, 需返回状态码为200的http响应`
**请求方式:**
- Method: POST
- Content-type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|status |是 |string |订单号对应状态(success/failed) |
|msg |是 |string | 任务结果的描述|
|order_id |是 |string | 任务订单号 |
|extras |否 |string | 合作方自定义数据|
**请求示例**
```json
{
"status": "success",
"msg": "操作成功",
"order_id": "20180************tfLVD232",
"extras": "esljdsd"
}
```
# **3** 获取用户数据
**简要描述:**
- 根据订单号获取用户数据
- 需要签名, 签名算法见`附录4.1`
## **3.1** 获取访问令牌token
>**请求URL:**
- ` zmop/getToken `
------------
>**请求方式:**
>- Method: POST
- Content-Type: application/json
- Charset: UTF-8
------------
> **参数:**
>
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|sign |是 |String |签名 |
|appKey |是 |String |公钥 |
|timestamp |是 |String | 时间戳 (单位:ms) |
------------
>**请求示例**
``` json
{
"sign":"SDSKKL5KJJKLL6JK1L",
"params":{
"appKey":"3FD179425381644F95424B66BE06E3E4",
"timestamp":"1494828184314"
}
}
```
>**返回示例1**
``` json
{
"code": 0,
"data": {
"token": "cd4283827366490eb037bf1b4b28dadc"
}
}
```
>**返回示例2**
``` json
{
"code": -1,
"msg": "参数错误"
}
```
>**返回参数说明**
>|参数名|类型|说明|
|:----- |:-----|----- |
|token |String |访问令牌(Token的有效期为2小时,当Token未失效时调用该接口,则返回新的Token,有效期重新计算,老的Token同时失效) |
|code |String |状态码 |
|msg |String |错误信息 |
------------
## **3.2** 获取芝麻分数据
**请求URL:**
- `zmop/data/score `
**请求方式:**
- Method: POST
- Content-type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|appKey |是 |string |公钥 |
|timestamp |是 |string | 时间戳 (单位:ms) |
|sign |是 |string | 签名 |
|token |是 |string | 访问令牌 |
|order_id |是 |string | 任务订单号 |
**请求示例**
``` json
{
"sign":"89D89A1D07E875C649D6A2D03F8E650A",
"params":{
"appKey": "88A03809137291F333BF2689AB85850E",
"timestamp":"3412xxxxxx01234567",
"token":"xx",
"order_id":"20180408121212555qwe23qwe1232sde"
}
}
```
**返回示例1**
``` json
{
"code": "0",
"data": {
//此处参考附录 4.3
...
}
}
```
**返回示例2**
``` json
{
"code": -1,
"msg": "无此订单数据"
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|data |String |数据结构参照芝麻分数据结构 |
|code |String |状态码 |
|msg |String |错误信息 |
## **3.3** 获取行业关注名单数据
**请求URL:**
- `zmop/data/watch_list `
**请求方式:**
- Method: POST
- Content-type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|appKey |是 |string |公钥 |
|timestamp |是 |string | 时间戳 (单位:ms) |
|sign |是 |string | 签名 |
|token |是 |string | 访问令牌 |
|order_id |是 |string | 任务订单号 |
**请求示例**
``` json
{
"sign":"89D89A1D07E875C649D6A2D03F8E650A",
"params":{
"appKey": "88A03809137291F333BF2689AB85850E",
"timestamp":"3412xxxxxx01234567",
"token":"xx",
"order_id":"20180408121212555qwe23qwe1232sde"
}
}
```
**返回示例1**
``` json
{
"code": "0",
"data": {
//此处参考附录 4.4
...
}
}
```
**返回示例2**
``` json
{
"code": -1,
"msg": "无此订单数据"
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|data |String |数据结构参照4.4 |
|code |String |状态码 |
|msg |String |错误信息 |
# **4** 附录
## **4.1** 签名算法
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
- 参数名ASCII码从小到大排序(字典序);
- 如果参数的值为空不参与签名;
- 参数名区分大小写;
第二步,在stringA最后拼接上appSecret得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
举例:
假设传送的参数如下:
``` json
appKey : 88A03809137291F333BF2689AB85850E,
order_id : 426ea0df-7f1b-4491-8989-5c130291e892,
phone : 18572387576,
timestamp : 1494649888152
token : 0eaeb00afcc4448da724d9179a50abe7
nonce_str:ibuaiVcKdpRxkhJA
```
第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:
``` javascript
stringA="appKey=092217B6B52ED02D46EFFFA7CFA20940&nonce_str=8224891888270884&order_id=3e993890-ff08-4af5-bb9b-04fda6dd2b78&phone=15658117723&timestamp=1494669826683&token=8731de2cd2604f4a856f210703541326";
```
第二步:拼接API密钥:
``` javascript
stringSignTemp=stringA+"&appSecret=192006250b4c09247ec02edce69f6a2d"
sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7"
```
## **4.2** 订单号
释义
>`订单号(order_id)`是合作方(或机构)与煎饼数据服务系统产生业务交互的唯一凭证,具体表现为一个长度为 `32` 位的字符串,仅能包含 `0-9A-Za-z_-` 等字符。每一个订单号(order_id)表明了合作方(或机构)与煎饼数据服务系统产生了一次确定的业务交互,煎饼数据服务系统给出了一个确定的返回结果,并以此作为与煎饼数据服务系统明细对账的唯一依据
生成规则
>订单号(order_id)推荐生成方式是,前 `17` 位为精确到`毫秒`的时间值(yyyyMMddHHmmssSSS)作为前缀,以合作方(或机构)自行生成的不重复字符串作为后缀,组成 `32` 位的字符串。
## **4.3** 芝麻分数据结构
**数据字典**
|参数名|类型|说明|
|:----- |:-----|----- |
|order_id |String |订单号 |
|create_time |String |从芝麻信用获取芝麻分的时间 |
|which_month |String |最新芝麻分所属月|
|score |String |芝麻分 |
### 数据样例
```json
{
"score": "746",
"which_month": "2018-04",
"create_time": "2018-04-28 11:26:02",
"order_id": "2018042710535*****QcPMRFLn8b7qYb"
}
```
## **4.4** 行业关注名单数据结构
**数据字典**
|名称|类型|描述|
|:---- |:--- |----- |
|order_id |String |订单号 |
|create_time |String |从芝麻信用获取数据的时间 |
|details |Array | 行业关注名单信息列表,由芝麻信用进行维护和升级 |
|isMatched |Boolean | true=命中 在关注名单中 false=未命中 |
**行业关注名单详细(details)信息详情:**
|名称|类型|描述|
|:---- |:---- |:----- |
|biz_code |String | 风险信息行业编码 |
|level |string | 风险等级 |
|type |String | 行业名单风险类型 |
|code |String | 风险编码 |
|refresh_time |Date | 数据刷新时间 |
|settlement |Boolean | 结清状态 |
|status |String | 用户本人对该条负面记录有异议时,表示该异议处理流程的状态 |
|statement |String | 当用户进行异议处理,并核查完毕之后,仍有异议时,给出的声明|
|extend_info |Array | 扩展信息 |
**扩展信息(extend_info)信息详情:**
|名称|类型|描述|
|:---- |:--- |----- |
|key |String | 补充信息字段的英文编码 |
|value |String | 补充信息字段的信息内容 |
|description |String | 补充信息字段的中文描述 |
### 数据样例
```json
{
"create_time": "2018-04-28 11:26:02",
"order_id": "2018042710535*****QcPMRFLn8b7qYb",
"details": [{ //行业关注名单信息列表,由芝麻信用进行维护和升级
"biz_code": "AH", //风险信息行业编码
"code": "AH001002", //风险编码
"extend_info": [{ //扩展信息
"description": "编号", //补充信息字段的中文描述
"key": "id", // 补充信息字段的英文编码
"value": "testlwztestlwz0d090d794bd563ba6053244b35fb2ccc" //补充信息字段的信息内容
}],
"level": 0, //风险等级
"refresh_time": 1465488000000, // 数据刷新时间
"settlement": true, //结清状态
"type": "AH001" //行业名单风险类型
}],
"is_matched": true //true=命中 在关注名单中 false=未命中
}
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>芝麻分接口文档</title>
<meta name="description" content="Description">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="vendor/themes/vue.css">
<style>
.markdown-section {
margin-left: 20px;
}
.field-support {
background: content-box;
font-size: 15px;
border: 1px solid #ddd;
padding: 6px 20px;
}
</style>
</head>
<body>
<div id="app"></div>
</body>
<script>
window.$docsify = {
name: '芝麻分接口文档',
repo: '', themeColor: '#3F51B5'
}
</script>
<script src="vendor/docsify.js"></script>
<script src="vendor/themes/bash.js"></script>
<script src="vendor/themes/json_base.js"></script>
</html>
const express = require('express');
const http = require('http');
const path = require('path');
const config = require('config');
// middlewares
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const timeInterval = config.get('timeInterval');
const scheduleproc = require('./lib/scheduleproc');
var app = express();
var login = require('./routers/login');
var pay = require('./routers/pay');
var tools = require('./routers/tools');
var main = require('./routers/main');
var data_service = require('./routers/data_service');
//X-Frame-Options: Allow-From http://www.growingio.com
app.use('*', function (req, res, next) {
res.setHeader('X-Frame-Options', 'ALLOW-FROM https://www.growingio.com');
next();
})
// 给app配置bodyParser中间件
// 通过如下配置再路由种处理request时,可以直接获得post请求的body部分
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
const aes = require('./lib/aes');
const token = require('./lib/token')
app.use(function (req, res, next) {
if (req.body.data) {
try {
req.body = aes.aesDecrypt(req.body.data)
if (!req.body) {
return res.send({code: 199, msg: '系统错误'})
}
req.body = JSON.parse(req.body)
} catch (e) {
console.log(e)
return res.send({code: 199, msg: '系统错误'})
}
}
// if (!/login/.test(req.path)) {
// try {
// let test = token.decode(req.headers.authorization)
// if (test) {
// req.body.userId = test.userId
// }
// }catch(e) {
// return res.send({code: -1, msg: '无效的authorization token'})
// }
// }
console.log(req.path, ': ', req.body)
next()
})
// 注册路由
app.use('/login', login);
app.use('/tools', tools);
app.use('/data', main);
app.use('/pay', pay);
app.use('/dataService', data_service);
const httpPort = config.get('httpPort')
var Server = http.createServer(app);
Server.listen(httpPort, function () {
console.log((new Date()) + ' server start http server and listen on: ' + JSON.stringify(Server.address()));
});
// 定时清理日志任务
scheduleproc.BeginCleanLogWork(timeInterval);
\ No newline at end of file
!function(){"use strict";function e(e){var t=Object.create(null);return function(n){var r=t[n];return r||(t[n]=e(n))}}function t(e){return"string"==typeof e||"number"==typeof e}function n(){}function r(e){return"function"==typeof e}function i(e){var t=["init","mounted","beforeEach","afterEach","doneEach","ready"];e._hooks={},e._lifecycle={},t.forEach(function(t){var n=e._hooks[t]=[];e._lifecycle[t]=function(e){return n.push(e)}})}function a(e,t,r,i){void 0===i&&(i=n);var a=r,o=e._hooks[t],s=function(e){var t=o[e];if(e>=o.length)i(a);else if("function"==typeof t)if(2===t.length)t(r,function(t){a=t,s(e+1)});else{var n=t(r);a=void 0!==n?n:a,s(e+1)}else s(e+1)};s(0)}function o(e,t){if(void 0===t&&(t=!1),"string"==typeof e){if("undefined"!=typeof window.Vue)return s(e);e=t?s(e):be[e]||(be[e]=s(e))}return e}function s(e,t){return t?e.querySelector(t):ye.querySelector(e)}function l(e,t){return[].slice.call(t?e.querySelectorAll(t):ye.querySelectorAll(e))}function c(e,t){return e=ye.createElement(e),t&&(e.innerHTML=t),e}function u(e,t){return e.appendChild(t)}function p(e,t){return e.insertBefore(t,e.children[0])}function h(e,t,n){r(t)?window.addEventListener(e,t):e.addEventListener(t,n)}function d(e,t,n){r(t)?window.removeEventListener(e,t):e.removeEventListener(t,n)}function g(e,t,n){e&&e.classList[n?t:"toggle"](n||t)}function f(e){var t={};return(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach(function(e){var n=e.replace(/\+/g," ").split("=");t[n[0]]=Ce(n[1])}),t):t}function m(e){var t=[];for(var n in e)t.push(($e(n)+"="+$e(e[n])).toLowerCase());return t.length?"?"+t.join("&"):""}function v(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return je(e.join("/"))}function b(e){var t=window.location.href.indexOf("#");window.location.replace(window.location.href.slice(0,t>=0?t:0)+"#"+e)}function y(){var e=k();return e=Oe(e),"/"===e.charAt(0)?b(e):void b("/"+e)}function k(){var e=window.location.href,t=e.indexOf("#");return t===-1?"":e.slice(t+1)}function w(e){void 0===e&&(e=window.location.href);var t="",n=e.indexOf("?");n>=0&&(t=e.slice(n+1),e=e.slice(0,n));var r=e.indexOf("#");return r&&(e=e.slice(r+1)),{path:e,query:f(t)}}function x(e,t,n){var r=n&&"#"===e[0],i=w(Oe(e));return i.query=pe({},i.query,t),e=i.path+m(i.query),e=e.replace(/\.md(\?)|\.md$/,"$1"),r&&(e=n+e),je("#/"+e)}function _(e){var t=function(e){return ke.classList.toggle("close")};e=o(e),h(e,"click",function(e){e.stopPropagation(),t()});var n=o(".sidebar");Le&&h(ke,"click",function(e){return ke.classList.contains("close")&&t()}),h(n,"click",function(e){return setTimeout(0)})}function S(){var e=o("section.cover");if(e){var t=e.getBoundingClientRect().height;window.pageYOffset>=t||e.classList.contains("hidden")?g(ke,"add","sticky"):g(ke,"remove","sticky")}}function L(e,t,n){e=o(e);var r,i=l(e,"a"),a="#"+k();return i.sort(function(e,t){return t.href.length-e.href.length}).forEach(function(e){var n=e.getAttribute("href"),i=t?e.parentNode:e;0!==a.indexOf(n)||r?g(i,"remove","active"):(r=e,g(i,"add","active"))}),n&&(ye.title=r?r.innerText+" - "+Pe:Pe),r}function C(){for(var e,t=o(".sidebar"),n=l(".anchor"),r=s(t,".sidebar-nav"),i=s(t,"li.active"),a=ke.scrollTop,c=0,u=n.length;c<u;c+=1){var p=n[c];if(p.offsetTop>a){e||(e=p);break}e=p}if(e){var h=qe[e.getAttribute("data-id")];if(h&&h!==i&&(i&&i.classList.remove("active"),h.classList.add("active"),i=h,!Ne&&ke.classList.contains("sticky"))){var d=t.clientHeight,g=0,f=i.offsetTop+i.clientHeight+40,m=i.offsetTop>=r.scrollTop&&f<=r.scrollTop+d,v=f-g<d,b=m?r.scrollTop:v?g:f-d;t.scrollTop=b}}}function $(){if(!Le){for(var e=o(".sidebar"),t=l(e,"li"),n=0,r=t.length;n<r;n+=1){var i=t[n],a=i.querySelector("a");if(a){var s=a.getAttribute("href");"/"!==s&&(s=w(s).query.id),qe[decodeURIComponent(s)]=i}}d("scroll",C),h("scroll",C),h(e,"mouseover",function(){Ne=!0}),h(e,"mouseleave",function(){Ne=!1})}}function E(e){var t=s("#"+e);t&&t.scrollIntoView()}function T(e){void 0===e&&(e=0),Fe.scrollTop=e===!0?0:Number(e)}function A(){var e=c("div");e.classList.add("progress"),u(ke,e),me=e}function j(e,t){void 0===t&&(t=!1);var r=new XMLHttpRequest,i=function(){r.addEventListener.apply(r,arguments)};return Ie[e]?{then:function(t){return t(Ie[e])},abort:n}:(r.open("GET",e),r.send(),{then:function(r,a){if(void 0===a&&(a=n),t){var o=setInterval(function(e){return He({step:Math.floor(5*Math.random()+1)})},500);i("progress",He),i("loadend",function(e){He(e),clearInterval(o)})}i("error",a),i("load",function(t){var n=t.target;n.status>=400?a(n):(Ie[e]=n.response,r(n.response))})},abort:function(e){return 4!==r.readyState&&r.abort()}})}function O(e,t){e.innerHTML=e.innerHTML.replace(/var\(\s*--theme-color.*?\)/g,t)}function M(e){return e?(/\/\//.test(e)||(e="https://github.com/"+e),e=e.replace(/^git\+/,""),'<a href="'+e+'" class="github-corner" aria-label="View source on Github"><svg viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>'):""}function P(e){var t='<button class="sidebar-toggle"><div class="sidebar-toggle-button"><span></span><span></span><span></span></div></button><aside class="sidebar">'+(e.name?'<h1><a class="app-name-link" data-nosearch>'+e.name+"</a></h1>":"")+'<div class="sidebar-nav"></div></aside>';return(Le?t+"<main>":"<main>"+t)+'<section class="content"><article class="markdown-section" id="main"></article></section></main>'}function q(){var e=", 100%, 85%",t="linear-gradient(to left bottom, hsl("+(Math.floor(255*Math.random())+e)+") 0%,hsl("+(Math.floor(255*Math.random())+e)+") 100%)";return'<section class="cover" style="background: '+t+'"><div class="cover-main"></div><div class="mask"></div></section>'}function N(e,t){return void 0===t&&(t=""),e&&e.length?(e.forEach(function(e){t+='<li><a class="section-link" href="'+e.slug+'">'+e.title+"</a></li>",e.children&&(t+='<li><ul class="children">'+N(e.children)+"</li></ul>")}),t):""}function F(e,t){return'<p class="'+e+'">'+t.slice(5).trim()+"</p>"}function H(e){return"<style>:root{--theme-color: "+e+";}</style>"}function I(e,t){return t={exports:{}},e(t,t.exports),t.exports}function z(e,t){var n=[],r={};return e.forEach(function(e){var i=e.level||1,a=i-1;i>t||(r[a]?r[a].children=(r[a].children||[]).concat(e):n.push(e),r[i]=e)}),n}function R(e){if("string"!=typeof e)return"";var t=e.toLowerCase().trim().replace(/<[^>\d]+>/g,"").replace(Ue,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),n=De[t];return n=De.hasOwnProperty(t)?n+1:0,De[t]=n,n&&(t=t+"-"+n),t}function W(e,t){return'<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/'+t+'.png" alt="'+t+'" />'}function B(e){return $docsify.noEmoji?e:e.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/:(\w+?):/gi,window.emojify||W).replace(/__colon__/g,":")}function D(e,t){var n="";if(e)n=Qe(e),n=n.match(/<ul[^>]*>([\s\S]+)<\/ul>/g)[0];else{var r=Ye[Xe]||z(Je,t);n=N(r,"<ul>"),Ye[Xe]=r}return n}function U(e,t){if(e){Je[0]&&Je[0].ignoreAllSubs&&(Je=[]),Je[0]&&1===Je[0].level&&Je.shift(),Je.forEach(function(e,t){e.ignoreSubHeading&&Je.splice(t,1)});var n=Ye[Xe]||z(Je,t);e.parentNode.innerHTML+=N(n,'<ul class="app-sub-sidebar">'),Ye[Xe]=n}Je=[]}function G(e){var t=Je.slice(),n=Qe(e);return Je=t.slice(),n}function V(){var e=l(".markdown-section>script").filter(function(e){return!/template/.test(e.type)})[0];if(!e)return!1;var t=e.innerText.trim();return!!t&&void setTimeout(function(e){window.__EXECUTE_RESULT__=new Function(t)()},0)}function X(e){e||(e="not found"),this._renderTo(".markdown-section",e),!this.config.loadSidebar&&this._renderSidebar(),this.config.executeScript===!1||"undefined"==typeof window.Vue||V()?this.config.executeScript&&V():setTimeout(function(e){var t=window.__EXECUTE_RESULT__;t&&t.$destroy&&t.$destroy(),window.__EXECUTE_RESULT__=(new window.Vue).$mount("#main")},0),this.config.auto2top&&T(this.config.auto2top)}function Z(e){var n=o(".app-name-link"),r=e.config.nameLink,i=e.route.path;if(n)if(t(e.config.nameLink))n.setAttribute("href",r);else if("object"==typeof r){var a=Object.keys(r).find(function(e){return i.indexOf(e)>-1});n.setAttribute("href",r[a])}}function Y(e){e._renderTo=function(e,t,n){var r=o(e);r&&(r[n?"outerHTML":"innerHTML"]=t)},e._renderSidebar=function(e){var t=this.config,n=t.maxLevel,r=t.subMaxLevel,i=t.autoHeader,a=t.loadSidebar;this._renderTo(".sidebar-nav",D(e,n));var s=L(".sidebar-nav",!0,!0);if(U(a?s:"",r),this.activeLink=s,$(),i&&s){var l=o("#main"),u=l.children[0];if(u&&"H1"!==u.tagName){var h=c("h1");h.innerText=s.innerText,p(l,h)}}},e._renderNav=function(e){e&&this._renderTo("nav",Qe(e)),L("nav")},e._renderMain=function(e){var t=this;a(this,"beforeEach",e,function(e){var n=t.isHTML?e:Qe(e);a(t,"afterEach",n,function(e){return X.call(t,e)})})},e._renderCover=function(e){var t=o(".cover");if(!e)return void g(t,"remove","show");g(t,"add","show");var n=this.coverIsHTML?e:G(e),r=n.trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$');if(r){if("color"===r[2])t.style.background=r[1]+(r[3]||"");else{var i=r[1];g(t,"add","has-mask"),Te(r[1])||(i=v(Ee(this.config.basePath),r[1])),t.style.backgroundImage="url("+i+")",t.style.backgroundSize="cover",t.style.backgroundPosition="center center"}n=n.replace(r[0],"")}this._renderTo(".cover-main",n),S()},e._updateRender=function(){Qe.update(),Z(this)}}function J(e){var t=e.config;Qe.init(t.markdown,t.basePath);var n=t.el||"#app",r=s("nav")||c("nav"),i=s(n),a="",o=ke;i||(i=c(n),u(ke,i)),t.repo&&(a+=M(t.repo)),t.coverpage&&(a+=q()),a+=P(t),e._renderTo(i,a,!0),t.mergeNavbar&&Le?o=s(".sidebar"):(r.classList.add("app-nav"),t.repo||r.classList.add("no-badge")),p(o,r),t.themeColor&&(ye.head.innerHTML+=H(t.themeColor),ze(t.themeColor)),g(ke,"ready")}function Q(e,t){return t[e]?Q(t[e],t):e}function K(e){return/\.(md|html)$/g.test(e)?e:/\/$/g.test(e)?e+"README.md":e+".md"}function ee(e){e.route={},e.$getFile=function(e){var t=this,n=t.config,r=Ee(n.basePath);return e=n.alias?Q(e,n.alias):e,e=K(e),e="/README.md"===e?n.homepage||e:e,e=Te(e)?e:v(r,e)}}function te(e){y(),et=e.route=w(),e._updateRender(),h("hashchange",function(t){return y(),e.route=w(),e._updateRender(),et.path===e.route.path?void e.$resetEvents():(e.$fetch(),void(et=e.route))})}function ne(e){e.$resetEvents=function(){E(this.route.query.id),L("nav")}}function re(e){_("button.sidebar-toggle"),e.config.coverpage?!Le&&h("scroll",S):ke.classList.add("sticky")}function ie(e,t,n,r,i){e=i?e:e.replace(/\/$/,""),e=Ae(e),e&&j(r.$getFile(e+t)).then(n,function(i){return ie(e,t,n,r)})}function ae(e){var t;e._fetch=function(e){var r=this;void 0===e&&(e=n);var i=this.route,a=i.path,o=this.config,s=o.loadNavbar,l=o.loadSidebar;t&&t.abort&&t.abort(),t=j(this.$getFile(a),!0),this.isHTML=/\.html$/g.test(a),t.then(function(t){if(r._renderMain(t),!l)return e();var n=function(t){r._renderSidebar(t),e()};ie(a,l,n,r,!0)},function(e){return r._renderMain(null)}),s&&ie(a,s,function(e){return r._renderNav(e)},this,!0)},e._fetchCover=function(){var e=this,t=this.config,n=t.coverpage,r=Ae(this.route.path),i=this.$getFile(r+n);return"/"===this.route.path&&n?(this.coverIsHTML=/\.html$/g.test(i),void j(i).then(function(t){return e._renderCover(t)})):void this._renderCover()},e.$fetch=function(e){var t=this;void 0===e&&(e=n),this._fetchCover(),this._fetch(function(n){t.$resetEvents(),a(t,"doneEach"),e()})}}function oe(e){e.$fetch(function(t){return a(e,"ready")})}function se(e){e._init=function(){var e=this;e.config=he||{},i(e),le(e),a(e,"init"),J(e),re(e),te(e),oe(e),a(e,"mounted")}}function le(e){[].concat(e.config.plugins).forEach(function(t){return r(t)&&t(e._lifecycle,e)})}function ce(){this._init()}var ue=e(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),pe=Object.assign||function(e){for(var t=arguments,n=Object.prototype.hasOwnProperty,r=1;r<arguments.length;r++){var i=Object(t[r]);for(var a in i)n.call(i,a)&&(e[a]=i[a])}return e},he=pe({el:"#app",repo:"",maxLevel:6,subMaxLevel:0,loadSidebar:null,loadNavbar:null,homepage:"README.md",coverpage:"",basePath:"",auto2top:!1,name:"",themeColor:"",nameLink:window.location.pathname,autoHeader:!1,executeScript:null,noEmoji:!1,ga:"",mergeNavbar:!1},window.$docsify),de=document.currentScript||[].slice.call(document.getElementsByTagName("script")).filter(function(e){return/docsify\./.test(e.src)})[0];if(de){for(var ge in he){var fe=de.getAttribute("data-"+ue(ge));t(fe)&&(he[ge]=""===fe||fe)}he.loadSidebar===!0&&(he.loadSidebar="_sidebar.md"),he.loadNavbar===!0&&(he.loadNavbar="_navbar.md"),he.coverpage===!0&&(he.coverpage="_coverpage.md"),he.repo===!0&&(he.repo=""),he.name===!0&&(he.name="")}window.$docsify=he;var me,ve,be={},ye=document,ke=ye.body,we=ye.head,xe=Object.freeze({getNode:o,$:ye,body:ke,head:we,find:s,findAll:l,create:c,appendTo:u,before:p,on:h,off:d,toggleClass:g}),_e=window.navigator.userAgent.toLowerCase(),Se=_e&&/msie|trident/.test(_e),Le=document.body.clientWidth<=600,Ce=decodeURIComponent,$e=encodeURIComponent,Ee=e(function(e){return/^(\/|https?:)/g.test(e)?e:je(window.location.pathname+"/"+e)}),Te=e(function(e){return/(:|(\/{2}))/.test(e)}),Ae=e(function(e){return/\/$/g.test(e)?e:(e=e.match(/(\S*\/)[^\/]+$/))?e[1]:""}),je=e(function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")}),Oe=e(function(e){return e.replace("#","?id=")}),Me=Object.freeze({normalize:y,getHash:k,parse:w,toURL:x,parseQuery:f,stringifyQuery:m,getBasePath:Ee,getPath:v,isAbsolutePath:Te,getParentPath:Ae,cleanPath:je}),Pe=ye.title,qe={},Ne=!1,Fe=ye.scrollingElement||ye.documentElement,He=function(e){var t,n=e.loaded,r=e.total,i=e.step;!me&&A(),i?(t=parseInt(me.style.width||0,10)+i,t=t>80?80:t):t=Math.floor(n/r*100),me.style.opacity=1,me.style.width=t>=95?"100%":t+"%",t>=95&&(clearTimeout(ve),ve=setTimeout(function(e){me.style.opacity=0,me.style.width="0%"},200))},Ie={},ze=function(e){if(!(window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)"))){var t=l("style:not(.inserted),link");[].forEach.call(t,function(t){if("STYLE"===t.nodeName)O(t,e);else if("LINK"===t.nodeName){var n=t.getAttribute("href");if(!/\.css$/.test(n))return;j(n).then(function(t){var n=c("style",t);we.appendChild(n),O(n,e)})}})}},Re="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},We=I(function(e,t){(function(){function t(e){this.tokens=[],this.tokens.links={},this.options=e||u.defaults,this.rules=p.normal,this.options.gfm&&(this.options.tables?this.rules=p.tables:this.rules=p.gfm)}function n(e,t){if(this.options=t||u.defaults,this.links=e,this.rules=h.normal,this.renderer=this.options.renderer||new r,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.gfm?this.options.breaks?this.rules=h.breaks:this.rules=h.gfm:this.options.pedantic&&(this.rules=h.pedantic)}function r(e){this.options=e||{}}function i(e){this.tokens=[],this.token=null,this.options=e||u.defaults,this.options.renderer=this.options.renderer||new r,this.renderer=this.options.renderer,this.renderer.options=this.options}function a(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function o(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g,function(e,t){return t=t.toLowerCase(),"colon"===t?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function s(e,t){return e=e.source,t=t||"",function n(r,i){return r?(i=i.source||i,i=i.replace(/(^|[^\[])\^/g,"$1"),e=e.replace(r,i),n):new RegExp(e,t)}}function l(){}function c(e){for(var t,n,r=arguments,i=1;i<arguments.length;i++){t=r[i];for(n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e}function u(e,n,r){if(r||"function"==typeof n){r||(r=n,n=null),n=c({},u.defaults,n||{});var o,s,l=n.highlight,p=0;try{o=t.lex(e,n)}catch(e){return r(e)}s=o.length;var h=function(e){if(e)return n.highlight=l,r(e);var t;try{t=i.parse(o,n)}catch(t){e=t}return n.highlight=l,e?r(e):r(null,t)};if(!l||l.length<3)return h();if(delete n.highlight,!s)return h();for(;p<o.length;p++)!function(e){return"code"!==e.type?--s||h():l(e.text,e.lang,function(t,n){return t?h(t):null==n||n===e.text?--s||h():(e.text=n,e.escaped=!0,void(--s||h()))})}(o[p])}else try{return n&&(n=c({},u.defaults,n)),i.parse(t.lex(e,n),n)}catch(e){if(e.message+="\nPlease report this to https://github.com/chjj/marked.",(n||u.defaults).silent)return"<p>An error occured:</p><pre>"+a(e.message+"",!0)+"</pre>";throw e}}var p={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:l,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:l,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:l,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};p.bullet=/(?:[*+-]|\d+\.)/,p.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,p.item=s(p.item,"gm")(/bull/g,p.bullet)(),p.list=s(p.list)(/bull/g,p.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+p.def.source+")")(),p.blockquote=s(p.blockquote)("def",p.def)(),p._tag="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b",p.html=s(p.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,p._tag)(),p.paragraph=s(p.paragraph)("hr",p.hr)("heading",p.heading)("lheading",p.lheading)("blockquote",p.blockquote)("tag","<"+p._tag)("def",p.def)(),p.normal=c({},p),p.gfm=c({},p.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),p.gfm.paragraph=s(p.paragraph)("(?!","(?!"+p.gfm.fences.source.replace("\\1","\\2")+"|"+p.list.source.replace("\\1","\\3")+"|")(),p.tables=c({},p.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),t.rules=p,t.lex=function(e,n){var r=new t(n);return r.lex(e)},t.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},t.prototype.token=function(e,t,n){for(var r,i,a,o,s,l,c,u,h,d=this,e=e.replace(/^ +$/gm,"");e;)if((a=d.rules.newline.exec(e))&&(e=e.substring(a[0].length),a[0].length>1&&d.tokens.push({type:"space"})),a=d.rules.code.exec(e))e=e.substring(a[0].length),a=a[0].replace(/^ {4}/gm,""),d.tokens.push({type:"code",text:d.options.pedantic?a:a.replace(/\n+$/,"")});else if(a=d.rules.fences.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"code",lang:a[2],text:a[3]||""});else if(a=d.rules.heading.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"heading",depth:a[1].length,text:a[2]});else if(t&&(a=d.rules.nptable.exec(e))){for(e=e.substring(a[0].length),l={type:"table",header:a[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:a[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:a[3].replace(/\n$/,"").split("\n")},u=0;u<l.align.length;u++)/^ *-+: *$/.test(l.align[u])?l.align[u]="right":/^ *:-+: *$/.test(l.align[u])?l.align[u]="center":/^ *:-+ *$/.test(l.align[u])?l.align[u]="left":l.align[u]=null;for(u=0;u<l.cells.length;u++)l.cells[u]=l.cells[u].split(/ *\| */);d.tokens.push(l)}else if(a=d.rules.lheading.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"heading",depth:"="===a[2]?1:2,text:a[1]});else if(a=d.rules.hr.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"hr"});else if(a=d.rules.blockquote.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"blockquote_start"}),a=a[0].replace(/^ *> ?/gm,""),d.token(a,t,!0),d.tokens.push({type:"blockquote_end"});else if(a=d.rules.list.exec(e)){for(e=e.substring(a[0].length),o=a[2],d.tokens.push({type:"list_start",ordered:o.length>1}),a=a[0].match(d.rules.item),r=!1,h=a.length,u=0;u<h;u++)l=a[u],c=l.length,l=l.replace(/^ *([*+-]|\d+\.) +/,""),~l.indexOf("\n ")&&(c-=l.length,l=d.options.pedantic?l.replace(/^ {1,4}/gm,""):l.replace(new RegExp("^ {1,"+c+"}","gm"),"")),d.options.smartLists&&u!==h-1&&(s=p.bullet.exec(a[u+1])[0],o===s||o.length>1&&s.length>1||(e=a.slice(u+1).join("\n")+e,u=h-1)),i=r||/\n\n(?!\s*$)/.test(l),u!==h-1&&(r="\n"===l.charAt(l.length-1),i||(i=r)),d.tokens.push({type:i?"loose_item_start":"list_item_start"}),d.token(l,!1,n),d.tokens.push({type:"list_item_end"});d.tokens.push({type:"list_end"})}else if(a=d.rules.html.exec(e))e=e.substring(a[0].length),d.tokens.push({type:d.options.sanitize?"paragraph":"html",pre:!d.options.sanitizer&&("pre"===a[1]||"script"===a[1]||"style"===a[1]),text:a[0]});else if(!n&&t&&(a=d.rules.def.exec(e)))e=e.substring(a[0].length),d.tokens.links[a[1].toLowerCase()]={href:a[2],title:a[3]};else if(t&&(a=d.rules.table.exec(e))){for(e=e.substring(a[0].length),l={type:"table",header:a[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:a[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:a[3].replace(/(?: *\| *)?\n$/,"").split("\n")},u=0;u<l.align.length;u++)/^ *-+: *$/.test(l.align[u])?l.align[u]="right":/^ *:-+: *$/.test(l.align[u])?l.align[u]="center":/^ *:-+ *$/.test(l.align[u])?l.align[u]="left":l.align[u]=null;for(u=0;u<l.cells.length;u++)l.cells[u]=l.cells[u].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */);d.tokens.push(l)}else if(t&&(a=d.rules.paragraph.exec(e)))e=e.substring(a[0].length),d.tokens.push({type:"paragraph",text:"\n"===a[1].charAt(a[1].length-1)?a[1].slice(0,-1):a[1]});else if(a=d.rules.text.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"text",text:a[0]});else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0));return this.tokens};var h={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:l,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:l,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};h._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/,h._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/,h.link=s(h.link)("inside",h._inside)("href",h._href)(),h.reflink=s(h.reflink)("inside",h._inside)(),h.normal=c({},h),h.pedantic=c({},h.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),h.gfm=c({},h.normal,{escape:s(h.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:s(h.text)("]|","~]|")("|","|https?://|")()}),h.breaks=c({},h.gfm,{br:s(h.br)("{2,}","*")(),text:s(h.gfm.text)("{2,}","*")()}),n.rules=h,n.output=function(e,t,r){var i=new n(t,r);return i.output(e)},n.prototype.output=function(e){for(var t,n,r,i,o=this,s="";e;)if(i=o.rules.escape.exec(e))e=e.substring(i[0].length),s+=i[1];else if(i=o.rules.autolink.exec(e))e=e.substring(i[0].length),"@"===i[2]?(n=":"===i[1].charAt(6)?o.mangle(i[1].substring(7)):o.mangle(i[1]),r=o.mangle("mailto:")+n):(n=a(i[1]),r=n),s+=o.renderer.link(r,null,n);else if(o.inLink||!(i=o.rules.url.exec(e))){if(i=o.rules.tag.exec(e))!o.inLink&&/^<a /i.test(i[0])?o.inLink=!0:o.inLink&&/^<\/a>/i.test(i[0])&&(o.inLink=!1),e=e.substring(i[0].length),s+=o.options.sanitize?o.options.sanitizer?o.options.sanitizer(i[0]):a(i[0]):i[0];else if(i=o.rules.link.exec(e))e=e.substring(i[0].length),o.inLink=!0,s+=o.outputLink(i,{href:i[2],title:i[3]}),o.inLink=!1;else if((i=o.rules.reflink.exec(e))||(i=o.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),t=o.links[t.toLowerCase()],!t||!t.href){s+=i[0].charAt(0),e=i[0].substring(1)+e;continue}o.inLink=!0,s+=o.outputLink(i,t),o.inLink=!1}else if(i=o.rules.strong.exec(e))e=e.substring(i[0].length),s+=o.renderer.strong(o.output(i[2]||i[1]));else if(i=o.rules.em.exec(e))e=e.substring(i[0].length),s+=o.renderer.em(o.output(i[2]||i[1]));else if(i=o.rules.code.exec(e))e=e.substring(i[0].length),s+=o.renderer.codespan(a(i[2],!0));else if(i=o.rules.br.exec(e))e=e.substring(i[0].length),s+=o.renderer.br();else if(i=o.rules.del.exec(e))e=e.substring(i[0].length),s+=o.renderer.del(o.output(i[1]));else if(i=o.rules.text.exec(e))e=e.substring(i[0].length),s+=o.renderer.text(a(o.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else e=e.substring(i[0].length),n=a(i[1]),r=n,s+=o.renderer.link(r,null,n);return s},n.prototype.outputLink=function(e,t){var n=a(t.href),r=t.title?a(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,a(e[1]))},n.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014\/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014\/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},n.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,i=0;i<r;i++)t=e.charCodeAt(i),Math.random()>.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},r.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'<pre><code class="'+this.options.langPrefix+a(t,!0)+'">'+(n?e:a(e,!0))+"\n</code></pre>\n":"<pre><code>"+(n?e:a(e,!0))+"\n</code></pre>"},r.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n){return"<h"+t+' id="'+this.options.headerPrefix+n.toLowerCase().replace(/[^\w]+/g,"-")+'">'+e+"</h"+t+">\n"},r.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},r.prototype.list=function(e,t){var n=t?"ol":"ul";return"<"+n+">\n"+e+"</"+n+">\n"},r.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},r.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},r.prototype.table=function(e,t){return"<table>\n<thead>\n"+e+"</thead>\n<tbody>\n"+t+"</tbody>\n</table>\n"},r.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td",r=t.align?"<"+n+' style="text-align:'+t.align+'">':"<"+n+">";return r+e+"</"+n+">\n"},r.prototype.strong=function(e){return"<strong>"+e+"</strong>"},r.prototype.em=function(e){return"<em>"+e+"</em>"},r.prototype.codespan=function(e){return"<code>"+e+"</code>"},r.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},r.prototype.del=function(e){return"<del>"+e+"</del>"},r.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(o(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:"))return""}var i='<a href="'+e+'"';return t&&(i+=' title="'+t+'"'),i+=">"+n+"</a>"},r.prototype.image=function(e,t,n){var r='<img src="'+e+'" alt="'+n+'"';return t&&(r+=' title="'+t+'"'),r+=this.options.xhtml?"/>":">"},r.prototype.text=function(e){return e},i.parse=function(e,t,n){var r=new i(t,n);return r.parse(e)},i.prototype.parse=function(e){var t=this;this.inline=new n(e.links,this.options,this.renderer),this.tokens=e.reverse();for(var r="";this.next();)r+=t.tok();return r},i.prototype.next=function(){return this.token=this.tokens.pop()},i.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},i.prototype.parseText=function(){for(var e=this,t=this.token.text;"text"===this.peek().type;)t+="\n"+e.next().text;return this.inline.output(t)},i.prototype.tok=function(){var e=this;switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var t,n,r,i,a,o="",s="";for(r="",t=0;t<this.token.header.length;t++)i={header:!0,align:e.token.align[t]},r+=e.renderer.tablecell(e.inline.output(e.token.header[t]),{header:!0,align:e.token.align[t]});for(o+=this.renderer.tablerow(r),t=0;t<this.token.cells.length;t++){for(n=e.token.cells[t],r="",a=0;a<n.length;a++)r+=e.renderer.tablecell(e.inline.output(n[a]),{header:!1,align:e.token.align[a]});s+=e.renderer.tablerow(r)}return this.renderer.table(o,s);case"blockquote_start":for(var s="";"blockquote_end"!==this.next().type;)s+=e.tok();return this.renderer.blockquote(s);case"list_start":for(var s="",l=this.token.ordered;"list_end"!==this.next().type;)s+=e.tok();return this.renderer.list(s,l);case"list_item_start":for(var s="";"list_item_end"!==this.next().type;)s+="text"===e.token.type?e.parseText():e.tok();return this.renderer.listitem(s);case"loose_item_start":for(var s="";"list_item_end"!==this.next().type;)s+=e.tok();return this.renderer.listitem(s);case"html":var c=this.token.pre||this.options.pedantic?this.token.text:this.inline.output(this.token.text);return this.renderer.html(c);case"paragraph":return this.renderer.paragraph(this.inline.output(this.token.text));case"text":return this.renderer.paragraph(this.parseText())}},l.exec=l,u.options=u.setOptions=function(e){return c(u.defaults,e),u},u.defaults={gfm:!0,tables:!0,breaks:!1,pedantic:!1,sanitize:!1,sanitizer:null,mangle:!0,smartLists:!1,silent:!1,highlight:null,langPrefix:"lang-",smartypants:!1,headerPrefix:"",renderer:new r,xhtml:!1},u.Parser=i,u.parser=i.parse,u.Renderer=r,u.Lexer=t,u.lexer=t.lex,u.InlineLexer=n,u.inlineLexer=n.output,u.parse=u,e.exports=u}).call(function(){return this||("undefined"!=typeof window?window:Re)}())}),Be=I(function(e){var t="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},n=function(){var e=/\blang(?:uage)?-(\w+)\b/i,n=0,r=t.Prism={util:{encode:function(e){return e instanceof i?new i(e.type,r.util.encode(e.content),e.alias):"Array"===r.util.type(e)?e.map(r.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++n}),e.__id},clone:function(e){var t=r.util.type(e);switch(t){case"Object":var n={};for(var i in e)e.hasOwnProperty(i)&&(n[i]=r.util.clone(e[i]));return n;case"Array":return e.map&&e.map(function(e){return r.util.clone(e)})}return e}},languages:{extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var i in t)n[i]=t[i];return n},insertBefore:function(e,t,n,i){i=i||r.languages;var a=i[e];if(2==arguments.length){n=arguments[1];for(var o in n)n.hasOwnProperty(o)&&(a[o]=n[o]);return a}var s={};for(var l in a)if(a.hasOwnProperty(l)){if(l==t)for(var o in n)n.hasOwnProperty(o)&&(s[o]=n[o]);
s[l]=a[l]}return r.languages.DFS(r.languages,function(t,n){n===i[e]&&t!=e&&(this[t]=s)}),i[e]=s},DFS:function(e,t,n,i){i=i||{};for(var a in e)e.hasOwnProperty(a)&&(t.call(e,a,e[a],n||a),"Object"!==r.util.type(e[a])||i[r.util.objId(e[a])]?"Array"!==r.util.type(e[a])||i[r.util.objId(e[a])]||(i[r.util.objId(e[a])]=!0,r.languages.DFS(e[a],t,a,i)):(i[r.util.objId(e[a])]=!0,r.languages.DFS(e[a],t,null,i)))}},plugins:{},highlightAll:function(e,t){var n={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};r.hooks.run("before-highlightall",n);for(var i,a=n.elements||document.querySelectorAll(n.selector),o=0;i=a[o++];)r.highlightElement(i,e===!0,n.callback)},highlightElement:function(n,i,a){for(var o,s,l=n;l&&!e.test(l.className);)l=l.parentNode;l&&(o=(l.className.match(e)||[,""])[1].toLowerCase(),s=r.languages[o]),n.className=n.className.replace(e,"").replace(/\s+/g," ")+" language-"+o,l=n.parentNode,/pre/i.test(l.nodeName)&&(l.className=l.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var c=n.textContent,u={element:n,language:o,grammar:s,code:c};if(r.hooks.run("before-sanity-check",u),!u.code||!u.grammar)return u.code&&(u.element.textContent=u.code),void r.hooks.run("complete",u);if(r.hooks.run("before-highlight",u),i&&t.Worker){var p=new Worker(r.filename);p.onmessage=function(e){u.highlightedCode=e.data,r.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(u.element),r.hooks.run("after-highlight",u),r.hooks.run("complete",u)},p.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=r.highlight(u.code,u.grammar,u.language),r.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(n),r.hooks.run("after-highlight",u),r.hooks.run("complete",u)},highlight:function(e,t,n){var a=r.tokenize(e,t);return i.stringify(r.util.encode(a),n)},tokenize:function(e,t,n){var i=r.Token,a=[e],o=t.rest;if(o){for(var s in o)t[s]=o[s];delete t.rest}e:for(var s in t)if(t.hasOwnProperty(s)&&t[s]){var l=t[s];l="Array"===r.util.type(l)?l:[l];for(var c=0;c<l.length;++c){var u=l[c],p=u.inside,h=!!u.lookbehind,d=!!u.greedy,g=0,f=u.alias;if(d&&!u.pattern.global){var m=u.pattern.toString().match(/[imuy]*$/)[0];u.pattern=RegExp(u.pattern.source,m+"g")}u=u.pattern||u;for(var v=0,b=0;v<a.length;b+=a[v].length,++v){var y=a[v];if(a.length>e.length)break e;if(!(y instanceof i)){u.lastIndex=0;var k=u.exec(y),w=1;if(!k&&d&&v!=a.length-1){if(u.lastIndex=b,k=u.exec(e),!k)break;for(var x=k.index+(h?k[1].length:0),_=k.index+k[0].length,S=v,L=b,C=a.length;S<C&&L<_;++S)L+=a[S].length,x>=L&&(++v,b=L);if(a[v]instanceof i||a[S-1].greedy)continue;w=S-v,y=e.slice(b,L),k.index-=b}if(k){h&&(g=k[1].length);var x=k.index+g,k=k[0].slice(g),_=x+k.length,$=y.slice(0,x),E=y.slice(_),T=[v,w];$&&T.push($);var A=new i(s,p?r.tokenize(k,p):k,f,k,d);T.push(A),E&&T.push(E),Array.prototype.splice.apply(a,T)}}}}}return a},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var i,a=0;i=n[a++];)i(t)}}},i=r.Token=function(e,t,n,r,i){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!i};if(i.stringify=function(e,t,n){if("string"==typeof e)return e;if("Array"===r.util.type(e))return e.map(function(n){return i.stringify(n,t,e)}).join("");var a={type:e.type,content:i.stringify(e.content,t,n),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:n};if("comment"==a.type&&(a.attributes.spellcheck="true"),e.alias){var o="Array"===r.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(a.classes,o)}r.hooks.run("wrap",a);var s=Object.keys(a.attributes).map(function(e){return e+'="'+(a.attributes[e]||"").replace(/"/g,"&quot;")+'"'}).join(" ");return"<"+a.tag+' class="'+a.classes.join(" ")+'"'+(s?" "+s:"")+">"+a.content+"</"+a.tag+">"},!t.document)return t.addEventListener?(t.addEventListener("message",function(e){var n=JSON.parse(e.data),i=n.language,a=n.code,o=n.immediateClose;t.postMessage(r.highlight(a,r.languages[i],i)),o&&t.close()},!1),t.Prism):t.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(r.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(r.highlightAll):window.setTimeout(r.highlightAll,16):document.addEventListener("DOMContentLoaded",r.highlightAll))),t.Prism}();e.exports&&(e.exports=n),"undefined"!=typeof Re&&(Re.Prism=n),n.languages.markup={comment:/<!--[\w\W]*?-->/,prolog:/<\?[\w\W]+?\?>/,doctype:/<!DOCTYPE[\w\W]+?>/i,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},n.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&amp;/,"&"))}),n.languages.xml=n.languages.markup,n.languages.html=n.languages.markup,n.languages.mathml=n.languages.markup,n.languages.svg=n.languages.markup,n.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},n.languages.css.atrule.inside.rest=n.util.clone(n.languages.css),n.languages.markup&&(n.languages.insertBefore("markup","tag",{style:{pattern:/(<style[\w\W]*?>)[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:n.languages.css,alias:"language-css"}}),n.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:n.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:n.languages.css}},alias:"language-css"}},n.languages.markup.tag)),n.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(true|false)\b/,function:/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},n.languages.javascript=n.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,function:/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*\*?|\/|~|\^|%|\.{3}/}),n.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}}),n.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\\\|\\?[^\\])*?`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:n.languages.javascript}},string:/[\s\S]+/}}}),n.languages.markup&&n.languages.insertBefore("markup","tag",{script:{pattern:/(<script[\w\W]*?>)[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:n.languages.javascript,alias:"language-javascript"}}),n.languages.js=n.languages.javascript,function(){"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(){var e={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"};Array.prototype.forEach&&Array.prototype.slice.call(document.querySelectorAll("pre[data-src]")).forEach(function(t){for(var r,i=t.getAttribute("data-src"),a=t,o=/\blang(?:uage)?-(?!\*)(\w+)\b/i;a&&!o.test(a.className);)a=a.parentNode;if(a&&(r=(t.className.match(o)||[,""])[1]),!r){var s=(i.match(/\.(\w+)$/)||[,""])[1];r=e[s]||s}var l=document.createElement("code");l.className="language-"+r,t.textContent="",l.textContent="Loading…",t.appendChild(l);var c=new XMLHttpRequest;c.open("GET",i,!0),c.onreadystatechange=function(){4==c.readyState&&(c.status<400&&c.responseText?(l.textContent=c.responseText,n.highlightElement(l)):c.status>=400?l.textContent="✖ Error "+c.status+" while fetching file: "+c.statusText:l.textContent="✖ Error: File does not exist or is empty")},c.send(null)})},document.addEventListener("DOMContentLoaded",self.Prism.fileHighlight))}()}),De={},Ue=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g;R.clear=function(){De={}};var Ge=We,Ve="",Xe="",Ze=new We.Renderer,Ye={},Je=[],Qe=e(function(e){var t="";return e?(t=Ge(e),t=B(t),R.clear(),t):e});Qe.renderer=Ze,Qe.init=function(e,t){void 0===e&&(e={}),void 0===t&&(t=window.location.pathname),Ve=Ee(t),r(e)?Ge=e(We,Ze):(Ze=pe(Ze,e.renderer),We.setOptions(pe(e,{renderer:Ze})))},Qe.update=function(){Xe=w().path},Ze.heading=function(e,t){var n={level:t,title:e};/{docsify-ignore}/g.test(e)&&(e=e.replace("{docsify-ignore}",""),n.title=e,n.ignoreSubHeading=!0),/{docsify-ignore-all}/g.test(e)&&(e=e.replace("{docsify-ignore-all}",""),n.title=e,n.ignoreAllSubs=!0);var r=R(e),i=x(Xe,{id:r});return n.slug=i,Je.push(n),"<h"+t+' id="'+r+'"><a href="'+i+'" data-id="'+r+'" class="anchor"><span>'+e+"</span></a></h"+t+">"},Ze.code=function(e,t){void 0===t&&(t="");var n=Be.highlight(e,Be.languages[t]||Be.languages.markup);return'<pre v-pre data-lang="'+t+'"><code class="lang-'+t+'">'+n+"</code></pre>"},Ze.link=function(e,t,n){var r="";return/:|(\/{2})/.test(e)?r=' target="_blank"':e=x(e,null,Xe),t&&(t=' title="'+t+'"'),'<a href="'+e+'"'+(t||"")+r+">"+n+"</a>"},Ze.paragraph=function(e){return/^!&gt;/.test(e)?F("tip",e):/^\?&gt;/.test(e)?F("warn",e):"<p>"+e+"</p>"},Ze.image=function(e,t,n){var r=e,i=t?' title="'+t+'"':"";return Te(e)||(r=v(Ve,e)),'<img src="'+r+'" data-origin="'+e+'" alt="'+n+'"'+i+">"};var Ke=Object.freeze({markdown:Qe,sidebar:D,subSidebar:U,cover:G}),et={},tt=Object.freeze({cached:e,hyphenate:ue,merge:pe,isPrimitive:t,noop:n,isFn:r,UA:_e,isIE:Se,isMobile:Le}),nt=function(){window.Docsify={util:tt,dom:xe,render:Ke,route:Me,get:j,slugify:R},window.marked=We,window.Prism=Be},rt=ce.prototype;se(rt),ee(rt),Y(rt),ae(rt),ne(rt),nt(),setTimeout(function(e){return new ce},0)}();
(function(Prism) {
var insideString = {
variable: [
// Arithmetic Environment
{
pattern: /\$?\(\([\s\S]+?\)\)/,
inside: {
// If there is a $ sign at the beginning highlight $(( and )) as variable
variable: [{
pattern: /(^\$\(\([\s\S]+)\)\)/,
lookbehind: true
},
/^\$\(\(/,
],
number: /\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee]-?\d+)?)\b/,
// Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,
// If there is no $ sign at the beginning highlight (( and )) as punctuation
punctuation: /\(\(?|\)\)?|,|;/
}
},
// Command Substitution
{
pattern: /\$\([^)]+\)|`[^`]+`/,
inside: {
variable: /^\$\(|^`|\)$|`$/
}
},
/\$(?:[a-z0-9_#\?\*!@]+|\{[^}]+\})/i
],
};
Prism.languages.bash = {
'shebang': {
pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,
alias: 'important'
},
'comment': {
pattern: /(^|[^"{\\])#.*/,
lookbehind: true
},
'string': [
//Support for Here-Documents https://en.wikipedia.org/wiki/Here_document
{
pattern: /((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,
lookbehind: true,
greedy: true,
inside: insideString
},
{
pattern: /(["'])(?:\\\\|\\?[^\\])*?\1/g,
greedy: true,
inside: insideString
}
],
'variable': insideString.variable,
// Originally based on http://ss64.com/bash/
'function': {
pattern: /(^|\s|;|\||&)(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\s|;|\||&)/,
lookbehind: true
},
'keyword': {
pattern: /(^|\s|;|\||&)(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\s|;|\||&)/,
lookbehind: true
},
'boolean': {
pattern: /(^|\s|;|\||&)(?:true|false)(?=$|\s|;|\||&)/,
lookbehind: true
},
'operator': /&&?|\|\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,
'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];]/
};
var inside = insideString.variable[1].inside;
inside['function'] = Prism.languages.bash['function'];
inside.keyword = Prism.languages.bash.keyword;
inside.boolean = Prism.languages.bash.boolean;
inside.operator = Prism.languages.bash.operator;
inside.punctuation = Prism.languages.bash.punctuation;
})(Prism);
Prism.languages.json = {
'property': /"(?:\\.|[^\\"])*"(?=\s*:)/ig,
'string': /"(?!:)(?:\\.|[^\\"])*"(?!:)/g,
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?)\b/g,
'punctuation': /[{}[\]);,]/g,
'operator': /:/g,
'boolean': /\b(true|false)\b/gi,
'null': /\bnull\b/gi
};
Prism.languages.jsonp = Prism.languages.json;
@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}.emoji{height:19.2px;height:1.2rem;vertical-align:middle}.progress{background-color:#42b983;background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;-webkit-transition:width .2s,opacity .4s;transition:width .2s,opacity .4s;width:0;z-index:5}.search .search-keyword,.search a:hover{color:#42b983;color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}.app-nav{left:0;margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:2}.app-nav p{margin:0}.app-nav>a{margin:0 16px;margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;-webkit-transition:color .3s;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:#42b983;color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 16px;margin:0 1rem;padding:5px 0;position:relative}.app-nav li ul{background-color:#fff;border:1px solid #ddd;border-bottom-color:#ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:scroll;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:16px;line-height:1rem;margin:0;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.app-nav.no-badge{margin-right:25px}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner svg{color:#fff;fill:#42b983;fill:var(--theme-color,#42b983);height:80px;width:80px}.github-corner:hover .octo-arm{-webkit-animation:a .56s ease-in-out;animation:a .56s ease-in-out}main{display:block;position:relative;width:100vw;height:100%}.anchor{display:inline-block;text-decoration:none;-webkit-transition:all .3s;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0;top:0;bottom:0;left:0;position:absolute;-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out;width:300px;z-index:3}.sidebar>h1{margin:0 auto 16px;margin:0 auto 1rem;font-size:24px;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar ul{margin:0;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;bottom:0;left:0;position:absolute;text-align:center;-webkit-transition:opacity .3s;transition:opacity .3s;width:30px;width:284px;z-index:4}.sidebar-toggle .sidebar-toggle-button:hover{opacity:.4}.sidebar-toggle span{background-color:#42b983;background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:20px;top:0;right:0;bottom:0;left:300px;position:absolute;-webkit-transition:left .25s ease;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:800px;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:16px;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;width:20px;height:20px;text-align:center;top:14px}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:16px;padding:1rem}body.close .sidebar{-webkit-transform:translateX(-300px);transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;overflow-x:hidden}.sidebar{left:-300px;-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.content{left:0;max-width:100vw;position:static;-webkit-transition:-webkit-transform .25s ease;transition:-webkit-transform .25s ease;transition:transform .25s ease;transition:transform .25s ease,-webkit-transform .25s ease}.app-nav,.github-corner{-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto}body.close .sidebar{-webkit-transform:translateX(300px);transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);-webkit-transition:background-color 1s;transition:background-color 1s;width:284px}body.close .content{-webkit-transform:translateX(300px);transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner .octo-arm{-webkit-animation:a .56s ease-in-out;animation:a .56s ease-in-out}.github-corner:hover .octo-arm{-webkit-animation:none;animation:none}}@-webkit-keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}section.cover{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;display:none}section.cover .cover-main{-webkit-box-flex:1;-ms-flex:1;flex:1;margin:-20px 16px 0;text-align:center;z-index:1}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:24px;line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:40px;font-size:2.5rem;font-weight:300;margin:10px 0 40px;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-7px;bottom:-.4375rem;font-size:16px;font-size:1rem;position:absolute}section.cover blockquote{font-size:24px;font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-color:#42b983;border:1px solid var(--theme-color,#42b983);border-radius:2rem;box-sizing:border-box;color:#42b983;color:var(--theme-color,#42b983);display:inline-block;font-size:16.8px;font-size:1.05rem;letter-spacing:1.6px;letter-spacing:.1rem;margin-right:16px;margin-right:1rem;padding:.75em 32px;padding:.75em 2rem;text-decoration:none;-webkit-transition:all .15s ease;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:#42b983;background-color:var(--theme-color,#42b983);color:#fff;margin-right:0}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983);-webkit-transition:color .3s;transition:color .3s}section.cover blockquote>p>a:hover{color:#42b983;color:var(--theme-color,#42b983)}section.cover.show{display:-webkit-box;display:-ms-flexbox;display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;width:100%;height:100%}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0 6px 15px}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar .section-link:before{content:"-";padding-right:4px}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:32px;font-size:2rem;margin:0 0 16px;margin:0 0 1rem}.markdown-section h2{font-size:28px;font-size:1.75rem;margin:45px 0 12.8px;margin:45px 0 .8rem}.markdown-section h3{font-size:24px;font-size:1.5rem;margin:40px 0 9.6px;margin:40px 0 .6rem}.markdown-section h4{font-size:20px;font-size:1.25rem}.markdown-section h5,.markdown-section h6{font-size:16px;font-size:1rem}.markdown-section h6{color:#777}.markdown-section figure,.markdown-section ol,.markdown-section p,.markdown-section ul{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:25.6px;line-height:1.6rem;word-spacing:.8px;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:24px;padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid #42b983;border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code{border-radius:2px;color:#e96900;font-size:12.8px;font-size:.8rem;margin:0 2px;padding:3px 5px;white-space:nowrap}.markdown-section code,.markdown-section pre{background-color:#f8f8f8;font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section pre{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;line-height:24px;line-height:1.5rem;margin:1.2em 0;overflow:auto;padding:0 22.4px;padding:0 1.4rem;position:relative;word-wrap:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:#42b983;color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:#42b983;color:var(--theme-color,#42b983)}.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;background-color:#f8f8f8;border-radius:2px;color:#525252;display:block;font-family:Roboto Mono,Monaco,courier,monospace;font-size:12.8px;font-size:.8rem;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;padding:2.2em 5px;white-space:inherit}.markdown-section code:after,.markdown-section code:before{letter-spacing:.8px;letter-spacing:.05rem}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:24px;min-height:1.5rem}pre:after{color:#ccc;content:attr(data-lang);font-size:9.6px;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0}
\ No newline at end of file
!function (a, b) {
function c(a) {
Object.defineProperty(this, "val", {value: a.toString(), enumerable: !0}), this.gt = function (a) {
return c.compare(this, a) > 0
}, this.gte = function (a) {
return c.compare(this, a) >= 0
}, this.lt = function (a) {
return c.compare(this, a) < 0
}, this.lte = function (a) {
return c.compare(this, a) <= 0
}, this.eq = function (a) {
return 0 === c.compare(this, a)
}
}
b.env = b.env || {}, c.prototype.toString = function () {
return this.val
}, c.prototype.valueOf = function () {
for (var a = this.val.split("."), b = [], c = 0; c < a.length; c++) {
var d = parseInt(a[c], 10);
isNaN(d) && (d = 0);
var e = d.toString();
e.length < 5 && (e = Array(6 - e.length).join("0") + e), b.push(e), 1 === b.length && b.push(".")
}
return parseFloat(b.join(""))
}, c.compare = function (a, b) {
a = a.toString().split("."), b = b.toString().split(".");
for (var c = 0; c < a.length || c < b.length; c++) {
var d = parseInt(a[c], 10), e = parseInt(b[c], 10);
if (window.isNaN(d) && (d = 0), window.isNaN(e) && (e = 0), e > d)return -1;
if (d > e)return 1
}
return 0
}, b.version = function (a) {
return new c(a)
}
}(window, window.lib || (window.lib = {})), function (a, b) {
b.env = b.env || {};
var c = a.location.search.replace(/^\?/, "");
if (b.env.params = {}, c)for (var d = c.split("&"), e = 0; e < d.length; e++) {
d[e] = d[e].split("=");
try {
b.env.params[d[e][0]] = decodeURIComponent(d[e][1])
} catch (f) {
b.env.params[d[e][0]] = d[e][1]
}
}
}(window, window.lib || (window.lib = {})), function (a, b) {
b.env = b.env || {};
var c, d = a.navigator.userAgent;
if (c = d.match(/Windows\sPhone\s(?:OS\s)?([\d\.]+)/))b.env.os = {
name: "Windows Phone",
isWindowsPhone: !0,
version: c[1]
}; else if (d.match(/Safari/) && (c = d.match(/Android[\s\/]([\d\.]+)/)))b.env.os = {version: c[1]}, d.match(/Mobile\s+Safari/) ? (b.env.os.name = "Android", b.env.os.isAndroid = !0) : (b.env.os.name = "AndroidPad", b.env.os.isAndroidPad = !0); else if (c = d.match(/(iPhone|iPad|iPod)/)) {
var e = c[1];
c = d.match(/OS ([\d_\.]+) like Mac OS X/), b.env.os = {
name: e,
isIPhone: "iPhone" === e || "iPod" === e,
isIPad: "iPad" === e,
isIOS: !0,
version: c[1].split("_").join(".")
}
} else b.env.os = {name: "unknown", version: "0.0.0"};
b.version && (b.env.os.version = b.version(b.env.os.version))
}(window, window.lib || (window.lib = {})), function (a, b) {
b.env = b.env || {};
var c, d = a.navigator.userAgent;
(c = d.match(/(?:UCWEB|UCBrowser\/)([\d\.]+)/)) ? b.env.browser = {
name: "UC",
isUC: !0,
version: c[1]
} : (c = d.match(/MQQBrowser\/([\d\.]+)/)) ? b.env.browser = {
name: "QQ",
isQQ: !0,
version: c[1]
} : (c = d.match(/Firefox\/([\d\.]+)/)) ? b.env.browser = {
name: "Firefox",
isFirefox: !0,
version: c[1]
} : (c = d.match(/MSIE\s([\d\.]+)/)) || (c = d.match(/IEMobile\/([\d\.]+)/)) ? (b.env.browser = {version: c[1]}, d.match(/IEMobile/) ? (b.env.browser.name = "IEMobile", b.env.browser.isIEMobile = !0) : (b.env.browser.name = "IE", b.env.browser.isIE = !0), d.match(/Android|iPhone/) && (b.env.browser.isIELikeWebkit = !0)) : (c = d.match(/(?:Chrome|CriOS)\/([\d\.]+)/)) ? (b.env.browser = {
name: "Chrome",
isChrome: !0,
version: c[1]
}, d.match(/Version\/[\d+\.]+\s*Chrome/) && (b.env.browser.name = "Chrome Webview", b.env.browser.isWebview = !0)) : d.match(/Safari/) && (c = d.match(/Android[\s\/]([\d\.]+)/)) ? b.env.browser = {
name: "Android",
isAndroid: !0,
version: c[1]
} : d.match(/iPhone|iPad|iPod/) ? d.match(/Safari/) ? (c = d.match(/Version\/([\d\.]+)/), b.env.browser = {
name: "Safari",
isSafari: !0,
version: c[1]
}) : (c = d.match(/OS ([\d_\.]+) like Mac OS X/), b.env.browser = {
name: "iOS Webview",
isWebview: !0,
version: c[1].replace(/\_/, ".")
}) : b.env.browser = {
name: "unknown",
version: "0.0.0"
}, b.version && (b.env.browser.version = b.version(b.env.browser.version))
}(window, window.lib || (window.lib = {})), function (a, b) {
b.env = b.env || {};
var c = a.navigator.userAgent;
c.match(/Weibo/i) ? b.env.thirdapp = {
appname: "Weibo",
isWeibo: !0
} : c.match(/MicroMessenger/i) ? b.env.thirdapp = {appname: "Weixin", isWeixin: !0} : b.env.thirdapp = !1
}(window, window.lib || (window.lib = {})), function (a, b) {
b.env = b.env || {};
var c, d, e = a.navigator.userAgent;
(d = e.match(/WindVane[\/\s]([\d\.\_]+)/)) && (c = d[1]);
var f = !1, g = "", h = "", i = "";
(d = e.match(/AliApp\(([A-Z\-]+)\/([\d\.]+)\)/)) && (f = !0, g = d[1], i = d[2], h = g.indexOf("-PD") > 0 ? b.env.os.isIOS ? "iPad" : b.env.os.isAndroid ? "AndroidPad" : b.env.os.name : b.env.os.name), !g && e.indexOf("TBIOS") > 0 && (g = "TB"), f ? b.env.aliapp = {
windvane: b.version(c || "0.0.0"),
appname: g || "unkown",
version: b.version(i || "0.0.0"),
platform: h || b.env.os.name
} : b.env.aliapp = !1, b.env.taobaoApp = b.env.aliapp
}(window, window.lib || (window.lib = {}));
!function (a, b) {
function c(a) {
var b = {};
Object.defineProperty(this, "params", {
set: function (a) {
if ("object" == typeof a) {
for (var c in b)delete b[c];
for (var c in a)b[c] = a[c]
}
}, get: function () {
return b
}, enumerable: !0
}), Object.defineProperty(this, "search", {
set: function (a) {
if ("string" == typeof a) {
0 === a.indexOf("?") && (a = a.substr(1));
var c = a.split("&");
for (var d in b)delete b[d];
for (var e = 0; e < c.length; e++) {
var f = c[e].split("=");
if (f[0])try {
b[decodeURIComponent(f[0])] = decodeURIComponent(f[1] || "")
} catch (g) {
b[f[0]] = f[1] || ""
}
}
}
}, get: function () {
var a = [];
for (var c in b)if (b[c])try {
a.push(encodeURIComponent(c) + "=" + encodeURIComponent(b[c]))
} catch (d) {
a.push(c + "=" + b[c])
} else try {
a.push(encodeURIComponent(c))
} catch (d) {
a.push(c)
}
return a.length ? "?" + a.join("&") : ""
}, enumerable: !0
});
var c;
Object.defineProperty(this, "hash", {
set: function (a) {
a && a.indexOf("#") < 0 && (a = "#" + a), c = a || ""
}, get: function () {
return c
}, enumerable: !0
}), this.set = function (a) {
a = a || "";
var b;
if (!(b = a.match(new RegExp("^([a-z0-9-]+:)?[/]{2}(?:([^@/:?]+)(?::([^@/:]+))?@)?([^:/?#]+)(?:[:]([0-9]+))?([/][^?#;]*)?(?:[?]([^?#]*))?(#[^#]*)?$", "i"))))throw new Error("Wrong uri scheme.");
this.protocol = b[1] || location.protocol, this.username = b[2] || "", this.password = b[3] || "", this.hostname = this.host = b[4], this.port = b[5] || "", this.pathname = b[6] || "/", this.search = b[7] || "", this.hash = b[8] || "", this.origin = this.protocol + "//" + this.hostname
}, this.toString = function () {
var a = this.protocol + "//";
return this.username && (a += this.username, this.password && (a += ":" + this.password), a += "@"), a += this.host, this.port && "80" !== this.port && (a += ":" + this.port), this.pathname && (a += this.pathname), this.search && (a += this.search), this.hash && (a += this.hash), a
}, a && this.set(a.toString())
}
b.httpurl = function (a) {
return new c(a)
}
}(window, window.lib || (window.lib = {}));
!function (a, b) {
function c(a, b) {
var c = new j(location.href), d = h.getElementById("buried"), e = c.params.ttid, f = c.params.ad_id, g = c.params.source_type, i = c.params.refpid, k = c.params.actparam, l = c.params.actname, m = c.params.ali_trackid, n = c.params.pid, o = h.cookie.match(/(?:^|\s)cna=([^;]+)(?:;|$)/);
c.search = "", c.hash = "";
var p = {};
if (d && (e = d.value), p.from = "h5", e && (p.ttid = e), i && (p.refpid = i), k && (p.actparam = k), l && (p.actname = l), p.url = c.toString(), n && (p.pid = n), f && (p.ad_id = f), g && (p.source_type = g), m && (p.ali_trackid = m), o && (p.h5_uid = o[1]), "object" == typeof b)for (var q in b)p[q] = b[q];
return a.params.point = JSON.stringify(p), a
}
function d(a, b) {
var c = new j(location.href), d = h.getElementById("buried");
for (var e in c.params)a.params.hasOwnProperty(e) || (a.params[e] = c.params[e]);
if (d && (a.params.ttid = d.value), "object" == typeof b)for (var e in b)a.params[e] = b[e];
return a
}
function e(a) {
o || (o = h.createElement("iframe"), o.id = "callapp_iframe_" + Date.now(), o.frameborder = "0", o.style.cssText = "display:none;border:0;width:0;height:0;", h.body.appendChild(o)), o.src = a
}
function f(a, b) {
b.replace === !1 || !l && b.replace !== !0 ? location.href = a : location.replace(a)
}
function g(a) {
var b = document.createElement("a");
b.setAttribute("href", a), b.style.display = "none", document.body.appendChild(b);
var c = document.createEvent("HTMLEvents");
c.initEvent("click", !1, !1), b.dispatchEvent(c)
}
var h = a.document, i = a.navigator.userAgent, j = b.httpurl, k = b.env.os, l = (b.env.params, b.env.aliapp), m = b.env.browser, n = {
"taobao:": "com.taobao.taobao",
"taobaowebview:": "com.taobao.taobao",
"tmall:": "com.tmall.wireless"
};
b.callapp = b.callapp || {};
var o;
b.callapp.gotoPage = function (a, b) {
b = b || {}, "undefined" == typeof b.point && (b.point = !0), "undefined" == typeof b.params && (b.params = !0);
var h = new j(a || location.href);
if (a = new j(a), ("http:" === a.protocol || "https:" === a.protocol) && (k.isAndroid && l && "TB" === l.appname ? (a = new j("taobaowebview://m.taobao.com/"), a.params.weburl = h.toString()) : a.protocol = "taobao:"), "taobao:" === a.protocol)b.point && c(a, b.point), b.params && d(a, b.params); else if ("taobaowebview:" === a.protocol) {
b.point && c(a, b.point);
var o = new j(a.params.weburl);
b.params && d(o, b.params), b.point && c(o, b.point), a.params.weburl = o.toString()
} else"tmall:" !== a.protocol.toLowerCase() && "kddcpublic:" !== a.protocol.toLowerCase() && "mdatadwphone:" !== a.protocol.toLowerCase() && b.params && d(a, b.params);
var p = k.isAndroid && m.isChrome && !m.isWebview, q = k.isAndroid && !!i.match(/samsung/i) && k.version.gte("4.3") && k.version.lt("4.5"), r = k.isIPhone && k.version.gte("9.0") && m.isSafari;
(p || q || b.forceIntent) && (a.hash = "Intent;scheme=" + a.protocol.replace(":", "") + ";package=" + (b["package"] || n[a.protocol]) + ";end", a.protocol = "intent:"), r ? setTimeout(function () {
g(a.toString(), b)
}, 100) : l || "intent:" === a.protocol ? setTimeout(function () {
f(a.toString(), b)
}, 100) : e(a.toString())
}, b.callapp.download = function (a, b) {
b = b || {}, a || (a = k.isIPhone ? "http://itunes.apple.com/cn/app/id387682726?mt=8" : k.isIPad ? "https://itunes.apple.com/app/id438865278" : k.isAndroid ? "//download.alicdn.com/wireless/taobao4android/latest/taobao4android_703248.apk" : ""), a = new j(a), k.isAndroid && a.pathname.match(/\.apk$/) ? (a.search = "", a.hash = "") : b.params && d(a, b.params), a = a.toString(), f(a, b)
}
}(window, window.lib || (window.lib = {}));
\ No newline at end of file
//document.documentElement.style.fontSize = document.documentElement.clientWidth/25 + 'px';
function getParams(data, key, default_value) {
if (data != undefined) {
return key in data ? data[key] : default_value;
}
return default_value;
}
function serializeParams(data) {
var serializedParams = '';
for (var pro in data) {
serializedParams += (serializedParams.length ? '&' : '') + pro + '=' + encodeURIComponent(data[pro]);
}
return serializedParams;
}
function getURLParams(url) {
var urlParts = url.split("?");
var result = {};
if (urlParts[1]) {
var params = urlParts[1].split("&");
for (var i = 0; i < params.length; ++i) {
var item = params[i].split("=");
var key = decodeURIComponent(item[0]);
var uri_encoded = item[1].replace(/%([^\da-fA-f].)/, "%25$1")
var val = decodeURIComponent(uri_encoded);
result[key] = val;
}
}
return result;
}
function doAjax(args) {
var request = new XMLHttpRequest(),
url = getParams(args, 'url', ''),
data = getParams(args, 'data', {}),
contentType = getParams(args, 'contentType', "application/x-www-form-urlencoded"),
type = getParams(args, 'type', 'get');
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 200) {
var dataType = null;
if ('dataType' in args) {
dataType = args.dataType;
} else {
if (/\bContent\-Type\s*:\s* ([^\n;]+)(?=\n|;)/i.test(request.getAllResponseHeaders())) {
var contentType = RegExp.$1;
if (/\bjson\b/i.test(contentType)) {
dataType = 'json';
} else {
dataType = 'text';
}
}
}
var data = null;
if (/^json$/i.test(dataType)) {
data = JSON.parse(request.responseText);
} else {
data = request.responseText;
}
try {
if (typeof args.success == 'function') {
args.success(data);
}
} catch (e) {
}
} else {
if (typeof args.error == 'function') {
args.error(request.status);
}
}
}
}
request.onloadstart = function () {
if (typeof args.loadstart == 'function') {
args.loadstart();
}
}
request.onprogress = function (event) {
if (typeof args.progress == 'function') {
args.progress(event);
}
}
request.timeout = getParams(args, 'timeout', 0);
if (/^post$/gi.test(type)) {
request.open("POST", url, true);
request.setRequestHeader("Content-Type", contentType);
if ("application/x-www-form-urlencoded" == contentType) {
var content = typeof data === 'string' ? data : serializeParams(data);
request.send(content);
} else if ("application/json" == contentType) {
var content = typeof data === 'string' ? data : JSON.stringify(data);
request.send(content);
}
} else {
url += (url.indexOf("?") >= 0 ? '&' : '?') + serializeParams(data);
request.open("GET", url, true);
request.send();
}
}
function doJsonAjax(url, data, success, failed, loadstart, progress) {
doAjax({
url: url,
type: 'post',
data: data,
contentType: 'application/json',
success: success,
error: failed,
loadstart: loadstart,
progress: progress
});
}
$.toast = function (text, delay) {
if (delay === undefined || +delay <= 0) {
delay = 3000;
}
var toast = $('#toast'), timer = 0;
if (toast.length === 0) {
toast = $('<div>', {'class': 'toast', id: 'toast'}).append($('<span>')).appendTo($('body'));
}
toast.find('span').html(text);
timer = toast.data('timer');
timer && clearTimeout(timer);
toast.show();
toast.data("timer", setTimeout(function () {
toast.detach().data("timer", 0);
}, delay));
}
function IdentityCodeValid(code) {
var city = {
11: "北京",
12: "天津",
13: "河北",
14: "山西",
15: "内蒙古",
21: "辽宁",
22: "吉林",
23: "黑龙江 ",
31: "上海",
32: "江苏",
33: "浙江",
34: "安徽",
35: "福建",
36: "江西",
37: "山东",
41: "河南",
42: "湖北 ",
43: "湖南",
44: "广东",
45: "广西",
46: "海南",
50: "重庆",
51: "四川",
52: "贵州",
53: "云南",
54: "西藏 ",
61: "陕西",
62: "甘肃",
63: "青海",
64: "宁夏",
65: "新疆",
71: "台湾",
81: "香港",
82: "澳门",
91: "国外 "
};
var tip = "";
var pass = true;
if (!code || !/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i.test(code)) {
tip = "身份证号格式错误";
pass = false;
}
else if (!city[code.substr(0, 2)]) {
tip = "地址编码错误";
pass = false;
} else {
var t = code.substr(6, 4) + '-' + code.substr(10, 2) + '-' + code.substr(12, 2);
var ar = t.split(/-/);
t = new Date(t);
if (ar[0] != t.getFullYear() || ar[1] != t.getMonth() + 1 || ar[2] != t.getDate()) {
pass = false;
tip = "身份证号出生年月错误";
}
//18位身份证需要验证最后一位校验位
if (code.length == 18) {
code = code.split('');
//∑(ai×Wi)(mod 11)
//加权因子
var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
//校验位
var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
var sum = 0;
var ai = 0;
var wi = 0;
for (var i = 0; i < 17; i++) {
ai = code[i];
wi = factor[i];
sum += ai * wi;
}
if (parity[sum % 11] != code[17]) {
tip = "校验位错误";
pass = false;
}
}
}
if (!pass) console.log("youchu ID error:", code, tip);
return pass;
}
var Zepto=function(){function a(a){return null==a?String(a):U[V.call(a)]||"object"}function b(b){return"function"==a(b)}function c(a){return null!=a&&a==a.window}function d(a){return null!=a&&a.nodeType==a.DOCUMENT_NODE}function e(b){return"object"==a(b)}function f(a){return e(a)&&!c(a)&&Object.getPrototypeOf(a)==Object.prototype}function g(a){return"number"==typeof a.length}function h(a){return D.call(a,function(a){return null!=a})}function i(a){return a.length>0?x.fn.concat.apply([],a):a}function j(a){return a.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function k(a){return a in G?G[a]:G[a]=new RegExp("(^|\\s)"+a+"(\\s|$)")}function l(a,b){return"number"!=typeof b||H[j(a)]?b:b+"px"}function m(a){var b,c;return F[a]||(b=E.createElement(a),E.body.appendChild(b),c=getComputedStyle(b,"").getPropertyValue("display"),b.parentNode.removeChild(b),"none"==c&&(c="block"),F[a]=c),F[a]}function n(a){return"children"in a?C.call(a.children):x.map(a.childNodes,function(a){return 1==a.nodeType?a:void 0})}function o(a,b,c){for(w in b)c&&(f(b[w])||Z(b[w]))?(f(b[w])&&!f(a[w])&&(a[w]={}),Z(b[w])&&!Z(a[w])&&(a[w]=[]),o(a[w],b[w],c)):b[w]!==v&&(a[w]=b[w])}function p(a,b){return null==b?x(a):x(a).filter(b)}function q(a,c,d,e){return b(c)?c.call(a,d,e):c}function r(a,b,c){null==c?a.removeAttribute(b):a.setAttribute(b,c)}function s(a,b){var c=a.className||"",d=c&&c.baseVal!==v;return b===v?d?c.baseVal:c:void(d?c.baseVal=b:a.className=b)}function t(a){try{return a?"true"==a||("false"==a?!1:"null"==a?null:+a+""==a?+a:/^[\[\{]/.test(a)?x.parseJSON(a):a):a}catch(b){return a}}function u(a,b){b(a);for(var c=0,d=a.childNodes.length;d>c;c++)u(a.childNodes[c],b)}var v,w,x,y,z,A,B=[],C=B.slice,D=B.filter,E=window.document,F={},G={},H={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},I=/^\s*<(\w+|!)[^>]*>/,J=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,K=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,L=/^(?:body|html)$/i,M=/([A-Z])/g,N=["val","css","html","text","data","width","height","offset"],O=["after","prepend","before","append"],P=E.createElement("table"),Q=E.createElement("tr"),R={tr:E.createElement("tbody"),tbody:P,thead:P,tfoot:P,td:Q,th:Q,"*":E.createElement("div")},S=/complete|loaded|interactive/,T=/^[\w-]*$/,U={},V=U.toString,W={},X=E.createElement("div"),Y={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},Z=Array.isArray||function(a){return a instanceof Array};return W.matches=function(a,b){if(!b||!a||1!==a.nodeType)return!1;var c=a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.matchesSelector;if(c)return c.call(a,b);var d,e=a.parentNode,f=!e;return f&&(e=X).appendChild(a),d=~W.qsa(e,b).indexOf(a),f&&X.removeChild(a),d},z=function(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():""})},A=function(a){return D.call(a,function(b,c){return a.indexOf(b)==c})},W.fragment=function(a,b,c){var d,e,g;return J.test(a)&&(d=x(E.createElement(RegExp.$1))),d||(a.replace&&(a=a.replace(K,"<$1></$2>")),b===v&&(b=I.test(a)&&RegExp.$1),b in R||(b="*"),g=R[b],g.innerHTML=""+a,d=x.each(C.call(g.childNodes),function(){g.removeChild(this)})),f(c)&&(e=x(d),x.each(c,function(a,b){N.indexOf(a)>-1?e[a](b):e.attr(a,b)})),d},W.Z=function(a,b){if(a=a||[],navigator.userAgent.indexOf("MSIE 10")>-1)for(var c in $.fn)a[c]=$.fn[c];else a.__proto__=$.fn;return a.selector=b||"",a},W.isZ=function(a){return a instanceof W.Z},W.init=function(a,c){var d;if(!a)return W.Z();if("string"==typeof a)if(a=a.trim(),"<"==a[0]&&I.test(a))d=W.fragment(a,RegExp.$1,c),a=null;else{if(c!==v)return x(c).find(a);d=W.qsa(E,a)}else{if(b(a))return x(E).ready(a);if(W.isZ(a))return a;if(Z(a))d=h(a);else if(e(a))d=[a],a=null;else if(I.test(a))d=W.fragment(a.trim(),RegExp.$1,c),a=null;else{if(c!==v)return x(c).find(a);d=W.qsa(E,a)}}return W.Z(d,a)},x=function(a,b){return W.init(a,b)},x.extend=function(a){var b,c=C.call(arguments,1);return"boolean"==typeof a&&(b=a,a=c.shift()),c.forEach(function(c){o(a,c,b)}),a},W.qsa=function(a,b){var c,e="#"==b[0],f=!e&&"."==b[0],g=e||f?b.slice(1):b,h=T.test(g);return d(a)&&h&&e?(c=a.getElementById(g))?[c]:[]:1!==a.nodeType&&9!==a.nodeType?[]:C.call(h&&!e?f?a.getElementsByClassName(g):a.getElementsByTagName(b):a.querySelectorAll(b))},x.contains=E.documentElement.contains?function(a,b){return a!==b&&a.contains(b)}:function(a,b){for(;b&&(b=b.parentNode);)if(b===a)return!0;return!1},x.type=a,x.isFunction=b,x.isWindow=c,x.isArray=Z,x.isPlainObject=f,x.isEmptyObject=function(a){var b;for(b in a)return!1;return!0},x.inArray=function(a,b,c){return B.indexOf.call(b,a,c)},x.camelCase=z,x.trim=function(a){return null==a?"":String.prototype.trim.call(a)},x.uuid=0,x.support={},x.expr={},x.map=function(a,b){var c,d,e,f=[];if(g(a))for(d=0;d<a.length;d++)c=b(a[d],d),null!=c&&f.push(c);else for(e in a)c=b(a[e],e),null!=c&&f.push(c);return i(f)},x.each=function(a,b){var c,d;if(g(a)){for(c=0;c<a.length;c++)if(b.call(a[c],c,a[c])===!1)return a}else for(d in a)if(b.call(a[d],d,a[d])===!1)return a;return a},x.grep=function(a,b){return D.call(a,b)},window.JSON&&(x.parseJSON=JSON.parse),x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){U["[object "+b+"]"]=b.toLowerCase()}),x.fn={forEach:B.forEach,reduce:B.reduce,push:B.push,sort:B.sort,indexOf:B.indexOf,concat:B.concat,map:function(a){return x(x.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return x(C.apply(this,arguments))},ready:function(a){return S.test(E.readyState)&&E.body?a(x):E.addEventListener("DOMContentLoaded",function(){a(x)},!1),this},get:function(a){return a===v?C.call(this):this[a>=0?a:a+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(a){return B.every.call(this,function(b,c){return a.call(b,c,b)!==!1}),this},filter:function(a){return b(a)?this.not(this.not(a)):x(D.call(this,function(b){return W.matches(b,a)}))},add:function(a,b){return x(A(this.concat(x(a,b))))},is:function(a){return this.length>0&&W.matches(this[0],a)},not:function(a){var c=[];if(b(a)&&a.call!==v)this.each(function(b){a.call(this,b)||c.push(this)});else{var d="string"==typeof a?this.filter(a):g(a)&&b(a.item)?C.call(a):x(a);this.forEach(function(a){d.indexOf(a)<0&&c.push(a)})}return x(c)},has:function(a){return this.filter(function(){return e(a)?x.contains(this,a):x(this).find(a).size()})},eq:function(a){return-1===a?this.slice(a):this.slice(a,+a+1)},first:function(){var a=this[0];return a&&!e(a)?a:x(a)},last:function(){var a=this[this.length-1];return a&&!e(a)?a:x(a)},find:function(a){var b,c=this;return b=a?"object"==typeof a?x(a).filter(function(){var a=this;return B.some.call(c,function(b){return x.contains(b,a)})}):1==this.length?x(W.qsa(this[0],a)):this.map(function(){return W.qsa(this,a)}):x()},closest:function(a,b){var c=this[0],e=!1;for("object"==typeof a&&(e=x(a));c&&!(e?e.indexOf(c)>=0:W.matches(c,a));)c=c!==b&&!d(c)&&c.parentNode;return x(c)},parents:function(a){for(var b=[],c=this;c.length>0;)c=x.map(c,function(a){return(a=a.parentNode)&&!d(a)&&b.indexOf(a)<0?(b.push(a),a):void 0});return p(b,a)},parent:function(a){return p(A(this.pluck("parentNode")),a)},children:function(a){return p(this.map(function(){return n(this)}),a)},contents:function(){return this.map(function(){return C.call(this.childNodes)})},siblings:function(a){return p(this.map(function(a,b){return D.call(n(b.parentNode),function(a){return a!==b})}),a)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(a){return x.map(this,function(b){return b[a]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=m(this.nodeName))})},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){var c=b(a);if(this[0]&&!c)var d=x(a).get(0),e=d.parentNode||this.length>1;return this.each(function(b){x(this).wrapAll(c?a.call(this,b):e?d.cloneNode(!0):d)})},wrapAll:function(a){if(this[0]){x(this[0]).before(a=x(a));for(var b;(b=a.children()).length;)a=b.first();x(a).append(this)}return this},wrapInner:function(a){var c=b(a);return this.each(function(b){var d=x(this),e=d.contents(),f=c?a.call(this,b):a;e.length?e.wrapAll(f):d.append(f)})},unwrap:function(){return this.parent().each(function(){x(this).replaceWith(x(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(a){return this.each(function(){var b=x(this);(a===v?"none"==b.css("display"):a)?b.show():b.hide()})},prev:function(a){return x(this.pluck("previousElementSibling")).filter(a||"*")},next:function(a){return x(this.pluck("nextElementSibling")).filter(a||"*")},html:function(a){return 0 in arguments?this.each(function(b){var c=this.innerHTML;x(this).empty().append(q(this,a,b,c))}):0 in this?this[0].innerHTML:null},text:function(a){return 0 in arguments?this.each(function(b){var c=q(this,a,b,this.textContent);this.textContent=null==c?"":""+c}):0 in this?this[0].textContent:null},attr:function(a,b){var c;return"string"!=typeof a||1 in arguments?this.each(function(c){if(1===this.nodeType)if(e(a))for(w in a)r(this,w,a[w]);else r(this,a,q(this,b,c,this.getAttribute(a)))}):this.length&&1===this[0].nodeType?!(c=this[0].getAttribute(a))&&a in this[0]?this[0][a]:c:v},removeAttr:function(a){return this.each(function(){1===this.nodeType&&a.split(" ").forEach(function(a){r(this,a)},this)})},prop:function(a,b){return a=Y[a]||a,1 in arguments?this.each(function(c){this[a]=q(this,b,c,this[a])}):this[0]&&this[0][a]},data:function(a,b){var c="data-"+a.replace(M,"-$1").toLowerCase(),d=1 in arguments?this.attr(c,b):this.attr(c);return null!==d?t(d):v},val:function(a){return 0 in arguments?this.each(function(b){this.value=q(this,a,b,this.value)}):this[0]&&(this[0].multiple?x(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(a){if(a)return this.each(function(b){var c=x(this),d=q(this,a,b,c.offset()),e=c.offsetParent().offset(),f={top:d.top-e.top,left:d.left-e.left};"static"==c.css("position")&&(f.position="relative"),c.css(f)});if(!this.length)return null;var b=this[0].getBoundingClientRect();return{left:b.left+window.pageXOffset,top:b.top+window.pageYOffset,width:Math.round(b.width),height:Math.round(b.height)}},css:function(b,c){if(arguments.length<2){var d,e=this[0];if(!e)return;if(d=getComputedStyle(e,""),"string"==typeof b)return e.style[z(b)]||d.getPropertyValue(b);if(Z(b)){var f={};return x.each(b,function(a,b){f[b]=e.style[z(b)]||d.getPropertyValue(b)}),f}}var g="";if("string"==a(b))c||0===c?g=j(b)+":"+l(b,c):this.each(function(){this.style.removeProperty(j(b))});else for(w in b)b[w]||0===b[w]?g+=j(w)+":"+l(w,b[w])+";":this.each(function(){this.style.removeProperty(j(w))});return this.each(function(){this.style.cssText+=";"+g})},index:function(a){return a?this.indexOf(x(a)[0]):this.parent().children().indexOf(this[0])},hasClass:function(a){return a?B.some.call(this,function(a){return this.test(s(a))},k(a)):!1},addClass:function(a){return a?this.each(function(b){if("className"in this){y=[];var c=s(this),d=q(this,a,b,c);d.split(/\s+/g).forEach(function(a){x(this).hasClass(a)||y.push(a)},this),y.length&&s(this,c+(c?" ":"")+y.join(" "))}}):this},removeClass:function(a){return this.each(function(b){if("className"in this){if(a===v)return s(this,"");y=s(this),q(this,a,b,y).split(/\s+/g).forEach(function(a){y=y.replace(k(a)," ")}),s(this,y.trim())}})},toggleClass:function(a,b){return a?this.each(function(c){var d=x(this),e=q(this,a,c,s(this));e.split(/\s+/g).forEach(function(a){(b===v?!d.hasClass(a):b)?d.addClass(a):d.removeClass(a)})}):this},scrollTop:function(a){if(this.length){var b="scrollTop"in this[0];return a===v?b?this[0].scrollTop:this[0].pageYOffset:this.each(b?function(){this.scrollTop=a}:function(){this.scrollTo(this.scrollX,a)})}},scrollLeft:function(a){if(this.length){var b="scrollLeft"in this[0];return a===v?b?this[0].scrollLeft:this[0].pageXOffset:this.each(b?function(){this.scrollLeft=a}:function(){this.scrollTo(a,this.scrollY)})}},position:function(){if(this.length){var a=this[0],b=this.offsetParent(),c=this.offset(),d=L.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(x(a).css("margin-top"))||0,c.left-=parseFloat(x(a).css("margin-left"))||0,d.top+=parseFloat(x(b[0]).css("border-top-width"))||0,d.left+=parseFloat(x(b[0]).css("border-left-width"))||0,{top:c.top-d.top,left:c.left-d.left}}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||E.body;a&&!L.test(a.nodeName)&&"static"==x(a).css("position");)a=a.offsetParent;return a})}},x.fn.detach=x.fn.remove,["width","height"].forEach(function(a){var b=a.replace(/./,function(a){return a[0].toUpperCase()});x.fn[a]=function(e){var f,g=this[0];return e===v?c(g)?g["inner"+b]:d(g)?g.documentElement["scroll"+b]:(f=this.offset())&&f[a]:this.each(function(b){g=x(this),g.css(a,q(this,e,b,g[a]()))})}}),O.forEach(function(b,c){var d=c%2;x.fn[b]=function(){var b,e,f=x.map(arguments,function(c){return b=a(c),"object"==b||"array"==b||null==c?c:W.fragment(c)}),g=this.length>1;return f.length<1?this:this.each(function(a,b){e=d?b:b.parentNode,b=0==c?b.nextSibling:1==c?b.firstChild:2==c?b:null;var h=x.contains(E.documentElement,e);f.forEach(function(a){if(g)a=a.cloneNode(!0);else if(!e)return x(a).remove();e.insertBefore(a,b),h&&u(a,function(a){null==a.nodeName||"SCRIPT"!==a.nodeName.toUpperCase()||a.type&&"text/javascript"!==a.type||a.src||window.eval.call(window,a.innerHTML)})})})},x.fn[d?b+"To":"insert"+(c?"Before":"After")]=function(a){return x(a)[b](this),this}}),W.Z.prototype=x.fn,W.uniq=A,W.deserializeValue=t,x.zepto=W,x}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(a){function b(b){return b=a(b),!(!b.width()&&!b.height())&&"none"!==b.css("display")}function c(a,b){a=a.replace(/=#\]/g,'="#"]');var c,d,e=h.exec(a);if(e&&e[2]in g&&(c=g[e[2]],d=e[3],a=e[1],d)){var f=Number(d);d=isNaN(f)?d.replace(/^["']|["']$/g,""):f}return b(a,c,d)}var d=a.zepto,e=d.qsa,f=d.matches,g=a.expr[":"]={visible:function(){return b(this)?this:void 0},hidden:function(){return b(this)?void 0:this},selected:function(){return this.selected?this:void 0},checked:function(){return this.checked?this:void 0},parent:function(){return this.parentNode},first:function(a){return 0===a?this:void 0},last:function(a,b){return a===b.length-1?this:void 0},eq:function(a,b,c){return a===c?this:void 0},contains:function(b,c,d){return a(this).text().indexOf(d)>-1?this:void 0},has:function(a,b,c){return d.qsa(this,c).length?this:void 0}},h=new RegExp("(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*"),i=/^\s*>/,j="Zepto"+ +new Date;d.qsa=function(b,f){return c(f,function(c,g,h){try{var k;!c&&g?c="*":i.test(c)&&(k=a(b).addClass(j),c="."+j+" "+c);var l=e(b,c)}catch(m){throw console.error("error performing selector: %o",f),m}finally{k&&k.removeClass(j)}return g?d.uniq(a.map(l,function(a,b){return g.call(a,b,l,h)})):l})},d.matches=function(a,b){return c(b,function(b,c,d){return!(b&&!f(a,b)||c&&c.call(a,null,d)!==a)})}}(Zepto),function(a){a.fn.end=function(){return this.prevObject||a()},a.fn.andSelf=function(){return this.add(this.prevObject||a())},"filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings".split(",").forEach(function(b){var c=a.fn[b];a.fn[b]=function(){var a=c.apply(this,arguments);return a.prevObject=this,a}})}(Zepto),function(a){function b(b,d){var i=b[h],j=i&&e[i];if(void 0===d)return j||c(b);if(j){if(d in j)return j[d];var k=g(d);if(k in j)return j[k]}return f.call(a(b),d)}function c(b,c,f){var i=b[h]||(b[h]=++a.uuid),j=e[i]||(e[i]=d(b));return void 0!==c&&(j[g(c)]=f),j}function d(b){var c={};return a.each(b.attributes||i,function(b,d){0==d.name.indexOf("data-")&&(c[g(d.name.replace("data-",""))]=a.zepto.deserializeValue(d.value))}),c}var e={},f=a.fn.data,g=a.camelCase,h=a.expando="Zepto"+ +new Date,i=[];a.fn.data=function(d,e){return void 0===e?a.isPlainObject(d)?this.each(function(b,e){a.each(d,function(a,b){c(e,a,b)})}):0 in this?b(this[0],d):void 0:this.each(function(){c(this,d,e)})},a.fn.removeData=function(b){return"string"==typeof b&&(b=b.split(/\s+/)),this.each(function(){var c=this[h],d=c&&e[c];d&&a.each(b||d,function(a){delete d[b?g(this):a]})})},["remove","empty"].forEach(function(b){var c=a.fn[b];a.fn[b]=function(){var a=this.find("*");return"remove"===b&&(a=a.add(this)),a.removeData(),c.call(this)}})}(Zepto),function(a){function b(a){return a._zid||(a._zid=m++)}function c(a,c,f,g){if(c=d(c),c.ns)var h=e(c.ns);return(q[b(a)]||[]).filter(function(a){return!(!a||c.e&&a.e!=c.e||c.ns&&!h.test(a.ns)||f&&b(a.fn)!==b(f)||g&&a.sel!=g)})}function d(a){var b=(""+a).split(".");return{e:b[0],ns:b.slice(1).sort().join(" ")}}function e(a){return new RegExp("(?:^| )"+a.replace(" "," .* ?")+"(?: |$)")}function f(a,b){return a.del&&!s&&a.e in t||!!b}function g(a){return u[a]||s&&t[a]||a}function h(c,e,h,i,k,m,n){var o=b(c),p=q[o]||(q[o]=[]);e.split(/\s/).forEach(function(b){if("ready"==b)return a(document).ready(h);var e=d(b);e.fn=h,e.sel=k,e.e in u&&(h=function(b){var c=b.relatedTarget;return!c||c!==this&&!a.contains(this,c)?e.fn.apply(this,arguments):void 0}),e.del=m;var o=m||h;e.proxy=function(a){if(a=j(a),!a.isImmediatePropagationStopped()){a.data=i;var b=o.apply(c,a._args==l?[a]:[a].concat(a._args));return b===!1&&(a.preventDefault(),a.stopPropagation()),b}},e.i=p.length,p.push(e),"addEventListener"in c&&c.addEventListener(g(e.e),e.proxy,f(e,n))})}function i(a,d,e,h,i){var j=b(a);(d||"").split(/\s/).forEach(function(b){c(a,b,e,h).forEach(function(b){delete q[j][b.i],"removeEventListener"in a&&a.removeEventListener(g(b.e),b.proxy,f(b,i))})})}function j(b,c){return(c||!b.isDefaultPrevented)&&(c||(c=b),a.each(y,function(a,d){var e=c[a];b[a]=function(){return this[d]=v,e&&e.apply(c,arguments)},b[d]=w}),(c.defaultPrevented!==l?c.defaultPrevented:"returnValue"in c?c.returnValue===!1:c.getPreventDefault&&c.getPreventDefault())&&(b.isDefaultPrevented=v)),b}function k(a){var b,c={originalEvent:a};for(b in a)x.test(b)||a[b]===l||(c[b]=a[b]);return j(c,a)}var l,m=1,n=Array.prototype.slice,o=a.isFunction,p=function(a){return"string"==typeof a},q={},r={},s="onfocusin"in window,t={focus:"focusin",blur:"focusout"},u={mouseenter:"mouseover",mouseleave:"mouseout"};r.click=r.mousedown=r.mouseup=r.mousemove="MouseEvents",a.event={add:h,remove:i},a.proxy=function(c,d){var e=2 in arguments&&n.call(arguments,2);if(o(c)){var f=function(){return c.apply(d,e?e.concat(n.call(arguments)):arguments)};return f._zid=b(c),f}if(p(d))return e?(e.unshift(c[d],c),a.proxy.apply(null,e)):a.proxy(c[d],c);throw new TypeError("expected function")},a.fn.bind=function(a,b,c){return this.on(a,b,c)},a.fn.unbind=function(a,b){return this.off(a,b)},a.fn.one=function(a,b,c,d){return this.on(a,b,c,d,1)};var v=function(){return!0},w=function(){return!1},x=/^([A-Z]|returnValue$|layer[XY]$)/,y={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};a.fn.delegate=function(a,b,c){return this.on(b,a,c)},a.fn.undelegate=function(a,b,c){return this.off(b,a,c)},a.fn.live=function(b,c){return a(document.body).delegate(this.selector,b,c),this},a.fn.die=function(b,c){return a(document.body).undelegate(this.selector,b,c),this},a.fn.on=function(b,c,d,e,f){var g,j,m=this;return b&&!p(b)?(a.each(b,function(a,b){m.on(a,c,d,b,f)}),m):(p(c)||o(e)||e===!1||(e=d,d=c,c=l),(o(d)||d===!1)&&(e=d,d=l),e===!1&&(e=w),m.each(function(l,m){f&&(g=function(a){return i(m,a.type,e),e.apply(this,arguments)}),c&&(j=function(b){var d,f=a(b.target).closest(c,m).get(0);return f&&f!==m?(d=a.extend(k(b),{currentTarget:f,liveFired:m}),(g||e).apply(f,[d].concat(n.call(arguments,1)))):void 0}),h(m,b,e,d,c,j||g)}))},a.fn.off=function(b,c,d){var e=this;return b&&!p(b)?(a.each(b,function(a,b){e.off(a,c,b)}),e):(p(c)||o(d)||d===!1||(d=c,c=l),d===!1&&(d=w),e.each(function(){i(this,b,d,c)}))},a.fn.trigger=function(b,c){return b=p(b)||a.isPlainObject(b)?a.Event(b):j(b),b._args=c,this.each(function(){b.type in t&&"function"==typeof this[b.type]?this[b.type]():"dispatchEvent"in this?this.dispatchEvent(b):a(this).triggerHandler(b,c)})},a.fn.triggerHandler=function(b,d){var e,f;return this.each(function(g,h){e=k(p(b)?a.Event(b):b),e._args=d,e.target=h,a.each(c(h,b.type||b),function(a,b){return f=b.proxy(e),e.isImmediatePropagationStopped()?!1:void 0})}),f},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(b){a.fn[b]=function(a){return 0 in arguments?this.bind(b,a):this.trigger(b)}}),a.Event=function(a,b){p(a)||(b=a,a=b.type);var c=document.createEvent(r[a]||"Events"),d=!0;if(b)for(var e in b)"bubbles"==e?d=!!b[e]:c[e]=b[e];return c.initEvent(a,d,!0),j(c)}}(Zepto),window.Zepto=Zepto,"$"in window||(window.$=Zepto),"function"==typeof define&&define.amd&&define("jquery",[],function(){return Zepto});
\ No newline at end of file
var express = require('express'),
router = express.Router(),
orm = require('../lib/orm'),
flow = require('../lib/flow'),
utils = require('../lib/utils'),
oss = require('../lib/oss-node'),
Alipay = require('../lib/alipay/alipay'),
moment = require('moment'),
config = require('config'),
log = console.log.bind(console),
warn = console.warn.bind(console),
error = console.error.bind(console),
URL = require("url")
const entities = config.get('entities')
router.use('*', function (req, res, next) {
let keys = Object.keys(req.query)
if (keys.length > 0) {
log('####### REQUEST ######\n [', req.baseUrl, ' ] query: ', req.query)
}
keys = Object.keys(req.body)
if (keys.length > 0) {
log('####### REQUEST ######\n [', req.baseUrl, ' ] body: ', req.body)
}
next()
})
let Room = new Map()
router.ws('/ws', function (ws, req) {
log('ws connected: ', JSON.stringify(req.query));
Room.set(req.query.order_id, ws)
ws.on('message', function (msg) {
// 心跳
ws.send(msg.replace(/heart/, 'alive'))
});
ws.on('close', function () {
Room.delete(req.query.order_id)
log('ws close: ', req.query.order_id)
log('ws total: ', Room.size)
})
});
router.post('/auth', async (req, res) => {
try {
let body = req.body
if (!body.redirect) {
throw new Error('参数错误')
}
if (!body.app_id) {
return res.sendStatus(400).end()
}
await utils.test_order_id(body.order_id)
await orm.check_app_key(body.appKey)
let app_id = body.app_id
let row = {
app_id: app_id,
platform: 'alipay',
app_key: body.appKey,
order_id: body.order_id,
cert_no: body.cert_no,
cert_name: body.cert_name,
cert_phone: body.cert_phone,
redirect: body.redirect,
}
// 上传到oss
let ret = await orm.company_info(body.appKey)
log(ret)
let oss_data = protocol(body.app_id, ret[0].company, ret[0].name, ret[0].partya)
let oss_key = `protocol/${moment().format('YYYY-MM-DD')}/${body.order_id}`
await oss.upload(oss_key, oss_data)
delete body.cert_no
delete body.cert_name
delete body.cert_phone
delete body.app_id
delete body.system
let redirect_uri = encodeURIComponent(`${config.get('host').replace('http', 'https')}/zmop/result`)
let state = utils.to_base64(JSON.stringify(body))
let auth_url = `https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=${app_id}&scope=auth_zhima&redirect_uri=${redirect_uri}&state=${encodeURIComponent(state)}`
let qrcode = encodeURIComponent(auth_url)
let scheme = `alipayqr://platformapi/startapp?saId=10000007&qrcode=${qrcode}`
await orm.create_task(row)
log('scheme: ', scheme)
res.json({code: 0, auth_url: scheme, channel: 'APP'})
} catch (e) {
warn(`[${req.originalUrl}-warn]: `, e)
if (e.message == '无效的appKey') {
return res.json({code: -1, msg: '无效的appKey'})
}
if (/[a-zA-Z]+/.test(e.message)) {
return res.json({code: -1, msg: '系统错误, 请稍后再试'})
}
return res.json({code: -1, msg: e.message})
}
})
// http://localhost:10031/zmop/result?state=eyJvcmRlcl9pZCI6IjIwMTgwNTA0MTEzMDA3NTcxb1gxSUpjaHBkb1RxcWxVIiwiZXh0cmFzIjoie1widXNlcl9pZFwiOjMyMTQ1NjV9In0=&app_id=2018042460057138&source=alipay_wallet&userOutputs=auth_zhima&scope=&alipay_token=&error_scope=auth_zhima,ZMCSP.ALIPAY_NOT_PRIVATE_ACCOUNT&auth_code=e909c5e8616a48acab4030448da1OX64
router.get('/result', async (req, res) => {
try {
let result = {
success: 'true',
error_msg: '操作成功'
}
if (req.query.order_id) {
if (req.query.status == 'success') {
result.success = 'true'
} else {
result.success = 'fail'
result.error_msg = req.query.msg
}
return res.render('result.html', result)
}
if (!req.query.app_id || !req.query.state) {
return res.render('error.html', {error_message: '参数错误'})
}
let query = req.query
if (query.scope != 'auth_zhima') {
result.success = 'false'
result.error_msg = query.error_scope
if (query.error_scope.indexOf('ZMCSP.ALIPAY_NOT_REAL_NAME_CERTIFY')!= -1){
result.error_msg = '支付宝账号未完成实名认证'
}
}
let state = JSON.parse(utils.from_base64(query.state.replace(/ /g,'+')))
log('state: ', state)
let resp = await Alipay.access_token(query.app_id, query.auth_code)
log('resp: ', resp)
if (resp.code && resp.code != '10000') {
result.success = 'false'
result.error_msg = resp.msg
if (resp.sub_code == 'isv.code-invalid') {
result.error_msg = '无效的授权码'
}
}
//检测姓名是否匹配
if (result.success == 'true') {
let check = await flow.checkName(state.appKey, resp.user_id, state.order_id);
if (check.code !== 0) {
result.success = 'fail';
result.error_msg = '支付宝账号和姓名不匹配,请确认姓名是否正确';
}else{
let task = {
open_id: resp.user_id,
platform: 'alipay',
app_id: query.app_id,
access_token: resp.access_token
}
let data = await flow.save_score(task)
log('\n#### Save zm_score #### \n order_id: ', state.order_id, ' \n app_key: ', data)
}
}
await flow.notify_result(state, result.success, result.error_msg)
let row = {
success: result.success,
error_msg: result.error_msg,
access_token: resp.access_token,
open_id: resp.user_id,
}
await orm.update_task(row, state.order_id)
await orm.insert_openId(resp.user_id,resp.access_token,query.app_id,'alipay');
if (Room.has(state.order_id)) {
log('Webscoket send: ', state.order_id, JSON.stringify(result))
Room.get(state.order_id).send(JSON.stringify(result))
}
res.render('result.html', result)
} catch (e) {
error(`[/zmop/result-error]: `, e)
if (e.message == '无效的授权码') {
return res.render('result.html', {error_msg: '无效的授权码'})
}
return res.render('result.html', {error_msg: '系统错误, 请稍后再试'})
}
})
function protocol(app_id, company, name, us) {
log('######## PROTOCOL ########: ', app_id, company, name, us)
if (!us) {
us = '杭州惠风网络科技有限公司'
}
if (app_id == '2018051160085345' && us == '杭州惠风网络科技有限公司') {
us = ''
}
return `用户授权服务协议
【重要提示】:
为了保障您的合法权益,请您务必审慎阅读、充分理解本授权书之条款、承诺,特别是涉及被授权方(包括但不限于${us}${entities[app_id]}及相关合作方、关联方等,下同)责任的条款,或限制您权利的条款,或加粗条款
除非您已阅读、接受并自愿遵守本授权书所有的条款,否则您无权使用被授权方提供的查询服务。您的申请、使用或登录等行为,亦或点击、勾选“确认”、“同意”、“申请”或“查询”按钮,亦或填写资料申请服务等,即表明您对本授权书含义及法律后果的知悉和全面理解,并自愿签署并遵照执行。
【致被授权方】:
(本人拟向__${company}___(下简称“${name}”)申请其提供的服务(包括但不限于融资服务、借贷咨询、借贷方案推荐、助贷服务、分期服务、委托服务、代办服务等,下同),需查询本人的芝麻信用数据。现本人不可撤销的授权:1)授权被授权方收集、存储、使用本人提交或本人授权${name}提交的姓名、身份证号码、手机号码等个人资料;2)授权被授权方根据芝麻信用管理有限公司(下简称“芝麻信用公司”)的规则向芝麻信用公司发起登录、收集、查询等服务请求,代为查询、收集、存储芝麻信用公司反馈的本人芝麻信用数据,并授权被授权方传输给${name}用于存储、分析使用、评估本人情况;必要时授权${name}可同时向本人所申请服务之实际提供方反馈本人之个人信息及评估结果。本人知悉,本授权书包含了被授权方收集、使用、查询、存储和传输本人芝麻信用数据的条款,并接受被授权方及${name}的规则/评估体系/评估方法。
就上述授权,本人同时确认并承诺如下:
1. 本人知悉,向被授权方/${name}提供的本人之个人信息(包括但不限于姓名、手机号码、身份证号码、芝麻信用数据等,下同)属于本人重要的个人信息,本人同意并不可撤销地授权被授权方在保证本人信息安全的前提下,存储、使用本人之个人信息,并仅向本人授权的相关方提供,因被授权方提供该等服务所得收益归被授权方所有。除前述情况及因国家机关、生效判决等强制性要求而必须提供外,被授权方不应将本人之个人信息提供给任何未经本人授权的其他机构或平台。
2. 本人知悉,被授权方会采用行业通行安全技术标准保护本人之个人信息,以防止个人信息及数据丢失、被盗用或遭窜改,除非遇到不可抗力(包括但不限于黑客攻击、系统故障、软硬件故障、自然灾害、政策变动等)的影响。
3. 本授权委托书系本人做出的单方承诺,效力具有独立性,不因其他合同的任何条款无效而失效。
4. 以上授权期限为本人作出本授权承诺之日起至本授权委托书约定事项完成之日止。
5. 若本人与被授权方发生任何纠纷或争议,首先应友好协商解决;协商不成的,本人同意将纠纷或争议提交杭州仲裁委员会仲裁解决。本授权书的成立、生效、履行、解释及纠纷解决,适用中华人民共和国大陆地区法律(不包括冲突法)。
6. 本人已知悉本授权书所有内容(特别是加粗字体内容)的意义以及由此产生的法律后果,自愿作出上述授权,本授权书是本人真实的意思表示,本人同意承担由此带来的一切法律后果。
7. 本授权书自填写个人资料,或点击、勾选“确认”、“同意”、“申请”或“查询”等按钮之日起生效。
特此授权。
`
}
module.exports = router;
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>芝麻认证</title>
<meta charset="utf-8">
<meta http-equiv="pragma" content="no-cache">
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<style>
.pannel {
margin-top: 10px;
padding-bottom: 32px;
background-color: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, .04)
}
.pannel .wrapper {
padding: 35px 0 1px
}
.pannel .wrapper .icon {
width: 72px;
height: 72px;
display: block;
margin: 0 auto;
background-image: url('/zmop/static/icon_rzsb2.png');
background-size: 100%
}
.pannel .wrapper .title {
display: block;
color: #14b25a;
font-size: 18px;
text-align: center;
margin-top: 20px
}
.pannel .wrapper p {
margin: 0;
color: #a6a6a6;
font-size: 14px;
padding: 16px 12px 0;
line-height: 20px;
text-align: center;
word-break: break-all
}
.pannel .wrapper p .red {
color: #ea6363
}
.pannel .wrapper.failed .icon {
background-image: url('/zmop/static/icon_rzsb2.png')
}
.pannel .wrapper .failed .title {
color: #fc8c28
}
</style>
</head>
<body>
<section>
<div class="pannel">
<div class="wrapper">
<div class="failed">
<div class="icon"></div>
<span class="title">{{ error_message }}</span></div>
</div>
</div>
</section>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>芝麻认证</title>
<meta charset="utf-8"/>
<meta http-equiv="pragma" content="no-cache"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="viewport"
content="width=device-width, initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<script type="text/javascript" src="/zmop/js/zepto.js"></script>
<script type="text/javascript" src="/zmop/js/common.js"></script>
<script type="text/javascript" src="/zmop/js/asset.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
html {
background: white;
}
.container {
padding: 75px 28px 0;
}
input {
border: none;
outline: none;
height: 22px;
margin: 20px 0;
font-size: 16px;
border-bottom: 1px solid #C0C4CC;
}
input::-webkit-input-placeholder, textarea::-webkit-input-placeholder {
color: #8E9091;
}
input:-moz-placeholder, textarea:-moz-placeholder {
color: #8E9091;
}
input::-moz-placeholder, textarea::-moz-placeholder {
color: #8E9091;
}
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
color: #8E9091;
}
.input-group {
margin-left: 10px;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.btn {
padding-top: 50px;
font-size: 14px;
}
button {
height: 48px;
width: 100%;
border-radius: 4px;
border: none;
color: #FFFFFF;
background: #1195F7;
}
button[disabled] {
background: #8DC1F4;
}
input[placeholder] {
letter-spacing: 0;
opacity: 0.7;
}
.toast {
position: fixed;
top: 40px;
max-width: 80%;
border-radius: 10px;
text-align: center;
color: white;
background-color: rgba(0, 0, 0, 0.75);
font-size: 0;
display: inline-block;
left: 50%;
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-ms-transform: translateX(-50%);
transform: translateX(-50%);
z-index: 100;
}
.toast > * {
display: inline-block;
vertical-align: middle;
}
.toast span {
font-size: 14px;
padding: 10px 10px;
display: block;
height: auto;
word-wrap: break-word;
}
</style>
</head>
<body>
<div class="container">
<div class="input-group">
<input id="cert_no" name="身份证" type="text" placeholder="身份证" data-re="^([\dxX]{15,18})$">
<input id="cert_name" name="姓名" type="text" placeholder="姓名" data-re="[^\d\s]">
<input id="cert_phone" name="手机号" type="text" placeholder="手机号"
data-re="^(((13[0-9]{1})|(14[0-9]{1})|(17[0-9]{1})|(15[0-3]{1})|(15[4-9]{1})|(18[0-9]{1})|(199))+\d{8})$">
</div>
<div class="btn">
<button id="submit" disabled="disabled" onclick="submit()">进行授权</button>
</div>
</div>
<input id="query" hidden="hidden" value="{{ query }}">
<script>
function submit() {
var data = {cert_no: $('#cert_no').val(), cert_name: $('#cert_name').val(), cert_phone: $('#cert_phone').val()}
if (!valid_input(data)) {
return
}
var query = JSON.parse($('#query').val())
query.cert_no = data.cert_no
query.cert_name = data.cert_name
query.cert_phone = data.cert_phone
var url = '/zmop/auth'
if (query.channel == 'H5') {
url = '/zmop/auth?channel=H5'
}
doAjax({
url: url,
type: 'POST',
data: query,
success: function (resp) {
if (resp.code == 0) {
if (resp.channel == 'H5') {
window.location.href = resp.auth_url
} else if (resp.channel == 'APP') {
call_alipay(resp.auth_url)
}
} else {
$.toast(resp.msg)
}
},
error: function (err) {
$.toast('系统错误, 请稍后再试')
}
})
}
$('input').each(function (index, item) {
item.onkeyup = function () {
check_inputs()
};
item.onpaste = function (e) {
setTimeout(function () {
check_inputs()
}, 200)
}
});
function call_alipay(scheme) {
if ($('#callApp')) {
$('#callApp').remove()
}
var n = window.lib.env.os.name
if (n == 'Android') {
var ifa = document.createElement('iframe');
ifa.id = 'callApp';
ifa.style.display = 'none';
ifa.style.width = '0%';
ifa.style.height = '0%';
ifa.style.border = 'none';
ifa.style.margin = '0';
ifa.style.padding = '0';
ifa.src = scheme
document.body.appendChild(ifa);
//document.body.removeChild(ifa);
ifa = null
}
if (n == 'iPhone' || n == 'iPad') {
var a = document.createElement('a');
a.setAttribute('href', scheme);
a.id = 'callApp';
a.style.display = 'none';
document.body.appendChild(a);
var e = document.createEvent('HTMLEvents');
e.initEvent('click', false, false);
a.dispatchEvent(e);
}
document.getElementById('callApp').click()
}
function check_inputs() {
var inputs = $('input')
var ready = true;
inputs.each(function (index, item) {
if (item.value == '' || !item.value) {
ready = false
}
});
if (ready) {
$('#submit').removeAttr('disabled')
} else {
$('#submit').attr('disabled', 'disabled')
}
}
function valid_input(data) {
var rt = true;
$.each(data, function (key) {
if (key == 'cert_no') {
if (!IdentityCodeValid(data[key])) {
$.toast('无效的身份证号');
rt = false
return rt
}
}
var index = 'input[id="' + key + '"]';
if ($(index).attr('data-re')) {
var re = new RegExp($(index).attr('data-re'))
if (!re.test(data[key])) {
$.toast($(index).attr('name') + '格式不对');
rt = false;
return rt
}
}
});
return rt
}
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>芝麻认证</title>
<meta charset="utf-8"/>
<meta http-equiv="pragma" content="no-cache"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="viewport"
content="width=device-width, initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<style>
* {
margin: 0;
padding: 0;
font-size: 14px;
text-align: center;
}
.container {
padding: 100px 28px 0;
}
img {
padding-bottom: 20px;
height: 66px;
}
.success {
color: #1195F7;
}
.fail {
color: #fc8c28;
}
button {
margin-top: 150px;
height: 60px;
width: 215px;
border: none;
color: #9B9B9B;
background: #F8F9FE;
}
</style>
</head>
<body>
<div class="container">
{% if success == 'true' %}
<div class="success">
<img src="/zmop/static/success.png">
<p>操作成功,请返回原app</p>
</div>
{% else %}
<div class="fail">
<img src="/zmop/static/fail.png">
<p>{{error_msg}}</p>
</div>
{% endif %}
<!--<div class="btn">-->
<!--<button type="submit" onclick="window.close()">关闭页面</button>-->
<!--</div>-->
</div>
</body>
</html>
\ No newline at end of file
const express = require('express');
const expressWs = require('express-ws');
const http = require('http');
const path = require('path');
const config = require('config');
const nunjucks = require('nunjucks');
// middlewares
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const timeInterval = config.get('timeInterval');
const scheduleproc = require('./lib/scheduleproc');
var app = express();
const httpPort = config.get('httpPort')
var Server = http.createServer(app);
Server.listen(httpPort, function () {
console.log((new Date()) + ' server start http server and listen on: ' + JSON.stringify(Server.address()));
});
expressWs(app, Server);
var index = require('./routers/index');
nunjucks.configure(path.join(__dirname, 'views'), { // 设置模板文件的目录,为views
autoescape: true,
express: app
});
app.set('view engine', 'html');
//X-Frame-Options: Allow-From http://www.growingio.com
app.use('*', function (req, res, next) {
res.setHeader('X-Frame-Options', 'ALLOW-FROM https://www.growingio.com');
next();
})
// 给app配置bodyParser中间件
// 通过如下配置再路由种处理request时,可以直接获得post请求的body部分
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json({limit: '1000kb'}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// 注册路由
app.use('/zmop', index);
// 定时清理日志任务
scheduleproc.BeginCleanLogWork(timeInterval);
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment