diff --git a/cpufreq/build.sh b/cpufreq/build.sh new file mode 100755 index 0000000..cbcfcc0 --- /dev/null +++ b/cpufreq/build.sh @@ -0,0 +1,30 @@ +#!/bin/sh + + +MODULE=cpufreq +VERSION=1.0 +TITLE=CPU频率设置 +DESCRIPTION='Intel CPU频率设置' +HOME_URL=Module_cpufreq.asp + +# Check and include base +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +if [ "$MODULE" == "" ]; then + echo "module not found" + exit 1 +fi + +if [ -f "$DIR/$MODULE/$MODULE/install.sh" ]; then + echo "install script not found" + exit 2 +fi + +# now include build_base.sh +. $DIR/../softcenter/build_base.sh + +# change to module directory +cd $DIR + +# do something here + +do_build_result diff --git a/cpufreq/config.json.js b/cpufreq/config.json.js new file mode 100644 index 0000000..4c1670a --- /dev/null +++ b/cpufreq/config.json.js @@ -0,0 +1,8 @@ +{ +"version":"1.0", +"md5":"e9ddf7d75daa25dc388ff5ef62407c6b", +"home_url":"Module_cpufreq.asp", +"title":"CPU频率设置", +"description":"Intel CPU频率设置", +"build_date":"2019-01-30_19:23:59" +} diff --git a/cpufreq/cpufreq.tar.gz b/cpufreq/cpufreq.tar.gz new file mode 100644 index 0000000..1ffa0c5 Binary files /dev/null and b/cpufreq/cpufreq.tar.gz differ diff --git a/cpufreq/cpufreq/bin/cpufreq-info b/cpufreq/cpufreq/bin/cpufreq-info new file mode 100755 index 0000000..6a65245 Binary files /dev/null and b/cpufreq/cpufreq/bin/cpufreq-info differ diff --git a/cpufreq/cpufreq/bin/cpufreq-set b/cpufreq/cpufreq/bin/cpufreq-set new file mode 100755 index 0000000..436c1eb Binary files /dev/null and b/cpufreq/cpufreq/bin/cpufreq-set differ diff --git a/cpufreq/cpufreq/install.sh b/cpufreq/cpufreq/install.sh new file mode 100644 index 0000000..1f8cf99 --- /dev/null +++ b/cpufreq/cpufreq/install.sh @@ -0,0 +1,25 @@ +#! /bin/sh + +export KSROOT=/jffs/softcenter +source $KSROOT/scripts/base.sh +find /jffs/softcenter/init.d/ -name "*cpufreq*" | xargs rm -rf +mkdir -p /jffs/softcenter/lib +cp -rf /tmp/cpufreq/bin/* /jffs/softcenter/bin/ +cp -rf /tmp/cpufreq/scripts/* /jffs/softcenter/scripts/ +cp -rf /tmp/cpufreq/webs/* /jffs/softcenter/webs/ +cp -rf /tmp/cpufreq/lib/* /jffs/softcenter/lib/ +cp -rf /tmp/cpufreq/res/* /jffs/softcenter/res/ +cp -rf /tmp/cpufreq/uninstall.sh /jffs/softcenter/scripts/uninstall_cpufreq.sh + +rm -fr /tmp/cpufreq* >/dev/null 2>&1 +chmod +x /jffs/softcenter/scripts/cpufreq*.sh +chmod +x /jffs/softcenter/scripts/uninstall_cpufreq.sh +[ ! -L "/jffs/softcenter/init.d/S99cpufreq.sh" ] && cp -rf /jffs/softcenter/scripts/cpufreq_config.sh /jffs/softcenter/init.d/S99cpufreq.sh + +dbus set cpufreq_version="1.0" +dbus set softcenter_module_cpufreq_version="1.0" +dbus set softcenter_module_cpufreq_description="Intel CPU频率设置" +dbus set softcenter_module_cpufreq_install=1 +dbus set softcenter_module_cpufreq_name=cpufreq +dbus set softcenter_module_cpufreq_title="CPU频率设置" + diff --git a/cpufreq/cpufreq/lib/libcpufreq.so b/cpufreq/cpufreq/lib/libcpufreq.so new file mode 100755 index 0000000..89e85fe Binary files /dev/null and b/cpufreq/cpufreq/lib/libcpufreq.so differ diff --git a/cpufreq/cpufreq/lib/libcpufreq.so.0 b/cpufreq/cpufreq/lib/libcpufreq.so.0 new file mode 100755 index 0000000..89e85fe Binary files /dev/null and b/cpufreq/cpufreq/lib/libcpufreq.so.0 differ diff --git a/cpufreq/cpufreq/lib/libcpufreq.so.0.0.0 b/cpufreq/cpufreq/lib/libcpufreq.so.0.0.0 new file mode 100755 index 0000000..89e85fe Binary files /dev/null and b/cpufreq/cpufreq/lib/libcpufreq.so.0.0.0 differ diff --git a/cpufreq/cpufreq/res/cpufreq_log.htm b/cpufreq/cpufreq/res/cpufreq_log.htm new file mode 100644 index 0000000..fd9be63 --- /dev/null +++ b/cpufreq/cpufreq/res/cpufreq_log.htm @@ -0,0 +1 @@ +<% nvram_dump("cpufreq.log",""); %> diff --git a/cpufreq/cpufreq/res/icon-cpufreq.png b/cpufreq/cpufreq/res/icon-cpufreq.png new file mode 100644 index 0000000..d31cb74 Binary files /dev/null and b/cpufreq/cpufreq/res/icon-cpufreq.png differ diff --git a/cpufreq/cpufreq/scripts/cpufreq_config.sh b/cpufreq/cpufreq/scripts/cpufreq_config.sh new file mode 100644 index 0000000..8e96338 --- /dev/null +++ b/cpufreq/cpufreq/scripts/cpufreq_config.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +eval `dbus export cpufreq` +start(){ +if [ "-n $cpufreq_set" ];then + [ "-z `echo ${LD_LIBRARY_PATH} |grep jffs`" ] && export LD_LIBRARY_PATH=/jffs/softcenter/lib:/lib:/usr/lib:/opt/lantiq/usr/lib:/opt/lantiq/usr/sbin/:/tmp/wireless/lantiq/usr/lib/:${LD_LIBRARY_PATH} + [ "$cpufreq_set" -gt "$cpufreq_max" ] && echo "$(date "+%F %T"): 频率设置错误" >> /tmp/cpufreq.log && exit 1 + [ "$cpufreq_set" -lt 150 ] && echo "$(date "+%F %T"): 频率设置错误" >> /tmp/cpufreq.log && exit 1 + if [ "$cpufreq_set" -eq 667 ] ;then + /jffs/softcenter/bin/cpufreq-set -f 666666 + else + /jffs/softcenter/bin/cpufreq-set -f ${cpufreq_set}MHz + fi + echo "$(date "+%F %T"): 已设置频率:${cpufreq_set}MHz" >> /tmp/cpufreq.log + /jffs/softcenter/scripts/cpufreq_status.sh +fi +} + +stop(){ +[ "-e /jffs/softcenter/init.d/S99cpufreq.sh" ] && rm -rf /jffs/softcenter/init.d/S99cpufreq.sh +} +restart() { + if [ "`dbus get cpufreq_enable`" == "1" ];then + [ "! -e /jffs/softcenter/init.d/S99cpufreq.sh" ] && cp -r /jffs/softcenter/scripts/cpufreq_config.sh /jffs/softcenter/init.d/S99cpufreq.sh + echo "$(date "+%F %T"): 已开启自动频率设置" >> /tmp/cpufreq.log + start + else + echo "$(date "+%F %T"): 插件未启用,已关闭自动频率设置" >> /tmp/cpufreq.log + stop + fi +} + +restart + diff --git a/cpufreq/cpufreq/scripts/cpufreq_status.sh b/cpufreq/cpufreq/scripts/cpufreq_status.sh new file mode 100644 index 0000000..730c0b4 --- /dev/null +++ b/cpufreq/cpufreq/scripts/cpufreq_status.sh @@ -0,0 +1,11 @@ +#!/bin/sh +[ "-z `echo ${LD_LIBRARY_PATH} |grep jffs`" ] && export LD_LIBRARY_PATH=/jffs/softcenter/lib:/lib:/usr/lib:/opt/lantiq/usr/lib:/opt/lantiq/usr/sbin/:/tmp/wireless/lantiq/usr/lib/:${LD_LIBRARY_PATH} +/jffs/softcenter/bin/cpufreq-info -c 0 > /tmp/cpufreq-info 2>&1 + +freq_cur=$(cat /tmp/cpufreq-info |grep 'current CPU' |awk '{printf $5}') +freq_max=$(cat /tmp/cpufreq-info |grep 'hardware limits' |awk '{printf $6}') + +dbus set cpufreq_cur=$freq_cur +dbus set cpufreq_max=$freq_max + + diff --git a/cpufreq/cpufreq/uninstall.sh b/cpufreq/cpufreq/uninstall.sh new file mode 100644 index 0000000..5948076 --- /dev/null +++ b/cpufreq/cpufreq/uninstall.sh @@ -0,0 +1,16 @@ +#!/bin/sh +eval `dbus export cpufreq_` +source /jffs/softcenter/scripts/base.sh + +sh /jffs/softcenter/scripts/cpufreq_config.sh stop + +find /jffs/softcenter/init.d/ -name "*cpufreq*" | xargs rm -rf +rm -rf /jffs/softcenter/bin/cpufreq-info +rm -rf /jffs/softcenter/bin/cpufreq-set +rm -rf /jffs/softcenter/res/icon-cpufreq.png +rm -rf /jffs/softcenter/scripts/cpufreq*.sh +rm -rf /jffs/softcenter/webs/Module_cpufreq.asp +rm -rf /jffs/softcenter/lib/libcpufreq.so +rm -rf /jffs/softcenter/lib/libcpufreq.so.0 +rm -rf /jffs/softcenter/lib/libcpufreq.so.0.0.0 +rm -f /jffs/softcenter/scripts/uninstall_cpufreq.sh diff --git a/cpufreq/cpufreq/webs/Module_cpufreq.asp b/cpufreq/cpufreq/webs/Module_cpufreq.asp new file mode 100644 index 0000000..13bfc7e --- /dev/null +++ b/cpufreq/cpufreq/webs/Module_cpufreq.asp @@ -0,0 +1,320 @@ + + + + + + + + + +CPU频率设置 + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + +"/> +"/> +"/> +"/> +"/> + + + + + + +
  + + + + + + + + +
+
+ + + + +
+
 
+
CPU频率设置
+
+
+
Intel CPU频率设置
请合理设置频率,过低会导致运行异常缓慢,频率越低温度越低
+
+ + + + + + + + + + + + + + +
设置
系统当前频率 + <% dbus_get_def("cpufreq_cur", "未知"); %>MHz +
+ + +
+ +
+
+
+
+ + + + + + + + + +
运行信息
+
+ +
+
+
+
+ +
+
+ Shell&Web by: paldier +
+
+
+
+
+ + + diff --git a/cpufreq/version b/cpufreq/version new file mode 100644 index 0000000..3dd932d --- /dev/null +++ b/cpufreq/version @@ -0,0 +1,2 @@ +1.0 +e9ddf7d75daa25dc388ff5ef62407c6b diff --git a/softcenter/app.json.js b/softcenter/app.json.js index d65c878..a4479cd 100644 --- a/softcenter/app.json.js +++ b/softcenter/app.json.js @@ -129,6 +129,16 @@ "tar_url": "ddnspod/ddnspod.tar.gz", "title": "DDnspod", "version": "0.1.6" + }, + { + "build_date": "2019-01-30_19:23:59", + "description": "Intel CPU频率设置", + "home_url": "Module_cpufreq.asp", + "md5": "e9ddf7d75daa25dc388ff5ef62407c6b", + "name": "cpufreq", + "tar_url": "cpufreq/cpufreq.tar.gz", + "title": "CPU频率设置", + "version": "1.0" } ], "home_url": "https://raw.githubusercontent.com/paldier/softcenter/master", diff --git a/softcenter/build.sh b/softcenter/build.sh index a9c45f5..5f6af3e 100755 --- a/softcenter/build.sh +++ b/softcenter/build.sh @@ -1,5 +1,5 @@ #! /bin/sh -VERSION=1.1.6 +VERSION=1.1.7 cat version rm -f softcenter.tar.gz diff --git a/softcenter/softcenter/scripts/base.sh b/softcenter/softcenter/scripts/base.sh index 32d499e..77c7172 100644 --- a/softcenter/softcenter/scripts/base.sh +++ b/softcenter/softcenter/scripts/base.sh @@ -73,5 +73,6 @@ kservice_reload() { } export PATH=$PATH:/jffs/softcenter/bin:/jffs/softcenter/scripts:/bin:/usr/bin:/sbin:/usr/sbin:/home/admin:/opt/sbin:/opt/bin:/opt/usr/sbin:/opt/usr/bin +export LD_LIBRARY_PATH=/jffs/softcenter/lib:/lib:/usr/lib:/opt/lantiq/usr/lib:/opt/lantiq/usr/sbin/:/tmp/wireless/lantiq/usr/lib/:${LD_LIBRARY_PATH} #logger "Leaving ${0##*/}." diff --git a/v2ray/config.json.js b/v2ray/config.json.js index 4b75761..92d9643 100644 --- a/v2ray/config.json.js +++ b/v2ray/config.json.js @@ -1,8 +1,8 @@ { "version":"4.13.0", -"md5":"4ff156ed5cfd6183ac19ebca1193ba16", +"md5":"9ef8deadd029b47b4bf59a2c7f9b8a96", "home_url":"Module_v2ray.asp", "title":"v2ray", "description":"v2ray", -"build_date":"2019-01-24_01:15:57" +"build_date":"2019-01-29_20:02:27" } diff --git a/v2ray/v2ray.tar.gz b/v2ray/v2ray.tar.gz index 36881ca..3ab165f 100644 Binary files a/v2ray/v2ray.tar.gz and b/v2ray/v2ray.tar.gz differ diff --git a/v2ray/v2ray/bin/dns2socks b/v2ray/v2ray/bin/dns2socks new file mode 100755 index 0000000..ae40607 Binary files /dev/null and b/v2ray/v2ray/bin/dns2socks differ diff --git a/v2ray/v2ray/bin/jq b/v2ray/v2ray/bin/jq new file mode 100755 index 0000000..2042dff Binary files /dev/null and b/v2ray/v2ray/bin/jq differ diff --git a/v2ray/v2ray/install.sh b/v2ray/v2ray/install.sh index b05d51a..bdc469a 100755 --- a/v2ray/v2ray/install.sh +++ b/v2ray/v2ray/install.sh @@ -6,11 +6,11 @@ cp -rf /tmp/v2ray/geosite.dat /jffs/softcenter/bin/ cp -rf /tmp/v2ray/geoip.dat /jffs/softcenter/bin/ cp -rf /tmp/v2ray/webs/Module_v2ray.asp /jffs/softcenter/webs/ cp -rf /tmp/v2ray/res/* /jffs/softcenter/res/ -cp -rf /tmp/v2ray/scripts/softcenter_v2ray.sh /jffs/softcenter/scripts/ +cp -rf /tmp/v2ray/scripts/*.sh /jffs/softcenter/scripts/ cd / rm -rf /tmp/v2ray* >/dev/null 2>&1 chmod 755 /jffs/softcenter/bin/v2* -chmod 755 /jffs/softcenter/scripts/softcenter_v2ray.sh +chmod 755 /jffs/softcenter/scripts/*.sh diff --git a/v2ray/v2ray/res/ss-menu.js b/v2ray/v2ray/res/ss-menu.js new file mode 100755 index 0000000..3bdd721 --- /dev/null +++ b/v2ray/v2ray/res/ss-menu.js @@ -0,0 +1,3168 @@ +function E(e) { + return (typeof(e) == 'string') ? document.getElementById(e) : e; +} +var retArea = E('log_content1'); +var autoTextarea = function(elem, extra, maxHeight) { + extra = extra || 0; + var isFirefox = !!document.getBoxObjectFor || 'mozInnerScreenX' in window, + isOpera = !!window.opera && !!window.opera.toString().indexOf('Opera'), + addEvent = function(type, callback) { + elem.addEventListener ? + elem.addEventListener(type, callback, false) : + elem.attachEvent('on' + type, callback); + }, + getStyle = elem.currentStyle ? function(name) { + var val = elem.currentStyle[name]; + + if (name === 'height' && val.search(/px/i) !== 1) { + var rect = elem.getBoundingClientRect(); + return rect.bottom - rect.top - + parseFloat(getStyle('paddingTop')) - + parseFloat(getStyle('paddingBottom')) + 'px'; + }; + + return val; + } : function(name) { + return getComputedStyle(elem, null)[name]; + }, + minHeight = parseFloat(getStyle('height')); + + elem.style.resize = 'none'; + + var change = function() { + var scrollTop, height, + padding = 0, + style = elem.style; + + if (elem._length === elem.value.length) return; + elem._length = elem.value.length; + + if (!isFirefox && !isOpera) { + padding = parseInt(getStyle('paddingTop')) + parseInt(getStyle('paddingBottom')); + }; + scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + + elem.style.height = minHeight + 'px'; + if (elem.scrollHeight > minHeight) { + if (maxHeight && elem.scrollHeight > maxHeight) { + height = maxHeight - padding; + style.overflowY = 'auto'; + } else { + height = elem.scrollHeight - padding; + style.overflowY = 'hidden'; + }; + style.height = height + extra + 'px'; + scrollTop += parseInt(style.height) - elem.currHeight; + document.body.scrollTop = scrollTop; + document.documentElement.scrollTop = scrollTop; + elem.currHeight = parseInt(style.height); + }; + }; + addEvent('propertychange', change); + addEvent('input', change); + addEvent('focus', change); + change(); +}; + +function browser_compatibility1(){ + //fw versiom + var _fw = "<% nvram_get("extendno"); %>"; + fw_version=parseFloat(_fw.split("X")[1]); + // chrome + var isChrome = navigator.userAgent.search("Chrome") > -1; + if(isChrome){ + var major = navigator.userAgent.match("Chrome\/([0-9]*)\."); //check for major version + var isChrome56 = (parseInt(major[1], 10) >= 56); + } else { + var isChrome56 = false; + } + if((isChrome56) && document.getElementById("FormTitle") && fw_version < 7.5){ + document.getElementById("FormTitle").className = "FormTitle_chrome56"; + }else if((isChrome56) && document.getElementById("FormTitle") && fw_version >= 7.5){ + document.getElementById("FormTitle").className = "FormTitle"; + } + //firefox + var isFirefox = navigator.userAgent.search("Firefox") > -1; + if((isFirefox) && document.getElementById("FormTitle") && fw_version < 7.5){ + document.getElementById("FormTitle").className = "FormTitle_firefox"; + if(current_url.indexOf("Main_Ss") == 0){ + document.getElementById("FormTitle").style.marginTop = "-100px" + } + + }else if((isFirefox) && document.getElementById("FormTitle") && fw_version >= 7.5){ + document.getElementById("FormTitle").className = "FormTitle_firefox"; + if(current_url.indexOf("Main_Ss") == 0){ + document.getElementById("FormTitle").style.marginTop = "0px" + E("FormTitle").style.height = "975px"; + } + } +} + +function menu_hook(title, tab) { + browser_compatibility1(); + tabtitle[tabtitle.length - 1] = new Array("", "科学上网设置", "负载均衡设置", "Socks5设置"); + tablink[tablink.length - 1] = new Array("", "Main_Ss_Content.asp", "Main_Ss_LoadBlance.asp", "Main_SsLocal_Content.asp"); +} + +function done_validating(action) { + return true; +} + +var Base64; +if (typeof btoa == "Function") { + Base64 = { + encode: function(e) { + return btoa(e); + }, + decode: function(e) { + return atob(e); + } + }; +} else { + Base64 = { + _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + encode: function(e) { + var t = ""; + var n, r, i, s, o, u, a; + var f = 0; + e = Base64._utf8_encode(e); + while (f < e.length) { + n = e.charCodeAt(f++); + r = e.charCodeAt(f++); + i = e.charCodeAt(f++); + s = n >> 2; + o = (n & 3) << 4 | r >> 4; + u = (r & 15) << 2 | i >> 6; + a = i & 63; + if (isNaN(r)) { + u = a = 64 + } else if (isNaN(i)) { + a = 64 + } + t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a) + } + return t + }, + decode: function(e) { + var t = ""; + var n, r, i; + var s, o, u, a; + var f = 0; + e = e.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + while (f < e.length) { + s = this._keyStr.indexOf(e.charAt(f++)); + o = this._keyStr.indexOf(e.charAt(f++)); + u = this._keyStr.indexOf(e.charAt(f++)); + a = this._keyStr.indexOf(e.charAt(f++)); + n = s << 2 | o >> 4; + r = (o & 15) << 4 | u >> 2; + i = (u & 3) << 6 | a; + t = t + String.fromCharCode(n); + if (u != 64) { + t = t + String.fromCharCode(r) + } + if (a != 64) { + t = t + String.fromCharCode(i) + } + } + t = Base64._utf8_decode(t); + return t + }, + _utf8_encode: function(e) { + e = e.replace(/\r\n/g, "\n"); + var t = ""; + for (var n = 0; n < e.length; n++) { + var r = e.charCodeAt(n); + if (r < 128) { + t += String.fromCharCode(r) + } else if (r > 127 && r < 2048) { + t += String.fromCharCode(r >> 6 | 192); + t += String.fromCharCode(r & 63 | 128) + } else { + t += String.fromCharCode(r >> 12 | 224); + t += String.fromCharCode(r >> 6 & 63 | 128); + t += String.fromCharCode(r & 63 | 128) + } + } + return t + }, + _utf8_decode: function(e) { + var t = ""; + var n = 0; + var r = c1 = c2 = 0; + while (n < e.length) { + r = e.charCodeAt(n); + if (r < 128) { + t += String.fromCharCode(r); + n++ + } else if (r > 191 && r < 224) { + c2 = e.charCodeAt(n + 1); + t += String.fromCharCode((r & 31) << 6 | c2 & 63); + n += 2 + } else { + c2 = e.charCodeAt(n + 1); + c3 = e.charCodeAt(n + 2); + t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63); + n += 3 + } + } + return t + } + } +} + +String.prototype.replaceAll = function(s1, s2) {   + return this.replace(new RegExp(s1, "gm"), s2); +} + +function showSSLoadingBar(seconds) { + if (window.scrollTo) + window.scrollTo(0, 0); + + disableCheckChangedStatus(); + + htmlbodyforIE = document.getElementsByTagName("html"); //this both for IE&FF, use "html" but not "body" because + htmlbodyforIE[0].style.overflow = "hidden"; //hidden the Y-scrollbar for preventing from user scroll it. + + winW_H(); + + var blockmarginTop; + var blockmarginLeft; + if (window.innerWidth) + winWidth = window.innerWidth; + else if ((document.body) && (document.body.clientWidth)) + winWidth = document.body.clientWidth; + + if (window.innerHeight) + winHeight = window.innerHeight; + else if ((document.body) && (document.body.clientHeight)) + winHeight = document.body.clientHeight; + + if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientWidth) { + winHeight = document.documentElement.clientHeight; + winWidth = document.documentElement.clientWidth; + } + + if (winWidth > 1050) { + + winPadding = (winWidth - 1050) / 2; + winWidth = 1105; + blockmarginLeft = (winWidth * 0.3) + winPadding - 150; + } else if (winWidth <= 1050) { + blockmarginLeft = (winWidth) * 0.3 + document.body.scrollLeft - 160; + + } + + if (winHeight > 660) + winHeight = 660; + + blockmarginTop = winHeight * 0.3 - 140 + + document.getElementById("loadingBarBlock").style.marginTop = blockmarginTop + "px"; + document.getElementById("loadingBarBlock").style.marginLeft = blockmarginLeft + "px"; + document.getElementById("loadingBarBlock").style.width = 770 + "px"; + document.getElementById("LoadingBar").style.width = winW + "px"; + document.getElementById("LoadingBar").style.height = winH + "px"; + + loadingSeconds = seconds; + progress = 100 / loadingSeconds; + y = 0; + LoadingSSProgress(seconds); +} + +function LoadingSSProgress(seconds) { + action = db_ss["ss_basic_action"]; + document.getElementById("LoadingBar").style.visibility = "visible"; + if (action == 0) { + document.getElementById("loading_block3").innerHTML = "科学上网功能关闭中 ..." + $("#loading_block2").html("
  • 插件工作有问题?请到GITHUB提交issue...
  • "); + } else if (action == 1) { + document.getElementById("loading_block3").innerHTML = "gfwlist模式启用中 ..." + $("#loading_block2").html("
  • 此期间请勿访问屏蔽网址,以免污染DNS进入缓存
  • 尝试不同的DNS解析方案,可以达到最佳的效果哦...
  • 请等待日志显示完毕,并出现自动关闭按钮!
  • 在此期间请不要刷新本页面,不然可能导致问题!
  • "); + } else if (action == 2) { + document.getElementById("loading_block3").innerHTML = "大陆白名单模式启用中 ..." + $("#loading_block2").html("
  • 此期间请勿访问屏蔽网址,以免污染DNS进入缓存
  • 请等待日志显示完毕,并出现自动关闭按钮!
  • 在此期间请不要刷新本页面,不然可能导致问题!
  • "); + } else if (action == 3) { + document.getElementById("loading_block3").innerHTML = "游戏模式启用中 ..." + $("#loading_block2").html("
  • 此期间请勿访问屏蔽网址,以免污染DNS进入缓存
  • 为确保游戏工作,请确保你的SS账号支持UDP转发...
  • 请等待日志显示完毕,并出现自动关闭按钮!
  • 在此期间请不要刷新本页面,不然可能导致问题!
  • "); + } else if (action == 5) { + document.getElementById("loading_block3").innerHTML = "全局模式启用中 ..." + $("#loading_block2").html("
  • 此期间请勿访问屏蔽网址,以免污染DNS进入缓存
  • 此模式非科学上网方式,会影响国内网页速度...
  • 注意:全局模式并非VPN,只支持TCP流量转发...
  • 请等待日志显示完毕,并出现自动关闭按钮!
  • 在此期间请不要刷新本页面,不然可能导致问题!
  • "); + } else if (action == 6) { + document.getElementById("loading_block3").innerHTML = "回国模式启用中 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,正在应用配置...
  • "); + } else if (action == 7) { + document.getElementById("loading_block3").innerHTML = "科学上网插件升级 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,等待脚本运行完毕后再刷新!
  • 升级服务会自动检测最新版本并下载升级...
  • "); + } else if (action == 8) { + document.getElementById("loading_block3").innerHTML = "科学上网规则更新 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,等待脚本运行完毕后再刷新!
  • 正在自动检测github上的更新...
  • "); + } else if (action == 9) { + document.getElementById("loading_block3").innerHTML = "恢复科学上网配置 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,配置恢复后需要重新提交!
  • 恢复配置中...
  • "); + } else if (action == 10) { + document.getElementById("loading_block3").innerHTML = "清空科学上网配置 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,正在清空科学上网配置...
  • "); + } else if (action == 11) { + document.getElementById("loading_block3").innerHTML = "插件打包中 ..." + $("#loading_block2").html("
  • 打包时间较长,请稍等...
  • 打包的插件可以用于离线安装...
  • "); + } else if (action == 12) { + document.getElementById("loading_block3").innerHTML = "应用负载均衡设置 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,应用负载均衡设置 ...
  • "); + } else if (action == 13) { + document.getElementById("loading_block3").innerHTML = "SSR节点订阅 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,正在订阅中 ...
  • "); + } else if (action == 14) { + document.getElementById("loading_block3").innerHTML = "socks5代理设置 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,应用中 ...
  • "); + } else if (action == 15) { + document.getElementById("loading_block3").innerHTML = "V2Ray 二进制文件更新 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,更新中 ...
  • "); + } else if (action == 16) { + document.getElementById("loading_block3").innerHTML = "设置插件重启定时任务 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,应用中 ...
  • "); + } else if (action == 17) { + document.getElementById("loading_block3").innerHTML = "设置插件触发重启定时任务 ..." + $("#loading_block2").html("
  • 请勿刷新本页面,应用中 ...
  • "); + } +} + +function hideSSLoadingBar() { + x = -1; + E("LoadingBar").style.visibility = "hidden"; + checkss = 0; + refreshpage(); +} + +function openssHint(itemNum) { + statusmenu = ""; + width = "350px"; + + if (itemNum == 10) { + statusmenu = "如果发现开关不能开启,那么请检查
    系统管理 -- 系统设置页面内Enable JFFS custom scripts and configs是否开启。"; + _caption = "服务器说明"; + } + if (itemNum == 0) { + width = "750px"; + bgcolor = "#CC0066", + statusmenu = "
  • 通过对路由器内ss访问(https://www.google.com.tw/)状态的检测,返回状态信息。状态检测默认每10秒进行一次,可以通过附加设置中的选项,更改检测时间间隔,每次检测都会请求https://www.google.com.tw/,该请求不会进行下载,仅仅请求HTTP头部,请求成功后,会返回working信息,请求失败,会返回Problem detected!
  • " + statusmenu += "
  • 状态检测只在SS主界面打开时进行,网页关闭后,后台是不会进行检测的,每次进入页面,或者切换模式,重新提交等操作,状态检测会在此后5秒后进行,在这之前,状态会显示为watting... 如果显示Waiting for first refresh...则表示正在等待首次状态检测的结果。
  • " + statusmenu += "
  • 状态检测反应的是路由器本身访问https://www.google.com.tw/的结果,并不代表电脑或路由器下其它终端的访问结果,透过状态检测,可以为使用SS代理中遇到的一些问题进行排查,一下列举一些常见的情况:
  • " + statusmenu += "
    1:双working,不能访问被墙网站:" + statusmenu += "
        1.1:DNS缓存:可能你在未开启ss的时候访问过被墙域名,DNS缓存受到了污染,只需要简单的刷新下缓存,window电脑通过在CMD中运行命令:ipconfig /flushdns刷新电脑DNS缓存,手机端可以通过尝试开启飞行模式后关闭飞行模式刷新DNS缓存。" + statusmenu += "
        1.2:自定义DNS:很多用户喜欢自己在电脑上定义DNS来使用,这样访问google等被墙网站,解析出来的域名基本都是污染的,因此建议将DNS解析改为自动获取。如果你的路由器很多人使用,你不能阻止别人自定义DNS,那么建议开启chromecast功能,路由器会将所有自定义的DNS劫持到自己的DNS服务器上,避免DNS污染。" + statusmenu += "
        1.3:host:电脑端以前设置过host翻墙,host翻墙失效快,DNS解析将通过host完成,不过路由器,如果host失效,使用chnroute翻墙的模式将无法使用;即使未失效,在gfwlist模式下,域名解析通过电脑host完成,而无法进入ipset,同样使得翻墙无法使用,因此强烈建议清除相关host!" + statusmenu += "
    2:国内working,国外Problem detected!:" + statusmenu += "
        2.1:检查你的SS账号:在电脑端用SS客户端检查是否正常;" + statusmenu += "
        2.2:是否使用了域名:一些SS服务商提供的域名,特别是较为复杂的域名,可能有解析不了的问题,可尝试更换为IP地址;" + statusmenu += "
        2.3:是否使用了含有特殊字符的密码:极少数情况下,电脑端账号使用正常,路由端却Problem detected!是因为使用了包含特殊字符的密码;" + statusmenu += "
        2.4:尝试更换国外dns:此部分详细解析,请看DNS部分帮助文档;" + statusmenu += "
        2.5:更换shadowsocks主程序:meirlin ss一直使用最新的shadowsocks-libev和shadowsocksR-libev代码编译主程序,如果某次更新后出现这种情况,在检查了以上均无问题后,可能出现的问题就是路由器内的ss主程序和服务器端的不匹配,此时你可以通过下载历史安装包,将旧的主程序替换掉新的,主程序位于路由器下的/paldier/softcenter/bin目录,shadowsocks-libev:ss-redir,ss-local,ss-tunnel;shadowsocksR-libev:rss-redir,rss-local,rss-tunnel;" + statusmenu += "
        2.6:更新服务器端:如果你不希望更换路由器端主程序,可以更新最新服务器端来尝试解决问题,另外建议使用原版SS的朋友,在服务器端部署和路由器端相同版本的shadowsocks-libev;" + statusmenu += "
        2.7:ntp时间问题:如果你使用SSR,一些混淆协议是需要验证ss服务器和路由器的时间的,如果时间相差太多,那么就会出现Problem detected! 。" + statusmenu += "
    3:双Problem detected!:" + statusmenu += "
        3.1:更换国内DNS:在电脑端用SS客户端检查是否正常;" + statusmenu += "
        3.2:逐项检查第2点中每个项目。" + statusmenu += "
    4:国内Problem detected!,国外working:" + statusmenu += "
        4.1:尝试更换国内DNS。" + statusmenu += "
    5:国外间歇性Problem detected!:" + statusmenu += "
        5.1:检查你的SS服务器ping和丢包:一些线路可能在高峰期或者线路调整期,导致丢包过多,获取状态失败;" + statusmenu += "
        5.2:升级新版本后出现这种情况:merlin ss插件从2015年6月,其核心部分就基本无改动,升级新版本出现这种情况,最大可能的原因,新版本升级了最新的ss或者ssr的主程序,解决方法可以通过回滚路由器内程序,也可以升级你的服务器端到最新,如果你是自己搭建的用户,建议最新原版shadowsocks-libev程序。" + statusmenu += "
    6:你遇到了非常少见的情况:来这里反馈吧:telegram。" + _caption = "状态检测"; + return overlib(statusmenu, OFFSETX, -460, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } + if (itemNum == 1) { + width = "700px"; + bgcolor = "#CC0066", + //gfwlist + statusmenu = "【1】gfwlist模式:
    " + statusmenu += "    该模式使用gfwlist区分流量,Shadowsocks会将所有访问gfwlist内域名的TCP链接转发到Shadowsocks服务器,实现透明代理;
    " + statusmenu += "    和真正的gfwlist模式相比较,路由器内的gfwlist模式还是有一定缺点,因为它没法做到像gfwlist PAC文件一样,对某些域名的二级域名有例外规则。
    " + statusmenu += "优点:节省SS流量,可防止迅雷和PT流量。
    " + statusmenu += "缺点:代理受限于名单内的4000多个被墙网站,需要维护黑名单。一些不走域名解析的应用,比如telegram,需要单独添加IP/CIDR黑名单。


    " + //redchn + statusmenu += "【2】大陆白名单模式:
    " + statusmenu += "    该模式使用chnroute IP网段区分国内外流量,ss-redir将流量转发到Shadowsocks服务器,实现透明代理;
    " + statusmenu += "    由于采用了预先定义的ip地址块(chnroute),所以DNS解析就非常重要,如果一个国内有的网站被解析到了国外地址,那么这个国内网站是会走ss的;
    " + statusmenu += "    因为使用了大量的cdn名单,能够保证常用的国内网站都获得国内的解析结果,但是即使如此还是不能完全保证国内的一些网站解析到国内地址,这个时候就推荐使用具备cdn解析能力的cdns或者chinadns2。
    " + statusmenu += "优点:所有被墙国外网站均能通过代理访问,无需维护域名黑名单;主机玩家用此模式可以实现TCP代理UDP国内直连。
    " + statusmenu += "缺点:消耗更多的Shadowsocks流量,迅雷下载和BT可能消耗SS流量。


    " + //game + statusmenu += "【3】游戏模式:
    " + statusmenu += "    游戏模式较于其它模式最大的特点就是支持UDP代理,能让游戏的UDP链接走SS,主机玩家用此模式可以实现TCP+UDP走SS代理;
    " + statusmenu += "    由于采用了预先定义的ip地址块(chnroute),所以DNS解析就非常重要,如果一个国内有的网站被解析到了国外地址,那么这个国内网站是会走ss的。
    " + statusmenu += "优点:除了具有大陆白名单模式的优点外,还能代理UDP链接,并且实现主机游戏 NAT2!
    " + statusmenu += "缺点:由于UDP链接也走SS,而迅雷等BT下载多为UDP链接,如果下载资源的P2P链接中有国外链接,这部分流量就会走SS!


    " + //overall + statusmenu += "【4】全局模式:
    " + statusmenu += "    除局域网和ss服务器等流量不走代理,其它都走代理(udp不走),高级设置中提供了对代理协议的选择。
    " + statusmenu += "优点:简单暴力,全部出国;可选仅web浏览走ss,还是全部tcp代理走ss,因为不需要区分国内外流量,因此性能最好。
    " + statusmenu += "缺点:国内网站全部走ss,迅雷下载和BT全部走SS流量。


    " + //overall + statusmenu += "【5】回国模式:
    " + statusmenu += "    提供给国外的朋友,通过在中间服务器翻回来,以享受一些视频、音乐等网络服务。
    " + statusmenu += "提示:回国模式选择外国DNS只能使用直连~
    " + _caption = "模式说明"; + return overlib(statusmenu, OFFSETX, -860, OFFSETY, -290, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 2) { + statusmenu = "此处填入你的ss/ssr/koolgame服务器的地址。
    建议优先填入IP地址。填入域名,特别是一些服务商给的复杂域名,有时遇到无法解析会导致国外无法连接!"; + _caption = "服务器"; + } else if (itemNum == 3) { + statusmenu = "此处填入你的ss/ssr/koolgame服务器的端口"; + _caption = "服务器端口"; + } else if (itemNum == 4) { + statusmenu = "此处填入你的ss/ssr/koolgame服务器的密码。
    注意:使用带有特殊字符的密码,可能会导致链接不上服务器。"; + _caption = "服务器密码"; + } else if (itemNum == 5) { + statusmenu = "此处填入你的ss/ssr/koolgame服务器的加密方式。
    建议如果是自己搭建服务器,建议使用对路由器负担比较小的加密方式,例如chacha20,chacha20-ietf等。"; + _caption = "服务器加密方式"; + } else if (itemNum == 6) { + statusmenu = "此处选择你希望UDP的通道。
    很多游戏都走udp的初衷就是加速udp连接。
    如果你到vps的udp链接较快,可以选择udp in udp,如果你的运营商封锁了udp,可以选择udp in tcp。"; + _caption = "游戏模式V2 UDP通道"; + } else if (itemNum == 8) { + statusmenu = "更多信息,请参考ShadowsocksR 协议插件文档" + _caption = "协议插件(protocol)"; + } else if (itemNum == 9) { + statusmenu = "更多信息,请参考ShadowsocksR 协议插件文档" + _caption = "混淆插件 (obfs)"; + + } else if (itemNum == 11) { + statusmenu = "如果不知道如何填写,请一定留空,不然可能带来副作用!" + statusmenu += "

    请参考协议插件(protocol)混淆插件 (obfs)内说明。" + statusmenu += "

    更多信息,请参考ShadowsocksR 协议插件文档" + _caption = "自定义参数 (obfs_param)"; + } else if (itemNum == 12) { + width = "500px"; + statusmenu = "此处显示你的SS插件当前的版本号,当前版本:<% dbus_get_def("ss_basic_version_local", "未知"); %>,如果需要回滚SS版本,请参考以下操作步骤:"; + statusmenu += "

    1  进入webshell或者其他telnet,ssh等能输入命令的工具"; + statusmenu += "
    2  请依次输入以下命令,等待上一条命令执行完后再运行下一条(这里以回滚1.5.0为例):"; + statusmenu += "

        cd /tmp"; + statusmenu += "
        wget --no-check-certificate https://raw.githubusercontent.com/paldier/softcenter/master/shadowsocks/history/shadowsocks_1.5.0.tar.gz"; + statusmenu += "
        mv shadowsocks_1.5.0.tar.gz shadowsocks.tar.gz"; + statusmenu += "
        tar -zxvf /tmp/shadowsocks.tar.gz"; + statusmenu += "
        chmod +x /tmp/shadowsocks/install.sh"; + statusmenu += "
        sh /tmp/shadowsocks/install.sh"; + statusmenu += "

    最后一条命令输入完后不会有任何打印信息。"; + statusmenu += "
    回滚其它版本号,请参考版本历史列表"; + _caption = "shadowsocks for merlin 版本"; + } else if (itemNum == 13) { + statusmenu = "    SSR表示shadowwocksR-libev,相比较原版shadowwocksR-libev,其提供了强大的协议混淆插件,让你避开gfw的侦测。" + statusmenu += "
        虽然你在节点编辑界面能够指定使用SS的类型,不过这里还是提供了勾选使用SSR的选项,是为了方便一些服务器端是兼容原版协议的用户,快速切换SS账号类型而设定。"; + _caption = "使用SSR"; + } else if (itemNum == 15) { + statusmenu = "    点击右侧的铅笔图标,进入节点界面,在节点界面,你可以进行节点的添加,修改,删除,应用,检查节点ping,和web访问性等操作。" + _caption = "选择节点"; + } else if (itemNum == 16) { + statusmenu = "    此处不同模式会显示不同的图标,如果你是从2.0以前的老版本升级过来的,可能有些节点不会显示图标,只需要编辑一下节点,选择好模式,然后保存即可显示。" + _caption = "模式"; + } else if (itemNum == 17) { + statusmenu = "节点名称支持中文,支持空格。" + _caption = "节点名称"; + } else if (itemNum == 18) { + statusmenu = "优先建议使用ip地址" + _caption = "服务器地址"; + } else if (itemNum == 19) { + statusmenu = "    ping/丢包功能用于检测你的路由器到ss服务器的ping值和丢包;" + statusmenu += "
        比如一些游戏线路对ping值和丢包有要求,可以选择ping值较低,丢包较少的节点;" + statusmenu += "
        一些奇葩的运营商可能会禁ping,一些SS服务器也会禁止ping,此处检测就会failed,所以遇到这种情况不必惊恐。" + _caption = "ping/丢包"; + } else if (itemNum == 21) { + statusmenu = "    编辑节点功能能帮助你快速的更改ss某个节点的设置,比如服务商更换IP地址之后,可以快速更改;" + statusmenu += "
        编辑节点目前只支持相同类型节点的编辑,比如不能将ss节点编辑为ssr节点,如果你的ssr节点是兼容原版协议的,建议你在主面板用使用ssr勾选框来进行更改。" + _caption = "编辑节点"; + } else if (itemNum == 22) { + statusmenu = "    删除节点功能能快速的删除某个特定的节点,为了方便快速删除,删除节点点击后生效,不会有是否确认弹出。" + _caption = "编辑节点"; + } else if (itemNum == 23) { + statusmenu = "    点击使用节点能快速的将该节点填入主面板,但是你需要在主面板点击提交,才能使用该节点。
    不同的颜色代表了不同的节点类型,SS:蓝色;SSR;粉色,V2:绿色" + _caption = "使用节点"; + } else if (itemNum == 24) { + statusmenu = "    导出功能可以将ss所有的设置全部导出,包括节点信息,dns设定,黑白名单设定等;" + statusmenu += "
        恢复配置功能可以使用之前导出的文件,也可以使用标准的json格式节点文件。" + _caption = "导出恢复"; + } else if (itemNum == 25) { + statusmenu = "1  在gfwlist模式下:"; + statusmenu += "
        此处定义的国内DNS仅在dns2socks和ss-tunnel下有效,chinadns1和chinadns2因为自带了国内外cdn,所以不需要。" + _caption = "国内DNS"; + } else if (itemNum == 26) { + width = "750px"; + statusmenu = "    国外DNS为大家提供了丰富的选择,其目的有二,一是为了保证大家有能用的国外DNS服务;二是在有能用的基础上,能够选择多种DNS解析方案,达到最佳的解析效果;所以如果你切换某个DNS程序,导致国外连接Problem detected! 那么更换能用的就好,不用纠结某个解析方案不能用。" + statusmenu += "    

    各DNS方案做简单介绍:" + //dns2socks + statusmenu += "
    1:dns2socks:" + statusmenu += "
        万金油方案,DNS请求通过一个socks5隧道转发到DNS服务器,然后由代理服务器向你定义的DNS发起tcp dns请求,和下文中ss-tunnel类似,不过dns2socks是利用了SOCK5隧道代理,ss-tunnel是利用了加密UDP;该DNS方案不受到ss服务是否支持udp限制,只要能建立socoks5链接,就能使用;"; + statusmenu += "
        国外解析通过SS服务器转发,国内cdn由cdn.txt提供,对cpu负担稍大,国外cdn很好。"; + //ss-tunnel + statusmenu += "
    2:ss-tunnel:" + statusmenu += "
        原理是将DNS请求,通过ss-tunnel利用UDP发送到ss服务器上,然后由代理服务器向你定义的DNS发起udp dns请求,解析出到正确的IP地址,的解析效果和dns2socks应该是一样的。" + statusmenu += "
        国外解析通过SS服务器转发,国内cdn由cdn.txt提供,对cpu负担稍大,国外cdn很好。"; + _caption = "国外DNS"; + //cdns + statusmenu += "
    3:cdns:" + statusmenu += "
        和chinadns2一样,支持ECS(EDNS Client Subnet),DNS请求时携带一个EDNS标签,解析成功后返回带该标签的解析结果,gfw投毒的解析结果则不会带该标签,以达到防dns污染的目的!"; + statusmenu += "
        国外解析本地直链国外DNS服务器,国内cdn由cdn.txt提供,对cpu负担稍大,国外cdn较弱。"; + //chinadns1 + statusmenu += "
    4:chinadns1:" + statusmenu += "
        使用dns2socks作为chinadns上游dns解析工具获取无污染dns,通过chinadns的国内dns请求国内dns获取国内解析结果"; + statusmenu += "
        国外解析通过SS服务器转发,具有很好的国内cdn,和很好的国外cdn,不需要cdn.txt作为国内加速,对cpu负担小。"; + //chinadns2 + statusmenu += "
    5:chinadns2:" + statusmenu += "
        支持ECS,并且chinadns2根据本地公网ip和ss服务器ip,发送两个带EDNS标签的请求,dns服务器会根据此信息选择离你最近的解析结果返回给你,因此具有非常好的cdn效果!需要上游DNS服务器支持ECS,所以此处固定为直连谷歌DNS,如果你的网络到谷歌DNS丢包严重、不通或你的上级路由开了国外代理,请不要使用此方案"; + statusmenu += "
        国外解析本地直链谷歌DNS服务器,国外cdn很好;不需要cdn.txt作为国内加速,对cpu负担小,国内cdn较好,但是有时候国内网站会解析到香港网站。"; + //https_dns_proxy + statusmenu += "
    6:https_dns_proxy:" + statusmenu += "
        https_dns_proxy是DNS Over https(DOH)方案,dns请求走https,支持ECS,因此具有非常好的国外cdn效果!此处默认使用了cloudflare的服务(1.1.1.1和1.0.0.1)"; + statusmenu += "
        国外解析本地直连cloudflare服务器,所以到cloudflare服务器的网络连接至关重要;国内cdn由cdn.txt提供,对cpu负担稍大。"; + //v2ray dns + statusmenu += "
    7:v2ray dns:" + statusmenu += "
        v2ray自带的dns,通过在v2ray的json配置文件中添加一个新的传入连接来转发dns请求,使用效果应该和ss/ssr下使用ss-tunnel一样"; + statusmenu += "
        国外解析通过v2ray服务器转发,国外cdn很好;国内cdn由cdn.txt提供,对cpu负担稍大。。"; + + return overlib(statusmenu, OFFSETX, -860, OFFSETY, -290, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 27) { + statusmenu = "
    1:不勾选(自动生成json):" + statusmenu += "
        此方式只支持vmess作为传出协议,不支持sock,shadowsocks;提交后会根据你的配置自动生成v2ray的json配置。" + statusmenu += "

    1:勾选(自定义json):" + statusmenu += "
        此方式支持配置v2ray支持的所有传出协议,插件会取你的json的outbound部分,并自动配置透明代理和socks传进协议,以便在路由器上工作。" + _caption = "使用json配置"; + } else if (itemNum == 28) { + width = "750px"; + statusmenu = "如果客户端json配置文件内没有此项,此处请留空!" + statusmenu += "

    1:传输协议tcp + 伪装类型http:" + statusmenu += "
      此参数在客户端json配置文件的【outbound → streamSettings → tcpSettings → headers → Host】位置" + statusmenu += "
      如有多个域名,请用英文逗号隔开,如:www.baidu.com,www.sina.com.cn" + statusmenu += "

    2:传输协议ws:" + statusmenu += "
      此参数在客户端json配置文件的【outbound → streamSettings → wsSettings → headers → Host】位置" + statusmenu += "

    3:传输协议h2:" + statusmenu += "
      此参数在客户端json配置文件的【outbound → streamSettings → httpSettings → host】位置" + statusmenu += "
      如有多个域名,请用英文逗号隔开,如:www.baidu.com,www.sina.com.cn" + _caption = "伪装域名 (host)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -290, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 29) { + width = "750px"; + statusmenu = "如果客户端json配置文件内没有此项,此处请留空!

    path的设定应该和服务器端保持一致,值应该和你nginx或者candy的配置内的一致!" + statusmenu += "

    1:ws path:" + statusmenu += "
      此参数在客户端json配置文件的【outbound → streamSettings → wsSettings → path】位置" + statusmenu += "

    2:h2 path:" + statusmenu += "
      此参数在客户端json配置文件的【outbound → streamSettings → httpSettings → path】位置" + _caption = "路径 (path)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -290, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 30) { + width = "750px"; + statusmenu = "此处控制开启或者关闭tls传输" + statusmenu += "

    此参数在客户端json配置文件的【outbound → streamSettings → security】位置" + _caption = "底层传输安全"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 31) { + width = "400px"; + statusmenu = "此处控制开启或者关闭多路复用 (Mux)" + statusmenu += "

    此参数在客户端json配置文件的【outbound → mux → enabled】位置" + _caption = "多路复用 (Mux)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 32) { + width = "750px"; + statusmenu = "控制Mux并发连接数,默认值:8,如果客户端json配置文件没有请留空" + statusmenu += "

    此参数在客户端json配置文件的【outbound → mux → concurrency】位置,如果没有,请留空" + _caption = "Mux并发连接数"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 33) { + statusmenu = "填入需要强制用国内DNS解析的域名,一行一个,格式如下:。" + statusmenu += "
    注意:不支持通配符!" + statusmenu += "

    koolshare.cn" + statusmenu += "
    baidu.com" + statusmenu += "

    需要注意的是,这里要填写的一定是网站的一级域名,比如taobao.com才是正确的,www.taobao.com,http://www.taobao.com/这些格式都是错误的!" + _caption = "自定义需要CDN加速网站"; + } else if (itemNum == 34) { + statusmenu = "填入自定义的dnsmasq设置,一行一个,格式如下:。" + statusmenu += "

    #例如hosts设置:" + statusmenu += "
    address=/koolshare.cn/2.2.2.2" + statusmenu += "

    #防DNS劫持设置" + statusmenu += "
    bogus-nxdomain=220.250.64.18" + statusmenu += "

    #指定config设置" + statusmenu += "
    conf-file=/jffs/mydnsmasq.conf" + statusmenu += "

    如果填入了错误的格式,可能导致dnsmasq启动失败!" + statusmenu += "

    如果填入的信息里带有英文逗号的,也会导致dnsmasq启动失败!" + _caption = "自定义dnsamsq"; + } else if (itemNum == 35) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → streamSettings → network】位置" + _caption = "传输协议 (network)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 36) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → streamSettings → tcpSettings → header → type】位置,如果没有此参数,则为不伪装" + _caption = "tcp伪装类型 (type)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 37) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → streamSettings → kcpSettings → header → type】位置,如果参数为none,则为不伪装" + _caption = "kcp伪装类型 (type)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -290, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 38) { + statusmenu = "填入不需要走代理的外网ip/cidr地址,一行一个,格式如下:。" + statusmenu += "

    2.2.2.2" + statusmenu += "
    3.3.3.3" + statusmenu += "
    4.4.4.4/24" + _caption = "IP/CIDR白名单"; + } else if (itemNum == 39) { + statusmenu = "填入不需要走代理的域名,一行一个,格式如下:。" + statusmenu += "

    google.com" + statusmenu += "
    facebook.com" + statusmenu += "

    需要注意的是,这里要填写的一定是网站的一级域名,比如google.com才是正确的,www.google.com,https://www.google.com/这些格式都是错误的!" + statusmenu += "

    需要清空电脑DNS缓存,才能立即看到效果" + _caption = "域名白名单"; + } else if (itemNum == 40) { + statusmenu = "填入需要强制走代理的外网ip/cidr地址,,一行一个,格式如下:。" + statusmenu += "

    5.5.5.5" + statusmenu += "
    6.6.6.6" + statusmenu += "
    7.7.7.7/8" + _caption = "IP/CIDR黑名单"; + } else if (itemNum == 41) { + statusmenu = "填入需要强制走代理的域名,,一行一个,格式如下:。" + statusmenu += "

    baidu.com" + statusmenu += "
    taobao.com" + statusmenu += "

    需要注意的是,这里要填写的一定是网站的一级域名,比如google.com才是正确的,www.baidu.com,http://www.baidu.com/这些格式都是错误的!" + statusmenu += "

    需要清空电脑DNS缓存,才能立即看到效果。" + _caption = "IP/CIDR黑名单"; + } else if (itemNum == 42) { + statusmenu = "此处定义ss状态检测更新时间间隔,默认5秒。" + _caption = "状态更新间隔"; + } else if (itemNum == 44) { + statusmenu = "shadowsocks规则更新包括了gfwlist模式中用到的gfwlist,在大陆白名单模式和游戏模式中用到的chnroute国内cdn名单" + statusmenu += "
    建议更新时间在凌晨闲时进行,以避免更新时重启ss服务器造成网络访问问题。" + _caption = "shadowsocks规则自动更新"; + } else if (itemNum == 45) { + statusmenu = "通过局域网客户端控制功能,你能定义在当前模式下某个局域网地址是否走SS。" + _caption = "局域网客户端控制"; + } else if (itemNum == 46) { + statusmenu = "一些用户的网络拨号可能比较滞后,为了保证SS在路由器开机后能正常启动,可以通过此功能,为ss的启动增加开机延迟。" + _caption = "开机启动延迟"; + } else if (itemNum == 47) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → settings → vnext → users → security】位置" + _caption = "加密方式 (security)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 48) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → settings → vnext → users → alterId】位置" + _caption = "额外ID (Alterld)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 49) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → settings → vnext → users → id】位置" + _caption = "加密方式 (security)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 50) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → settings → vnext → port】位置" + _caption = "端口(port)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 51) { + width = "750px"; + statusmenu = "
    此参数在客户端json配置文件的【outbound → settings → vnext → address】位置" + _caption = "地址(address)"; + return overlib(statusmenu, OFFSETX, -560, OFFSETY, -90, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + } else if (itemNum == 54) { + statusmenu = "更多信息,请参考ShadowsocksR 协议参数文档" + _caption = "协议参数(protocol)"; + } else if (itemNum == 90) { + statusmenu = "此处设定为预设不可更改。
        1. 单开KCPTUN的情况下,ss-redir的TCP流量都会转发到此;
        2. KCPTUN和UDP2raw串联的模式下,ss-redir的TCP流量才会转发到UDP2raw;" + _caption = "说明:"; + } else if (itemNum == 91) { + width = "600px"; + statusmenu = "    1. 单独加速:此处配置为服务器ip+服务器端口(或者留空+服务器端口),KCPTUN的UDP流量会转发给服务器;
        2. 串联1:此处配置为127.0.0.1:1092(即UDPspeeder监听端口)时,可配置kcptun和UDPspeeder串联,KCPTUN的UDP流量会转发给UDPspeeder,然后转为tcp,并转发给服务器的UDP2raw。同时你需要在服务器端配置KCPTUN和UDP2raw的串联。
        2. 串联3:此处配置为127.0.0.1:1093(即UDP2raw监听端口)时,可配置kcptun和udp2raw串联,KCPTUN的UDP流量会转发给UDP2raw,然后转为tcp,并转发给服务器的UDP2raw。同时你需要在服务器端配置KCPTUN和UDP2raw的串联。" + _caption = "说明:"; + } else if (itemNum == 97) { + width = "600px"; + statusmenu = "    UDPspeeder(V1/V2)针对udp传输进行优化,能加速udp,降低udp的丢包,特别适合游戏。
        UDP2raw可以将udp协议转为tcp,这对一些对udp有限制或者qos的情况特别好用,UDP2raw不是一个udp加速工具,如果需要udp加速,还需要配合UDPspeeder(V1/V2)串联使用。
        正确开启的姿势是需要在服务器端配置UDPspeeder(V1/V2)/UDP2raw的服务器端程序,然后在路由器下,需要以下条件才能正常开启:
    1. 当前正在使用游戏模式或者访问控制主机中有游戏模式主机;
    2. 此处加速的节点和正在使用的节点一致;
    3. 正确配置并开启UDPspeeder(V1/V2)或UDP2raw,或者两者都开启(串联模式)。
    " + _caption = "说明:"; + } else if (itemNum == 98) { + statusmenu = "    此处设定的MTU值将用于ss-redir/ssr-redir。
        因为UDPspeeder(V1/V2)和UDP2raw对上游软件的MTU有要求,此处方便高级用户对其进行设定,以达到更好的UDP加速效果。不知道如何设定的请选择不设定,以免造成不必要的问题
        此处的设定只有在UDPspeeder(V1/V2)/UDP2raw开启或者两者都开启的情况下才会生效。" + _caption = "说明:"; + } else if (itemNum == 99) { + statusmenu = "此处设定为预设不可更改。
        1. 单开UDPspeeder(V1/V2)模式或者UDPspeeder(V1/V2)和UDP2raw双开(串联模式下),ss-redir的UDP流量都会转发到此;
        2. 只有UDPepeeder未开启且UDP2raw开启的情况下,ss-redir的UDP流量才会转发到UDP2raw;" + _caption = "说明:"; + } else if (itemNum == 100) { + width = "600px"; + statusmenu = "    1.单开UDPspeeder(V1/V2)模式下,ss-redir的udp流量经过UDPspeeder(V1/V2)加速后的UDP流量会转发到服务器,此处应按填写服务器的ip和服务器端UDPspeeder(V1/V2)的监听端口;
        2.UDPspeeder(V1/V2)和UDP2raw双开(串联模式下),ss-redir的udp流量经过UDPspeeder(V1/V2)加速后的UDP流量会先转发给本地的UDP2raw程序,然后由UDP2raw和服务器的UDP2raw之间利用TCP(faketcp模式)协议进行通讯,然后服务器的UDP2raw收到TCP(faketcp模式)后还原为UDPspeeder(V1/V2)加速后的流量转发给服务器的UDPspeeder(V1/V2),然后服务器的UDPspeeder(V1/V2)将此流量继续还原为ss-redir的UDP流量,转发给服务器的ss服务器程序。 所以路由器下UDPspeeder(V1/V2)和UDP2raw的串联也需要服务器端UDPspeeder(V1/V2)和UDP2raw的串联。" + _caption = "说明:"; + } else if (itemNum == 101) { + width = "600px"; + statusmenu = "此处设定为预设不可更改。
        1.单开UDP2raw模式下,ss-redir的UDP流量会转发到此;
        2.UDPspeeder(V1/V2)和UDP2raw双开(串联模式下),ss-redir的UDP流量会转发到UDPspeeder(V1/V2),经过UDPspeeder(V1/V2)加速后的udp流量流量会转发到此(即转发到UDP2raw),形成UDPspeeder(V1/V2)和UDP2raw的串联。" + _caption = "说明"; + } else if (itemNum == 102) { + width = "600px"; + statusmenu = "    1.单开udp2raw模式下,ss-redir的udp流量经过udp2raw转换为tcp后的流量会转发此处设置的到服务器端口,此处应按填写服务器的ip和服务器端UDPspeeder(V1/V2)的监听端口;
        2.在UDPspeeder(V1/V2)和UDP2raw双开(串联模式下),ss-redir的udp流量经过UDPspeeder(V1/V2)加速后的UDP流量,经过udp2raw转换为tcp后的流量会转发此处设置的到服务器端口,此处应按填写服务器的ip和服务器端UDPspeeder(V1/V2)的监听端口;" + _caption = "说明:"; + } else if (itemNum == 103) { + width = "600px"; + statusmenu = "梅林固件推荐使用auto.
        大部分udp2raw不能连通的情况都是设置了不兼容的iptables造成的。--lower-level选项允许绕过本地iptables。
        虽然作者推荐merlin固件使用auto,但是merlin固件在某些拨号网络下可能无法通过--lower-level auto自动获取参数,而导致udp2raw启动失败,此时可以手动填写此处或者留空(实测留空也是可以工作的)" + _caption = "说明:"; + } else if (itemNum == 104) { + width = "600px"; + statusmenu = "
        UDPspeeder有两个版本,V2是V1的升级版本,只有V2版才支持FEC;V1和V2版都支持多倍发包,V2通过配置FEC比例就能达到V1的多倍发包效果。
    如果你只需要多倍发包,可以直接用V1版,V1版配置更简单,占用内存更小,而且经过了几个月的考验,很稳定。V2版在梅林固件下的消耗更高一些。" + _caption = "说明:"; + } else if (itemNum == 105) { + width = "600px"; + statusmenu = "帮助信息:
    dnsmasq配置文件里的ipset,address,server规则一多,路由器CPU使用率就上去了。
    而现在gfwlist 5000+条server规则,5000+多条ipset规则!
    而为了更好的国内解析效果,还引入了40000+条的server规则!
    一旦访问网页,每次域名解析的时候,dnsmasq都会遍历这些名单,造成大量的cpu消耗!!
    而改进版的dnsmasq,这里称dnsmasq-fastlookup,见原作者infinet帖作者原帖
    大概的意思就是原版的dnsmasq很慢(因为遍历查询方式)
    而原作者infinet改的dnsmasq很快(因为hash查询方式)
    可以大大的解放路由器cpu因dns查询带来的消耗!加快dns查询速度!
    相关链接:dnsmasq-fastlookup源码dnsmasq-fastlookup性能测试
    -----------------------------------------------------------------------------------------
    原先dnsmasq-fastlookup有问题可能会导致进程死掉,造成无法上网,而现在经过作者更新,已经相当稳定,故而添加此功能。
    请根据自己实际需要选择替换方案~" + _caption = "说明:"; + } else if (itemNum == 106) { + width = "600px"; + statusmenu = "DNS劫持(原chromecast功能).
        开启该功能后,局域网内所有客户端的DNS解析请求将会被强制劫持到使用路由器提供的DNS进行解析,以避免DNS污染。
        例如当局域网内有用户在电脑上自定义DNS解析服务器为8.8.8.8时候,该电脑向8.8.8.8的DNS请求,将会被强制劫持到路由器的dns服务器如:192.168.50.1,例如访问谷歌网站,虽然路由器本身已经具备访问能力,但是如果设备请求道了污染的DNS,会导致该设备无法访问谷歌,所以当你无法控制局域网内一些设备自定义DNS行为的情况下,启用该功能可以保证局域网内所有客户端不会受到DNS污染。" + _caption = "说明:"; + } else if (itemNum == 107) { + width = "600px"; + statusmenu = "节点域名解析DNS服务器.
        一些SS/SSR/V2RAY的服务器为域名格式,在启用的时候需要对其进行解析,以获取正确的IP地址,此处定义用以解析服务器域名的DNS服务器。
        一些机场节点的域名托管在国外服务商,此时自定义定义国外的DNS服务器效果可能更好。" + _caption = "说明:"; + } + return overlib(statusmenu, OFFSETX, -160, LEFT, STICKY, WIDTH, 'width', CAPTION, _caption, CLOSETITLE, ''); + + var tag_name = document.getElementsByTagName('a'); + for (var i = 0; i < tag_name.length; i++) + tag_name[i].onmouseout = nd; + + if (helpcontent == [] || helpcontent == "" || hint_array_id > helpcontent.length) + return overlib('<#defaultHint#>', HAUTO, VAUTO); + else if (hint_array_id == 0 && hint_show_id > 21 && hint_show_id < 24) + return overlib(helpcontent[hint_array_id][hint_show_id], FIXX, 270, FIXY, 30); + else { + if (hint_show_id > helpcontent[hint_array_id].length) + return overlib('<#defaultHint#>', HAUTO, VAUTO); + else + return overlib(helpcontent[hint_array_id][hint_show_id], HAUTO, VAUTO); + } +} + +function showDropdownClientList(_callBackFun, _callBackFunParam, _interfaceMode, _containerID, _pullArrowID, _clientState) { + document.body.addEventListener("click", function(_evt) { + control_dropdown_client_block(_containerID, _pullArrowID, _evt); + }) + if (clientList.length == 0) { + setTimeout(function() { + genClientList(); + showDropdownClientList(_callBackFun, _callBackFunParam, _interfaceMode, _containerID, _pullArrowID); + }, 500); + return false; + } + + var htmlCode = ""; + htmlCode += "
    "; + htmlCode += "
    Show Offline Client List
    "; + htmlCode += "
    "; + document.getElementById(_containerID).innerHTML = htmlCode; + + var param = _callBackFunParam.split(">"); + var clientMAC = ""; + var clientIP = ""; + var getClientValue = function(_attribute, _clienyObj) { + var attribute_value = ""; + switch (_attribute) { + case "mac": + attribute_value = _clienyObj.mac; + break; + case "ip": + if (clientObj.ip != "offline") { + attribute_value = _clienyObj.ip; + } + break; + case "name": + attribute_value = (clientObj.nickName == "") ? clientObj.name.replace(/'/g, "\\'") : clientObj.nickName.replace(/'/g, "\\'"); + break; + default: + attribute_value = _attribute; + break; + } + return attribute_value; + }; + + var genClientItem = function(_state) { + var code = ""; + var clientName = (clientObj.nickName == "") ? clientObj.name : clientObj.nickName; + + code += ''; + if (_state == "online") + code += '
    '; + code += ''; + if (clientName.length > 32) { + code += clientName.substring(0, 30) + ".."; + } else { + code += clientName; + } + code += ''; + if (_state == "offline") + code += '×'; + code += '
    '; + return code; + }; + + for (var i = 0; i < clientList.length; i += 1) { + var clientObj = clientList[clientList[i]]; + switch (_clientState) { + case "all": + if (_interfaceMode == "wl" && (clientList[clientList[i]].isWL == 0)) { + continue; + } + if (_interfaceMode == "wired" && (clientList[clientList[i]].isWL != 0)) { + continue; + } + if (clientObj.isOnline) { + document.getElementById("" + _containerID + "_clientlist_online").innerHTML += genClientItem("online"); + } else if (clientObj.from == "nmpClient") { + document.getElementById("" + _containerID + "_clientlist_offline").innerHTML += genClientItem("offline"); + } + break; + case "online": + if (_interfaceMode == "wl" && (clientList[clientList[i]].isWL == 0)) { + continue; + } + if (_interfaceMode == "wired" && (clientList[clientList[i]].isWL != 0)) { + continue; + } + if (clientObj.isOnline) { + document.getElementById("" + _containerID + "_clientlist_online").innerHTML += genClientItem("online"); + } + break; + case "offline": + if (_interfaceMode == "wl" && (clientList[clientList[i]].isWL == 0)) { + continue; + } + if (_interfaceMode == "wired" && (clientList[clientList[i]].isWL != 0)) { + continue; + } + if (clientObj.from == "nmpClient") { + document.getElementById("" + _containerID + "_clientlist_offline").innerHTML += genClientItem("offline"); + } + break; + } + } + + if (document.getElementById("" + _containerID + "_clientlist_offline").childNodes.length == "0") { + if (document.getElementById("" + _containerID + "_clientlist_dropdown_expand") != null) { + removeElement(document.getElementById("" + _containerID + "_clientlist_dropdown_expand")); + } + if (document.getElementById("" + _containerID + "_clientlist_offline") != null) { + removeElement(document.getElementById("" + _containerID + "_clientlist_offline")); + } + } else { + if (document.getElementById("" + _containerID + "_clientlist_dropdown_expand").innerText == "Show Offline Client List") { + document.getElementById("" + _containerID + "_clientlist_offline").style.display = "none"; + } else { + document.getElementById("" + _containerID + "_clientlist_offline").style.display = ""; + } + } + if (document.getElementById("" + _containerID + "_clientlist_online").childNodes.length == "0") { + if (document.getElementById("" + _containerID + "_clientlist_online") != null) { + removeElement(document.getElementById("" + _containerID + "_clientlist_online")); + } + } + if (document.getElementById(_containerID).childNodes.length == "0") + document.getElementById(_pullArrowID).style.display = "none"; + else + document.getElementById(_pullArrowID).style.display = ""; +} + +//===================================== +function do_js_beautify(source) { + js_source = source.replace(/^\s+/, ''); + tab_size = 2; + tabchar = ' '; + //tab_size = 1; + //tabchar = '\t'; + return js_beautify(js_source, tab_size, tabchar); +} + +function pack_js(source) { + //var input = document.getElementById('ss_basic_v2ray_json').value; + var input = source; + var packer = new Packer; + var output = packer.pack(input, 0, 0); + return output +} + + +function js_beautify(js_source_text, indent_size, indent_character, indent_level) { + + var input, output, token_text, last_type, last_text, last_word, current_mode, modes, indent_string; + var whitespace, wordchar, punct, parser_pos, line_starters, in_case; + var prefix, token_type, do_block_just_closed, var_line, var_line_tainted; + + function trim_output() { + while (output.length && (output[output.length - 1] === ' ' || output[output.length - 1] === indent_string)) { + output.pop(); + } + } + + function print_newline(ignore_repeated) { + ignore_repeated = typeof ignore_repeated === 'undefined' ? true : ignore_repeated; + + trim_output(); + + if (!output.length) { + return; // no newline on start of file + } + + if (output[output.length - 1] !== "\n" || !ignore_repeated) { + output.push("\n"); + } + for (var i = 0; i < indent_level; i++) { + output.push(indent_string); + } + } + + function print_space() { + var last_output = output.length ? output[output.length - 1] : ' '; + if (last_output !== ' ' && last_output !== '\n' && last_output !== indent_string) { // prevent occassional duplicate space + output.push(' '); + } + } + + function print_token() { + output.push(token_text); + } + + function indent() { + indent_level++; + } + + function unindent() { + if (indent_level) { + indent_level--; + } + } + + function remove_indent() { + if (output.length && output[output.length - 1] === indent_string) { + output.pop(); + } + } + + function set_mode(mode) { + modes.push(current_mode); + current_mode = mode; + } + + function restore_mode() { + do_block_just_closed = current_mode === 'DO_BLOCK'; + current_mode = modes.pop(); + } + + function in_array(what, arr) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] === what) { + return true; + } + } + return false; + } + + function get_next_token() { + var n_newlines = 0; + var c = ''; + + do { + if (parser_pos >= input.length) { + return ['', 'TK_EOF']; + } + c = input.charAt(parser_pos); + + parser_pos += 1; + if (c === "\n") { + n_newlines += 1; + } + } + while (in_array(c, whitespace)); + + if (n_newlines > 1) { + for (var i = 0; i < 2; i++) { + print_newline(i === 0); + } + } + var wanted_newline = (n_newlines === 1); + + + if (in_array(c, wordchar)) { + if (parser_pos < input.length) { + while (in_array(input.charAt(parser_pos), wordchar)) { + c += input.charAt(parser_pos); + parser_pos += 1; + if (parser_pos === input.length) { + break; + } + } + } + + // small and surprisingly unugly hack for 1E-10 representation + if (parser_pos !== input.length && c.match(/^[0-9]+[Ee]$/) && input.charAt(parser_pos) === '-') { + parser_pos += 1; + + var t = get_next_token(parser_pos); + c += '-' + t[0]; + return [c, 'TK_WORD']; + } + + if (c === 'in') { // hack for 'in' operator + return [c, 'TK_OPERATOR']; + } + return [c, 'TK_WORD']; + } + + if (c === '(' || c === '[') { + return [c, 'TK_START_EXPR']; + } + + if (c === ')' || c === ']') { + return [c, 'TK_END_EXPR']; + } + + if (c === '{') { + return [c, 'TK_START_BLOCK']; + } + + if (c === '}') { + return [c, 'TK_END_BLOCK']; + } + + if (c === ';') { + return [c, 'TK_END_COMMAND']; + } + + if (c === '/') { + var comment = ''; + // peek for comment /* ... */ + if (input.charAt(parser_pos) === '*') { + parser_pos += 1; + if (parser_pos < input.length) { + while (!(input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/') && parser_pos < input.length) { + comment += input.charAt(parser_pos); + parser_pos += 1; + if (parser_pos >= input.length) { + break; + } + } + } + parser_pos += 2; + return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT']; + } + // peek for comment // ... + if (input.charAt(parser_pos) === '/') { + comment = c; + while (input.charAt(parser_pos) !== "\x0d" && input.charAt(parser_pos) !== "\x0a") { + comment += input.charAt(parser_pos); + parser_pos += 1; + if (parser_pos >= input.length) { + break; + } + } + parser_pos += 1; + if (wanted_newline) { + print_newline(); + } + return [comment, 'TK_COMMENT']; + } + + } + + if (c === "'" || // string + c === '"' || // string + (c === '/' && + ((last_type === 'TK_WORD' && last_text === 'return') || (last_type === 'TK_START_EXPR' || last_type === 'TK_END_BLOCK' || last_type === 'TK_OPERATOR' || last_type === 'TK_EOF' || last_type === 'TK_END_COMMAND')))) { // regexp + var sep = c; + var esc = false; + c = ''; + + if (parser_pos < input.length) { + + while (esc || input.charAt(parser_pos) !== sep) { + c += input.charAt(parser_pos); + if (!esc) { + esc = input.charAt(parser_pos) === '\\'; + } else { + esc = false; + } + parser_pos += 1; + if (parser_pos >= input.length) { + break; + } + } + + } + + parser_pos += 1; + if (last_type === 'TK_END_COMMAND') { + print_newline(); + } + return [sep + c + sep, 'TK_STRING']; + } + + if (in_array(c, punct)) { + while (parser_pos < input.length && in_array(c + input.charAt(parser_pos), punct)) { + c += input.charAt(parser_pos); + parser_pos += 1; + if (parser_pos >= input.length) { + break; + } + } + return [c, 'TK_OPERATOR']; + } + + return [c, 'TK_UNKNOWN']; + } + + //---------------------------------- + + indent_character = indent_character || ' '; + indent_size = indent_size || 4; + + indent_string = ''; + while (indent_size--) { + indent_string += indent_character; + } + + input = js_source_text; + + last_word = ''; // last 'TK_WORD' passed + last_type = 'TK_START_EXPR'; // last token type + last_text = ''; // last token text + output = []; + + do_block_just_closed = false; + var_line = false; + var_line_tainted = false; + + whitespace = "\n\r\t ".split(''); + wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split(''); + punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |='.split(' '); + + // words which should always start on new line. + line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(','); + + // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'. + // some formatting depends on that. + current_mode = 'BLOCK'; + modes = [current_mode]; + + indent_level = indent_level || 0; + parser_pos = 0; // parser position + in_case = false; // flag for parser that case/default has been processed, and next colon needs special attention + while (true) { + var t = get_next_token(parser_pos); + token_text = t[0]; + token_type = t[1]; + if (token_type === 'TK_EOF') { + break; + } + + switch (token_type) { + + case 'TK_START_EXPR': + var_line = false; + set_mode('EXPRESSION'); + if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR') { + // do nothing on (( and )( and ][ and ]( .. + } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') { + print_space(); + } else if (in_array(last_word, line_starters) && last_word !== 'function') { + print_space(); + } + print_token(); + break; + + case 'TK_END_EXPR': + print_token(); + restore_mode(); + break; + + case 'TK_START_BLOCK': + + if (last_word === 'do') { + set_mode('DO_BLOCK'); + } else { + set_mode('BLOCK'); + } + if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') { + if (last_type === 'TK_START_BLOCK') { + print_newline(); + } else { + print_space(); + } + } + print_token(); + indent(); + break; + + case 'TK_END_BLOCK': + if (last_type === 'TK_START_BLOCK') { + // nothing + trim_output(); + unindent(); + } else { + unindent(); + print_newline(); + } + print_token(); + restore_mode(); + break; + + case 'TK_WORD': + + if (do_block_just_closed) { + print_space(); + print_token(); + print_space(); + break; + } + + if (token_text === 'case' || token_text === 'default') { + if (last_text === ':') { + // switch cases following one another + remove_indent(); + } else { + // case statement starts in the same line where switch + unindent(); + print_newline(); + indent(); + } + print_token(); + in_case = true; + break; + } + + + prefix = 'NONE'; + if (last_type === 'TK_END_BLOCK') { + if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) { + prefix = 'NEWLINE'; + } else { + prefix = 'SPACE'; + print_space(); + } + } else if (last_type === 'TK_END_COMMAND' && (current_mode === 'BLOCK' || current_mode === 'DO_BLOCK')) { + prefix = 'NEWLINE'; + } else if (last_type === 'TK_END_COMMAND' && current_mode === 'EXPRESSION') { + prefix = 'SPACE'; + } else if (last_type === 'TK_WORD') { + prefix = 'SPACE'; + } else if (last_type === 'TK_START_BLOCK') { + prefix = 'NEWLINE'; + } else if (last_type === 'TK_END_EXPR') { + print_space(); + prefix = 'NEWLINE'; + } + + if (last_type !== 'TK_END_BLOCK' && in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) { + print_newline(); + } else if (in_array(token_text, line_starters) || prefix === 'NEWLINE') { + if (last_text === 'else') { + // no need to force newline on else break + print_space(); + } else if ((last_type === 'TK_START_EXPR' || last_text === '=') && token_text === 'function') { + // no need to force newline on 'function': (function + // DONOTHING + } else if (last_type === 'TK_WORD' && (last_text === 'return' || last_text === 'throw')) { + // no newline between 'return nnn' + print_space(); + } else if (last_type !== 'TK_END_EXPR') { + if ((last_type !== 'TK_START_EXPR' || token_text !== 'var') && last_text !== ':') { + // no need to force newline on 'var': for (var x = 0...) + if (token_text === 'if' && last_type === 'TK_WORD' && last_word === 'else') { + // no newline for } else if { + print_space(); + } else { + print_newline(); + } + } + } else { + if (in_array(token_text, line_starters) && last_text !== ')') { + print_newline(); + } + } + } else if (prefix === 'SPACE') { + print_space(); + } + print_token(); + last_word = token_text; + + if (token_text === 'var') { + var_line = true; + var_line_tainted = false; + } + + break; + + case 'TK_END_COMMAND': + + print_token(); + var_line = false; + break; + + case 'TK_STRING': + + if (last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK') { + print_newline(); + } else if (last_type === 'TK_WORD') { + print_space(); + } + print_token(); + break; + + case 'TK_OPERATOR': + + var start_delim = true; + var end_delim = true; + if (var_line && token_text !== ',') { + var_line_tainted = true; + if (token_text === ':') { + var_line = false; + } + } + + if (token_text === ':' && in_case) { + print_token(); // colon really asks for separate treatment + print_newline(); + break; + } + + in_case = false; + + if (token_text === ',') { + if (var_line) { + if (var_line_tainted) { + print_token(); + print_newline(); + var_line_tainted = false; + } else { + print_token(); + print_space(); + } + } else if (last_type === 'TK_END_BLOCK') { + print_token(); + print_newline(); + } else { + if (current_mode === 'BLOCK') { + print_token(); + print_newline(); + } else { + // EXPR od DO_BLOCK + print_token(); + print_space(); + } + } + break; + } else if (token_text === '--' || token_text === '++') { // unary operators special case + if (last_text === ';') { + // space for (;; ++i) + start_delim = true; + end_delim = false; + } else { + start_delim = false; + end_delim = false; + } + } else if (token_text === '!' && last_type === 'TK_START_EXPR') { + // special case handling: if (!a) + start_delim = false; + end_delim = false; + } else if (last_type === 'TK_OPERATOR') { + start_delim = false; + end_delim = false; + } else if (last_type === 'TK_END_EXPR') { + start_delim = true; + end_delim = true; + } else if (token_text === '.') { + // decimal digits or object.property + start_delim = false; + end_delim = false; + + } else if (token_text === ':') { + // zz: xx + // can't differentiate ternary op, so for now it's a ? b: c; without space before colon + if (last_text.match(/^\d+$/)) { + // a little help for ternary a ? 1 : 0; + start_delim = true; + } else { + start_delim = false; + } + } + if (start_delim) { + print_space(); + } + + print_token(); + + if (end_delim) { + print_space(); + } + break; + + case 'TK_BLOCK_COMMENT': + + print_newline(); + print_token(); + print_newline(); + break; + + case 'TK_COMMENT': + + // print_newline(); + print_space(); + print_token(); + print_newline(); + break; + + case 'TK_UNKNOWN': + print_token(); + break; + } + + last_type = token_type; + last_text = token_text; + } + + return output.join(''); + +} + +// ==================================== +var base2 = { + name: "base2", + version: "1.0", + exports: "Base,Package,Abstract,Module,Enumerable,Map,Collection,RegGrp,Undefined,Null,This,True,False,assignID,detect,global", + namespace: "" +}; +new + +function(_y) { + var Undefined = K(), + Null = K(null), + True = K(true), + False = K(false), + This = function() { + return this + }; + var global = This(); + var base2 = global.base2; + var _z = /%([1-9])/g; + var _g = /^\s\s*/; + var _h = /\s\s*$/; + var _i = /([\/()[\]{}|*+-.,^$?\\])/g; + var _9 = /try/.test(detect) ? /\bbase\b/ : /.*/; + var _a = ["constructor", "toString", "valueOf"]; + var _j = detect("(jscript)") ? new RegExp("^" + rescape(isNaN).replace(/isNaN/, "\\w+") + "$") : { + test: False + }; + var _k = 1; + var _2 = Array.prototype.slice; + _5(); + + function assignID(a) { + if (!a.base2ID) a.base2ID = "b2_" + _k++; + return a.base2ID + }; + var _b = function(a, b) { + base2.__prototyping = this.prototype; + var c = new this; + if (a) extend(c, a); + delete base2.__prototyping; + var e = c.constructor; + + function d() { + if (!base2.__prototyping) { + if (this.constructor == arguments.callee || this.__constructing) { + this.__constructing = true; + e.apply(this, arguments); + delete this.__constructing + } else { + return extend(arguments[0], c) + } + } + return this + }; + c.constructor = d; + for (var f in Base) d[f] = this[f]; + d.ancestor = this; + d.base = Undefined; + if (b) extend(d, b); + d.prototype = c; + if (d.init) d.init(); + return d + }; + var Base = _b.call(Object, { + constructor: function() { + if (arguments.length > 0) { + this.extend(arguments[0]) + } + }, + base: function() {}, + extend: delegate(extend) + }, + Base = { + ancestorOf: function(a) { + return _7(this, a) + }, + extend: _b, + forEach: function(a, b, c) { + _5(this, a, b, c) + }, + implement: function(a) { + if (typeof a == "function") { + a = a.prototype + } + extend(this.prototype, a); + return this + } + }); + var Package = Base.extend({ + constructor: function(e, d) { + this.extend(d); + if (this.init) this.init(); + if (this.name && this.name != "base2") { + if (!this.parent) this.parent = base2; + this.parent.addName(this.name, this); + this.namespace = format("var %1=%2;", this.name, String2.slice(this, 1, -1)) + } + if (e) { + var f = base2.JavaScript ? base2.JavaScript.namespace : ""; + e.imports = Array2.reduce(csv(this.imports), + function(a, b) { + var c = h(b) || h("JavaScript." + b); + return a += c.namespace + }, + "var base2=(function(){return this.base2})();" + base2.namespace + f) + lang.namespace; + e.exports = Array2.reduce(csv(this.exports), + function(a, b) { + var c = this.name + "." + b; + this.namespace += "var " + b + "=" + c + ";"; + return a += "if(!" + c + ")" + c + "=" + b + ";" + }, + "", this) + "this._l" + this.name + "();"; + var g = this; + var i = String2.slice(this, 1, -1); + e["_l" + this.name] = function() { + Package.forEach(g, + function(a, b) { + if (a && a.ancestorOf == Base.ancestorOf) { + a.toString = K(format("[%1.%2]", i, b)); + if (a.prototype.toString == Base.prototype.toString) { + a.prototype.toString = K(format("[object %1.%2]", i, b)) + } + } + }) + } + } + + function h(a) { + a = a.split("."); + var b = base2, + c = 0; + while (b && a[c] != null) { + b = b[a[c++]] + } + return b + } + }, + exports: "", + imports: "", + name: "", + namespace: "", + parent: null, + addName: function(a, b) { + if (!this[a]) { + this[a] = b; + this.exports += "," + a; + this.namespace += format("var %1=%2.%1;", a, this.name) + } + }, + addPackage: function(a) { + this.addName(a, new Package(null, { + name: a, + parent: this + })) + }, + toString: function() { + return format("[%1]", this.parent ? String2.slice(this.parent, 1, -1) + "." + this.name : this.name) + } + }); + var Abstract = Base.extend({ + constructor: function() { + throw new TypeError("Abstract class cannot be instantiated."); + } + }); + var _m = 0; + var Module = Abstract.extend(null, { + namespace: "", + extend: function(a, b) { + var c = this.base(); + var e = _m++; + c.namespace = ""; + c.partial = this.partial; + c.toString = K("[base2.Module[" + e + "]]"); + Module[e] = c; + c.implement(this); + if (a) c.implement(a); + if (b) { + extend(c, b); + if (c.init) c.init() + } + return c + }, + forEach: function(c, e) { + _5(Module, this.prototype, + function(a, b) { + if (typeOf(a) == "function") { + c.call(e, this[b], b, this) + } + }, + this) + }, + implement: function(a) { + var b = this; + var c = b.toString().slice(1, -1); + if (typeof a == "function") { + if (!_7(a, b)) { + this.base(a) + } + if (_7(Module, a)) { + for (var e in a) { + if (b[e] === undefined) { + var d = a[e]; + if (typeof d == "function" && d.call && a.prototype[e]) { + d = _n(a, e) + } + b[e] = d + } + } + b.namespace += a.namespace.replace(/base2\.Module\[\d+\]/g, c) + } + } else { + extend(b, a); + _c(b, a) + } + return b + }, + partial: function() { + var c = Module.extend(); + var e = c.toString().slice(1, -1); + c.namespace = this.namespace.replace(/(\w+)=b[^\)]+\)/g, "$1=" + e + ".$1"); + this.forEach(function(a, b) { + c[b] = partial(bind(a, c)) + }); + return c + } + }); + + function _c(a, b) { + var c = a.prototype; + var e = a.toString().slice(1, -1); + for (var d in b) { + var f = b[d], + g = ""; + if (d.charAt(0) == "@") { + if (detect(d.slice(1))) _c(a, f) + } else if (!c[d]) { + if (d == d.toUpperCase()) { + g = "var " + d + "=" + e + "." + d + ";" + } else if (typeof f == "function" && f.call) { + g = "var " + d + "=base2.lang.bind('" + d + "'," + e + ");"; + c[d] = _o(a, d) + } + if (a.namespace.indexOf(g) == -1) { + a.namespace += g + } + } + } + }; + + function _n(a, b) { + return function() { + return a[b].apply(a, arguments) + } + }; + + function _o(b, c) { + return function() { + var a = _2.call(arguments); + a.unshift(this); + return b[c].apply(b, a) + } + }; + var Enumerable = Module.extend({ + every: function(c, e, d) { + var f = true; + try { + forEach(c, + function(a, b) { + f = e.call(d, a, b, c); + if (!f) throw StopIteration; + }) + } catch (error) { + if (error != StopIteration) throw error; + } + return !!f + }, + filter: function(e, d, f) { + var g = 0; + return this.reduce(e, + function(a, b, c) { + if (d.call(f, b, c, e)) { + a[g++] = b + } + return a + }, []) + }, + invoke: function(b, c) { + var e = _2.call(arguments, 2); + return this.map(b, (typeof c == "function") ? + function(a) { + return a == null ? undefined : c.apply(a, e) + } : function(a) { + return a == null ? undefined : a[c].apply(a, e) + }) + }, + map: function(c, e, d) { + var f = [], + g = 0; + forEach(c, + function(a, b) { + f[g++] = e.call(d, a, b, c) + }); + return f + }, + pluck: function(b, c) { + return this.map(b, + function(a) { + return a == null ? undefined : a[c] + }) + }, + reduce: function(c, e, d, f) { + var g = arguments.length > 2; + forEach(c, + function(a, b) { + if (g) { + d = e.call(f, d, a, b, c) + } else { + d = a; + g = true + } + }); + return d + }, + some: function(a, b, c) { + return !this.every(a, not(b), c) + } + }); + var _1 = "#"; + var Map = Base.extend({ + constructor: function(a) { + if (a) this.merge(a) + }, + clear: function() { + for (var a in this) + if (a.indexOf(_1) == 0) { + delete this[a] + } + }, + copy: function() { + base2.__prototyping = true; + var a = new this.constructor; + delete base2.__prototyping; + for (var b in this) + if (this[b] !== a[b]) { + a[b] = this[b] + } + return a + }, + forEach: function(a, b) { + for (var c in this) + if (c.indexOf(_1) == 0) { + a.call(b, this[c], c.slice(1), this) + } + }, + get: function(a) { + return this[_1 + a] + }, + getKeys: function() { + return this.map(II) + }, + getValues: function() { + return this.map(I) + }, + has: function(a) { + /*@cc_on @*/ + /*@if(@_jscript_version<5.5)return $Legacy.has(this,_1+a);@else @*/ + return _1 + a in this; + /*@end @*/ + }, + merge: function(b) { + var c = flip(this.put); + forEach(arguments, + function(a) { + forEach(a, c, this) + }, + this); + return this + }, + put: function(a, b) { + this[_1 + a] = b + }, + remove: function(a) { + delete this[_1 + a] + }, + size: function() { + var a = 0; + for (var b in this) + if (b.indexOf(_1) == 0) a++; + return a + }, + union: function(a) { + return this.merge.apply(this.copy(), arguments) + } + }); + Map.implement(Enumerable); + Map.prototype.filter = function(e, d) { + return this.reduce(function(a, b, c) { + if (!e.call(d, b, c, this)) { + a.remove(c) + } + return a + }, + this.copy(), this) + }; + var _0 = "~"; + var Collection = Map.extend({ + constructor: function(a) { + this[_0] = new Array2; + this.base(a) + }, + add: function(a, b) { + assert(!this.has(a), "Duplicate key '" + a + "'."); + this.put.apply(this, arguments) + }, + clear: function() { + this.base(); + this[_0].length = 0 + }, + copy: function() { + var a = this.base(); + a[_0] = this[_0].copy(); + return a + }, + forEach: function(a, b) { + var c = this[_0]; + var e = c.length; + for (var d = 0; d < e; d++) { + a.call(b, this[_1 + c[d]], c[d], this) + } + }, + getAt: function(a) { + var b = this[_0].item(a); + return (b === undefined) ? undefined : this[_1 + b] + }, + getKeys: function() { + return this[_0].copy() + }, + indexOf: function(a) { + return this[_0].indexOf(String(a)) + }, + insertAt: function(a, b, c) { + assert(this[_0].item(a) !== undefined, "Index out of bounds."); + assert(!this.has(b), "Duplicate key '" + b + "'."); + this[_0].insertAt(a, String(b)); + this[_1 + b] = null; + this.put.apply(this, _2.call(arguments, 1)) + }, + item: function(a) { + return this[typeof a == "number" ? "getAt" : "get"](a) + }, + put: function(a, b) { + if (!this.has(a)) { + this[_0].push(String(a)) + } + var c = this.constructor; + if (c.Item && !instanceOf(b, c.Item)) { + b = c.create.apply(c, arguments) + } + this[_1 + a] = b + }, + putAt: function(a, b) { + arguments[0] = this[_0].item(a); + assert(arguments[0] !== undefined, "Index out of bounds."); + this.put.apply(this, arguments) + }, + remove: function(a) { + if (this.has(a)) { + this[_0].remove(String(a)); + delete this[_1 + a] + } + }, + removeAt: function(a) { + var b = this[_0].item(a); + if (b !== undefined) { + this[_0].removeAt(a); + delete this[_1 + b] + } + }, + reverse: function() { + this[_0].reverse(); + return this + }, + size: function() { + return this[_0].length + }, + slice: function(a, b) { + var c = this.copy(); + if (arguments.length > 0) { + var e = this[_0], + d = e; + c[_0] = Array2(_2.apply(e, arguments)); + if (c[_0].length) { + d = d.slice(0, a); + if (arguments.length > 1) { + d = d.concat(e.slice(b)) + } + } + for (var f = 0; f < d.length; f++) { + delete c[_1 + d[f]] + } + } + return c + }, + sort: function(c) { + if (c) { + this[_0].sort(bind(function(a, b) { + return c(this[_1 + a], this[_1 + b], a, b) + }, + this)) + } else this[_0].sort(); + return this + }, + toString: function() { + return "(" + (this[_0] || "") + ")" + } + }, { + Item: null, + create: function(a, b) { + return this.Item ? new this.Item(a, b) : b + }, + extend: function(a, b) { + var c = this.base(a); + c.create = this.create; + if (b) extend(c, b); + if (!c.Item) { + c.Item = this.Item + } else if (typeof c.Item != "function") { + c.Item = (this.Item || Base).extend(c.Item) + } + if (c.init) c.init(); + return c + } + }); + var _p = /\\(\d+)/g, + _q = /\\./g, + _r = /\(\?[:=!]|\[[^\]]+\]/g, + _s = /\(/g, + _t = /\$(\d+)/, + _u = /^\$\d+$/; + var RegGrp = Collection.extend({ + constructor: function(a, b) { + this.base(a); + this.ignoreCase = !!b + }, + ignoreCase: false, + exec: function(g, i) { + g += ""; + var h = this, + j = this[_0]; + if (!j.length) return g; + if (i == RegGrp.IGNORE) i = 0; + return g.replace(new RegExp(this, this.ignoreCase ? "gi" : "g"), + function(a) { + var b, c = 1, + e = 0; + while ((b = h[_1 + j[e++]])) { + var d = c + b.length + 1; + if (arguments[c]) { + var f = i == null ? b.replacement : i; + switch (typeof f) { + case "function": + return f.apply(h, _2.call(arguments, c, d)); + case "number": + return arguments[c + f]; + default: + return f + } + } + c = d + } + return a + }) + }, + insertAt: function(a, b, c) { + if (instanceOf(b, RegExp)) { + arguments[1] = b.source + } + return base(this, arguments) + }, + test: function(a) { + return this.exec(a) != a + }, + toString: function() { + var d = 1; + return "(" + this.map(function(c) { + var e = (c + "").replace(_p, + function(a, b) { + return "\\" + (d + Number(b)) + }); + d += c.length + 1; + return e + }).join(")|(") + ")" + } + }, { + IGNORE: "$0", + init: function() { + forEach("add,get,has,put,remove".split(","), + function(b) { + _8(this, b, + function(a) { + if (instanceOf(a, RegExp)) { + arguments[0] = a.source + } + return base(this, arguments) + }) + }, + this.prototype) + }, + Item: { + constructor: function(a, b) { + if (b == null) b = RegGrp.IGNORE; + else if (b.replacement != null) b = b.replacement; + else if (typeof b != "function") b = String(b); + if (typeof b == "string" && _t.test(b)) { + if (_u.test(b)) { + b = parseInt(b.slice(1)) + } else { + var c = '"'; + b = b.replace(/\\/g, "\\\\").replace(/"/g, "\\x22").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\$(\d+)/g, c + "+(arguments[$1]||" + c + c + ")+" + c).replace(/(['"])\1\+(.*)\+\1\1$/, "$1"); + b = new Function("return " + c + b + c) + } + } + this.length = RegGrp.count(a); + this.replacement = b; + this.toString = K(a + "") + }, + length: 0, + replacement: "" + }, + count: function(a) { + a = (a + "").replace(_q, "").replace(_r, ""); + return match(a, _s).length + } + }); + var lang = { + name: "lang", + version: base2.version, + exports: "assert,assertArity,assertType,base,bind,copy,extend,forEach,format,instanceOf,match,pcopy,rescape,trim,typeOf", + namespace: "" + }; + + function assert(a, b, c) { + if (!a) { + throw new(c || Error)(b || "Assertion failed."); + } + }; + + function assertArity(a, b, c) { + if (b == null) b = a.callee.length; + if (a.length < b) { + throw new SyntaxError(c || "Not enough arguments."); + } + }; + + function assertType(a, b, c) { + if (b && (typeof b == "function" ? !instanceOf(a, b) : typeOf(a) != b)) { + throw new TypeError(c || "Invalid type."); + } + }; + + function copy(a) { + var b = {}; + for (var c in a) { + b[c] = a[c] + } + return b + }; + + function pcopy(a) { + _d.prototype = a; + return new _d + }; + + function _d() {}; + + function base(a, b) { + return a.base.apply(a, b) + }; + + function extend(a, b) { + if (a && b) { + if (arguments.length > 2) { + var c = b; + b = {}; + b[c] = arguments[2] + } + var e = global[(typeof b == "function" ? "Function" : "Object")].prototype; + if (base2.__prototyping) { + var d = _a.length, + c; + while ((c = _a[--d])) { + var f = b[c]; + if (f != e[c]) { + if (_9.test(f)) { + _8(a, c, f) + } else { + a[c] = f + } + } + } + } + for (c in b) { + if (e[c] === undefined) { + var f = b[c]; + if (c.charAt(0) == "@") { + if (detect(c.slice(1))) extend(a, f) + } else { + var g = a[c]; + if (g && typeof f == "function") { + if (f != g) { + if (_9.test(f)) { + _8(a, c, f) + } else { + f.ancestor = g; + a[c] = f + } + } + } else { + a[c] = f + } + } + } + } + } + return a + }; + + function _7(a, b) { + while (b) { + if (!b.ancestor) return false; + b = b.ancestor; + if (b == a) return true + } + return false + }; + + function _8(c, e, d) { + var f = c[e]; + var g = base2.__prototyping; + if (g && f != g[e]) g = null; + + function i() { + var a = this.base; + this.base = g ? g[e] : f; + var b = d.apply(this, arguments); + this.base = a; + return b + }; + i.method = d; + i.ancestor = f; + c[e] = i + }; + if (typeof StopIteration == "undefined") { + StopIteration = new Error("StopIteration") + } + + function forEach(a, b, c, e) { + if (a == null) return; + if (!e) { + if (typeof a == "function" && a.call) { + e = Function + } else if (typeof a.forEach == "function" && a.forEach != arguments.callee) { + a.forEach(b, c); + return + } else if (typeof a.length == "number") { + _e(a, b, c); + return + } + } + _5(e || Object, a, b, c) + }; + forEach.csv = function(a, b, c) { + forEach(csv(a), b, c) + }; + forEach.detect = function(c, e, d) { + forEach(c, + function(a, b) { + if (b.charAt(0) == "@") { + if (detect(b.slice(1))) forEach(a, arguments.callee) + } else e.call(d, a, b, c) + }) + }; + + function _e(a, b, c) { + if (a == null) a = global; + var e = a.length || 0, + d; + if (typeof a == "string") { + for (d = 0; d < e; d++) { + b.call(c, a.charAt(d), d, a) + } + } else { + for (d = 0; d < e; d++) { + /*@cc_on @*/ + /*@if(@_jscript_version<5.2)if($Legacy.has(a,d))@else @*/ + if (d in a) + /*@end @*/ + b.call(c, a[d], d, a) + } + } + }; + + function _5(g, i, h, j) { + var k = function() { + this.i = 1 + }; + k.prototype = { + i: 1 + }; + var l = 0; + for (var m in new k) l++; + _5 = (l > 1) ? + function(a, b, c, e) { + var d = {}; + for (var f in b) { + if (!d[f] && a.prototype[f] === undefined) { + d[f] = true; + c.call(e, b[f], f, b) + } + } + } : function(a, b, c, e) { + for (var d in b) { + if (a.prototype[d] === undefined) { + c.call(e, b[d], d, b) + } + } + }; + _5(g, i, h, j) + }; + + function instanceOf(a, b) { + if (typeof b != "function") { + throw new TypeError("Invalid 'instanceOf' operand."); + } + if (a == null) return false; + /*@cc_on if(typeof a.constructor!="function"){return typeOf(a)==typeof b.prototype.valueOf()}@*/ + if (a.constructor == b) return true; + if (b.ancestorOf) return b.ancestorOf(a.constructor); + /*@if(@_jscript_version<5.1)@else @*/ + if (a instanceof b) return true; + /*@end @*/ + if (Base.ancestorOf == b.ancestorOf) return false; + if (Base.ancestorOf == a.constructor.ancestorOf) return b == Object; + switch (b) { + case Array: + return !!(typeof a == "object" && a.join && a.splice); + case Function: + return typeOf(a) == "function"; + case RegExp: + return typeof a.constructor.$1 == "string"; + case Date: + return !!a.getTimezoneOffset; + case String: + case Number: + case Boolean: + return typeOf(a) == typeof b.prototype.valueOf(); + case Object: + return true + } + return false + }; + + function typeOf(a) { + var b = typeof a; + switch (b) { + case "object": + return a == null ? "null" : typeof a.constructor == "undefined" ? _j.test(a) ? "function" : b : typeof a.constructor.prototype.valueOf(); + case "function": + return typeof a.call == "function" ? b : "object"; + default: + return b + } + }; + var JavaScript = { + name: "JavaScript", + version: base2.version, + exports: "Array2,Date2,Function2,String2", + namespace: "", + bind: function(c) { + var e = global; + global = c; + forEach.csv(this.exports, + function(a) { + var b = a.slice(0, -1); + extend(c[b], this[a]); + this[a](c[b].prototype) + }, + this); + global = e; + return c + } + }; + + function _6(b, c, e, d) { + var f = Module.extend(); + var g = f.toString().slice(1, -1); + forEach.csv(e, + function(a) { + f[a] = unbind(b.prototype[a]); + f.namespace += format("var %1=%2.%1;", a, g) + }); + forEach(_2.call(arguments, 3), f.implement, f); + var i = function() { + return f(this.constructor == f ? c.apply(null, arguments) : arguments[0]) + }; + i.prototype = f.prototype; + for (var h in f) { + if (h != "prototype" && b[h]) { + f[h] = b[h]; + delete f.prototype[h] + } + i[h] = f[h] + } + i.ancestor = Object; + delete i.extend; + i.namespace = i.namespace.replace(/(var (\w+)=)[^,;]+,([^\)]+)\)/g, "$1$3.$2"); + return i + }; + if ((new Date).getYear() > 1900) { + Date.prototype.getYear = function() { + return this.getFullYear() - 1900 + }; + Date.prototype.setYear = function(a) { + return this.setFullYear(a + 1900) + } + } + var _f = new Date(Date.UTC(2006, 1, 20)); + _f.setUTCDate(15); + if (_f.getUTCHours() != 0) { + forEach.csv("FullYear,Month,Date,Hours,Minutes,Seconds,Milliseconds", + function(b) { + extend(Date.prototype, "setUTC" + b, + function() { + var a = base(this, arguments); + if (a >= 57722401000) { + a -= 3600000; + this.setTime(a) + } + return a + }) + }) + } + Function.prototype.prototype = {}; + if ("".replace(/^/, K("$$")) == "$") { + extend(String.prototype, "replace", + function(a, b) { + if (typeof b == "function") { + var c = b; + b = function() { + return String(c.apply(null, arguments)).split("$").join("$$") + } + } + return this.base(a, b) + }) + } + var Array2 = _6(Array, Array, "concat,join,pop,push,reverse,shift,slice,sort,splice,unshift", Enumerable, { + combine: function(e, d) { + if (!d) d = e; + return Array2.reduce(e, + function(a, b, c) { + a[b] = d[c]; + return a + }, {}) + }, + contains: function(a, b) { + return Array2.indexOf(a, b) != -1 + }, + copy: function(a) { + var b = _2.call(a); + if (!b.swap) Array2(b); + return b + }, + flatten: function(c) { + var e = 0; + return Array2.reduce(c, + function(a, b) { + if (Array2.like(b)) { + Array2.reduce(b, arguments.callee, a) + } else { + a[e++] = b + } + return a + }, []) + }, + forEach: _e, + indexOf: function(a, b, c) { + var e = a.length; + if (c == null) { + c = 0 + } else if (c < 0) { + c = Math.max(0, e + c) + } + for (var d = c; d < e; d++) { + if (a[d] === b) return d + } + return -1 + }, + insertAt: function(a, b, c) { + Array2.splice(a, b, 0, c); + return c + }, + item: function(a, b) { + if (b < 0) b += a.length; + return a[b] + }, + lastIndexOf: function(a, b, c) { + var e = a.length; + if (c == null) { + c = e - 1 + } else if (c < 0) { + c = Math.max(0, e + c) + } + for (var d = c; d >= 0; d--) { + if (a[d] === b) return d + } + return -1 + }, + map: function(c, e, d) { + var f = []; + Array2.forEach(c, + function(a, b) { + f[b] = e.call(d, a, b, c) + }); + return f + }, + remove: function(a, b) { + var c = Array2.indexOf(a, b); + if (c != -1) Array2.removeAt(a, c) + }, + removeAt: function(a, b) { + Array2.splice(a, b, 1) + }, + swap: function(a, b, c) { + if (b < 0) b += a.length; + if (c < 0) c += a.length; + var e = a[b]; + a[b] = a[c]; + a[c] = e; + return a + } + }); + Array2.reduce = Enumerable.reduce; + Array2.like = function(a) { + return typeOf(a) == "object" && typeof a.length == "number" + }; + var _v = /^((-\d+|\d{4,})(-(\d{2})(-(\d{2}))?)?)?T((\d{2})(:(\d{2})(:(\d{2})(\.(\d{1,3})(\d)?\d*)?)?)?)?(([+-])(\d{2})(:(\d{2}))?|Z)?$/; + var _4 = { + FullYear: 2, + Month: 4, + Date: 6, + Hours: 8, + Minutes: 10, + Seconds: 12, + Milliseconds: 14 + }; + var _3 = { + Hectomicroseconds: 15, + UTC: 16, + Sign: 17, + Hours: 18, + Minutes: 20 + }; + var _w = /(((00)?:0+)?:0+)?\.0+$/; + var _x = /(T[0-9:.]+)$/; + var Date2 = _6(Date, + function(a, b, c, e, d, f, g) { + switch (arguments.length) { + case 0: + return new Date; + case 1: + return typeof a == "number" ? new Date(a) : Date2.parse(a); + default: + return new Date(a, b, arguments.length == 2 ? 1 : c, e || 0, d || 0, f || 0, g || 0) + } + }, + "", { + toISOString: function(c) { + var e = "####-##-##T##:##:##.###"; + for (var d in _4) { + e = e.replace(/#+/, + function(a) { + var b = c["getUTC" + d](); + if (d == "Month") b++; + return ("000" + b).slice(-a.length) + }) + } + return e.replace(_w, "").replace(_x, "$1Z") + } + }); + delete Date2.forEach; + Date2.now = function() { + return (new Date).valueOf() + }; + Date2.parse = function(a, b) { + if (arguments.length > 1) { + assertType(b, "number", "default date should be of type 'number'.") + } + var c = match(a, _v); + if (c.length) { + if (c[_4.Month]) c[_4.Month] --; + if (c[_3.Hectomicroseconds] >= 5) c[_4.Milliseconds] ++; + var e = new Date(b || 0); + var d = c[_3.UTC] || c[_3.Hours] ? "UTC" : ""; + for (var f in _4) { + var g = c[_4[f]]; + if (!g) continue; + e["set" + d + f](g); + if (e["get" + d + f]() != c[_4[f]]) { + return NaN + } + } + if (c[_3.Hours]) { + var i = Number(c[_3.Sign] + c[_3.Hours]); + var h = Number(c[_3.Sign] + (c[_3.Minutes] || 0)); + e.setUTCMinutes(e.getUTCMinutes() + (i * 60) + h) + } + return e.valueOf() + } else { + return Date.parse(a) + } + }; + var String2 = _6(String, + function(a) { + return new String(arguments.length == 0 ? "" : a) + }, + "charAt,charCodeAt,concat,indexOf,lastIndexOf,match,replace,search,slice,split,substr,substring,toLowerCase,toUpperCase", { + csv: csv, + format: format, + rescape: rescape, + trim: trim + }); + delete String2.forEach; + + function trim(a) { + return String(a).replace(_g, "").replace(_h, "") + }; + + function csv(a) { + return a ? (a + "").split(/\s*,\s*/) : [] + }; + + function format(c) { + var e = arguments; + var d = new RegExp("%([1-" + (arguments.length - 1) + "])", "g"); + return (c + "").replace(d, + function(a, b) { + return e[b] + }) + }; + + function match(a, b) { + return (a + "").match(b) || [] + }; + + function rescape(a) { + return (a + "").replace(_i, "\\$1") + }; + var Function2 = _6(Function, Function, "", { + I: I, + II: II, + K: K, + bind: bind, + compose: compose, + delegate: delegate, + flip: flip, + not: not, + partial: partial, + unbind: unbind + }); + + function I(a) { + return a + }; + + function II(a, b) { + return b + }; + + function K(a) { + return function() { + return a + } + }; + + function bind(a, b) { + var c = typeof a != "function"; + if (arguments.length > 2) { + var e = _2.call(arguments, 2); + return function() { + return (c ? b[a] : a).apply(b, e.concat.apply(e, arguments)) + } + } else { + return function() { + return (c ? b[a] : a).apply(b, arguments) + } + } + }; + + function compose() { + var c = _2.call(arguments); + return function() { + var a = c.length, + b = c[--a].apply(this, arguments); + while (a--) b = c[a].call(this, b); + return b + } + }; + + function delegate(b, c) { + return function() { + var a = _2.call(arguments); + a.unshift(this); + return b.apply(c, a) + } + }; + + function flip(a) { + return function() { + return a.apply(this, Array2.swap(arguments, 0, 1)) + } + }; + + function not(a) { + return function() { + return !a.apply(this, arguments) + } + }; + + function partial(e) { + var d = _2.call(arguments, 1); + return function() { + var a = d.concat(), + b = 0, + c = 0; + while (b < d.length && c < arguments.length) { + if (a[b] === undefined) a[b] = arguments[c++]; + b++ + } + while (c < arguments.length) { + a[b++] = arguments[c++] + } + if (Array2.contains(a, undefined)) { + a.unshift(e); + return partial.apply(null, a) + } + return e.apply(this, a) + } + }; + + function unbind(b) { + return function(a) { + return b.apply(a, _2.call(arguments, 1)) + } + }; + + function detect() { + var d = NaN + /*@cc_on||@_jscript_version@*/ + ; + var f = global.java ? true : false; + if (global.navigator) { + var g = /MSIE[\d.]+/g; + var i = document.createElement("span"); + var h = navigator.userAgent.replace(/([a-z])[\s\/](\d)/gi, "$1$2"); + if (!d) h = h.replace(g, ""); + if (g.test(h)) h = h.match(g)[0] + " " + h.replace(g, ""); + base2.userAgent = navigator.platform + " " + h.replace(/like \w+/gi, ""); + f &= navigator.javaEnabled() + } + var j = {}; + detect = function(a) { + if (j[a] == null) { + var b = false, + c = a; + var e = c.charAt(0) == "!"; + if (e) c = c.slice(1); + if (c.charAt(0) == "(") { + try { + b = new Function("element,jscript,java,global", "return !!" + c)(i, d, f, global) + } catch (ex) {} + } else { + b = new RegExp("(" + c + ")", "i").test(base2.userAgent) + } + j[a] = !!(e ^ b) + } + return j[a] + }; + return detect(arguments[0]) + }; + base2 = global.base2 = new Package(this, base2); + var exports = this.exports; + lang = new Package(this, lang); + exports += this.exports; + JavaScript = new Package(this, JavaScript); + eval(exports + this.exports); + lang.base = base; + lang.extend = extend +}; + +new function() { + new base2.Package(this, { + imports: "Function2,Enumerable" + }); + eval(this.imports); + var i = RegGrp.IGNORE; + var S = "~"; + var A = ""; + var F = " "; + var p = RegGrp.extend({ + put: function(a, c) { + if (typeOf(a) == "string") { + a = p.dictionary.exec(a) + } + this.base(a, c) + } + }, { + dictionary: new RegGrp({ + OPERATOR: /return|typeof|[\[(\^=,{}:;&|!*?]/.source, + CONDITIONAL: /\/\*@\w*|\w*@\*\/|\/\/@\w*|@\w+/.source, + COMMENT1: /\/\/[^\n]*/.source, + COMMENT2: /\/\*[^*]*\*+([^\/][^*]*\*+)*\//.source, + REGEXP: /\/(\\[\/\\]|[^*\/])(\\.|[^\/\n\\])*\/[gim]*/.source, + STRING1: /'(\\.|[^'\\])*'/.source, + STRING2: /"(\\.|[^"\\])*"/.source + }) + }); + var B = Collection.extend({ + add: function(a) { + if (!this.has(a)) this.base(a); + a = this.get(a); + if (!a.index) { + a.index = this.size() + } + a.count++; + return a + }, + sort: function(d) { + return this.base(d || function(a, c) { + return (c.count - a.count) || (a.index - c.index) + }) + } + }, { + Item: { + constructor: function(a) { + this.toString = K(a) + }, + index: 0, + count: 0, + encoded: "" + } + }); + var v = Base.extend({ + constructor: function(a, c, d) { + this.parser = new p(d); + if (a) this.parser.put(a, ""); + this.encoder = c + }, + parser: null, + encoder: Undefined, + search: function(c) { + var d = new B; + this.parser.putAt(-1, function(a) { + d.add(a) + }); + this.parser.exec(c); + return d + }, + encode: function(c) { + var d = this.search(c); + d.sort(); + var b = 0; + forEach(d, function(a) { + a.encoded = this.encoder(b++) + }, this); + this.parser.putAt(-1, function(a) { + return d.get(a).encoded + }); + return this.parser.exec(c) + } + }); + var w = v.extend({ + constructor: function() { + return this.base(w.PATTERN, function(a) { + return "_" + Packer.encode62(a) + }, w.IGNORE) + } + }, { + IGNORE: { + CONDITIONAL: i, + "(OPERATOR)(REGEXP)": i + }, + PATTERN: /\b_[\da-zA-Z$][\w$]*\b/g + }); + var q = v.extend({ + encode: function(d) { + var b = this.search(d); + b.sort(); + var f = new Collection; + var e = b.size(); + for (var h = 0; h < e; h++) { + f.put(Packer.encode62(h), h) + } + + function C(a) { + return b["#" + a].replacement + }; + var k = K(""); + var l = 0; + forEach(b, function(a) { + if (f.has(a)) { + a.index = f.get(a); + a.toString = k + } else { + while (b.has(Packer.encode62(l))) l++; + a.index = l++; + if (a.count == 1) { + a.toString = k + } + } + a.replacement = Packer.encode62(a.index); + if (a.replacement.length == a.toString().length) { + a.toString = k + } + }); + b.sort(function(a, c) { + return a.index - c.index + }); + b = b.slice(0, this.getKeyWords(b).split("|").length); + d = d.replace(this.getPattern(b), C); + var r = this.escape(d); + var m = "[]"; + var t = this.getCount(b); + var g = this.getKeyWords(b); + var n = this.getEncoder(b); + var u = this.getDecoder(b); + return format(q.UNPACK, r, m, t, g, n, u) + }, + search: function(a) { + var c = new B; + forEach(a.match(q.WORDS), c.add, c); + return c + }, + escape: function(a) { + return a.replace(/([\\'])/g, "\\$1").replace(/[\r\n]+/g, "\\n") + }, + getCount: function(a) { + return a.size() || 1 + }, + getDecoder: function(c) { + var d = new RegGrp({ + "(\\d)(\\|\\d)+\\|(\\d)": "$1-$3", + "([a-z])(\\|[a-z])+\\|([a-z])": "$1-$3", + "([A-Z])(\\|[A-Z])+\\|([A-Z])": "$1-$3", + "\\|": "" + }); + var b = d.exec(c.map(function(a) { + if (a.toString()) return a.replacement; + return "" + }).slice(0, 62).join("|")); + if (!b) return "^$"; + b = "[" + b + "]"; + var f = c.size(); + if (f > 62) { + b = "(" + b + "|"; + var e = Packer.encode62(f).charAt(0); + if (e > "9") { + b += "[\\\\d"; + if (e >= "a") { + b += "a"; + if (e >= "z") { + b += "-z"; + if (e >= "A") { + b += "A"; + if (e > "A") b += "-" + e + } + } else if (e == "b") { + b += "-" + e + } + } + b += "]" + } else if (e == 9) { + b += "\\\\d" + } else if (e == 2) { + b += "[12]" + } else if (e == 1) { + b += "1" + } else { + b += "[1-" + e + "]" + } + b += "\\\\w)" + } + return b + }, + getEncoder: function(a) { + var c = a.size(); + return q["ENCODE" + (c > 10 ? c > 36 ? 62 : 36 : 10)] + }, + getKeyWords: function(a) { + return a.map(String).join("|").replace(/\|+$/, "") + }, + getPattern: function(a) { + var a = a.map(String).join("|").replace(/\|{2,}/g, "|").replace(/^\|+|\|+$/g, "") || "\\x0"; + return new RegExp("\\b(" + a + ")\\b", "g") + } + }, { + WORDS: /\b[\da-zA-Z]\b|\w{2,}/g, + ENCODE10: "String", + ENCODE36: "function(c){return c.toString(36)}", + ENCODE62: "function(c){return(c<62?'':e(parseInt(c/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))}", + UNPACK: "eval(function(p,a,c,k,e,r){e=%5;if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'%6'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('%1',%2,%3,'%4'.split('|'),0,{}))" + }); + global.Packer = Base.extend({ + constructor: function() { + this.minifier = new j; + this.shrinker = new o; + this.privates = new w; + this.base62 = new q + }, + minifier: null, + shrinker: null, + privates: null, + base62: null, + pack: function(a, c, d, b) { + a = this.minifier.minify(a); + if (d) a = this.shrinker.shrink(a); + if (b) a = this.privates.encode(a); + if (c) a = this.base62.encode(a); + return a + } + }, { + version: "3.1", + init: function() { + eval("var e=this.encode62=" + q.ENCODE62) + }, + data: new p({ + "STRING1": i, + 'STRING2': i, + "CONDITIONAL": i, + "(OPERATOR)\\s*(REGEXP)": "$1$2" + }), + encode52: function(c) { + function d(a) { + return (a < 52 ? '' : d(parseInt(a / 52))) + ((a = a % 52) > 25 ? String.fromCharCode(a + 39) : String.fromCharCode(a + 97)) + }; + var b = d(c); + if (/^(do|if|in)$/.test(b)) b = b.slice(1) + 0; + return b + } + }); + var j = Base.extend({ + minify: function(a) { + a += "\n"; + a = a.replace(j.CONTINUE, ""); + a = j.comments.exec(a); + a = j.clean.exec(a); + a = j.whitespace.exec(a); + a = j.concat.exec(a); + return a + } + }, { + CONTINUE: /\\\r?\n/g, + init: function() { + this.concat = new p(this.concat).merge(Packer.data); + extend(this.concat, "exec", function(a) { + var c = this.base(a); + while (c != a) { + a = c; + c = this.base(a) + } + return c + }); + forEach.csv("comments,clean,whitespace", function(a) { + this[a] = Packer.data.union(new p(this[a])) + }, this); + this.conditionalComments = this.comments.copy(); + this.conditionalComments.putAt(-1, " $3"); + this.whitespace.removeAt(2); + this.comments.removeAt(2) + }, + clean: { + "\\(\\s*([^;)]*)\\s*;\\s*([^;)]*)\\s*;\\s*([^;)]*)\\)": "($1;$2;$3)", + "throw[^};]+[};]": i, + ";+\\s*([};])": "$1" + }, + comments: { + ";;;[^\\n]*\\n": A, + "(COMMENT1)\\n\\s*(REGEXP)?": "\n$3", + "(COMMENT2)\\s*(REGEXP)?": function(a, c, d, b) { + if (/^\/\*@/.test(c) && /@\*\/$/.test(c)) { + c = j.conditionalComments.exec(c) + } else { + c = "" + } + return c + " " + (b || "") + } + }, + concat: { + "(STRING1)\\+(STRING1)": function(a, c, d, b) { + return c.slice(0, -1) + b.slice(1) + }, + "(STRING2)\\+(STRING2)": function(a, c, d, b) { + return c.slice(0, -1) + b.slice(1) + } + }, + whitespace: { + "\\/\\/@[^\\n]*\\n": i, + "@\\s+\\b": "@ ", + "\\b\\s+@": " @", + "(\\d)\\s+(\\.\\s*[a-z\\$_\\[(])": "$1 $2", + "([+-])\\s+([+-])": "$1 $2", + "\\b\\s+\\$\\s+\\b": " $ ", + "\\$\\s+\\b": "$ ", + "\\b\\s+\\$": " $", + "\\b\\s+\\b": F, + "\\s+": A + } + }); + var o = Base.extend({ + decodeData: function(d) { + var b = this._data; + delete this._data; + return d.replace(o.ENCODED_DATA, function(a, c) { + return b[c] + }) + }, + encodeData: function(f) { + var e = this._data = []; + return Packer.data.exec(f, function(a, c, d) { + var b = "\x01" + e.length + "\x01"; + if (d) { + b = c + b; + a = d + } + e.push(a); + return b + }) + }, + shrink: function(g) { + g = this.encodeData(g); + + function n(a) { + return new RegExp(a.source, "g") + }; + var u = /((catch|do|if|while|with|function)\b[^~{};]*(\(\s*[^{};]*\s*\))\s*)?(\{[^{}]*\})/; + var G = n(u); + var x = /\{[^{}]*\}|\[[^\[\]]*\]|\([^\(\)]*\)|~[^~]+~/; + var H = n(x); + var D = /~#?(\d+)~/; + var I = /[a-zA-Z_$][\w\$]*/g; + var J = /~#(\d+)~/; + var L = /\bvar\b/g; + var M = /\bvar\s+[\w$]+[^;#]*|\bfunction\s+[\w$]+/g; + var N = /\b(var|function)\b|\sin\s+[^;]+/g; + var O = /\s*=[^,;]*/g; + var s = []; + var E = 0; + + function P(a, c, d, b, f) { + if (!c) c = ""; + if (d == "function") { + f = b + y(f, J); + c = c.replace(x, ""); + b = b.slice(1, -1); + if (b != "_no_shrink_") { + var e = match(f, M).join(";").replace(L, ";var"); + while (x.test(e)) { + e = e.replace(H, "") + } + e = e.replace(N, "").replace(O, "") + } + f = y(f, D); + if (b != "_no_shrink_") { + var h = 0, + C; + var k = match([b, e], I); + var l = {}; + for (var r = 0; r < k.length; r++) { + id = k[r]; + if (!l["#" + id]) { + l["#" + id] = true; + id = rescape(id); + while (new RegExp(o.PREFIX + h + "\\b").test(f)) h++; + var m = new RegExp("([^\\w$.])" + id + "([^\\w$:])"); + while (m.test(f)) { + f = f.replace(n(m), "$1" + o.PREFIX + h + "$2") + } + var m = new RegExp("([^{,\\w$.])" + id + ":", "g"); + f = f.replace(m, "$1" + o.PREFIX + h + ":"); + h++ + } + } + E = Math.max(E, h) + } + var t = c + "~" + s.length + "~"; + s.push(f) + } else { + var t = "~#" + s.length + "~"; + s.push(c + f) + } + return t + }; + + function y(d, b) { + while (b.test(d)) { + d = d.replace(n(b), function(a, c) { + return s[c] + }) + } + return d + }; + while (u.test(g)) { + g = g.replace(G, P) + } + g = y(g, D); + var z, Q = 0; + var R = new v(o.SHRUNK, function() { + do z = Packer.encode52(Q++); while (new RegExp("[^\\w$.]" + z + "[^\\w$:]").test(g)); + return z + }); + g = R.encode(g); + return this.decodeData(g) + } + }, { + ENCODED_DATA: /\x01(\d+)\x01/g, + PREFIX: "\x02", + SHRUNK: /\x02\d+\b/g + }) +}; diff --git a/v2ray/v2ray/res/v2ray_log.htm b/v2ray/v2ray/res/v2ray_log.htm new file mode 100644 index 0000000..34a977d --- /dev/null +++ b/v2ray/v2ray/res/v2ray_log.htm @@ -0,0 +1 @@ +<% nvram_dump("v2ray.log",""); %> diff --git a/v2ray/v2ray/scripts/softcenter_v2ray.sh b/v2ray/v2ray/scripts/softcenter_v2ray.sh deleted file mode 100644 index bd7126c..0000000 --- a/v2ray/v2ray/scripts/softcenter_v2ray.sh +++ /dev/null @@ -1,269 +0,0 @@ -#!/bin/sh - -udp_enable=`nvram get v2ray_udp_enable` -v2ray_user=`nvram get v2ray_user` -v2ray_sip=`nvram get v2ray_srcip` -dns_mode=`nvram get v2ray_dnsmode` -ss_dns_china=`nvram get v2ray_dns` -mdisk=`nvram get k3c_disk` -usb_disk="/tmp/mnt/$mdisk" -usbmount=`ls /tmp/mnt/` -V2RAY_CONFIG_FILE="/tmp/etc/v2rayconfig.json" -TEMP_CONFIG_FILE="/tmp/v2rayconfig.pb" - -gen_conf() { -json_data=`/jffs/softcenter/bin/jq . $V2RAY_CONFIG_FILE` -/jffs/softcenter/bin/jq -e . $V2RAY_CONFIG_FILE >/dev/null 2>&1 || return 2 -local json_key="socks" -local json_value="\"dokodemo-door\"" -local line_data=$(echo "$json_data" | grep -w "$json_key" ) -[ "${line_data:$((${#line_data}-1))}" = "," ] && json_value="${json_value}," -local json_new_data=$(echo "$json_data" | sed "s/$line_data/ \"protocol\": $json_value/") -echo "$json_new_data" | /jffs/softcenter/bin/jq -e . >/dev/null 2>&1 || return 3 -json_data="$json_new_data" && echo "$json_data" > $V2RAY_CONFIG_FILE -} -gen_conf1() { -json_data=`/jffs/softcenter/bin/jq . $V2RAY_CONFIG_FILE` -/jffs/softcenter/bin/jq -e . $V2RAY_CONFIG_FILE >/dev/null 2>&1 || return 2 -local json_key="1080," -local json_value="1234" -local line_data=$(echo "$json_data" | grep -w "$json_key" ) -[ "${line_data:$((${#line_data}-1))}" = "," ] && json_value="${json_value}," -local json_new_data=$(echo "$json_data" | sed "s/$line_data/ \"port\": $json_value/") -echo "$json_new_data" | /jffs/softcenter/bin/jq -e . >/dev/null 2>&1 || return 3 -json_data="$json_new_data" && echo "$json_data" > $V2RAY_CONFIG_FILE -} -gen_conf2() { -json_data=`/jffs/softcenter/bin/jq . $V2RAY_CONFIG_FILE` -/jffs/softcenter/bin/jq -e . $V2RAY_CONFIG_FILE >/dev/null 2>&1 || return 2 -local json_key="127.0.0.1" -local json_value=" \"followRedirect\": true" -local line_data=$(echo "$json_data" | grep -w "$json_key" ) -[ "${line_data:$((${#line_data}-1))}" = "," ] && json_value="${json_value}," && json_key="\"${json_key}\"," -local json_new_data=$(echo "$json_data" | sed "s/$line_data/ \"ip\": $json_key\n$json_value/") -json_data="$json_new_data" && echo "$json_data" > $V2RAY_CONFIG_FILE -} - -download_v2ray(){ -# - PKG_VERSION=$(wget --no-check-certificate https://api.github.com/repos/v2ray/v2ray-core/releases/latest -q -O -|grep tag_name|awk {'print $2'}|cut -d '"' -f 2) - V2RA_VER=`/jffs/softcenter/bin/v2ray --version 2>/dev/null | head -n1 | awk '{print $2}'` || 0 - Tmpv2ray=v2ray - Tmpv2ctl=v2ctl - tarfile=v2ray-linux-mips.zip - v2ray_bin=https://github.com/v2ray/v2ray-core/releases/download/"$PKG_VERSION"/$tarfile - v2ray_bin2=http://k3c.paldier.com/tools/$tarfile - d_rule() { - wget --no-check-certificate --timeout=10 --tries=3 -qO $1 $2 - } - echo "$(date "+%F %T") 在线版本: $PKG_VERSION" >> /tmp/v2ray.log - echo "$(date "+%F %T") 本地版本: v$V2RA_VER" >> /tmp/v2ray.log - logger -t "【v2ray】" "在线版本 $PKG_VERSION" - logger -t "【v2ray】" "本地版本 v$V2RA_VER" - if [ "v$V2RA_VER" != "$PKG_VERSION" ]; then - logger -t "【v2ray】" "本地版本与在线版本不同,下载 $PKG_VERSION ......" - echo "$(date "+%F %T"): 本地版本与在线版本不同,下载 $PKG_VERSION ......" >> /tmp/v2ray.log - cd /tmp - d_rule $tarfile $v2ray_bin - [ "$?" != "0" ] && sleep 2 && d_rule $tarfile $v2ray_bin2 && \ - [ "$?" != "0" ] && logger -t "【v2ray】" "$PKG_VERSION 下载失败" && echo "$(date "+%F %T"): $PKG_VERSION 下载失败" >> /tmp/v2ray.log && exit 1 - mkdir /tmp/v2ray-"$PKG_VERSION"-linux-mips - unzip -o /tmp/$tarfile -d /tmp/v2ray-"$PKG_VERSION"-linux-mips - mv /tmp/v2ray-"$PKG_VERSION"-linux-mips/v2ray /jffs/softcenter/bin/v2ray && chmod 755 /jffs/softcenter/bin/v2ray - mv /tmp/v2ray-"$PKG_VERSION"-linux-mips/v2ctl /jffs/softcenter/bin/v2ctl && chmod 755 /jffs/softcenter/bin/v2ctl - mv /tmp/v2ray-"$PKG_VERSION"-linux-mips/geosite.dat /jffs/softcenter/bin/geosite.dat && chmod 755 /jffs/softcenter/bin/geosite.dat - mv /tmp/v2ray-"$PKG_VERSION"-linux-mips/geoip.dat /jffs/softcenter/bin/geoip.dat && chmod 755 /jffs/softcenter/bin/geoip.dat - if [ ! -e "/jffs/softcenter/bin/jq" ] ;then - wget --no-check-certificate --timeout=10 --tries=3 -qO /jffs/softcenter/bin/jq http://k3c.paldier.com/tools/jq - wget --no-check-certificate --timeout=10 --tries=3 -qO /jffs/softcenter/bin/dns2socks http://k3c.paldier.com/tools/dns2socks - chmod 755 /jffs/softcenter/bin/jq >/dev/null 2>&1 - chmod 755 /jffs/softcenter/bin/dns2socks >/dev/null 2>&1 - fi - jqmd5=`md5sum /jffs/softcenter/bin/jq |awk '{print $1}'` - if [ "$jqmd5" != "91d61fbe4378a0d077109f9c9047dffa" ] ;then - wget --no-check-certificate --timeout=10 --tries=3 -qO /jffs/softcenter/bin/jq http://k3c.paldier.com/tools/jq - [ "$?" != "0" ] && sleep 2 && wget --no-check-certificate --timeout=10 --tries=3 -qO /jffs/softcenter/bin/jq http://k3c.paldier.com/tools/jq - [ "$?" != "0" ] && echo "$(date "+%F %T"): jq 下载失败" >> /tmp/v2ray.log && exit 1 - fi - logger -t "【v2ray】" "$PKG_VERSION 下载成功!" - echo "$(date "+%F %T"): $PKG_VERSION 下载成功" >> /tmp/v2ray.log - rm -rf /tmp/$tarfile /tmp/v2ray-"$PKG_VERSION"-linux-mips >/dev/null 2>&1 - fi -} - -v2ray_test(){ -echo "$(date "+%F %T"): 测试V2Ray配置文件....." >> /tmp/v2ray.log -result=$(/jffs/softcenter/bin/v2ray -test -config="$V2RAY_CONFIG_FILE" | grep "Configuration OK.") -if [ -n "$result" ];then - echo $result - echo "$(date "+%F %T"): V2Ray配置文件通过测试!!!" >> /tmp/v2ray.log - logger -t "【v2ray】" "配置文件通过测试!" - [ "$v2ray_user" = "1" ] && { - cp -f "$V2RAY_CONFIG_FILE" /jffs/softcenter/etc/v2rayconfig.json.bak - echo "$(date "+%F %T"): V2Ray配置文件已备份!!!" >> /tmp/v2ray.log - echo "$(date "+%F %T"): 运行正常后请关闭启用配置选项,不然每重启均保存一次!" >> /tmp/v2ray.log - logger -t "【v2ray】" "配置文件已备份!" - logger -t "【v2ray】" "运行正常后请关闭启用配置选项,不然每重启均保存一次!" - } - /jffs/softcenter/bin/v2ctl config < "$V2RAY_CONFIG_FILE" > "$TEMP_CONFIG_FILE" -else - echo "$(date "+%F %T"): V2Ray配置文件没有通过测试,请检查设置!!!" >> /tmp/v2ray.log - logger -t "【v2ray】" "配置文件没有通过测试,请检查设置!" - exit 1 -fi - -} - -v2ray_serverip(){ -# 检测用户json的服务器ip地址 -v2ray_protocal=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.protocol` -case $v2ray_protocal in - vmess) - v2ray_server=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.settings.vnext[0].address` - ;; - socks) - v2ray_server=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.settings.servers[0].address` - ;; - shadowsocks) - v2ray_server=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.settings.servers[0].address` - ;; - *) - v2ray_server="" - ;; -esac - -if [ -n "$v2ray_server" -a "$v2ray_server" != "null" ];then - IFIP_VS=`echo $v2ray_server|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` - if [ -n "$IFIP_VS" ];then - v2ray_server_ip="$v2ray_server" - echo "$(date "+%F %T"): 检测到你的json配置的v2ray服务器是:$v2ray_server" >> /tmp/v2ray.log - else - echo "$(date "+%F %T"): 检测到你的json配置的v2ray服务器:$v2ray_server不是ip格式!" >> /tmp/v2ray.log - echo "$(date "+%F %T"): 为了确保v2ray的正常工作,建议配置ip格式的v2ray服务器地址!" >> /tmp/v2ray.log - echo "$(date "+%F %T"): 尝试解析v2ray服务器的ip地址..." >> /tmp/v2ray.log - v2ray_server_ip=`nslookup "$v2ray_server" 114.114.114.114 | sed '1,4d' | awk '{print $3}' | grep -v :|awk 'NR==1{print}'` - if [ "$?" == "0" ]; then - v2ray_server_ip=`echo $v2ray_server_ip|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` - else - echo "$(date "+%F %T"): v2ray服务器域名解析失败!" >> /tmp/v2ray.log - echo "$(date "+%F %T"): 尝试用resolveip方式解析..." >> /tmp/v2ray.log - v2ray_server_ip=`resolveip -4 -t 2 $ss_basic_server|awk 'NR==1{print}'` - if [ "$?" == "0" ];then - v2ray_server_ip=`echo $v2ray_server_ip|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` - fi - fi - if [ -n "$v2ray_server_ip" ];then - echo "$(date "+%F %T"): v2ray服务器的ip地址解析成功:$v2ray_server_ip" >> /tmp/v2ray.log - echo "address=/$v2ray_server/$v2ray_server_ip" > /etc/dnsmasq.user/ss_host.conf - v2ray_server_ip="$v2ray_server_ip" - else - echo "$(date "+%F %T"): v2ray服务器的ip地址解析失败!插件将继续运行,域名解析将由v2ray自己进行!" >> /tmp/v2ray.log - echo "$(date "+%F %T"): 请自行将v2ray服务器的ip地址填入IP/CIDR白名单中!" >> /tmp/v2ray.log - echo "$(date "+%F %T"): 为了确保v2ray的正常工作,建议配置ip格式的v2ray服务器地址!" >> /tmp/v2ray.log - fi - fi -else - echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" >> /tmp/v2ray.log - echo "+ 没有检测到你的v2ray服务器地址,如果你确定你的配置是正确的 +" >> /tmp/v2ray.log - echo "+ 请自行将v2ray服务器的ip地址填入黑名单中,以确保正常使用 +" >> /tmp/v2ray.log - echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" >> /tmp/v2ray.log -fi -mip=$v2ray_server_ip -} - -stop() { -killall -q -9 v2ray_mon.sh >/dev/null 2>&1 && killall v2ray_mon.sh >/dev/null 2>&1 -killall -q -9 dns2socks 2>/dev/null && killall dns2socks 2>/dev/null -killall -q -9 v2ray 2>/dev/null && killall v2ray 2>/dev/null -killall -q pdnsd 2>/dev/null -service restart_dnsmasq >/dev/null 2>&1 - -} - -start() { -killall -q -9 v2ray_mon.sh >/dev/null 2>&1 -icount=`ps -w|grep v2rayconfig |grep -v grep|wc -l` - -if [ $icount != 0 ] ;then - stop - sleep 2s -fi - -if [ "$usbmount" == "" ];then - echo " $(date "+%F %T"):""系统正在启动,等待USB设备挂载中!" >> /tmp/v2ray.log -fi -while [ "$usbmount" == "" ] -do - sleep 5s - usbmount=`ls /tmp/mnt/ |grep $mdisk` -done -[ "$ss_dns_china" == "0" ] && GFWCDN="208.67.222.222" -[ "$ss_dns_china" == "1" ] && GFWCDN="8.8.8.8" - -download_v2ray - -if [ "$v2ray_user" = "1" ] ;then - echo $v2ray_sip > $V2RAY_CONFIG_FILE - sed -i "s/,yushi,/\n/g" $V2RAY_CONFIG_FILE - -gen_conf -gen_conf1 -gen_conf2 -else - if [ -f /jffs/softcenter/etc/v2rayconfig.json.bak ];then - rm -rf "$V2RAY_CONFIG_FILE" - cp -f /jffs/softcenter/etc/v2rayconfig.json.bak "$V2RAY_CONFIG_FILE" - echo "$(date "+%F %T"): V2Ray使用备份配置启动!!!" >> /tmp/v2ray.log - logger -t "【v2ray】" "使用备份配置启动!" - else - echo "$(date "+%F %T"): V2Ray没选择启用配置,地球上也找不到备份配置,暂时休息!!!" >> /tmp/v2ray.log - logger -t "【v2ray】" "没选择启用配置,地球上也找不到备份配置,暂时休息!" - exit 1 - fi -fi - -# -v2ray_test -v2ray_serverip - -#if [ -f "$TEMP_CONFIG_FILE" ];then - /jffs/softcenter/bin/v2ray -format pb -config "$TEMP_CONFIG_FILE" >/dev/null 2>&1 & -#else -# /jffs/toolscript/ssr/v2ray -config "$V2RAY_CONFIG_FILE" >/dev/null 2>&1 & -#fi -if [ "$udp_enable" == "1" ];then - echo "$(date "+%F %T"): V2Ray暂不支持前端UDP转发这个选项,不影响程序继续运行!!!" >> /tmp/v2ray.log - logger -t "【v2ray】" "V2Ray暂不支持前端UDP转发这个选项,不影响程序继续运行!" -fi -if [ "$dns_mode" == "2" ];then - /jffs/softcenter/bin/dns2socks 127.0.0.1:23456 $GFWCDN:53 127.0.0.1:7913 >/dev/null 2>&1 & -fi -if [ "$dns_mode" == "0" ];then - echo "$(date "+%F %T"): V2Ray暂不支持远程解析模式,请选择其它解析模式再试!!!" >> /tmp/v2ray.log - logger -t "【v2ray】" "暂不支持远程解析模式,请选择其它解析模式再试!" - exit 1 -fi -/usr/sbin/v2ray-rules $mip 1234 & - -/usr/sbin/ssr-state 2>/dev/null & -rm -rf $V2RAY_CONFIG_FILE -exit 0 -} - -restart() { - stop - sleep 2 - menable=`nvram get v2ray_enable` - kenable=`nvram get k3c_enable` - if [ "$menable" == "1" ];then - if [ "$kenable" == "1" ] ;then - start - else - logger -t "K3C" "K3C扩展设置挂载未开启!" - echo " $(date "+%F %T"):""K3C扩展设置挂载未开启!" >> /tmp/v2ray.log - fi - fi -} - -restart - diff --git a/v2ray/v2ray/scripts/v2ray-rules.sh b/v2ray/v2ray/scripts/v2ray-rules.sh new file mode 100644 index 0000000..6490739 --- /dev/null +++ b/v2ray/v2ray/scripts/v2ray-rules.sh @@ -0,0 +1,279 @@ +#!/bin/sh + +flush_r() { + +iptables -t nat -F v2ray_pre > /dev/null 2>&1 +iptables -t nat -D kool_chain -p tcp -j v2ray_pre > /dev/null 2>&1 +iptables -t nat -D PREROUTING -p tcp -j v2ray_pre > /dev/null 2>&1 +iptables -t nat -D OUTPUT -p tcp -m multiport --dports 53,80,443 -m set --match-set ssr dst -j REDIRECT --to-ports $local_port > /dev/null 2>&1 +iptables -t nat -D OUTPUT -p tcp -m multiport --dports 53,80,443 -d 93.46.8.89/32 -j REDIRECT --to-ports $local_port > /dev/null 2>&1 +iptables -t nat -X v2ray_pre > /dev/null 2>&1 + +ipset -F ssr >/dev/null 2>&1 && ipset -X ssr >/dev/null 2>&1 +ipset -F ssr_ignore >/dev/null 2>&1 && ipset -X ssr_ignore >/dev/null 2>&1 +ipset -F white_list >/dev/null 2>&1 && ipset -X white_list >/dev/null 2>&1 + +#udp +iptables -t mangle -F SS_SPEC_TPROXY 2>/dev/null +iptables -t mangle -D PREROUTING -p udp -j SS_SPEC_TPROXY 2>/dev/null +iptables -t mangle -D kool_chain -p udp -j SS_SPEC_TPROXY 2>/dev/null +iptables -t mangle -X SS_SPEC_TPROXY 2>/dev/null +ip rule del fwmark 1 table 100 2>/dev/null +ip route del local default dev lo table 100 2>/dev/null + +return 0 +} + +gen_iplist() { + cat <<-EOF + 0.0.0.0/8 + 10.0.0.0/8 + 100.64.0.0/10 + 127.0.0.0/8 + 169.254.0.0/16 + 172.16.0.0/12 + 192.0.0.0/24 + 192.0.2.0/24 + 192.88.99.0/24 + 192.168.0.0/16 + 198.18.0.0/15 + 198.51.100.0/24 + 203.0.113.0/24 + 224.0.0.0/4 + 240.0.0.0/4 + 255.255.255.255 + $(cat ${IGNORE2:=/dev/null} 2>/dev/null) +EOF +} + +gen_iplist2() { + cat <<-EOF + $(cat ${IGNORE:=/dev/null} 2>/dev/null) +EOF +} + +start_pdnsd() { + mkdir -p /var/etc /var/pdnsd + CACHE=/var/pdnsd/pdnsd.cache + + if ! test -f "$CACHE"; then + mkdir -p `dirname $CACHE` 2>/dev/null + dd if=/dev/zero of="$CACHE" bs=1 count=4 2>/dev/null + chown -R nobody.nogroup /var/pdnsd 2>/dev/null + fi + + cat > /var/etc/pdnsd.conf </var/pdnsd/pdnsd.cache 2>/dev/null +chown -R nobody.nogroup /var/pdnsd 2>/dev/null +} + +# Get argument +server=$1 +local_port=$2 +if [ "$server" == "clean" ] ;then + flush_r + exit 0 +fi + + + +[ ! -f $IGNORE ] && echo "$IGNORE not found." && exit 1 + +# Check variable +[ -z $server ] || [ -z $local_port ] && { + echo "Invalid variable, please check CONFIG." + exit 1 +} + +all_proxy=`dbus get v2ray_mode` +dns_mode=`dbus get v2ray_dnsmode` +udp_enable=`dbus get v2ray_udp_enable` + +# Create a new chain +menable=`dbus get koolproxy_enable` +if [ "$menable" = "1" ]; then +BEGIN="*nat\n\ +:v2ray_pre - [0:0]\n\ +-I kool_chain -p tcp -j v2ray_pre\n\ +" +else +BEGIN="*nat\n\ +:v2ray_pre - [0:0]\n\ +-I PREROUTING -p tcp -j v2ray_pre\n\ +" +fi + + +ADD_white() { + +ISP_DNS1=$(nvram get wan0_dns|sed 's/ /\n/g'|grep -v 0.0.0.0|grep -v 127.0.0.1|sed -n 1p) +ISP_DNS2=$(nvram get wan0_dns|sed 's/ /\n/g'|grep -v 0.0.0.0|grep -v 127.0.0.1|sed -n 2p) +IFIP_DNS1=`echo $ISP_DNS1|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` +IFIP_DNS2=`echo $ISP_DNS2|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` +# white ip/cidr +[ -n "$server" ] && SERVER_IP="$server" || SERVER_IP="" +[ -n "$IFIP_DNS1" ] && ISP_DNS_a="$ISP_DNS1" || ISP_DNS_a="" +[ -n "$IFIP_DNS2" ] && ISP_DNS_b="$ISP_DNS2" || ISP_DNS_b="" +ip_lan="0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4 223.5.5.5 223.6.6.6 114.114.114.114 114.114.115.115 1.2.4.8 210.2.4.8 112.124.47.27 114.215.126.16 180.76.76.76 119.29.29.29 $ISP_DNS_a $ISP_DNS_b $SERVER_IP" +for ip in $ip_lan +do + ipset -! add white_list $ip >/dev/null 2>&1 +done + +} + +ipset -! create ssr nethash && ipset flush ssr +ipset -! create white_list nethash && ipset flush white_list +if [ "$dns_mode" = "1" ] ;then + cp -f /usr/sbin/ssr/gfw_list.conf /tmp/etc/dnsmasq.user/gfw_list.conf + if [ -f "/jffs/configs/ssr_gfw.txt" ] ;then + icount=`cat /jffs/configs/ssr_gfw.txt|grep .|wc -l` + if [ $icount -gt 0 ] ;then + sed '/.*/s/.*/server=\/&\/127.0.0.1#1053\nipset=\/&\/ssr/' /jffs/configs/ssr_gfw.txt > /tmp/etc/dnsmasq.user/gfw_user.conf + else + [ -f "/tmp/etc/dnsmasq.user/gfw_user.conf" ] && rm -f /tmp/etc/dnsmasq.user/gfw_user.conf + fi + fi +start_pdnsd +else + cp -f /usr/sbin/ssr/gfw_addr.conf /tmp/etc/dnsmasq.user/gfw_addr.conf + if [ -f "/jffs/configs/ssr_gfw.txt" ] ;then + icount=`cat /jffs/configs/ssr_gfw.txt|grep .|wc -l` + if [ $icount -gt 0 ] ;then + sed '/.*/s/.*/address=\/&\/93.46.8.89/' /jffs/configs/ssr_gfw.txt > /tmp/etc/dnsmasq.user/gfw_user.conf + else + [ -f "/tmp/etc/dnsmasq.user/gfw_user.conf" ] && rm -f /tmp/etc/dnsmasq.user/gfw_user.conf + fi + fi +fi + +service restart_dnsmasq + + + +/jffs/softcenter/scripts/v2ray_mon.sh & + +logger -t "v2ray" "守护进程启动" + + +if [ "$all_proxy" = "1" ] ;then + +ip_gfw="208.67.222.222 208.67.220.220 8.8.8.8 8.8.4.4" +for ip in $ip_gfw +do + ipset -! add ssr $ip 2>/dev/null +done + +ip_tg="149.154.0.0/16 91.108.4.0/22 91.108.56.0/24 109.239.140.0/24 67.198.55.0/24 " +for ip in $ip_tg +do + ipset -! add ssr $ip 2>/dev/null +done +ADD_white + +if [ "$dns_mode" = "1" ] ;then +echo -e "$BEGIN\ +-A v2ray_pre -p tcp -m set --match-set white_list dst -j RETURN\n\ +-A v2ray_pre -p tcp -m set ! --match-set ssr dst -j RETURN\n\ +-A v2ray_pre -p tcp -m set --match-set ssr dst -j REDIRECT --to-ports $local_port\n\ +-I OUTPUT 1 -p tcp -m multiport --dports 53,80,443 -m set --match-set ssr dst -j REDIRECT --to-ports $local_port\n\ + +COMMIT" | iptables-restore -n +else +echo -e "$BEGIN\ +-A v2ray_pre -p tcp -m set --match-set white_list dst -j RETURN\n\ +-A v2ray_pre -p tcp -d 93.46.8.89/32 -j REDIRECT --to-ports $local_port\n\ +-A v2ray_pre -p tcp -m set --match-set ssr dst -j REDIRECT --to-ports $local_port\n\ +-I OUTPUT 1 -p tcp -m multiport --dports 53,80,443 -d 93.46.8.89/32 -j REDIRECT --to-ports $local_port\n\ +-A OUTPUT -p tcp -m multiport --dports 53,80,443 -m set --match-set ssr dst -j REDIRECT --to-ports $local_port\n\ + +COMMIT" | iptables-restore -n +fi + +if [ -f "$FORCE" ] ;then +sed "/.*/s/.*/iptables -t nat -A v2ray_pre -p tcp -d & -j REDIRECT --to-ports $local_port /" $FORCE 2>/dev/null | sh +fi + +#udp +if [ "$udp_enable" == "1" ] ;then + ip rule add fwmark 1 table 100 + ip route add local default dev lo table 100 + iptables -t mangle -N SS_SPEC_TPROXY + if [ "$dns_mode" = "1" ] ;then + iptables -t mangle -A SS_SPEC_TPROXY -p udp -m set --match-set ssr dst \ + -j TPROXY --on-port $local_port --tproxy-mark 0x01/0x01 + else + iptables -t mangle -A SS_SPEC_TPROXY -p udp -d 93.46.8.89/32 \ + -j TPROXY --on-port $local_port --tproxy-mark 0x01/0x01 + fi +fi + logger -t "v2ray" "启动完毕!" +exit 0 +fi + + +ipset -! create ssr_ignore nethash && ipset flush ssr_ignore +echo -e "$BEGIN\n\ +-A v2ray_pre -p tcp -m set --match-set white_list dst -j RETURN\n\ +-A v2ray_pre -m set --match-set ssr_ignore dst -j RETURN \n\ +-A v2ray_pre -p tcp -j REDIRECT --to-ports $local_port\n\ +-I OUTPUT 1 -p tcp -m multiport --dports 53,80,443 -m set --match-set ssr dst -j REDIRECT --to-ports $local_port\n\ + +COMMIT" | iptables-restore -n + + +#udp +if [ "$udp_enable" == "1" ] ;then + ip rule add fwmark 1 table 100 + ip route add local default dev lo table 100 + iptables -t mangle -N SS_SPEC_TPROXY + + iptables -t mangle -A SS_SPEC_TPROXY -p udp -m set ! --match-set ssr_ignore dst \ + -j TPROXY --on-port $local_port --tproxy-mark 0x01/0x01 + if [ "$menable" = "1" ]; then + iptables -t mangle -I kool_chain 1 -p udp -j SS_SPEC_TPROXY + else + iptables -t mangle -I PREROUTING 1 -p udp -j SS_SPEC_TPROXY + fi + logger -t "v2ray" "启动完毕!" +exit 0 +fi + diff --git a/v2ray/v2ray/scripts/v2ray_config.sh b/v2ray/v2ray/scripts/v2ray_config.sh new file mode 100644 index 0000000..2ad6f62 --- /dev/null +++ b/v2ray/v2ray/scripts/v2ray_config.sh @@ -0,0 +1,330 @@ +#!/bin/sh + +eval `dbus export v2ray_` +source /jffs/softcenter/scripts/base.sh + +V2RAY_CONFIG_FILE="/tmp/etc/v2rayconfig.json" +V2RAY_CONFIG_FILE_PB="/tmp/v2rayconfig.pb" +V2RAY_CONFIG_FILE_TMP="/tmp/v2rayconfig.json" + +gen_conf() { +json_data=`/jffs/softcenter/bin/jq . $V2RAY_CONFIG_FILE` +/jffs/softcenter/bin/jq -e . $V2RAY_CONFIG_FILE >/dev/null 2>&1 || return 2 +local json_key="socks" +local json_value="\"dokodemo-door\"" +local line_data=$(echo "$json_data" | grep -w "$json_key" ) +[ "${line_data:$((${#line_data}-1))}" = "," ] && json_value="${json_value}," +local json_new_data=$(echo "$json_data" | sed "s/$line_data/ \"protocol\": $json_value/") +echo "$json_new_data" | /jffs/softcenter/bin/jq -e . >/dev/null 2>&1 || return 3 +json_data="$json_new_data" && echo "$json_data" > $V2RAY_CONFIG_FILE +} +gen_conf1() { +json_data=`/jffs/softcenter/bin/jq . $V2RAY_CONFIG_FILE` +/jffs/softcenter/bin/jq -e . $V2RAY_CONFIG_FILE >/dev/null 2>&1 || return 2 +local json_key="1080," +local json_value="1234" +local line_data=$(echo "$json_data" | grep -w "$json_key" ) +[ "${line_data:$((${#line_data}-1))}" = "," ] && json_value="${json_value}," +local json_new_data=$(echo "$json_data" | sed "s/$line_data/ \"port\": $json_value/") +echo "$json_new_data" | /jffs/softcenter/bin/jq -e . >/dev/null 2>&1 || return 3 +json_data="$json_new_data" && echo "$json_data" > $V2RAY_CONFIG_FILE +} +gen_conf2() { +json_data=`/jffs/softcenter/bin/jq . $V2RAY_CONFIG_FILE` +/jffs/softcenter/bin/jq -e . $V2RAY_CONFIG_FILE >/dev/null 2>&1 || return 2 +local json_key="127.0.0.1" +local json_value=" \"followRedirect\": true" +local line_data=$(echo "$json_data" | grep -w "$json_key" ) +[ "${line_data:$((${#line_data}-1))}" = "," ] && json_value="${json_value}," && json_key="\"${json_key}\"," +local json_new_data=$(echo "$json_data" | sed "s/$line_data/ \"ip\": $json_key\n$json_value/") +json_data="$json_new_data" && echo "$json_data" > $V2RAY_CONFIG_FILE +} +get_function_switch() { + case "$1" in + 1) + echo "true" + ;; + 0|*) + echo "false" + ;; + esac +} +v2ray_serverip(){ +# 检测用户json的服务器ip地址 +v2ray_protocal=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.protocol` +case $v2ray_protocal in + vmess) + v2ray_server=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.settings.vnext[0].address` + ;; + socks) + v2ray_server=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.settings.servers[0].address` + ;; + shadowsocks) + v2ray_server=`cat "$V2RAY_CONFIG_FILE" | /jffs/softcenter/bin/jq -r .outbound.settings.servers[0].address` + ;; + *) + v2ray_server="" + ;; +esac + +if [ -n "$v2ray_server" -a "$v2ray_server" != "null" ];then + IFIP_VS=`echo $v2ray_server|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` + if [ -n "$IFIP_VS" ];then + v2ray_server_ip="$v2ray_server" + echo "$(date "+%F %T"): 检测到你的json配置的v2ray服务器是:$v2ray_server" >> /tmp/v2ray.log + else + echo "$(date "+%F %T"): 检测到你的json配置的v2ray服务器:$v2ray_server不是ip格式!" >> /tmp/v2ray.log + echo "$(date "+%F %T"): 为了确保v2ray的正常工作,建议配置ip格式的v2ray服务器地址!" >> /tmp/v2ray.log + echo "$(date "+%F %T"): 尝试解析v2ray服务器的ip地址..." >> /tmp/v2ray.log + v2ray_server_ip=`nslookup "$v2ray_server" 114.114.114.114 | sed '1,4d' | awk '{print $3}' | grep -v :|awk 'NR==1{print}'` + if [ "$?" == "0" ]; then + v2ray_server_ip=`echo $v2ray_server_ip|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` + else + echo "$(date "+%F %T"): v2ray服务器域名解析失败!" >> /tmp/v2ray.log + echo "$(date "+%F %T"): 尝试用resolveip方式解析..." >> /tmp/v2ray.log + v2ray_server_ip=`resolveip -4 -t 2 $ss_basic_server|awk 'NR==1{print}'` + if [ "$?" == "0" ];then + v2ray_server_ip=`echo $v2ray_server_ip|grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}|:"` + fi + fi + if [ -n "$v2ray_server_ip" ];then + echo "$(date "+%F %T"): v2ray服务器的ip地址解析成功:$v2ray_server_ip" >> /tmp/v2ray.log + echo "address=/$v2ray_server/$v2ray_server_ip" > /etc/dnsmasq.user/ss_host.conf + v2ray_server_ip="$v2ray_server_ip" + else + echo "$(date "+%F %T"): v2ray服务器的ip地址解析失败!插件将继续运行,域名解析将由v2ray自己进行!" >> /tmp/v2ray.log + echo "$(date "+%F %T"): 请自行将v2ray服务器的ip地址填入IP/CIDR白名单中!" >> /tmp/v2ray.log + echo "$(date "+%F %T"): 为了确保v2ray的正常工作,建议配置ip格式的v2ray服务器地址!" >> /tmp/v2ray.log + fi + fi +else + echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" >> /tmp/v2ray.log + echo "+ 没有检测到你的v2ray服务器地址,如果你确定你的配置是正确的 +" >> /tmp/v2ray.log + echo "+ 请自行将v2ray服务器的ip地址填入黑名单中,以确保正常使用 +" >> /tmp/v2ray.log + echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" >> /tmp/v2ray.log +fi +mip=$v2ray_server_ip +} +creat_v2ray_json(){ + rm -rf "$V2RAY_CONFIG_FILE_TMP" + rm -rf "$V2RAY_CONFIG_FILE" + if [ "$v2ray_use_json" == "0" ];then + echo "$(date "+%F %T")生成V2Ray配置文件... " >> /tmp/v2ray.log + local kcp="null" + local tcp="null" + local ws="null" + local h2="null" + local tls="null" + + # tcp和kcp下tlsSettings为null,ws和h2下tlsSettings + [ "$v2ray_network_security" == "none" ] && local v2ray_network_security="" + #if [ "$ss_basic_v2ray_network" == "ws" -o "$ss_basic_v2ray_network" == "h2" ];then + case "$v2ray_network_security" in + tls) + local tls="{ + \"allowInsecure\": true, + \"serverName\": null + }" + ;; + *) + local tls="null" + ;; + esac + #fi + # incase multi-domain input + if [ "`echo $v2ray_network_host | grep ","`" ];then + v2ray_network_host=`echo $v2ray_network_host | sed 's/,/", "/g'` + fi + + case "$v2ray_network" in + tcp) + if [ "$v2ray_headtype_tcp" == "http" ];then + local tcp="{ + \"connectionReuse\": true, + \"header\": { + \"type\": \"http\", + \"request\": { + \"version\": \"1.1\", + \"method\": \"GET\", + \"path\": [\"/\"], + \"headers\": { + \"Host\": [\"$v2ray_network_host\"], + \"User-Agent\": [\"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36\",\"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46\"], + \"Accept-Encoding\": [\"gzip, deflate\"], + \"Connection\": [\"keep-alive\"], + \"Pragma\": \"no-cache\" + } + }, + \"response\": { + \"version\": \"1.1\", + \"status\": \"200\", + \"reason\": \"OK\", + \"headers\": { + \"Content-Type\": [\"application/octet-stream\",\"video/mpeg\"], + \"Transfer-Encoding\": [\"chunked\"], + \"Connection\": [\"keep-alive\"], + \"Pragma\": \"no-cache\" + } + } + } + }" + else + local tcp="null" + fi + ;; + kcp) + local kcp="{ + \"mtu\": 1350, + \"tti\": 50, + \"uplinkCapacity\": 12, + \"downlinkCapacity\": 100, + \"congestion\": false, + \"readBufferSize\": 2, + \"writeBufferSize\": 2, + \"header\": { + \"type\": \"$v2ray_headtype_kcp\", + \"request\": null, + \"response\": null + } + }" + ;; + ws) + local ws="{ + \"connectionReuse\": true, + \"path\": $(get_path $v2ray_network_path), + \"headers\": $(get_ws_header $v2ray_network_host) + }" + ;; + h2) + local h2="{ + \"path\": $(get_path $v2ray_network_path), + \"host\": $(get_h2_host $v2ray_network_host) + }" + ;; + esac + cat > "$V2RAY_CONFIG_FILE_TMP" <<-EOF + { + "log": { + "access": "/dev/null", + "error": "/tmp/v2ray_log.log", + "loglevel": "error" + }, + EOF + cat >> "$V2RAY_CONFIG_FILE_TMP" <<-EOF + "inboundDetour": [ + { + "listen": "0.0.0.0", + "port": 1234, + "protocol": "dokodemo-door", + "settings": { + "network": "tcp,udp", + "followRedirect": true + } + } + ], + "outbound": { + "tag": "agentout", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "`dbus get v2ray_server`", + "port": $v2ray_port, + "users": [ + { + "id": "$v2ray_uuid", + "alterId": $v2ray_alterid, + "security": "$v2ray_security" + } + ] + } + ], + "servers": null + }, + "streamSettings": { + "network": "$v2ray_network", + "security": "$v2ray_network_security", + "tlsSettings": $tls, + "tcpSettings": $tcp, + "kcpSettings": $kcp, + "wsSettings": $ws, + "httpSettings": $h2 + }, + "mux": { + "enabled": $(get_function_switch $v2ray_mux_enable) + } + } + } + EOF + echo "$(date "+%F %T")解析V2Ray配置文件... " >> /tmp/v2ray.log + cat "$V2RAY_CONFIG_FILE_TMP" | jq --tab . > "$V2RAY_CONFIG_FILE" + echo "$(date "+%F %T")V2Ray配置文件写入成功到 $V2RAY_CONFIG_FILE" >> /tmp/v2ray.log + elif [ "$v2ray_use_json" == "1" ];then + echo "$(date "+%F %T")使用自定义的v2ray json配置文件..." >> /tmp/v2ray.log + echo "$v2ray_json" | base64_decode > "$V2RAY_CONFIG_FILE" + gen_conf + gen_conf1 + gen_conf2 + fi + + echo "$(date "+%F %T")测试V2Ray配置文件..... " >> /tmp/v2ray.log + cd /koolshare/bin + result=$(v2ray -test -config="$V2RAY_CONFIG_FILE" | grep "Configuration OK.") + if [ -n "$result" ];then + echo "$(date "+%F %T") $result" >> /tmp/v2ray.log + echo "$(date "+%F %T") V2Ray配置文件通过测试!!!" >> /tmp/v2ray.log + /jffs/softcenter/bin/v2ctl config < "$V2RAY_CONFIG_FILE" > "$TEMP_CONFIG_FILE" + else + rm -rf "$V2RAY_CONFIG_FILE_TMP" + rm -rf "$V2RAY_CONFIG_FILE" + echo "$(date "+%F %T") V2Ray配置文件没有通过测试,请检查设置!!!" >> /tmp/v2ray.log + fi +} +stop() { +killall -q -9 v2ray_mon.sh >/dev/null 2>&1 && killall v2ray_mon.sh >/dev/null 2>&1 +killall -q -9 dns2socks 2>/dev/null && killall dns2socks 2>/dev/null +killall -q -9 v2ray 2>/dev/null && killall v2ray 2>/dev/null +killall -q pdnsd 2>/dev/null +service restart_dnsmasq >/dev/null 2>&1 +[ "-e /jffs/softcenter/init.d/S99v2ray.sh" ] && rm -rf /jffs/softcenter/init.d/S99v2ray.sh +} +start_v2ray(){ +illall -q -9 v2ray_mon.sh >/dev/null 2>&1 +icount=`ps -w|grep v2rayconfig |grep -v grep|wc -l` + +if [ $icount != 0 ] ;then + stop + sleep 2s +fi +[ "$v2ray_dns" == "0" ] && GFWCDN="208.67.222.222" +[ "$v2ray_dns" == "1" ] && GFWCDN="8.8.8.8" +if [ "$udp_enable" == "1" ];then + echo "$(date "+%F %T"): V2Ray暂不支持前端UDP转发这个选项,不影响程序继续运行!!!" >> /tmp/v2ray.log + logger -t "【v2ray】" "V2Ray暂不支持前端UDP转发这个选项,不影响程序继续运行!" +fi +if [ "$v2ray_dnsmode" == "2" ];then + /jffs/softcenter/bin/dns2socks 127.0.0.1:23456 $GFWCDN:53 127.0.0.1:7913 >/dev/null 2>&1 & +fi +if [ "$v2ray_dnsmode" == "0" ];then + echo "$(date "+%F %T"): V2Ray暂不支持远程解析模式,请选择其它解析模式再试!!!" >> /tmp/v2ray.log + logger -t "【v2ray】" "暂不支持远程解析模式,请选择其它解析模式再试!" + exit 1 +fi +v2ray_serverip +/jffs/softcenter/bin/v2ray -format pb -config "$V2RAY_CONFIG_FILE_PB" >/dev/null 2>&1 & +/jffs/softcenter/scripts/v2ray-rules.sh $mip 1234 & +/usr/sbin/ssr-state 2>/dev/null & +exit 0 +} +restart() { + stop + sleep 2 + if [ "`dbus get v2ray_enable`" == "1" ];then + creat_v2ray_json + start_v2ray + [ "! -e /jffs/softcenter/init.d/S99v2ray.sh" ] && cp -r /jffs/softcenter/scripts/v2ray_config.sh /jffs/softcenter/init.d/S99v2ray.sh + fi +} + +restart + diff --git a/v2ray/v2ray/scripts/v2ray_mon.sh b/v2ray/v2ray/scripts/v2ray_mon.sh new file mode 100755 index 0000000..833e79e --- /dev/null +++ b/v2ray/v2ray/scripts/v2ray_mon.sh @@ -0,0 +1,30 @@ +#!/bin/sh +check_time=120 +dns_mode=`dbus get v2ray_dnsmode` +while [ "1" = "1" ] +do + sleep $check_time + +#check iptables + + icount=`ps -w|grep v2rayconfig |grep -v grep |wc -l` + + icount2=`iptables -t nat -S|grep v2ray|wc -l` + if [ $icount = 0 -o $icount2 -lt 5 ] ;then + logger -t "v2ray" "iptables error,restart v2ray!" + /jffs/softcenter/scripts/softcenter_v2ray.sh + exit 0 + fi + +#check pdnsd +if [ "$dns_mode" = "1" ] ;then + icount=`ps -w|grep pdnsd |grep -v grep |wc -l` + if [ $icount = 0 ] ;then + logger -t "v2ray" "pdnsd error,restart v2ray!" + /jffs/softcenter/scripts/softcenter_v2ray.sh + exit 0 + fi +fi + +done + diff --git a/v2ray/v2ray/webs/Module_v2ray.asp b/v2ray/v2ray/webs/Module_v2ray.asp index 854a1bd..65c77d5 100644 --- a/v2ray/v2ray/webs/Module_v2ray.asp +++ b/v2ray/v2ray/webs/Module_v2ray.asp @@ -24,6 +24,8 @@ + +
    - + "> - - + + - + " disabled> "> -"> -"> +"> +"> "> "> -"> -"> +"> +"> +"> @@ -186,7 +346,7 @@ function menu_hook(title, tab) {
    -
    工具箱 - v2ray
    +
    v2ray
    @@ -199,15 +359,15 @@ function menu_hook(title, tab) {
    -
    +
       使用步骤:
      -
    1. 首先打开扩展挂载并挂载虚拟内存
    2. +
    3. 挂载虚拟内存
    4. 然后自行获取服务器参数
    5. -
    6. 最后手动上传配置文件或在自定义配置里粘贴配置
    7. +
    8. 最后填写配置或在自定义配置里粘贴配置
    注意:
      @@ -222,12 +382,12 @@ function menu_hook(title, tab) {
      - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      启用代理启用V2ray
      -
      +
      使用json配置 +
      自定义配置
      @@ -338,9 +584,9 @@ document.form.v2ray_user.value = 0;
    - +
    + +
    diff --git a/v2ray/version b/v2ray/version index 5f133b7..88e5230 100644 --- a/v2ray/version +++ b/v2ray/version @@ -1,2 +1,2 @@ 4.13.0 -4ff156ed5cfd6183ac19ebca1193ba16 +9ef8deadd029b47b4bf59a2c7f9b8a96