更新配置

This commit is contained in:
ling 2023-04-09 18:11:53 +08:00
parent 34ad59d34e
commit 405213d682
283 changed files with 13014 additions and 9885 deletions

View File

@ -2,12 +2,8 @@
module("luci.controller.schedule", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
page = entry({"admin", "services", "schedule"}, cbi("schedule"), _(translate("Scheduled Reboot")), 61)
page = entry({"admin", "services", "schedule"}, cbi("schedule"), _("Scheduled Reboot"), 61)
page.dependent = true
end

View File

@ -23,8 +23,8 @@ o = d1:option(DummyValue, "zonename", translate("Timezone : "), translate("Be su
d = m:section(TypedSection, "reboot", " ")
c1 = d:option(ListValue, "enable", " ");
c1:value("0", translate("Disabled"))
c1:value("1", translate("Enabled"))
c1:value("0", "Disabled")
c1:value("1", "Enabled")
c1.default=0
sdhour = d:option(ListValue, "sdhour", translate("Reboot Time :"))

View File

@ -3,9 +3,6 @@
module("luci.controller.p910ndx", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
if not nixio.fs.access("/etc/config/p910nd") then
return
@ -13,6 +10,6 @@ function index()
local page
page = entry({"admin", "services", "p910ndx"}, cbi("p910ndx"), _(translate("Print Server")), 60)
page = entry({"admin", "services", "p910ndx"}, cbi("p910ndx"), _("Print Server"), 60)
page.dependent = true
end

View File

@ -3,15 +3,13 @@
module("luci.controller.hd_idle", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
if not nixio.fs.access("/etc/config/hd-idle") then
return
end
local page
page = entry({"admin", "services", "hd_idle"}, cbi("hd_idle"), _(translate("Hard Drive Idle")), 60)
page = entry({"admin", "services", "hd_idle"}, cbi("hd_idle"), _("Hard Drive Idle"), 60)
page.dependent = true
end

View File

@ -1,11 +1,8 @@
module("luci.controller.umount", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
page = entry({"admin", "services", "umount"}, cbi("umount", {hidesavebtn=true, hideresetbtn=true}), translate("Safely Eject Drive"), 25)
page = entry({"admin", "services", "umount"}, cbi("umount", {hidesavebtn=true, hideresetbtn=true}), "Safely Eject Drive", 25)
page.dependent = true
end

View File

@ -4,7 +4,8 @@
require("nixio.fs")
m = Map("hd-idle", "Hard Drive Idle",
translate("This is a utility program for spinning-down external disks after a period of idle time."))
translate("This is a utility program for spinning-down external " ..
"disks after a period of idle time."))
s = m:section(TypedSection, "hd-idle", translate("Settings"))
s.anonymous = true

View File

@ -5,22 +5,21 @@ translate = I18N.translate
function index()
local fs = require "nixio.fs"
if not fs.stat("/etc/nosms") then
local page
page = entry({"admin", "modem", "sms"}, template("rooter/sms"), translate("短信功能"), 35)
page.dependent = true
end
if not fs.stat("/etc/nosms") then
local page
page = entry({"admin", "modem", "sms"}, template("rooter/sms"), translate("短信功能"), 35)
page.dependent = true
end
entry({"admin", "modem", "check_read"}, call("action_check_read"))
entry({"admin", "modem", "del_sms"}, call("action_del_sms"))
entry({"admin", "modem", "send_sms"}, call("action_send_sms"))
entry({"admin", "modem", "change_sms"}, call("action_change_sms"))
entry({"admin", "modem", "change_smsdn"}, call("action_change_smsdn"))
entry({"admin", "modem", "change_smsflag"}, call("action_change_smsflag"))
entry({"admin", "modem", "delall_sms"}, call("action_delall_sms"))
end
function trim(s)
@ -71,12 +70,16 @@ function action_send_sms()
luci.http.write_json(rv)
end
function action_delall_sms()
smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum")
os.execute("/usr/lib/sms/delall.sh " .. smsnum)
end
function action_del_sms()
local set = tonumber(luci.http.formvalue("set"))
if set ~= nil and set > 0 then
set = set - 1;
local set = luci.http.formvalue("set")
if set ~= nil then
smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum")
os.execute("/usr/lib/sms/delsms.sh " .. smsnum .. " " .. set)
os.execute("/usr/lib/sms/delsms.sh " .. smsnum .. " " .. set)
os.execute("touch /tmp/smswakeup" .. smsnum)
end
end
@ -122,7 +125,7 @@ function action_check_read()
line = file:read("*line")
full = full .. line
if k < i then
full = full .. '<br />'
full = full .. '\n'
end
end
else
@ -157,4 +160,3 @@ function action_change_smsflag()
local set = tonumber(luci.http.formvalue("set"))
os.execute("/usr/lib/sms/toggle.sh " .. set)
end

View File

@ -22,7 +22,7 @@
if ( ss == "0" )
{
clearListBox("smsList");
document.getElementById('message').innerHTML="";
document.getElementById('message').value="";
document.getElementById('total').innerHTML="";
document.getElementById('used').innerHTML="";
document.getElementById('mslots').innerHTML="";
@ -32,7 +32,7 @@
if ( ss == "1" )
{
clearListBox("smsList");
document.getElementById('message').innerHTML="";
document.getElementById('message').value="";
document.getElementById('total').innerHTML="";
document.getElementById('used').innerHTML="";
document.getElementById('mslots').innerHTML="";
@ -86,7 +86,7 @@
var i;
for(i=0;i<len;i++)
{
index[indx] = parseInt(arr[i]);
index[indx] = arr[i];
number[indx] = arr[i+1];
ttext[indx] = arr[i+2];
var txtline = arr[i+3];
@ -102,7 +102,7 @@
if ( selectline == -1 )
{
select.value = 0;
document.getElementById('message').innerHTML=ttext[0];
document.getElementById('message').value=ttext[0];
selectline = 0;
}
else
@ -112,7 +112,7 @@
selectline = indx -1 ;
}
select.value = selectline;
document.getElementById('message').innerHTML=ttext[selectline];
document.getElementById('message').value=ttext[selectline];
}
}
}
@ -120,7 +120,7 @@
}
);
document.getElementById('message').innerHTML=" ";
document.getElementById('message').value=" ";
document.getElementById('total').innerHTML="0";
document.getElementById('used').innerHTML="0";
document.getElementById('mslots').innerHTML="0";
@ -167,7 +167,7 @@
{
var s = document.getElementById("smsList").value;
selectline = s;
document.getElementById('message').innerHTML=ttext[s];
document.getElementById('message').value=ttext[s];
}
function sendsms()
@ -203,7 +203,7 @@
}
num = num.concat(t);
alert("<%:SMS will be queued for processing.\nA status update will follow.%>");
document.getElementById("sstat").innerHTML="<%:状态 :消息正在发送%>";
document.getElementById("sstat").innerHTML="<%:状态 消息正在发送%>";
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "send_sms")%>',
{ set: num },
function(x, rv)
@ -215,90 +215,113 @@
);
}
function readcheck()
{
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "check_read")%>', null,
function(x, rv)
{
var ss = rv.ready;
document.getElementById('message').style.color = "initial";
document.getElementById('conntype').innerHTML=rv.conntype;
if ( ss == "1" )
{
clearListBox("smsList");
document.getElementById('message').value="";
document.getElementById('total').innerHTML="";
document.getElementById('used').innerHTML="";
document.getElementById('supported').innerHTML="<%:您有未读的短信,请前往查看%>";
}
if ( ss == "3" )
{
document.getElementById('supported').innerHTML="<%:消息读取有问题%>";
}
if ( ss == "2" )
{
document.getElementById('supported').innerHTML="<%:存在短信%>";
clearListBox("smsList");
document.getElementById('total').innerHTML=rv.max;
document.getElementById('used').innerHTML=rv.used;
var line=rv.line;
var arr=(line.split("\x1D"));
var len = arr.length;
indx = 0;
var i;
for(i=0;i<len;i++)
{
index[indx] = parseInt(arr[i]);
number[indx] = arr[i+1];
ttext[indx] = arr[i+2];
var txtline = arr[i+3];
txtline = txtline.replace(/ /g,"\240");
var select = document.getElementById("smsList");
select.options[select.options.length] = new Option(txtline, indx);
i = i + 3;
indx = indx + 1;
}
if ( indx != -1 )
{
if ( selectline == -1 )
{
select.value = 0;
document.getElementById('message').value=ttext[0];
selectline = 0;
}
else
{
if ( selectline > indx-1 )
{
selectline = indx -1 ;
}
select.value = selectline;
document.getElementById('message').value=ttext[selectline];
}
}
}
}
);
}
function delallsms()
{
var r=confirm("<%:是否确定要删除所有短信?%>");
if (r==false)
{
return false;
}
clearListBox("smsList");
document.getElementById('message').style.color = "red";
document.getElementById('message').value="<%:将删除所有短信.更新列表可能需要一些时间.%>";
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "删除所有短信")%>',
null,
function()
{
readcheck();
}
);
}
function delsms()
{
if ( selectline == -1 )
{
return false;
}
var r=confirm("<%:确认删除选中消息 %>");
var r=confirm("<%:确认删除选中消息?%>");
if (r==false)
{
return false;
}
var s = document.getElementById("smsList").value;
var dx = index[s];
dx = dx + 1;
clearListBox("smsList");
document.getElementById('message').style.color = "red";
document.getElementById('message').innerHTML="<%:短信将被删除,同步到列表可能会很久(反复提交删除申请一样很久)%>";
document.getElementById('message').value="<%:短信将被删除,同步到列表可能会很久(反复提交删除申请一样很久)%>";
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "del_sms")%>',
{ set: dx },
function()
{
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "check_read")%>', null,
function(x, rv)
{
var ss = rv.ready;
document.getElementById('message').style.color = "initial";
document.getElementById('conntype').innerHTML=rv.conntype;
if ( ss == "1" )
{
clearListBox("smsList");
document.getElementById('message').innerHTML="";
document.getElementById('total').innerHTML="";
document.getElementById('used').innerHTML="";
document.getElementById('supported').innerHTML="<%:您有未读的短信,请前往查看%>";
}
if ( ss == "3" )
{
document.getElementById('supported').innerHTML="<%:消息读取有问题%>";
}
if ( ss == "2" )
{
document.getElementById('supported').innerHTML="<%:存在短信%>";
clearListBox("smsList");
document.getElementById('total').innerHTML=rv.max;
document.getElementById('used').innerHTML=rv.used;
var line=rv.line;
var arr=(line.split("\x1D"));
var len = arr.length;
indx = 0;
var i;
for(i=0;i<len;i++)
{
index[indx] = parseInt(arr[i]);
number[indx] = arr[i+1];
ttext[indx] = arr[i+2];
var txtline = arr[i+3];
txtline = txtline.replace(/ /g,"\240");
var select = document.getElementById("smsList");
select.options[select.options.length] = new Option(txtline, indx);
i = i + 3;
indx = indx + 1;
}
if ( indx != -1 )
{
if ( selectline == -1 )
{
select.value = 0;
document.getElementById('message').innerHTML=ttext[0];
selectline = 0;
}
else
{
if ( selectline > indx-1 )
{
selectline = indx -1 ;
}
select.value = selectline;
document.getElementById('message').innerHTML=ttext[selectline];
}
}
}
}
);
readcheck();
}
);
}
@ -413,8 +436,8 @@
<table width="550" border="0">
<tr>
<td width="18%"><div align="center"><strong><%:SIM可存放的短信空间 (条)%></strong></div></td>
<td width="18%"><div align="center"><strong><%:已使用的SIM短信空间 (条)%></strong></div></td>
<td width="18%"><div align="center"><strong><u><%:SIM可存放的短信空间 (条)%></u></strong></div></td>
<td width="18%"><div align="center"><strong><u><%:已使用的SIM短信空间 (条)%></u></strong></div></td>
<td width="34%">&nbsp;</td>
</tr>
<tr>
@ -443,6 +466,14 @@
</tr>
</table>
<table width="700" border="0">
<tr>
<td width="3%">&nbsp;</td>
<td width="17%"><input type="button" id="delallbtn" class="cbi-button cbi-button-remove" value="<%:删除所有短信%>" onclick="return delallsms()" /></td>
<td width="80%">&nbsp;</td>
</tr>
</table>
<table width="700" border="0">
<tr>
<td width="4%"><div align="center"><strong><u><%:已读状态%></u></strong></div></td>
@ -450,7 +481,6 @@
<td width="8%"><div align="left"><strong><u><%:Date%></u></strong></div></td>
<td width="11%"><div align="left"><strong><u><%:时间%></u></strong></div></td>
<td width="35%"><div align="left"><strong><u><%:短信%></u></strong></div></td>
<td width="24%"><div align="left"> </div></td>
</tr>
@ -467,15 +497,18 @@
<table width="550" border="0">
<tr>
<td width="15%"><div align="left"><strong><%:短信内容 :%></strong></div></td>
<td width="70%"><ul id="message"></ul></td>
<td width="15%">&nbsp;</td>
<td width="7%"><div align="left"><strong><%:短信内容 :%></strong></div></td>
<!-- <td width="70%"><ul id="message"></ul></td> -->
<td width="80%">
<textarea readonly="readonly" name="message" id="message" rows="6" style="font-size : 20px;width: 600px;" maxlength="160"></textarea>
</td>
<td width="13%">&nbsp;</td>
</tr>
</table>
<table width="550" border="0">
<tr>
<td width="17%"><input type="button" id="delbtn" class="cbi-button cbi-button-apply" value="<%:删除短信%>" onclick="return delsms()" /></td>
<td width="17%"><input type="button" id="delbtn" class="cbi-button cbi-button-remove" value="<%:删除短信%>" onclick="return delsms()" /></td>
<td width="17%"><input type="button" id="replybtn" class="cbi-button cbi-button-apply" value="<%:回复短信%>" onclick="return replysms()" /></td>
<td width="17%"><input type="button" id="newbtn" class="cbi-button cbi-button-apply" value="<%:新建短信%>" onclick="return newsms()" /></td>
<td width="49%">&nbsp;</td>
@ -494,7 +527,6 @@
<table id="sendtxt" width="700" border="0" style="display:table;">
<tr>
<td width="100%">
<textarea name="txtmessage" id="txtmessage" rows="6" style="width: 600px;" maxlength="160"></textarea>
</td>
@ -522,4 +554,3 @@
</div>
</form>
<%+footer%>

View File

@ -0,0 +1,35 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
log() {
modlog "Delete SMS" "$@"
}
CURRMODEM=$1
COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport)
SMSLOC=$(uci -q get modem.modem$CURRMODEM.smsloc)
LOCKDIR="/tmp/smslock$CURRMODEM"
PIDFILE="${LOCKDIR}/PID"
while [ 1 -lt 6 ]; do
if mkdir "${LOCKDIR}" &>/dev/null; then
echo "$$" > "${PIDFILE}"
ATCMDD="AT+CPMS=\"$SMSLOC\";+CMGD=1,4"
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
log "$OX"
uci set modem.modem$CURRMODEM.smsnum=999
uci commit modem
break
else
OTHERPID="$(cat "${PIDFILE}")"
if [ $? = 0 ]; then
if ! kill -0 $OTHERPID &>/dev/null; then
rm -rf "${LOCKDIR}"
fi
fi
sleep 1
fi
done
rm -rf "${LOCKDIR}"

View File

@ -3,12 +3,13 @@
ROOTER=/usr/lib/rooter
log() {
logger -t "Delete SMS" "$@"
modlog "Delete SMS" "$@"
}
CURRMODEM=$1
shift 1
SLOTS="$@"
log "$SLOTS"
COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport)
@ -17,13 +18,14 @@ SMSLOC=$(uci -q get modem.modem$CURRMODEM.smsloc)
LOCKDIR="/tmp/smslock$CURRMODEM"
PIDFILE="${LOCKDIR}/PID"
while [ 1 -lt 6 ]; do
while [ true ]; do
if mkdir "${LOCKDIR}" &>/dev/null; then
echo "$$" > "${PIDFILE}"
for SLOT in $SLOTS
do
ATCMDD="AT+CPMS=\"$SMSLOC\";+CMGD=$SLOT"
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
log "$OX"
done
uci set modem.modem$CURRMODEM.smsnum=999
uci commit modem

View File

@ -0,0 +1,165 @@
#!/usr/bin/lua
function ltrim(s)
return s:match'^%s*(.*)'
end
file=arg[1]
filet=arg[1]
overall = {}
cntr = 1
filein = io.open(file, "r")
maxslot = -1
repeat
message = {}
local line = filein:read("*line")
if line == nil then
break
end
if cntr < 2 then
maxused = line
line = filein:read("*line")
maxslots = line
cntr=2
else
message['slot'] = line
message['phone'] = filein:read("*line")
nline = filein:read("*line")
message['nline'] = nline
ncntr = 1
msg=""
message['msgnum'] = "xxx"
message['msgord'] = "xxx"
message['msgmax'] = "xxx"
lines = filein:read("*line")
s, e = lines:find("Msg# ")
if s ~= nil then
bs, be = lines:find(",", e+1)
msgnum = lines:sub(e+1, be-1)
message['msgnum'] = msgnum
s, e = lines:find("/", be+1)
msgord = lines:sub(be+1, e-1)
message['msgord'] = msgord
message['msgmax'] = lines:sub(e+1)
lines = filein:read("*line")
end
msg = lines
nc = tonumber(nline)
if nc > 2 then
for i=1,nc-2,1
do
lines = filein:read("*line")
if lines ~= "" then
msg = msg .. "\n" .. lines
else
if i == nc-2 then
if msgord == message['msgmax'] then
msg = msg .. "\n\n"
else
msg = msg .. "\n\n"
end
else
msg = msg .. "\n"
end
end
end
--print(nln, msg)
--msg = msg .. "\n"
end
message['msg'] = msg
message['numlines'] = nc - 1
sht = filein:read("*line")
s, e = sht:find("Msg#")
if s ~= nil then
shtt = sht:sub(1, s-1)
bs, be = sht:find("/", e)
sht = shtt .. sht:sub(be+2)
end
message['short'] = sht
overall[message['slot']] = message
if maxslot < tonumber(message['slot']) then
maxslot = tonumber(message['slot'])
end
end
until 1==0
filein:close()
fileout = io.open(filet, "w")
fileout:write(maxused, "\n")
fileout:write(maxslots, "\n")
for i=0,maxslot,1
do
msgbuild = {}
shortmsg = {}
if overall[tostring(i)] ~= nil then
--print(i, overall[tostring(i)]['msgnum'])
if overall[tostring(i)]['msgnum'] == "xxx" then
fileout:write(overall[tostring(i)]['slot'], "\n")
fileout:write(overall[tostring(i)]['phone'], "\n")
fileout:write(overall[tostring(i)]['nline'], "\n")
fileout:write(overall[tostring(i)]['msg'], "\n")
fileout:write(overall[tostring(i)]['short'], "\n")
else
msgnum = overall[tostring(i)]['msgnum']
msgtmp = overall[tostring(i)]['slot']
msgord = overall[tostring(i)]['msgord']
msgmax = tonumber(overall[tostring(i)]['msgmax'])
msg = overall[tostring(i)]['msg']
numlines = overall[tostring(i)]['numlines']
--print(numlines)
msgbuild[overall[tostring(i)]['msgord']] = overall[tostring(i)]['msg']
shortmsg[overall[tostring(i)]['msgord']] = overall[tostring(i)]['short']
for j=i+1,maxslot,1
do
if overall[tostring(j)] ~= nil then
if overall[tostring(j)]['msgnum'] == msgnum then
numlines = numlines + (overall[tostring(j)]['numlines'])
--print(overall[tostring(j)]['numlines'])
msgtmp = msgtmp .. " " .. overall[tostring(j)]['slot']
msgbuild[overall[tostring(j)]['msgord']] = overall[tostring(j)]['msg']
shortmsg[overall[tostring(j)]['msgord']] = overall[tostring(j)]['short']
overall[tostring(j)] = nil
end
end
end
msg=""
mflg = 0
short = nil
for j=1,msgmax,1
do
if msgbuild[tostring(j)] ~= nil then
msg = msg .. msgbuild[tostring(j)]
if short == nil then
short = shortmsg[tostring(j)]
end
else
mflg = 1
end
end
fileout:write(msgtmp, "\n")
fileout:write(overall[tostring(i)]['phone'], "\n")
if mflg ~= 0 then
msg = "Partial Message : " .. msg
t = short:gsub("%s+", " ")
short = "Partial Message " .. t
end
endc = string.sub(msg, -2)
if endc == "\n\n" then
mlen = msg:len() - 2
msg = string.sub(msg,1,mlen)
end
local _,n = msg:gsub("\n","")
fileout:write(tostring(n+1), "\n")
fileout:write(msg, "\n")
fileout:write(short, "\n")
end
end
end
fileout:close()

View File

@ -855,6 +855,7 @@ else
end
tfile:close()
end
os.execute("/usr/lib/sms/merge.lua " .. tfname)
os.execute("mv " .. tfname .. " /tmp/smstext" .. modemn)
if #delslots > 0 then

View File

@ -1,15 +1,12 @@
module("luci.controller.guestwifi", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
if not nixio.fs.access("/etc/config/wireless") then
return
end
page = entry({"admin", "network", "guestwifi"}, cbi("guestwifi", {hidesavebtn=true, hideresetbtn=true}), translate("Guest Wifi"), 22)
page = entry({"admin", "network", "guestwifi"}, cbi("guestwifi", {hidesavebtn=true, hideresetbtn=true}), "Guest Wifi", 22)
page.dependent = true
entry( {"admin", "network", "guestwifi", "edit"}, cbi("guestwifi-edit"), nil ).leaf = true

View File

@ -99,12 +99,12 @@ function auto.cfgvalue(self, section)
val = 0
end
if val == "1" then
return translate("WPA-PSK (Medium Security)")
return "WPA-PSK (Medium Security)"
else
if val == "2" then
return translate("WPA2-PSK (Strong Security)")
return "WPA2-PSK (Strong Security)"
else
return translate("None")
return "None"
end
end
end
@ -118,9 +118,9 @@ function qos.cfgvalue(self, section)
if val == "1" then
dl_cfg = self.map:get(section, "dl")
ul_cfg = self.map:get(section, "ul")
return translate("Download : ") .. dl_cfg .. translate(" Mbit/s / Upload : ") .. ul_cfg .. translate(" Mbit/s")
return "Download : " .. dl_cfg .. " Mbit/s / Upload : " .. ul_cfg .. " Mbit/s"
else
return translate("Disabled")
return "Disabled"
end
end

View File

@ -328,6 +328,14 @@ _proto_mbim_setup() {
log "Failed to connect to network"
return 1
fi
log "Save Connect Data"
uci set modem.modem$CURRMODEM.mdevice=$device
uci set modem.modem$CURRMODEM.mapn=$apn
uci set modem.modem$CURRMODEM.mipt=$itp
uci set modem.modem$CURRMODEM.mauth=$auth
uci set modem.modem$CURRMODEM.musername=$username
uci set modem.modem$CURRMODEM.mpassword=$password
uci commit modem
tid=$((tid + 1))
@ -467,6 +475,10 @@ _proto_mbim_setup() {
# SIGNAL=$(umbim $DBG -n -t $tid -d $device signal)
# CSQ=$(echo "$SIGNAL" | awk '/rssi:/ {print $2}')
if [ -e $ROOTER/modem-led.sh ]; then
$ROOTER/modem-led.sh $CURRMODEM 3
fi
$ROOTER/log/logger "Modem #$CURRMODEM Connected"
log "Modem $CURRMODEM Connected"
@ -540,7 +552,8 @@ _proto_mbim_setup() {
$ROOTER/timezone.sh &
fi
fi
CLB=$(uci -q get modem.modeminfo$CURRMODEM.lb)
#CLB=$(uci -q get modem.modeminfo$CURRMODEM.lb)
CLB=1
if [ -e /etc/config/mwan3 ]; then
INTER=$(uci get modem.modeminfo$CURRMODEM.inter)
if [ -z $INTER ]; then
@ -577,6 +590,8 @@ proto_mbim_setup() {
CPORT=$(uci get modem.modem$CURRMODEM.commport)
ATCMDD="AT+COPS=0"
OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
#log "Restart Modem"
#/usr/lib/rooter/luci/restart.sh $CURRMODEM
sleep 5
}

View File

@ -32,11 +32,7 @@ define Package/rqmi/description
endef
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include \
-ffunction-sections \
-fdata-sections \
-Wno-error=dangling-pointer \
-Wno-error=maybe-uninitialized
-I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections
TARGET_LDFLAGS += -Wl,--gc-sections

View File

@ -202,6 +202,14 @@ for isp in $isplist
if [[ -z $(echo "$CONN" | grep -o "disconnected") ]]; then
ret=0
uci set modem.modem$CURRMODEM.mdevice=$device
uci set modem.modem$CURRMODEM.mcid=$cid
uci set modem.modem$CURRMODEM.mapn=$NAPN
uci set modem.modem$CURRMODEM.mauth=$auth
uci set modem.modem$CURRMODEM.musername=$username
uci set modem.modem$CURRMODEM.mpassword=$password
uci commit modem
CONN4=$(uqmi -s -d "$device" --set-client-id wds,"$cid" --get-current-settings)
log "GET-CURRENT-SETTINGS is $CONN4"

View File

@ -1,34 +0,0 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=mesh-mesh
PKG_VERSION:=4.500
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/mesh-mesh
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Mesh Support
DEPENDS:=+kmod-batman-adv +alfred +batctl +ip
TITLE:=Install scripts for Mesh Network
PKGARCH:=all
endef
define Package/mesh-mesh/description
Install scripts for Mesh Network
endef
define Build/Compile
endef
define Package/mesh-mesh/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,mesh-mesh))

View File

@ -1,16 +0,0 @@
config mesh 'bat0'
option aggregated_ogms '1'
option ap_isolation '0'
option bonding '0'
option fragmentation '0'
option gw_bandwidth '10000/2000'
option gw_mode 'client'
option gw_sel_class '20'
option log_level '2'
option orig_interval '1000'
option bridge_loop_avoidance '1'
option distributed_arp_table '1'
option multicast_mode '1'
option network_coding '0'
option hop_penalty '30'
option isolation_mark '0'

View File

@ -1,18 +0,0 @@
config radio 'radio'
option radionumber '0'
option usedfs '1'
option channelwidth '0'
option channellist '0'
option channelindex '10'
option dedicated '0'
config network 'network'
option networkid 'MeshCloud'
option netencrypted '1'
option netpassword 'MeshPassword123'
config roam 'roam'
option signalenable '1'
option signalid 'abcd'

View File

@ -1,34 +0,0 @@
#!/bin/sh
dhcp4_discover () {
ifup lan_dhcp
}
dhcp4_kill () {
ifdown lan_dhcp
}
dnsmasq_start () {
uci revert -P/var/state dhcp.@dnsmasq[0].domainneeded
uci revert -P/var/state dhcp.@dnsmasq[0].boguspriv
uci revert -P/var/state dhcp.@dnsmasq[0].rebind_protection
uci revert -P/var/state dhcp.lan.ignore
/etc/init.d/dnsmasq restart
}
dnsmasq_stop () {
uci set -P/var/state dhcp.@dnsmasq[0].domainneeded=
uci set -P/var/state dhcp.@dnsmasq[0].boguspriv=
uci set -P/var/state dhcp.@dnsmasq[0].rebind_protection=0
uci set -P/var/state dhcp.lan.ignore=1
echo no-dhcp-interface=br-lan >> /var/etc/dnsmasq.conf
/etc/init.d/dnsmasq restart
}
if [ "$BATTYPE" = "gw" ] ; then
case "$BATACTION" in
add) dnsmasq_stop ; dhcp4_discover ;;
del) dhcp4_kill ; dnsmasq_start ;;
change) dhcp4_kill ; sleep 5 ; dhcp4_discover ;;
esac
fi

View File

@ -1,9 +0,0 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006 OpenWrt.org
START=99
start() {
/usr/lib/mesh/checker.sh
}

View File

@ -1,249 +0,0 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <xm@subsignal.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
]]--
module("luci.controller.batman", package.seeall)
local function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
function index()
local page
page = node("admin", "mesh", "batman")
page.target = template("batman/batman")
page.title = _("Mesh Status")
page.order = 1
node("batman")
page = node("batman", "json")
page.target = call("act_json")
page = node("batman", "topo")
page.target = call("act_topo")
page.leaf = true
page = node("batman", "graph")
page.target = template("batman_graph")
page.leaf = true
end
function act_topo(mode)
if not mode or mode == "dot" or mode == "json" then
local fd = io.popen("batadv-vis -f %s" %( mode or "dot" ))
if fd then
if mode == "json" then
luci.http.prepare_content("application/json")
luci.http.write("[")
local ln
repeat
ln = fd:read("*l")
if ln then
luci.http.write(ln)
luci.http.write(", ")
end
until not ln
luci.http.write("{ } ]")
else
luci.http.prepare_content("text/vnd.graphviz")
luci.http.header("Content-Disposition",
"attachment; filename=topo-%s-%s.vd"
%{ luci.sys.hostname(), os.date("%Y%m%d-%H%M%S") })
luci.http.write(fd:read("*a"))
end
fd:close()
else
luci.http.status(500, "No data")
end
else
luci.http.status(500, "Bad mode")
end
end
function act_json()
local v, l, fd
local rv = {
interfaces = { },
originators = { },
gateways = { }
}
--
-- interfaces
--
fd = io.popen("batctl if")
if fd then
repeat
l = fd:read("*l")
v = l and l:match("^(.-):")
if v then
rv.interfaces[#rv.interfaces+1] = v
end
until not l
fd:close()
end
os.execute("cat /proc/net/arp > /tmp/arp")
iplist = {}
maclist = {}
index = 0
fd = io.open("/tmp/arp")
if fd then
-- skip header line
fd:read("*l")
repeat
l = fd:read("*l")
if l then
lan = l
s1, e1 = lan:find("0x2")
if s1 ~= nil then
s, e = l:find(" ")
if s ~= nil then
ip = l:sub(0, e-1)
fc = io.popen("batctl translate " .. ip)
if fc then
mac = fc:read("*l")
fc:close()
iplist[index] = ip
maclist[index] = mac
index = index + 1
end
end
end
end
until not l
fd:close()
end
--
-- originators
--
local originators_command = (
"batctl o -H 2>/dev/null ".. -- gets originators from batctl
"| tr -d '[]()' ".. -- removes brackets and parenthesis
"| sed 's/^ / -/g' ".. -- normalizes output, adding a minus when no asterisk is outputed in each line
"| sed 's/^ //g' ".. -- removes the space from the beginning of the line
"| sed -r 's/\\s+/,/g'".. -- replaces tabs for commas
"| sed -r 's/s,/,/g'" -- removes the 's' from the last_seen field referencing seconds
)
fd = io.popen(originators_command)
if fd then
repeat
l = fd:read()
if l then
local asterisk, originator_name, last_seen, link_quality, next_hop, outgoing_if
asterisk, originator_name, last_seen, link_quality, next_hop, outgoing_if = unpack(split(l, ","))
if originator_name and last_seen and link_quality then
if originator_name == next_hop then
next_hop = "Here"
end
if index > 0 then
for j=0,index-1 do
if maclist[j] == originator_name then
originator_name = iplist[j] .. " (" .. originator_name .. ")"
end
if maclist[j] == next_hop then
next_hop = iplist[j]
end
end
end
rv.originators[#rv.originators+1] = {
originator_name,
tonumber(last_seen) * 1000,
tonumber(link_quality),
next_hop,
outgoing_if
}
end
end
until not l
fd:close()
end
--
-- gateways
--
fd = io.popen("batctl gwl")
if fd then
-- skip header line
fd:read("*l")
fd:read("*l")
repeat
l = fd:read("*l")
if l then
local a, m, q, n, i, r = l:match("^(%S*) +([^ ]+) +%( *(%d+)%) +([^ ]+) +%[ *(%S+)%]: +(%S+)")
if a and m and q and n and i and r then
c="0"
if index > 0 then
for j=0,index-1 do
if maclist[j] == m then
m = iplist[j]
end
if maclist[j] == n then
n = iplist[j]
end
end
end
rv.gateways[#rv.gateways+1] = {
#a > 0,
m,
tonumber(q),
n,
i,
tonumber(c),
r
}
end
end
until not l
fd:close()
end
-- local Gateway status
rv.status = "Client"
fd = io.popen("batctl gw")
if fd then
l = fd:read("*l")
s, e = l:find("server")
if s ~= nil then
rv.status = "Server"
end
fd:close()
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end

View File

@ -1,76 +0,0 @@
module("luci.controller.mesh", package.seeall)
function index()
local page
entry({"admin", "mesh"}, firstchild(), "Mesh", 71).dependent=false
page = entry({"admin", "mesh", "mesh"}, template("mesh/mesh-setup"), "Mesh Configuration", 71)
page.dependent = true
entry({"admin", "mesh", "getstate"}, call("action_getstate"))
entry({"admin", "mesh", "sendmeshstate"}, call("action_sendmeshstate"))
entry({"admin", "mesh", "meshcfg"}, call("action_meshcfg"))
entry({"admin", "mesh", "meshstartstop"}, call("action_meshstartstop"))
end
function action_getstate()
local rv = {}
local radiolist = {}
file = io.open("/etc/meshrun", "r")
if file == nil then
rv["state"] = "0"
else
rv["state"] = "1"
file:close()
end
os.execute("/usr/lib/mesh/radio.sh ")
file = io.open("/tmp/radiolist", "r")
if file ~= nil then
j = file:read("*line")
rv['radio'] = j
if j ~=0 then
for i=0, j-1 do
radiolist[i] = file:read("*line")
end
rv['radiolist'] = radiolist
end
rv['radionumber'] = file:read("*line")
rv['channelindex'] = file:read("*line")
rv['channellist'] = file:read("*line")
rv['channelwidth'] = file:read("*line")
rv['usedfs'] = file:read("*line")
rv['dedicated'] = file:read("*line")
rv['networkid'] = file:read("*line")
rv['netencrypted'] = file:read("*line")
rv['netpassword'] = file:read("*line")
rv['signalenable'] = file:read("*line")
rv['signalid'] = file:read("*line")
file:close()
else
rv["radio"] = "0"
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
function action_sendmeshstate()
local set = luci.http.formvalue("set")
os.execute('/usr/lib/mesh/save.sh "' .. set .. '"')
end
function action_meshcfg()
local set = luci.http.formvalue("set")
os.execute('/usr/lib/mesh/savecfg.sh "' .. set .. '"')
end
function action_meshstartstop()
os.execute('/usr/lib/mesh/startstop.sh')
os.execute("reboot &")
end

View File

@ -1,300 +0,0 @@
<%#
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <xm@subsignal.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
-%>
<% luci.http.prepare_content("text/html") %>
<%+header%>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript" src="<%=resource%>/dracula/raphael-min.js"></script>
<script type="text/javascript" src="<%=resource%>/dracula/dracula_graffle.js"></script>
<script type="text/javascript" src="<%=resource%>/dracula/dracula_graph.js"></script>
<script type="text/javascript" src="<%=resource%>/jquery/jquery-1.4.js"></script>
<script type="text/javascript">//<![CDATA[
function gw_apply(field)
{
var mode, val;
if (field.type == 'radio') {
val = '';
mode = field.value;
}
else {
val = field.value;
mode = document.getElementById('gw_gateway').checked ? 'server' : 'client';
}
document.getElementById('gw_apply').style.display = '';
document.getElementById('gw_form').style.display = 'none';
document.getElementById('gw_form_val').parentNode.style.display = (mode != 'off') ? '' : 'none';
XHR.get('<%=luci.dispatcher.build_url("batman/gw")%>/'+mode+'/'+encodeURIComponent(val), null,
function(x, info) {
document.getElementById('gw_form').style.display = '';
document.getElementById('gw_apply').style.display = 'none';
document.getElementById('gw_form_val').value = info;
});
}
XHR.poll(5, '<%=luci.dispatcher.build_url("batman/json")%>', null,
function(x, info)
{
var t;
var og = info.originators;
var gw = info.gateways;
var server = info.status;
if ( server == 'Client' )
{
document.getElementById('status').innerHTML="No local Internet access, running as Client";
}
else
{
document.getElementById('status').innerHTML="Local Internet access, running as Gateway Server";
}
if (!!(t = document.getElementById('originator_table')))
{
/* clear all rows */
while (t.rows.length > 1)
t.rows[0].parentNode.deleteRow(1);
og.sort(function(a, b) { return parseInt(b[2]) - parseInt(a[2]) });
for (var i = 0; i < og.length; i++)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (1 + (i % 2));
var icon;
if (og[i][2] < 64)
icon = "<%=resource%>/icons/signal-0-25.png";
else if (og[i][2] < 128)
icon = "<%=resource%>/icons/signal-25-50.png";
else if (og[i][2] < 192)
icon = "<%=resource%>/icons/signal-50-75.png";
else
icon = "<%=resource%>/icons/signal-75-100.png";
tr.insertCell(-1).innerHTML = String.format(
'<img src="%s" title="<%:Quality%>: %d / 255" style="vertical-align:middle" /> %d/255',
icon, og[i][2], og[i][2]
);
if ( og[i][3] == "Here" )
{
tr.insertCell(-1).innerHTML = '<strong>' + og[i][0] + '</strong>' ;
og[i][3] = " ";
}
else
{
tr.insertCell(-1).innerHTML = og[i][0];
}
tr.insertCell(-1).innerHTML = String.format('%dms', og[i][1]);
tr.insertCell(-1).innerHTML = og[i][4];
tr.insertCell(-1).innerHTML = og[i][3];
}
if (t.rows.length == 1)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 3;
td.innerHTML = '<br /><em><%:There are no active neighbors%></em>';
}
}
if (!!(t = document.getElementById('gateway_table')))
{
/* clear all rows */
while (t.rows.length > 1)
t.rows[0].parentNode.deleteRow(1);
gw.sort(function(a, b) { return a[0] > b[0] });
for (var i = 0; i < gw.length; i++)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (1 + (i % 2));
tr.insertCell(-1).innerHTML = gw[i][0]
? String.format('<strong>%s (active)</strong>', gw[i][1])
: gw[i][1];
tr.insertCell(-1).innerHTML = gw[i][6];
tr.insertCell(-1).innerHTML = String.format('%d/255', gw[i][2]);
tr.insertCell(-1).innerHTML = gw[i][4];
tr.insertCell(-1).innerHTML = gw[i][3];
}
if (t.rows.length == 1)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 3;
td.innerHTML = '<br /><em><%:There are no active mesh gateways%></em>';
}
}
}
);
XHR.get('<%=luci.dispatcher.build_url("batman/topo/json")%>', null,
function(x, data)
{
var g = new Graph();
var render = function(r, node) {
var color = Raphael.getColor();
var rect = r.rect(node.point[0]-50, node.point[1]-10, 100, 20)
.attr({"fill": color, "stroke": color, "stroke-width": 2, r : "9px"})
var set = r.set().
push(rect).
push(r.text(node.point[0], node.point[1], node.label || node.id)
.attr({"fill": "#000"}));
return set;
};
for (var i = 0; i < (data.length-1); i++)
{
// node->node
if (data[i].router && data[i].neighbor) {
g.addNode(data[i].router, { render: render });
g.addNode(data[i].neighbor, { render: render });
g.addEdge(data[i].router, data[i].neighbor,
{ label: parseFloat(data[i].label).toFixed(1),
directed: true, stroke: '#aaaaaa' });
}
else if (data[i].secondary) {
g.addNode(data[i].secondary, { render: render });
g.addNode(data[i].of, { render: render });
g.addEdge(data[i].secondary, data[i].of,
{ fill: "#000" } );
}
}
document.getElementById('canvas').innerHTML = "";
var canvas = document.getElementById('canvas');
var layouter = new Graph.Layout.Spring(g);
layouter.layout();
var renderer = new Graph.Renderer.Raphael(canvas.id, g, canvas.offsetWidth, canvas.offsetHeight);
renderer.draw();
}
);
XHR.poll(25, '<%=luci.dispatcher.build_url("batman/topo/json")%>', null,
function(x, data)
{
var g = new Graph();
var render = function(r, node) {
var color = Raphael.getColor();
var rect = r.rect(node.point[0]-50, node.point[1]-10, 100, 20)
.attr({"fill": color, "stroke": color, "stroke-width": 2, r : "9px"})
var set = r.set().
push(rect).
push(r.text(node.point[0], node.point[1], node.label || node.id)
.attr({"fill": "#000"}));
return set;
};
for (var i = 0; i < (data.length-1); i++)
{
// node->node
if (data[i].router && data[i].neighbor) {
g.addNode(data[i].router, { render: render });
g.addNode(data[i].neighbor, { render: render });
g.addEdge(data[i].router, data[i].neighbor,
{ label: parseFloat(data[i].label).toFixed(1),
directed: true, stroke: '#aaaaaa' });
}
else if (data[i].secondary) {
g.addNode(data[i].secondary, { render: render });
g.addNode(data[i].of, { render: render });
g.addEdge(data[i].secondary, data[i].of,
{ fill: "#000" } );
}
}
document.getElementById('canvas').innerHTML = "";
var canvas = document.getElementById('canvas');
var layouter = new Graph.Layout.Spring(g);
layouter.layout();
var renderer = new Graph.Renderer.Raphael(canvas.id, g, canvas.offsetWidth, canvas.offsetHeight);
renderer.draw();
}
);
//]]></script>
<h2><a id="content" name="content"><%:Mesh Status%></a></h2>
<fieldset class="cbi-section">
<table width="550" border="0">
<tr>
<td width="17%"><div align="right"><strong>Internet Status : </strong></div></td>
<td width="19%"><ul id="status"></ul></td>
<td width="65%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section">
<legend><%:Active Mesh Nodes%></legend>
<table class="cbi-section-table" id="originator_table">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell"><%:Link Quality%></th>
<th class="cbi-section-table-cell"><%:MAC-Address%></th>
<th class="cbi-section-table-cell"><%:Last Seen%></th>
<th class="cbi-section-table-cell"><%:Interface%></th>
<th class="cbi-section-table-cell"><%:Next Hop%></th>
</tr>
<tr class="cbi-section-table-row">
<td colspan="3"><em><br /><%:Collecting data...%></em></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section">
<legend><%:Other Mesh Nodes with Internet Access%></legend>
<table class="cbi-section-table" id="gateway_table">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell"><%:MAC-Address%></th>
<th class="cbi-section-table-cell"><%:Speed%></th>
<th class="cbi-section-table-cell"><%:Link Quality%></th>
<th class="cbi-section-table-cell"><%:Interface%></th>
<th class="cbi-section-table-cell"><%:Next Hop%></th>
</tr>
<tr class="cbi-section-table-row">
<td colspan="3"><em><br /><%:Collecting data...%></em></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section">
<legend><%:Visualization%></legend>
<div id="canvas" style="min-width:800px; min-height:600px"></div>
</fieldset>
<%+footer%>

View File

@ -1,912 +0,0 @@
<%+header%>
<%
local sys = require "luci.sys"
local utl = require "luci.util"
local fs = require "nixio.fs"
function showicon(lck)
if lck == 0 then
return resource .. "/icons/unlock1.png"
else
return resource .. "/icons/lock1.png"
end
end
-%>
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
var change=0;
var radnum = 1; // radio number option radionumber '0'
var channelindex = 0 ; // index in to list option channelindex '0'
var channellist = 0; // list number 0-2 option channellist "0"
var channelwidth = 1; // index of bw 0-3 option channelwidth '0'
var usedfs = 0; // 1 is dfs channels option usedfs "0"
var detecatedradio = 1; // 1 is dedicated radio option dedicated "0"
var networkid = "MeshCloud";
var netencrypted = 0;
var netpassword = "password";
var signalenable = 1;
var signalid = "mesh";
var radiolist = new Array() ;
var partsArray = new Array;
var channels = new Array;
var cwidth = ["20", "40", "80", "80"];
var channelnum = 0;
var chan2num = 14;
var chan5num = 10;
var chan5dfsnum = 23;
var channel2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" ];
var channel5 = ["36", "40", "44", "48", "149", "153", "157", "161", "165", "169"];
var channel5dfs = ["36", "40", "44", "48", "52", "56", "60", "64", "100", "104", "104", "112", "116", "132", "136", "140", "144", "149", "153", "157", "161", "165", "169"];
function setwidth(width)
{
switch (width)
{
case "0":
num = 1;
dropname = "drop5";
break;
case "1":
num = 2;
dropname = "drop6";
break;
case "2":
num = 3;
dropname = "drop7";
break;
case "3":
num = 3;
dropname = "drop8";
break;
}
x = document.getElementById(dropname);
for (i = 0; i < num; i++)
{
option = document.createElement("option");
option.text = cwidth[i] + "Mhz";
x.add(option);
}
}
function changebw(flg)
{
partsArray = radiolist[radnum].split('|');
channelw = partsArray[2];
switch (channelw)
{
case "0":
document.getElementById("radio46").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio46").style.display = "";
}
document.getElementById("drop5").selectedIndex = channelwidth;
document.getElementById("radio47").style.display = "none";
document.getElementById("radio47").style.visibility="hidden";
document.getElementById("radio48").style.display = "none";
document.getElementById("radio48").style.visibility="hidden";
document.getElementById("radio49").style.display = "none";
document.getElementById("radio49").style.visibility="hidden";
break;
case "1":
document.getElementById("radio47").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio47").style.display = "";
}
document.getElementById("drop6").selectedIndex = channelwidth;
document.getElementById("radio46").style.display = "none";
document.getElementById("radio46").style.visibility="hidden";
document.getElementById("radio48").style.display = "none";
document.getElementById("radio48").style.visibility="hidden";
document.getElementById("radio49").style.display = "none";
document.getElementById("radio49").style.visibility="hidden";
break;
case "2":
document.getElementById("radio48").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio48").style.display = "";
}
document.getElementById("drop7").selectedIndex = channelwidth;
document.getElementById("radio46").style.display = "none";
document.getElementById("radio46").style.visibility="hidden";
document.getElementById("radio47").style.display = "none";
document.getElementById("radio47").style.visibility="hidden";
document.getElementById("radio49").style.display = "none";
document.getElementById("radio49").style.visibility="hidden";
break;
case "3":
document.getElementById("radio49").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio49").style.display = "";
}
document.getElementById("drop8").selectedIndex = channelwidth;
document.getElementById("radio46").style.display = "none";
document.getElementById("radio46").style.visibility="hidden";
document.getElementById("radio47").style.display = "none";
document.getElementById("radio47").style.visibility="hidden";
document.getElementById("radio48").style.display = "none";
document.getElementById("radio48").style.visibility="hidden";
break;
}
}
function vischannel(flg)
{
partsArray = radiolist[radnum].split('|');
if ( partsArray[0] == "1" )
{
document.getElementById("radio3").style.display = "none";
document.getElementById("radio3").style.visibility="hidden";
document.getElementById("radio33").style.display = "none";
document.getElementById("radio33").style.visibility="hidden";
document.getElementById("drop2").style.display = "none";
document.getElementById("drop2").style.visibility="hidden";
if ( usedfs == 0 )
{
document.getElementById("radio4").style.display = "block";
document.getElementById("radio4").style.visibility="visible";
document.getElementById("drop3").style.display = "block";
document.getElementById("drop3").style.visibility="visible";
document.getElementById("radio44").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio44").style.display = "";
}
channellist = 1;
document.getElementById("drop3").selectedIndex = channelindex;
document.getElementById("radio5").style.display = "none";
document.getElementById("radio5").style.visibility="hidden";
document.getElementById("drop4").style.display = "none";
document.getElementById("drop4").style.visibility="hidden";
document.getElementById("radio55").style.display = "none";
document.getElementById("radio55").style.visibility="hidden";
}
else
{
document.getElementById("radio5").style.display = "block";
document.getElementById("radio5").style.visibility="visible";
document.getElementById("drop4").style.display = "block";
document.getElementById("drop4").style.visibility="visible";
document.getElementById("radio55").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio55").style.display = "";
}
channellist = 2;
document.getElementById("drop4").selectedIndex = channelindex;
document.getElementById("radio4").style.display = "none";
document.getElementById("radio4").style.visibility="hidden";
document.getElementById("drop3").style.display = "none";
document.getElementById("drop3").style.visibility="hidden";
document.getElementById("radio44").style.display = "none";
document.getElementById("radio44").style.visibility="hidden";
}
}
else
{
document.getElementById("radio3").style.display = "block";
document.getElementById("radio3").style.visibility="visible";
document.getElementById("radio33").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio33").style.display = "";
}
channellist = 0;
document.getElementById("drop2").style.display = "block";
document.getElementById("drop2").style.visibility="visible";
document.getElementById("drop2").selectedIndex = channelindex;
document.getElementById("radio4").style.display = "none";
document.getElementById("radio4").style.visibility="hidden";
document.getElementById("drop3").style.display = "none";
document.getElementById("drop3").style.visibility="hidden";
document.getElementById("radio44").style.display = "none";
document.getElementById("radio44").style.visibility="hidden";
document.getElementById("radio5").style.display = "none";
document.getElementById("radio5").style.visibility="hidden";
document.getElementById("drop4").style.display = "none";
document.getElementById("drop4").style.visibility="hidden";
document.getElementById("radio55").style.display = "none";
document.getElementById("radio55").style.visibility="hidden";
}
}
function setchannels(freq)
{
switch ( freq )
{
case "0" :
channels = channel2;
chansize = chan2num;
dropname = "drop2";
break;
case "1" :
channels = channel5;
chansize = chan5num;
dropname = "drop3";
break;
case "2" :
channels = channel5dfs;
chansize = chan5dfsnum;
dropname = "drop4";
break;
default :
break;
}
x = document.getElementById(dropname);
for (i = 0; i < chansize; i++)
{
option = document.createElement("option");
option.text = "Channel " + channels[i];
x.add(option);
}
x.selectedIndex = channelnum;
}
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "getstate")%>',
null,
function(x, rv)
{
document.getElementById("cbi-modw").style.display = "none";
document.getElementById("cbi-modw").style.visibility="hidden";
document.getElementById("cbi-mod1").style.display = "block";
document.getElementById("cbi-mod1").style.visibility="visible";
document.getElementById("cbi-mod2").style.display = "block";
document.getElementById("cbi-mod2").style.visibility="visible";
document.getElementById("cbi-mod3").style.display = "block";
document.getElementById("cbi-mod3").style.visibility="visible";
radnum = parseInt(rv.radionumber);
channelindex = parseInt(rv.channelindex);
channellist = parseInt(rv.channellist);
channelwidth = parseInt(rv.channelwidth);
usedfs = parseInt(rv.usedfs);
detecatedradio = parseInt(rv.dedicated);
networkid = rv.networkid;
netencrypted = parseInt(rv.netencrypted);
netpassword = rv.netpassword;
signalenable = parseInt(rv.signalenable);
signalid = rv.signalid;
document.getElementById("dedicated").checked = false;
if ( detecatedradio == 1 )
{
document.getElementById("dedicated").checked = true;
}
document.getElementById("dfs").checked = false;
document.getElementById("dfs3").checked = false;
if ( usedfs == 1)
{
document.getElementById("dfs").checked = true;
document.getElementById("dfs3").checked = true;
}
num_radio = parseInt(rv.radio);
if ( num_radio > 0 )
{
radiolist = rv.radiolist;
x = document.getElementById("drop1");
for (i = 0; i < num_radio; i++)
{
partsArray = radiolist[i].split('|');
dropradio = "Radio" + partsArray[1];
if ( partsArray[0] == "1" )
{
dropradio = dropradio + " (5Ghz)";
}
else
{
dropradio = dropradio + " (2.4Ghz)";
}
option = document.createElement("option");
option.text = dropradio;
x.add(option);
}
x.selectedIndex = radnum;
setchannels("0");
setchannels("1");
setchannels("2");
setwidth("0");
setwidth("1");
setwidth("2");
setwidth("3");
vischannel(0);
changebw(0);
document.getElementById("idnam").value = networkid;
document.getElementById("encr").checked = false;
document.getElementById("enc2").style.display = "none";
document.getElementById("enc2").style.visibility="hidden";
document.getElementById("netpass").style.display = "none";
document.getElementById("netpass").style.visibility="hidden";
if ( netencrypted == 1 )
{
document.getElementById("encr").checked = true;
document.getElementById("enc2").style.display = "block";
document.getElementById("enc2").style.visibility="visible";
document.getElementById("netpass").style.display = "block";
document.getElementById("netpass").style.visibility="visible";
}
document.getElementById("netpass").value = netpassword;
document.getElementById("sigenb").checked = false;
document.getElementById("roam11").style.display = "none";
document.getElementById("roam11").style.visibility="hidden";
document.getElementById("idsig").value = signalid;
if ( signalenable == 1 )
{
document.getElementById("sigenb").checked = true;
document.getElementById("roam11").style.display = "";
document.getElementById("roam11").style.visibility="visible";
}
}
}
);
function changes(value)
{
change = value;
if ( value == 0 )
{
document.getElementById("meshstat1").innerHTML = "No Changes";
document.getElementById("meshstat1").style.color = "inherit";
document.getElementById("meshstat1").style.fontWeight = "bold" ;
}
else
{
document.getElementById("meshstat1").innerHTML = "Unsaved Changes";
document.getElementById("meshstat1").style.color = "red";
document.getElementById("meshstat1").style.fontWeight = "bold" ;
}
}
function radiochange(drop)
{
radnum = document.getElementById("drop1").selectedIndex;
channelindex = 0;
vischannel(1);
channelwidth = 0;
changebw(1);
changes(1);
}
function dedicatedrad(check)
{
if ( check.checked == true )
{
detecatedradio = 1;
}
else
{
detecatedradio = 0;
}
changes(1);
}
function setdfs(check)
{
if ( check.checked == true )
{
usedfs = 1;
radiochange();
document.getElementById("dfs").checked = true;
document.getElementById("dfs3").checked = true;
}
else
{
usedfs = 0;
radiochange();
document.getElementById("dfs").checked = false;
document.getElementById("dfs3").checked = false;
}
changes(1);
}
function bwchange(bwbox)
{
bw = bwbox.selectedIndex;
channelwidth = bw;
changes(1);
}
function channelchange(chn)
{
channelindex = chn.selectedIndex;
radnum = document.getElementById("drop1").selectedIndex;
partsArray = radiolist[radnum].split('|');
if ( partsArray[0] == "1" )
{
channellist = 1;
if ( usedfs == 1 )
{
channellist = 2;
}
}
else
{
channellist = 0;
}
changes(1);
}
function setencr(check)
{
if ( check.checked == true )
{
document.getElementById("enc2").style.display = "block";
document.getElementById("enc2").style.visibility="visible";
document.getElementById("netpass").style.display = "block";
document.getElementById("netpass").style.visibility="visible";
netencrypted = 1;
}
else
{
document.getElementById("enc2").style.display = "none";
document.getElementById("enc2").style.visibility="hidden";
document.getElementById("netpass").style.display = "none";
document.getElementById("netpass").style.visibility="hidden";
netencrypted = 0;
}
changes(1);
}
function setlow(check)
{
if ( check.checked == true )
{
document.getElementById("roam11").style.display = "";
document.getElementById("roam11").style.visibility="visible";
signalenable = 1;
}
else
{
document.getElementById("roam11").style.display = "none";
document.getElementById("roam11").style.visibility="hidden";
signalenable = 0;
}
changes(1);
}
function changeid()
{
changes(1);
}
function changesigid()
{
signalid = document.getElementById("idsig").value ;
if ( !signalid )
{
document.getElementById("idsig").value = 'abcd' ;
signalid = 'abcd';
}
changes(1);
}
function configup(btn)
{
var filex = btn.files[0];
var reader = new FileReader();
reader.readAsText(filex);
reader.onload = loaded;
}
function loaded(evt)
{
var fileString = evt.target.result;
partsArray = fileString.split('|');
if ( partsArray[0] == "meshcfg" )
{
radionumber = parseInt(partsArray[0]);
channelindex = parseInt(partsArray[1]);
channellist = parseInt(partsArray[2]);
usedfs = parseInt(partsArray[3]);
channelwidth = parseInt(partsArray[4]);
detecatedradio = parseInt(partsArray[5]);
networkid=partsArray[6];
netencrypted = parseInt(partsArray[7]);
netpassword=partsArray[8];
signalenable = parseInt(partsArray[9]);
signalmeasure = parseInt(partsArray[10]);
signalinterval = parseInt(partsArray[11]);
signalcount = parseInt(partsArray[12]);
snrconnect = parseInt(partsArray[13]);
snrchange = parseInt(partsArray[14]);
sigconnect = parseInt(partsArray[15]);
sigchange = parseInt(partsArray[16]);
window.location.reload(false);
}
changes(1);
}
function buildsave()
{
netpassword = document.getElementById("netpass").value;
if ( netencrypted == 1 )
{
if ( netpassword.length < 8 )
{
alert("You must enter a password at least 8 charactets long!!");
return "1";
}
}
if ( netpassword.length < 8 )
{
netpassword="password";
}
var stat = radnum.toString() + "|" + channelindex.toString() + "|" + channellist.toString() + "|" + usedfs.toString() + "|" + channelwidth.toString() + "|" + detecatedradio.toString() + "|" + networkid + "|" + netencrypted.toString() + "|" + netpassword + "|" ;
var rom = signalenable.toString() + "|" + signalid + "|" ;
stat = stat + rom;
return stat;
}
function saveconf(btn)
{
statusm = buildsave();
if ( statusm == "1" )
{
return false;
}
statusm = "meshcfg|" + statusm;
//document.getElementById("attxt").value=statusm;
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "meshcfg")%>',
{ set: statusm },
function()
{
window.open('http://'+window.location.hostname+'/package/meshcfg.meshcfg', '_self')
}
);
}
function savemesh(btn)
{
statusm = buildsave();
if ( statusm == "1" )
{
return false;
}
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "sendmeshstate")%>',
{ set: statusm },
function()
{
window.location.reload(false);
}
);
}
function reloadmesh()
{
changes(0);
window.location.reload(false);
}
var tries = 0,
message = document.querySelector('p.reboot-message'),
label = message.querySelector('span');
function ok() {
window.location = '<%=url("admin")%>';
}
function check() {
window.setTimeout(ping, 5000);
}
function ping() {
var img = document.createElement('img');
img.onload = ok;
img.onerror = check;
img.src = '<%=resource%>/icons/loading.gif?' + Math.random();
if (tries++ >= 30) {
message.classList.remove('notice');
message.classList.add('warning');
label.innerHTML = '<%:Device unreachable! Still waiting for device...%>';
}
}
function startstopmesh(btn)
{
if (change == 1 )
{
savech = confirm("Unsaved changes will be lost. Save first?");
if ( savech == true )
{
statusm = buildsave();
if ( statusm !== "1" )
{
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "sendmeshstate")%>',
{ set: statusm },
function()
{
}
);
changes(0);
}
}
}
cont = confirm("Router will reboot after applying settings. Continue?");
if ( cont == false )
{
return false;
}
document.getElementById("cbi-modw").style.display = "block";
document.getElementById("cbi-modw").style.visibility="visible";
document.getElementById("cbi-mod1").style.display = "none";
document.getElementById("cbi-mod1").style.visibility="hidden";
document.getElementById("cbi-mod2").style.display = "none";
document.getElementById("cbi-mod2").style.visibility="hidden";
document.getElementById("cbi-mod3").style.display = "none";
document.getElementById("cbi-mod3").style.visibility="hidden";
document.getElementById("fileup").disabled=true;
document.getElementById("meshconf").disabled=true;
document.getElementById("meshsave").disabled=true;
document.getElementById("meshstart").disabled=true;
document.getElementById("meshstat1").style.display = "none";
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "meshstartstop")%>',
{ set: "1" },
function()
{
}
);
check();
}
//document.getElementById("attxt").value=partsArray[0].toString();
//]]></script>
<form method="post" action="<%=REQUEST_URI%>">
<div class="cbi-map" id="cbi-modem">
<h2><a id="content" name="content">Mesh Network Configuration</a></h2>
<div class="cbi-map-descr"> </div>
<fieldset class="cbi-section" id="cbi-mod">
<table width="100%" border="0" id="meshstatus">
<tr>
<td width="20%"><div align="center" id="meshstat2" style="font-size:1.5em"><strong>Config Status</strong></div></td>
<td width="20%"><div align="center" id="upl2" ><strong>Import Configuration File</strong></div></td>
<td width="13%"><div align="center" id="upl3" ><strong>Export Configuration File</strong></div></td>
<td width="10%"><div align="center" id="up42" ><strong>Save Settings</strong></div></td>
<td width="10%"><div align="center" id="up52" ><strong>Apply Settings</strong></div></td>
<td width="10%"><div align="center" id="up52" ><strong>Reload Settings</strong></div></td>
<td width="17%"></td>
</tr>
<tr>
<td width="20%"><div align="center" id="meshstat1" ><strong>No Changes</strong></div></td>
<td width="20%"><input type="file" accept=".meshcfg" align="center" name="fileup" id="fileup" class="cbi-button cbi-button-positive" onchange="return configup(this)" /></td>
<td width="13%"><input type="button" align="center" id="meshconf" class="cbi-button cbi-button-positive" value="<%:Save Configuration File%>" onclick="return saveconf(this)" /></td>
<td width="10%"><input type="button" align="center" id="meshsave" class="cbi-button cbi-button-positive" value="<%:Save Settings%>" onclick="return savemesh(this)" /></td>
<td width="10%"><input type="button" align="center" id="meshstart" class="cbi-button cbi-button-positive" value="<%:Apply Settings%>" onclick="return startstopmesh(this)" /></td>
<td width="10%"><input type="button" align="center" id="meshreload" class="cbi-button cbi-button-positive" value="<%:Reload Settings%>" onclick="return reloadmesh(this)" /></td>
<td width="17%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-modw" style="visibility:hidden">
<table width="100%" cellspacing="10" id="waiting">
<tr>
<td width="40%"></td>
<td id="waiticon"><img src="<%=resource%>/icons/loading.gif" style="vertical-align:middle" /> Waiting for Reboot...</td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-mod1">
<table width="100%" border="0" id="meshradio" >
<tr>
<td width="17%"><div align="left" id="radio1" style="font-size:1.5em"><strong>Mesh Radio Settings</strong></div></td>
<td width="15%"></td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="radio2" ><strong>Select Backhaul Radio </strong></div></td>
<td width="15%">
<select style="width:200px" name="raddrop" id="drop1" onchange="return radiochange(this)">
</select>
</td>
<td width="12%"><div align="left" id="dedicated1" style="font-size:1em"><strong>Dedicated Backhaul Radio </strong></div></td>
<td width="5%"><input type="checkbox" id="dedicated" onclick="return dedicatedrad(this)" /></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio33">
<td width="17%"><div align="right" id="radio3" ><strong>Select Backhaul Channel </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop" id="drop2" onchange="return channelchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio44">
<td width="17%"><div align="right" id="radio4" ><strong>Select Backhaul Channel </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop1" id="drop3" onchange="return channelchange(this)">
</select>
</td>
<td width="12%"><div align="left" id="dfs1" style="font-size:1em"><strong>Use DFS Channels </strong></div></td>
<td width="5%"><input type="checkbox" id="dfs" onclick="return setdfs(this)" /></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio55">
<td width="17%"><div align="right" id="radio5" ><strong>Select Backhaul Channel </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop2" id="drop4" onchange="return channelchange(this)">
</select>
</td>
<td width="12%"><div align="left" id="dfs2" style="font-size:1em"><strong>Use DFS Channels </strong></div></td>
<td width="5%"><input type="checkbox" id="dfs3" onclick="return setdfs(this)" /></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio46">
<td width="17%"><div align="right" id="radio6" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop5" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio47">
<td width="17%"><div align="right" id="radio7" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop6" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio48">
<td width="17%"><div align="right" id="radio7" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop7" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio49">
<td width="17%"><div align="right" id="radio7" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop8" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-mod2" >
<table width="100%" border="0" id="meshnet" >
<tr>
<td width="17%"><div align="left" id="net1" style="font-size:1.5em"><strong>Mesh Network Settings</strong></div></td>
<td width="10%"></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="net2" ><strong>Mesh Network ID </strong></div></td>
<td width="10%" ><input style="width: 200px;" type="text" name="idnam" id="idnam" class="cbi-input-text" value="MeshCloud" onchange="return changeid()" ></input></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="enc1" style="font-size:1em"><strong>Network Encrypted </strong></div></td>
<td width="10%"><input type="checkbox" id="encr" onclick="return setencr(this)" /></td>
<td width="12%"><div align="left" id="enc2" style="font-size:1em; visibility:hidden"><strong>Network Password </strong></div></td>
<td width="15%"><input style="width: 200px; visibility:hidden" type="text" name="netpass" id="netpass" class="cbi-input-text" placeholder="password" onchange="return changeid()" ></input></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-mod3" >
<table width="100%" border="0" id="meshroam" >
<tr>
<td width="17%"><div align="left" id="roam1" style="font-size:1.5em"><strong>Access Point Roaming</strong></div></td>
<td width="10%"></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="enc1" style="font-size:1em"><strong>Enable Low Signal Roaming </strong></div></td>
<td width="10%"><input type="checkbox" id="sigenb" onclick="return setlow(this)" /></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr id="roam11">
<td width="17%"><div align="right" id="roam1" ><strong>Roaming ID </strong></div></td>
<td width="10%" ><input style="width: 200px;" type="text" name="idsig" id="idsig" class="cbi-input-text" value="mesh" onchange="return changesigid()" ></input></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
</table>
<table id="cmdtxt" width="700" border="0" style="display:table;">
<tr>
<td width="100%">
<textarea readonly="readonly" name="attxt" id="attxt" rows="6" style="width: 600px;" maxlength="160"></textarea>
</td>
</tr>
</table>
</fieldset>
</div>
</form>
<%+footer%>

View File

@ -1,251 +0,0 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Checker" "$@"
}
channel2="1,2,3,4,5,6,7,8,9,10,11,12,13,14"
channel5="36,40,44,48,149,153,157,161,165,169"
channel5dfs="36,40,44,48,52,56,60,64,100,104,104,112,116,132,136,140,144,149,153,157,161,165,169"
absolute() {
num=$1
if [ "$num" -lt 0 ]; then
num=$((-num))
fi
}
loadconfig() {
X=$(uci -q get wireless.wmesh.device)
uci set mesh.radio.radionumber=$(echo ${X#radio})
uci set mesh.radio.dedicated=$(uci -q get wireless.default_$X.disabled)
chanwidth=$(uci -q get wireless.$X.htmode)
case $chanwidth in
"HT20" )
chanwidth=0
;;
"HT40" )
chanwidth=1
;;
"VHT80" )
chanwidth=2
;;
"VHT160" )
chanwidth=2
;;
esac
uci set mesh.radio.channelwidth=$chanwidth
chan=$(uci -q get wireless.$X.channel)
if [ $chan -lt 15 ]; then
uci set mesh.radio.channellist=0
uci set mesh.radio.channelindex=$((${chan}-1))
else
dfs=$(uci -q get wireless.$X.usedfs)
if [ -z $dfs ]; then
dfs=1
uci set mesh.radio.usedfs=1
else
uci set mesh.radio.usedfs=$dfs
fi
if [ $dfs -eq 0 ]; then
uci set mesh.radio.channellist=1
clist=$channel5
else
uci set mesh.radio.channellist=2
clist=$channel5dfs
fi
cindex=1
while [ true ]
do
chan=$(echo "$clist" | cut -d, -f$cindex)
if [ $chan -eq $channel ]; then
uci set mesh.radio.channelindex=$((${cindex}-1))
break
fi
cindex=$((${cindex}+1))
done
fi
enc=$(uci -q get wireless.wmesh.encryption)
if [ $enc = "sae" ]; then
uci set mesh.network.netencrypted=1
uci set mesh.network.netpassword=$(uci -q get wireless.wmesh.key)
else
uci set mesh.network.netencrypted=0
uci set mesh.network.netpassword="password"
fi
uci set mesh.network.networkid=$(uci -q get wireless.wmesh.mesh_id)
snr=$(uci -q get wireless.default_$X.ieee80211r)
if [ ! -z $snr ]; then
uci set mesh.roam.signalenable=$snr
uci set mesh.roam.signalid=$(uci -q get wireless.default_$X.mobility_domain)
else
uci set mesh.roam.signalenable=0
uci set mesh.roam.signalid="abcd"
fi
uci commit mesh
}
count_radio() {
local config=$1
local channel
uci set wireless.default_radio$count.ieee80211r=$signalenable
uci set wireless.default_radio$count.mobility_domain=$signalid
uci set wireless.default_radio$count.ft_over_ds="1"
uci set wireless.default_radio$count.ft_psk_generate_local="1"
count=$((${count}+1))
}
loadmesh() {
radionum=$(uci -q get mesh.radio.radionumber)
dedicated=$(uci -q get mesh.radio.dedicated)
if [ -z $dedicated ]; then
dedicated="0"
fi
log "default_radio$radionum disabled = $dedicated"
chanwidth=$(uci -q get mesh.radio.channelwidth)
case $chanwidth in
"0" )
chanwidth=20
;;
"1" )
chanwidth=40
;;
"2" )
chanwidth=80
;;
"3" )
chanwidth=80
;;
esac
cwidth=$(uci -q get wireless.radio$radionum.htmode)
ht=$(echo "$cwidth" | grep "VHT")
if [ ! -z $ht ]; then
cwidth="VHT"$chanwidth
else
cwidth="HT"$chanwidth
fi
log "radio$radionum htmode = $cwidth"
clist=$(uci -q get mesh.radio.channellist)
cindex=$(uci -q get mesh.radio.channelindex)
cindex=$((${cindex}+1))
case $clist in
"0" )
channel=$(echo "$channel2" | cut -d, -f$cindex)
;;
"1" )
channel=$(echo "$channel5" | cut -d, -f$cindex)
;;
"2" )
channel=$(echo "$channel5dfs" | cut -d, -f$cindex)
;;
esac
log "radio$radionum channel = $channel"
networkid=$(uci -q get mesh.network.networkid)
netencrypted=$(uci -q get mesh.network.netencrypted)
netpassword=$(uci -q get mesh.network.netpassword)
log "mesh_id = $networkid"
log "encryption = $netencrypted key = $netpassword"
signalenable=$(uci -q get mesh.roam.signalenable)
signalid=$(uci -q get mesh.roam.signalid)
log "roam enable = $signalenable"
log "id = $signalid"
ipaddr=$(uci -q get network.lan.ipaddr)
uci set wireless.default_radio$radionum.disabled=$dedicated
uci set wireless.radio$radionum.htmode=$cwidth
uci set wireless.radio$radionum.channel=$channel
count=0
config_load wireless
config_foreach count_radio wifi-iface
uci set wireless.wmesh=wifi-iface
uci set wireless.wmesh.device=radio$radionum
uci set wireless.wmesh.network="mesh"
uci set wireless.wmesh.ifname="if-mesh"
uci set wireless.wmesh.mode="mesh"
uci set wireless.wmesh.mesh_fwding="0"
uci set wireless.wmesh.mesh_id=$networkid
uci set wireless.w.encryption="none"
if [ $netencrypted = "1" ]; then
uci set wireless.wmesh.encryption="sae"
uci set wireless.wmesh.key=$netpassword
fi
uci set wireless.wmesh.mesh_ttl='1'
uci set wireless.wmesh.mcast_rate='24000'
uci set wireless.wmesh.disabled='0'
uci commit wireless
uci set alfred.alfred.batmanif='bat0'
uci set alfred.alfred.disabled='0'
uci commit alfred
uci set network.bat0=interface
uci set network.bat0.proto='batadv'
uci set network.bat0.routing_algo='BATMAN_IV'
uci set network.bat0.aggregated_ogms='1'
uci set network.bat0.ap_isolation='0'
uci set network.bat0.bonding='0'
uci set network.bat0.bridge_loop_avoidance='1'
uci set network.bat0.distributed_arp_table='1'
uci set network.bat0.fragmentation='1'
uci set network.bat0.gw_mode='off'
uci set network.bat0.hop_penalty='30'
uci set network.bat0.isolation_mark='0x00000000/0x00000000'
uci set network.bat0.log_level='0'
uci set network.bat0.multicast_mode='1'
uci set network.bat0.multicast_fanout='16'
uci set network.bat0.network_coding='0'
uci set network.bat0.orig_interval='1000'
uci set network.mesh=interface
uci set network.mesh.proto='batadv_hardif'
uci set network.mesh.master='bat0'
uci set network.mesh.mtu='2304'
uci set network.mesh.throughput_override='0'
uci set network.bat0_hardif_eth0=interface
uci set network.bat0_hardif_eth0.proto='batadv_hardif'
uci set network.bat0_hardif_eth0.master='bat0'
uci set network.bat0_hardif_eth0.mtu='1536'
uci set network.bat0_hardif_eth0.device='eth0'
uci set network.bat0_lan=interface
uci set network.bat0_lan.proto='static'
uci set network.bat0_lan.ipaddr=$ipaddr
uci set network.bat0_lan.netmask='255.255.255.0'
uci set network.bat0_lan.ip6assign='60'
uci set network.bat0_lan.device='bat0'
uci commit network
}
cmd=$1
if [ -z $cmd ]; then
WW=$(uci get wireless.wmesh)
if [ -z $WW ]; then
loadmesh
reboot -f
else
loadconfig
/usr/lib/mesh/ping.sh &
fi
else
loadmesh
fi
return

View File

@ -1,34 +0,0 @@
#!/bin/sh
. /lib/functions.sh
pinging() {
PING=0
RETURN_CODE_1=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.google.com/)
RETURN_CODE_2=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.example.org/)
RETURN_CODE_3=$(curl -m 10 -s -o /dev/null -w "%{http_code}" https://github.com)
if [[ "$RETURN_CODE_1" != "200" && "$RETURN_CODE_2" != "200" && "$RETURN_CODE_3" != "200" ]]; then
PING=1
fi
}
gateway() {
mode=$1
# batman-adv gateway handling (DHCP mangling)
[ "$(uci -q get batman-adv.bat0.gw_mode)" == "client" ] || return
if grep -q "^=>" /sys/kernel/debug/batman_adv/bat0/gateways ; then
BATTYPE=gw BATACTION=$mode /etc/hotplug.d/net/99-batman-gw
fi
}
while true ; do
sleep 20
pinging
if [ $PING -eq 1 ]; then
gateway add
batctl gw_mode client
else
gateway del
batctl gw_mode server 10000
fi
done

View File

@ -1,78 +0,0 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Radio" "$@"
}
count_radio() {
local config=$1
local channel
config_get channel $1 channel
count=$((${count}+1))
}
do_radio() {
local config=$1
local channel
config_get channel $1 channel
rn=${config#radio}
freq="1"
if [ $channel -lt 15 ]; then
freq="0"
fi
iwin=$(iw phy phy$rn info)
hw=0
hwt=$(echo "$iwin" | grep 'short GI for 40 MHz')
if [ ! -z "$hwt" ]; then
hw=1
fi
hwt=$(echo "$iwin" | grep 'short GI (80 MHz)')
if [ ! -z "$hwt" ]; then
hw=2
fi
hwt=$(echo "$iwin" | grep 'short GI (160')
if [ ! -z "$hwt" ]; then
hw=3
fi
echo "$freq|$rn|$hw" >> /tmp/radiolist
}
count=0
rm -f /tmp/radiolist
config_load wireless
config_foreach count_radio wifi-device
if [ $count -gt 0 ]; then
echo "$count" > /tmp/radiolist
config_foreach do_radio wifi-device
fi
CF1=$(uci -q get mesh.radio.radionumber)
CF2=$(uci -q get mesh.radio.channelindex)
CF3=$(uci -q get mesh.radio.channellist)
CF4=$(uci -q get mesh.radio.channelwidth)
CF5=$(uci -q get mesh.radio.usedfs)
CF6=$(uci -q get mesh.radio.dedicated)
echo "$CF1" >> /tmp/radiolist
echo "$CF2" >> /tmp/radiolist
echo "$CF3" >> /tmp/radiolist
echo "$CF4" >> /tmp/radiolist
echo "$CF5" >> /tmp/radiolist
echo "$CF6" >> /tmp/radiolist
CF1=$(uci -q get mesh.network.networkid)
CF2=$(uci -q get mesh.network.netencrypted)
CF3=$(uci -q get mesh.network.netpassword)
echo "$CF1" >> /tmp/radiolist
echo "$CF2" >> /tmp/radiolist
echo "$CF3" >> /tmp/radiolist
CF1=$(uci -q get mesh.roam.signalenable)
CF2=$(uci -q get mesh.roam.signalid)
echo "$CF1" >> /tmp/radiolist
echo "$CF2" >> /tmp/radiolist

View File

@ -1,25 +0,0 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Save" "$@"
}
state=$1
state=$(echo "$state" | tr "|" ",")
uci set mesh.radio.radionumber=$(echo "$state" | cut -d, -f1)
uci set mesh.radio.channelindex=$(echo "$state" | cut -d, -f2)
uci set mesh.radio.channellist=$(echo "$state" | cut -d, -f3)
uci set mesh.radio.usedfs=$(echo "$state" | cut -d, -f4)
uci set mesh.radio.channelwidth=$(echo "$state" | cut -d, -f5)
uci set mesh.radio.dedicated=$(echo "$state" | cut -d, -f6)
uci set mesh.network.networkid=$(echo "$state" | cut -d, -f7)
uci set mesh.network.netencrypted=$(echo "$state" | cut -d, -f8)
uci set mesh.network.netpassword=$(echo "$state" | cut -d, -f9)
uci set mesh.roam.signalenable=$(echo "$state" | cut -d, -f10)
uci set mesh.roam.signalid=$(echo "$state" | cut -d, -f11)
uci commit mesh

View File

@ -1,16 +0,0 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Save" "$@"
}
state=$1
PKI_DIR="/www"
cd ${PKI_DIR}
mkdir -p package
cd ..
chmod -R 0777 ${PKI_DIR}/package
echo "$state" > ${PKI_DIR}/package/meshcfg.meshcfg

View File

@ -1,8 +0,0 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Start Mesh" "$@"
}
/usr/lib/mesh/checker.sh 1

View File

@ -1 +0,0 @@
Raphael.fn.connection=function(a,b,c){var d=this,e={draw:function(){for(var f=a.getBBox(),g=b.getBBox(),h=0,i=0,j=[{x:f.x+f.width/2,y:f.y-h},{x:f.x+f.width/2,y:f.y+f.height+h},{x:f.x-h,y:f.y+f.height/2},{x:f.x+f.width+h,y:f.y+f.height/2},{x:g.x+g.width/2,y:g.y-i},{x:g.x+g.width/2,y:g.y+g.height+i},{x:g.x-i,y:g.y+g.height/2},{x:g.x+g.width+i,y:g.y+g.height/2}],k={},l=[],m=0;m<4;m++)for(var n=4;n<8;n++){var o=Math.abs(j[m].x-j[n].x),p=Math.abs(j[m].y-j[n].y);(m==n-4||(3!=m&&6!=n||j[m].x<j[n].x)&&(2!=m&&7!=n||j[m].x>j[n].x)&&(0!=m&&5!=n||j[m].y>j[n].y)&&(1!=m&&4!=n||j[m].y<j[n].y))&&(l.push(o+p),k[l[l.length-1].toFixed(3)]=[m,n])}var q=0==l.length?[0,4]:k[Math.min.apply(Math,l).toFixed(3)],r=j[q[0]].x,s=j[q[0]].y,t=j[q[1]].x,u=j[q[1]].y,o=Math.max(Math.abs(r-t)/2,10),p=Math.max(Math.abs(s-u)/2,10),v=[r,r,r-o,r+o][q[0]].toFixed(3),w=[s-p,s+p,s,s][q[0]].toFixed(3),x=[0,0,0,0,t,t,t-o,t+o][q[1]].toFixed(3),y=[0,0,0,0,s+p,s-p,u,u][q[1]].toFixed(3),z=["M",r.toFixed(3),s.toFixed(3),"C",v,w,x,y,t.toFixed(3),u.toFixed(3)].join(",");if(c&&c.directed){var A=Math.sqrt((u-y)*(u-y)+(t-x)*(t-x)),B=function(a,b){return-a*(b||5)/A},C=[{x:(B(t-x)+B(u-y)+t).toFixed(3),y:(B(u-y)+B(t-x)+u).toFixed(3)},{x:(B(t-x)-B(u-y)+t).toFixed(3),y:(B(u-y)-B(t-x)+u).toFixed(3)}];z=z+",M"+C[0].x+","+C[0].y+",L"+t+","+u+",L"+C[1].x+","+C[1].y}var D="attr";e.fg&&e.fg[D]({path:z})||(e.fg=d.path(z).attr({stroke:c&&c.stroke||"#000",fill:"none"}).toBack()),e.bg&&e.bg[D]({path:z})||c&&c.fill&&(e.bg=c.fill.split&&d.path(z).attr({stroke:c.fill.split("|")[0],fill:"none","stroke-width":c.fill.split("|")[1]||3}).toBack()),c&&c.label&&(e.label&&e.label.attr({x:(r+t)/2,y:(s+u)/2})||(e.label=d.text((r+t)/2,(s+u)/2,c.label).attr({fill:"#000","font-size":c["font-size"]||"12px"}))),c&&c.label&&c["label-style"]&&e.label&&e.label.attr(c["label-style"]),c&&c.callback&&c.callback(e)}};return e.draw(),e};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,154 +0,0 @@
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

View File

@ -1,8 +0,0 @@
'use strict';
'require network';
return network.registerProtocol('batadv', {
getI18n: function() {
return _('Batman');
}
});

View File

@ -1,8 +0,0 @@
'use strict';
'require network';
return network.registerProtocol('batadv_hardif', {
getI18n: function() {
return _('Mesh');
}
});

View File

@ -1,29 +0,0 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=mesh-wpad
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/mesh-wpad
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Mesh Support
DEPENDS:=+wpad-mesh-openssl
TITLE:=Support for Mesh routing
PKGARCH:=all
endef
define Package/mesh-wpad/description
Helper scripts to install Meshing
endef
define Build/Compile
endef
$(eval $(call BuildPackage,mesh-wpad))

View File

@ -238,7 +238,7 @@ btn.inputtitle = translate("Send Test of Text or Email")
btn.inputstyle = "apply"
btn:depends("text", "1")
function btn.write()
luci.sys.call("/usr/lib/bwmon/dotext.sh")
luci.sys.call("/usr/lib/bwmon/dotext.sh &")
end
b4 = s:option(DummyValue, "blank", " ");

View File

@ -6,7 +6,7 @@ START=60
start() {
WX=$(uci -q get custom.bwallocate.lock)
if [ "$WX" = "1" ]; then
uci set bwmon.general.enabled=$enable
uci set bwmon.general.enabled=1
uci commit bwmon
fi
/usr/lib/bwmon/wrtbwmon.sh &

View File

@ -23,8 +23,14 @@ end
aamt = arg[1]
uamt = arg[2]
amt = aamt - uamt
amts = calc(amt)
if uamt > aamt then
amt = uamt - aamt
amts = calc(amt)
amts = "-" .. amts
else
amt = aamt - uamt
amts = calc(math.abs(amt))
end
tfile = io.open("/tmp/amtleft", "w")
tfile:write(amts, "\n")
tfile:close()

View File

@ -4,10 +4,11 @@ alloc = arg[1] -- allocate increment in GB
per = arg[2] -- fixed percentage in GB
used = arg[3] -- amt used in Kb
used = used / 10000 -- used in GB
percent = used / alloc
--used = used / 10000 -- used in GB
percent = (used / alloc) * 100
running = "0"
if percent >= per then
if percent >= tonumber(per) then
running = "1"
end

View File

@ -2,7 +2,7 @@
. /lib/functions.sh
log() {
logger -t "TEXTING" "$@"
modlog "TEXTING" "$@"
}
checktime() {
@ -96,7 +96,7 @@ checkper() {
istime=$(checktime)
if [ $istime = '1' ]; then
prev=$(uci -q get custom.texting.used)
per=$(uci -q get custom.bwallocate.percent)
per=$(uci -q get custom.texting.percent)
persent=$(uci -q get custom.bwallocate.persent)
if [ "$persent" != "1" ]; then
getbw
@ -141,7 +141,7 @@ do
if [ $running = "1" ]; then
EN=$(uci -q get custom.texting.text)
if [ $EN = "1" ]; then
/usr/lib/bwmon/dotext.sh
/usr/lib/bwmon/dotext.sh &
sleep $delay
fi
else

View File

@ -1,13 +1,10 @@
module("luci.controller.blacklist", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
local lock = luci.model.uci.cursor():get("custom", "menu", "full")
--if lock == "1" then
page = entry({"admin", "adminmenu", "blacklist"}, cbi("blacklist"), translate("Blacklist by Mac"), 10)
if lock == "1" then
page = entry({"admin", "adminmenu", "blacklist"}, cbi("blacklist"), "---Blacklist by Mac", 10)
page.dependent = true
--end
end
end

View File

@ -3,34 +3,33 @@
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-domain
PKG_NAME:=ext-blockport
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-domain
define Package/ext-blockport
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Optional Applications
DEPENDS:=+dnsmasq-full +ipset
TITLE:=Domain Filter
TITLE:=Install Port Blocking
PKGARCH:=all
endef
define Package/ext-domain/description
Helper scripts to install Domain Filter on ROOter
define Package/ext-blockport/description
Helper scripts to install Port Blocking
endef
define Build/Compile
endef
define Package/ext-domain/install
define Package/ext-blockport/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-domain))
$(eval $(call BuildPackage,ext-blockport))

View File

@ -0,0 +1,4 @@
config port 'port'

View File

@ -1 +0,0 @@
config filter filter

View File

@ -1,46 +0,0 @@
#!/bin/sh /etc/rc.common
START=99
log() {
logger -t "Domain Filter " "$@"
}
start()
{
ff=$(uci -q get firewall.filter)
if [ -z $ff ]; then
uci set firewall.filter="ipset"
uci set firewall.filter.name="filter"
uci set firewall.filter.family="ipv4"
uci set firewall.filter.storage="hash"
uci set firewall.filter.match="ip"
uci set firewall.filter6="ipset"
uci set firewall.filter6.name="filter6"
uci set firewall.filter6.family="ipv6"
uci set firewall.filter6.storage="hash"
uci set firewall.filter6.match="ip"
# Filter LAN client traffic with IP sets
uci set firewall.filter_fwd="rule"
uci set firewall.filter_fwd.name="Filter-IPset-DNS-Forward"
uci set firewall.filter_fwd.src="lan"
uci set firewall.filter_fwd.dest="wan"
uci set firewall.filter_fwd.ipset="filter dest"
uci set firewall.filter_fwd.family="ipv4"
uci set firewall.filter_fwd.proto="all"
uci set firewall.filter_fwd.target="REJECT"
uci set firewall.filter6_fwd="rule"
uci set firewall.filter6_fwd.name="Filter6-IPset-DNS-Forward"
uci set firewall.filter6_fwd.src="lan"
uci set firewall.filter6_fwd.dest="wan"
uci set firewall.filter6_fwd.ipset="filter6 dest"
uci set firewall.filter6_fwd.family="ipv6"
uci set firewall.filter6_fwd.proto="all"
uci set firewall.filter6_fwd.target="REJECT"
uci commit firewall
/etc/init.d/firewall restart
fi
/usr/lib/domain/filter.sh
}

View File

@ -0,0 +1,37 @@
#!/bin/sh
. /lib/functions.sh
config="firewall"
do_block_remove() {
config_get name $1 name
if [ "$name" = "Block_src" ]; then
uci delete $config".""$1"
fi
}
handle_port() {
echo $1
uci add $config rule
uci set $config.@rule[-1].src='lan'
uci set $config.@rule[-1].family='ipv4'
uci set $config.@rule[-1].dest='wan'
uci set $config.@rule[-1].target='DROP'
uci set $config.@rule[-1].proto='tcp'
uci set $config.@rule[-1].src_port="$1"
uci set $config.@rule[-1].name='Block_src'
}
do_port() {
config_list_foreach "$1" block handle_port
}
sleep 8
config_load $config
config_foreach do_block_remove rule
config_load blockport
config_foreach do_port port
uci commit $config
/etc/init.d/firewall restart 2>/dev/null

View File

@ -1,26 +0,0 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Domain Filter " "$@"
}
handle_ipset() {
local ips=$1
uci add_list dhcp.@dnsmasq[0].ipset='/'$ips'/filter,filter6'
}
do_ipset() {
local config=$1
local ipset
config_list_foreach "$config" ipset handle_ipset
}
sleep 3
uci -q delete dhcp.@dnsmasq[0].ipset
config_load filter
config_foreach do_ipset filter
uci commit dhcp
/etc/init.d/dnsmasq restart

View File

@ -0,0 +1,12 @@
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.blockport", package.seeall)
function index()
local lock = luci.model.uci.cursor():get("custom", "menu", "full")
if lock == "1" then
local page
page = entry({"admin", "adminmenu", "blockport"}, cbi("portblk"), _("---Port Blocking"), 10)
page.dependent = true
end
end

View File

@ -1,15 +0,0 @@
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.domain", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local lock = luci.model.uci.cursor():get("custom", "menu", "full")
--if lock == "1" then
local page
page = entry({"admin", "adminmenu", "domain"}, cbi("domainfltr"), _(translate("Domain Filter")), 9)
page.dependent = true
--end
end

View File

@ -5,17 +5,17 @@ local zones = require "luci.sys.zoneinfo"
local fs = require "nixio.fs"
local conf = require "luci.config"
m = Map("filter", translate("Domain Filter"), translate("Block traffic to specified URLs"))
m = Map("blockport", translate("Port Blocking"), translate("Block traffic using specific ports"))
m.on_after_save = function(self)
luci.sys.call("/usr/lib/domain/filter.sh &")
luci.sys.call("/usr/lib/blockport/blockport.sh &")
end
s = m:section(TypedSection, "filter", translate("Block List"))
s = m:section(TypedSection, "port", translate("Block Port List"))
s.anonymous = true
s.addremove = false
s:option(DynamicList, "ipset", translate("Domain URLs"))
s:option(DynamicList, "block", translate("Ports"))
return m

View File

@ -1,35 +0,0 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-menu
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-menu
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Optional Applications
TITLE:=Menu Selection
PKGARCH:=all
endef
define Package/ext-menu/description
Helper scripts to install Menu Selection on ROOter
endef
define Build/Compile
endef
define Package/ext-menu/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-menu))

View File

@ -1,10 +0,0 @@
#!/bin/sh
fv=$(uci -q get custom.menu.full)
if [ $fv = "0" ]; then
fv="1"
else
fv="0"
fi
/usr/lib/fullmenu/setmenu.sh $fv

View File

@ -1,28 +0,0 @@
module("luci.controller.firewall", package.seeall)
function index()
entry({"admin", "network", "firewall"},
alias("admin", "network", "firewall", "zones"),
_("Firewall"), 60)
entry({"admin", "network", "firewall", "zones"},
view("firewall/zones"), _("General Settings"), 10)
entry({"admin", "network", "firewall", "forwards"},
view("firewall/forwards"), _("Port Forwards"), 20)
entry({"admin", "network", "firewall", "rules"},
view("firewall/rules"), _("Traffic Rules"), 30)
entry({"admin", "network", "firewall", "snats"},
view("firewall/snats"), _("NAT Rules"), 40)
entry({"admin", "network", "firewall", "custom"},
view("firewall/custom"), _("Custom Rules"), 45).leaf = true
if nixio.fs.access("/etc/config/modem") then
entry({"admin", "network", "firewall", "ttl"},
cbi("firewall/ttlx"),
_("Custom TTL Settings"), 50).leaf = true
end
end

View File

@ -1,103 +0,0 @@
{
"admin/status/overview": {
"title": "Overview",
"order": 1,
"action": {
"type": "template",
"path": "admin_status/index"
}
},
"admin/status/iptables": {
"title": "Firewall",
"order": 2,
"action": {
"type": "view",
"path": "status/iptables"
}
},
"admin/status/routes": {
"title": "Routes",
"order": 3,
"action": {
"type": "view",
"path": "status/routes"
}
},
"admin/status/syslog": {
"title": "System Log",
"order": 4,
"action": {
"type": "view",
"path": "status/syslog"
}
},
"admin/status/dmesg": {
"title": "Kernel Log",
"order": 5,
"action": {
"type": "view",
"path": "status/dmesg"
}
},
"admin/status/processes": {
"title": "Processes",
"order": 6,
"action": {
"type": "view",
"path": "status/processes"
}
},
"admin/status/realtime": {
"title": "Realtime Graphs",
"order": 7,
"action": {
"type": "alias",
"path": "admin/status/realtime/load"
}
},
"admin/status/realtime/load": {
"title": "Load",
"order": 1,
"action": {
"type": "view",
"path": "status/load"
}
},
"admin/status/realtime/bandwidth": {
"title": "Traffic",
"order": 2,
"action": {
"type": "view",
"path": "status/bandwidth"
}
},
"admin/status/realtime/wireless": {
"title": "Wireless",
"order": 3,
"action": {
"type": "view",
"path": "status/wireless"
},
"depends": {
"uci": { "wireless": { "@wifi-device": true } }
}
},
"admin/status/realtime/connections": {
"title": "Connections",
"order": 4,
"action": {
"type": "view",
"path": "status/connections"
}
}
}

View File

@ -1,111 +0,0 @@
{
"admin/system/system": {
"title": "System",
"order": 1,
"action": {
"type": "view",
"path": "system/system"
}
},
"admin/system/admin": {
"title": "Administration",
"order": 2,
"action": {
"type": "firstchild"
}
},
"admin/system/admin/password": {
"title": "Router Password",
"order": 1,
"action": {
"type": "view",
"path": "system/password"
}
},
"admin/system/admin/dropbear": {
"title": "SSH Access",
"order": 2,
"action": {
"type": "view",
"path": "system/dropbear"
},
"depends": {
"fs": { "/usr/sbin/dropbear": "executable" }
}
},
"admin/system/admin/sshkeys": {
"title": "SSH-Keys",
"order": 3,
"action": {
"type": "view",
"path": "system/sshkeys"
},
"depends": {
"fs": { "/usr/sbin/dropbear": "executable" }
}
},
"admin/system/startup": {
"title": "Startup",
"order": 45,
"action": {
"type": "view",
"path": "system/startup"
}
},
"admin/system/crontab": {
"title": "Scheduled Tasks",
"order": 46,
"action": {
"type": "view",
"path": "system/crontab"
}
},
"admin/system/mounts": {
"title": "Mount Points",
"order": 50,
"action": {
"type": "view",
"path": "system/mounts"
},
"depends": {
"fs": { "/sbin/block": "executable" }
}
},
"admin/system/leds": {
"title": "LED Configuration",
"order": 60,
"action": {
"type": "view",
"path": "system/leds"
},
"depends": {
"fs": { "/sys/class/leds": "directory" }
}
},
"admin/system/flash": {
"title": "Backup / Flash Firmware",
"order": 70,
"action": {
"type": "view",
"path": "system/flash"
}
},
"admin/system/reboot": {
"title": "Reboot",
"order": 90,
"action": {
"type": "view",
"path": "system/reboot"
}
}
}

View File

@ -1,44 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011-2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.admin.network", package.seeall)
function index()
local page
-- if page.inreq then
page = entry({"admin", "network", "switch"}, view("network/switch"), _("Switch"), 20)
page.uci_depends = { network = { ["@switch[0]"] = "switch" } }
page = entry({"admin", "network", "wireless"}, view("network/wireless"), _('Wireless'), 15)
page.uci_depends = { wireless = { ["@wifi-device[0]"] = "wifi-device" } }
page.leaf = true
page = entry({"admin", "network", "network"}, view("network/interfaces"), _("Interfaces"), 10)
page.leaf = true
page.subindex = true
page = node("admin", "network", "dhcp")
page.uci_depends = { dhcp = true }
page.target = view("network/dhcp")
page.title = _("DHCP and DNS")
page.order = 30
page = node("admin", "network", "hosts")
page.uci_depends = { dhcp = true }
page.target = view("network/hosts")
page.title = _("Hostnames")
page.order = 40
page = node("admin", "network", "routes")
page.target = view("network/routes")
page.title = _("Static Routes")
page.order = 50
page = node("admin", "network", "diagnostics")
page.target = view("network/diagnostics")
page.title = _("Diagnostics")
page.order = 60
-- end
end

View File

@ -1,117 +0,0 @@
-- Copyright 2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.opkg", package.seeall)
function index()
entry({"admin", "system", "opkg"}, template("opkg"), _("Software"), 30)
entry({"admin", "system", "opkg", "list"}, call("action_list")).leaf = true
entry({"admin", "system", "opkg", "exec"}, post("action_exec")).leaf = true
entry({"admin", "system", "opkg", "statvfs"}, call("action_statvfs")).leaf = true
entry({"admin", "system", "opkg", "config"}, post_on({ data = true }, "action_config")).leaf = true
end
function action_list(mode)
local util = require "luci.util"
local cmd
if mode == "installed" then
cmd = { "/bin/cat", "/usr/lib/opkg/status" }
else
local lists_dir = nil
local fd = io.popen([[sed -rne 's#^lists_dir \S+ (\S+)#\1#p' /etc/opkg.conf /etc/opkg/*.conf 2>/dev/null]], "r")
if fd then
lists_dir = fd:read("*l")
fd:close()
end
if not lists_dir or #lists_dir == "" then
lists_dir = "/tmp/opkg-lists"
end
cmd = { "/bin/sh", "-c", [[find %s -type f '!' -name '*.sig' | xargs -r gzip -cd]] % util.shellquote(lists_dir) }
end
luci.http.prepare_content("text/plain; charset=utf-8")
luci.sys.process.exec(cmd, luci.http.write)
end
function action_exec(command, package)
local sys = require "luci.sys"
local cmd = { "/bin/opkg", "--force-removal-of-dependent-packages" }
local pkg = luci.http.formvalue("package")
if luci.http.formvalue("autoremove") == "true" then
cmd[#cmd + 1] = "--autoremove"
end
if luci.http.formvalue("overwrite") == "true" then
cmd[#cmd + 1] = "--force-overwrite"
end
cmd[#cmd + 1] = command
if pkg then
cmd[#cmd + 1] = pkg
end
luci.http.prepare_content("application/json")
luci.http.write_json(sys.process.exec(cmd, true, true))
end
function action_statvfs()
local fs = require "nixio.fs"
luci.http.prepare_content("application/json")
luci.http.write_json(fs.statvfs("/") or {})
end
function action_config()
local fs = require "nixio.fs"
local js = require "luci.jsonc"
local data = luci.http.formvalue("data")
if data then
data = js.parse(data)
if not data then
luci.http.status(400, "Bad Request")
return
end
local file, content
for file, content in pairs(data) do
if type(content) ~= "string" or
(file ~= "opkg.conf" and not file:match("^opkg/[^/]+%.conf$"))
then
luci.http.status(400, "Bad Request")
return
end
local path = "/etc/%s" % file
if not fs.access(path, "w") then
luci.http.status(403, "Permission denied")
return
end
fs.writefile(path, content:gsub("\r\n", "\n"))
end
luci.http.status(204, "Saved")
else
local rv = { ["opkg.conf"] = fs.readfile("/etc/opkg.conf") }
local entries = fs.dir("/etc/opkg")
if entries then
local entry
for entry in entries do
if entry:match("%.conf$") then
rv["opkg/%s" % entry] = fs.readfile("/etc/opkg/%s" % entry)
end
end
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
end

View File

@ -1,70 +0,0 @@
{
"admin/network/firewall": {
"title": "Firewall",
"order": 60,
"action": {
"type": "alias",
"path": "admin/network/firewall/zones"
},
"depends": {
"acl": [ "luci-app-firewall" ],
"fs": { "/sbin/fw3": "executable" },
"uci": { "firewall": true }
}
},
"admin/network/firewall/zones": {
"title": "General Settings",
"order": 10,
"action": {
"type": "view",
"path": "firewall/zones"
}
},
"admin/network/firewall/forwards": {
"title": "Port Forwards",
"order": 20,
"action": {
"type": "view",
"path": "firewall/forwards"
}
},
"admin/network/firewall/rules": {
"title": "Traffic Rules",
"order": 30,
"action": {
"type": "view",
"path": "firewall/rules"
}
},
"admin/network/firewall/snats": {
"title": "NAT Rules",
"order": 40,
"action": {
"type": "view",
"path": "firewall/snats"
}
},
"admin/network/firewall/custom": {
"title": "Custom Rules",
"order": 50,
"action": {
"type": "view",
"path": "firewall/custom"
}
},
"admin/network/firewall/customttl": {
"title": "Custom TTL Settings",
"order": 55,
"action": {
"type": "cbi",
"path": "firewall/ttlx"
}
}
}

View File

@ -1,13 +0,0 @@
{
"admin/system/opkg": {
"title": "Software",
"order": 30,
"action": {
"type": "view",
"path": "opkg"
},
"depends": {
"acl": [ "luci-app-opkg" ]
}
}
}

View File

@ -1,98 +0,0 @@
{
"admin/network/switch": {
"title": "Switch",
"order": 20,
"action": {
"type": "view",
"path": "network/switch"
},
"depends": {
"acl": [ "luci-mod-network-config" ],
"fs": { "/sbin/swconfig": "executable" },
"uci": { "network": { "@switch": true } }
}
},
"admin/network/wireless": {
"title": "Wireless",
"order": 15,
"action": {
"type": "view",
"path": "network/wireless"
},
"depends": {
"acl": [ "luci-mod-network-config" ],
"uci": { "wireless": { "@wifi-device": true } }
}
},
"admin/network/remote_addr/*": {
"action": {
"type": "call",
"module": "luci.controller.admin.network",
"function": "remote_addr"
}
},
"admin/network/network": {
"title": "Interfaces",
"order": 10,
"action": {
"type": "view",
"path": "network/interfaces"
},
"depends": {
"acl": [ "luci-mod-network-config" ]
}
},
"admin/network/dhcp": {
"title": "DHCP and DNS",
"order": 30,
"action": {
"type": "view",
"path": "network/dhcp"
},
"depends": {
"acl": [ "luci-mod-network-dhcp" ],
"uci": { "dhcp": true }
}
},
"admin/network/hosts": {
"title": "Hostnames",
"order": 40,
"action": {
"type": "view",
"path": "network/hosts"
},
"depends": {
"acl": [ "luci-mod-network-dhcp" ],
"uci": { "dhcp": true }
}
},
"admin/network/routes": {
"title": "Static Routes",
"order": 50,
"action": {
"type": "view",
"path": "network/routes"
},
"depends": {
"acl": [ "luci-mod-network-config" ]
}
},
"admin/network/diagnostics": {
"title": "Diagnostics",
"order": 60,
"action": {
"type": "view",
"path": "network/diagnostics"
},
"depends": {
"acl": [ "luci-mod-network-diagnostics" ]
}
}
}

View File

@ -1,137 +0,0 @@
{
"admin/status/overview": {
"title": "Overview",
"order": 1,
"action": {
"type": "template",
"path": "admin_status/index"
},
"depends": {
"acl": [ "luci-mod-status-index" ]
}
},
"admin/status/iptables": {
"title": "Firewall",
"order": 2,
"action": {
"type": "view",
"path": "status/iptables"
},
"depends": {
"acl": [ "luci-mod-status-firewall" ]
}
},
"admin/status/routes": {
"title": "Routes",
"order": 3,
"action": {
"type": "view",
"path": "status/routes"
},
"depends": {
"acl": [ "luci-mod-status-routes" ]
}
},
"admin/status/syslog": {
"title": "System Log",
"order": 4,
"action": {
"type": "view",
"path": "status/syslog"
},
"depends": {
"acl": [ "luci-mod-status-logs" ]
}
},
"admin/status/dmesg": {
"title": "Kernel Log",
"order": 5,
"action": {
"type": "view",
"path": "status/dmesg"
},
"depends": {
"acl": [ "luci-mod-status-logs" ]
}
},
"admin/status/processes": {
"title": "Processes",
"order": 6,
"action": {
"type": "view",
"path": "status/processes"
},
"depends": {
"acl": [ "luci-mod-status-processes" ]
}
},
"admin/status/channel_analysis": {
"title": "Channel Analysis",
"order": 7,
"action": {
"type": "view",
"path": "status/channel_analysis"
},
"depends": {
"acl": [ "luci-mod-status-channel_analysis" ],
"uci": { "wireless": { "@wifi-device": true } }
}
},
"admin/status/realtime": {
"title": "Realtime Graphs",
"order": 7,
"action": {
"type": "alias",
"path": "admin/status/realtime/load"
},
"depends": {
"acl": [ "luci-mod-status-realtime" ]
}
},
"admin/status/realtime/load": {
"title": "Load",
"order": 1,
"action": {
"type": "view",
"path": "status/load"
}
},
"admin/status/realtime/bandwidth": {
"title": "Traffic",
"order": 2,
"action": {
"type": "view",
"path": "status/bandwidth"
}
},
"admin/status/realtime/wireless": {
"title": "Wireless",
"order": 3,
"action": {
"type": "view",
"path": "status/wireless"
},
"depends": {
"uci": { "wireless": { "@wifi-device": true } }
}
},
"admin/status/realtime/connections": {
"title": "Connections",
"order": 4,
"action": {
"type": "view",
"path": "status/connections"
}
}
}

View File

@ -1,136 +0,0 @@
{
"admin/system/system": {
"title": "System",
"order": 1,
"action": {
"type": "view",
"path": "system/system"
},
"depends": {
"acl": [ "luci-mod-system-config" ]
}
},
"admin/system/admin": {
"title": "Administration",
"order": 2,
"action": {
"type": "firstchild"
},
"depends": {
"acl": [ "luci-mod-system-config", "luci-mod-system-ssh" ]
}
},
"admin/system/admin/password": {
"title": "Router Password",
"order": 1,
"action": {
"type": "view",
"path": "system/password"
},
"depends": {
"acl": [ "luci-mod-system-config" ]
}
},
"admin/system/admin/dropbear": {
"title": "SSH Access",
"order": 2,
"action": {
"type": "view",
"path": "system/dropbear"
},
"depends": {
"acl": [ "luci-mod-system-ssh" ],
"fs": { "/usr/sbin/dropbear": "executable" }
}
},
"admin/system/admin/sshkeys": {
"title": "SSH-Keys",
"order": 3,
"action": {
"type": "view",
"path": "system/sshkeys"
},
"depends": {
"acl": [ "luci-mod-system-ssh" ],
"fs": { "/usr/sbin/dropbear": "executable" }
}
},
"admin/system/startup": {
"title": "Startup",
"order": 45,
"action": {
"type": "view",
"path": "system/startup"
},
"depends": {
"acl": [ "luci-mod-system-init" ]
}
},
"admin/system/crontab": {
"title": "Scheduled Tasks",
"order": 46,
"action": {
"type": "view",
"path": "system/crontab"
},
"depends": {
"acl": [ "luci-mod-system-cron" ]
}
},
"admin/system/mounts": {
"title": "Mount Points",
"order": 50,
"action": {
"type": "view",
"path": "system/mounts"
},
"depends": {
"acl": [ "luci-mod-system-mounts" ],
"fs": { "/sbin/block": "executable" }
}
},
"admin/system/leds": {
"title": "LED Configuration",
"order": 60,
"action": {
"type": "view",
"path": "system/leds"
},
"depends": {
"acl": [ "luci-mod-system-config" ],
"fs": { "/sys/class/leds": "directory" }
}
},
"admin/system/flash": {
"title": "Backup / Flash Firmware",
"order": 70,
"action": {
"type": "view",
"path": "system/flash"
},
"depends": {
"acl": [ "luci-mod-system-flash" ]
}
},
"admin/system/reboot": {
"title": "Reboot",
"order": 90,
"action": {
"type": "view",
"path": "system/reboot"
},
"depends": {
"acl": [ "luci-mod-system-reboot" ]
}
}
}

View File

@ -1,28 +0,0 @@
module("luci.controller.firewall", package.seeall)
function index()
entry({"admin", "network", "firewall"},
alias("admin", "network", "firewall", "zones"),
_("Firewall"), 60)
entry({"admin", "network", "firewall", "zones"},
view("firewall/zones"), _("General Settings"), 10)
entry({"admin", "network", "firewall", "forwards"},
view("firewall/forwards"), _("Port Forwards"), 20)
entry({"admin", "network", "firewall", "rules"},
view("firewall/rules"), _("Traffic Rules"), 30)
entry({"admin", "network", "firewall", "snats"},
view("firewall/snats"), _("NAT Rules"), 40)
entry({"admin", "network", "firewall", "custom"},
view("firewall/custom"), _("Custom Rules"), 45).leaf = true
if nixio.fs.access("/etc/config/modem") then
entry({"admin", "network", "firewall", "ttl"},
cbi("firewall/ttlx"),
_("Custom TTL Settings"), 50).leaf = true
end
end

View File

@ -1,19 +0,0 @@
{
"admin/status/overview": {
"title": "Overview",
"order": 1,
"action": {
"type": "template",
"path": "admin_status/index"
}
},
"admin/status/syslog": {
"title": "System Log",
"order": 4,
"action": {
"type": "view",
"path": "status/syslog"
}
}
}

View File

@ -1,45 +0,0 @@
{
"admin/system/system": {
"title": "System",
"order": 1,
"action": {
"type": "view",
"path": "system/system"
}
},
"admin/system/admin": {
"title": "Administration",
"order": 2,
"action": {
"type": "firstchild"
}
},
"admin/system/admin/password": {
"title": "Router Password",
"order": 1,
"action": {
"type": "view",
"path": "system/password"
}
},
"admin/system/flash": {
"title": "Flash Firmware",
"order": 70,
"action": {
"type": "view",
"path": "system/flash"
}
},
"admin/system/reboot": {
"title": "Reboot",
"order": 90,
"action": {
"type": "view",
"path": "system/reboot"
}
}
}

View File

@ -1,44 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011-2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.admin.network", package.seeall)
function index()
local page
-- if page.inreq then
page = entry({"admin", "network", "switch"}, view("network/switch"), _("Switch"), 20)
page.uci_depends = { network = { ["@switch[0]"] = "switch" } }
page = entry({"admin", "network", "wireless"}, view("network/wireless"), _('Wireless'), 15)
page.uci_depends = { wireless = { ["@wifi-device[0]"] = "wifi-device" } }
page.leaf = true
page = entry({"admin", "network", "network"}, view("network/interfaces"), _("Interfaces"), 10)
page.leaf = true
page.subindex = true
page = node("admin", "network", "dhcp")
page.uci_depends = { dhcp = true }
page.target = view("network/dhcp")
page.title = _("DHCP and DNS")
page.order = 30
page = node("admin", "network", "hosts")
page.uci_depends = { dhcp = true }
page.target = view("network/hosts")
page.title = _("Hostnames")
page.order = 40
page = node("admin", "network", "routes")
page.target = view("network/routes")
page.title = _("Static Routes")
page.order = 50
page = node("admin", "network", "diagnostics")
page.target = view("network/diagnostics")
page.title = _("Diagnostics")
page.order = 60
-- end
end

View File

@ -1,117 +0,0 @@
-- Copyright 2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.opkg", package.seeall)
function index()
entry({"admin", "system", "opkg"}, template("opkg"), _("Software"), 30)
entry({"admin", "system", "opkg", "list"}, call("action_list")).leaf = true
entry({"admin", "system", "opkg", "exec"}, post("action_exec")).leaf = true
entry({"admin", "system", "opkg", "statvfs"}, call("action_statvfs")).leaf = true
entry({"admin", "system", "opkg", "config"}, post_on({ data = true }, "action_config")).leaf = true
end
function action_list(mode)
local util = require "luci.util"
local cmd
if mode == "installed" then
cmd = { "/bin/cat", "/usr/lib/opkg/status" }
else
local lists_dir = nil
local fd = io.popen([[sed -rne 's#^lists_dir \S+ (\S+)#\1#p' /etc/opkg.conf /etc/opkg/*.conf 2>/dev/null]], "r")
if fd then
lists_dir = fd:read("*l")
fd:close()
end
if not lists_dir or #lists_dir == "" then
lists_dir = "/tmp/opkg-lists"
end
cmd = { "/bin/sh", "-c", [[find %s -type f '!' -name '*.sig' | xargs -r gzip -cd]] % util.shellquote(lists_dir) }
end
luci.http.prepare_content("text/plain; charset=utf-8")
luci.sys.process.exec(cmd, luci.http.write)
end
function action_exec(command, package)
local sys = require "luci.sys"
local cmd = { "/bin/opkg", "--force-removal-of-dependent-packages" }
local pkg = luci.http.formvalue("package")
if luci.http.formvalue("autoremove") == "true" then
cmd[#cmd + 1] = "--autoremove"
end
if luci.http.formvalue("overwrite") == "true" then
cmd[#cmd + 1] = "--force-overwrite"
end
cmd[#cmd + 1] = command
if pkg then
cmd[#cmd + 1] = pkg
end
luci.http.prepare_content("application/json")
luci.http.write_json(sys.process.exec(cmd, true, true))
end
function action_statvfs()
local fs = require "nixio.fs"
luci.http.prepare_content("application/json")
luci.http.write_json(fs.statvfs("/") or {})
end
function action_config()
local fs = require "nixio.fs"
local js = require "luci.jsonc"
local data = luci.http.formvalue("data")
if data then
data = js.parse(data)
if not data then
luci.http.status(400, "Bad Request")
return
end
local file, content
for file, content in pairs(data) do
if type(content) ~= "string" or
(file ~= "opkg.conf" and not file:match("^opkg/[^/]+%.conf$"))
then
luci.http.status(400, "Bad Request")
return
end
local path = "/etc/%s" % file
if not fs.access(path, "w") then
luci.http.status(403, "Permission denied")
return
end
fs.writefile(path, content:gsub("\r\n", "\n"))
end
luci.http.status(204, "Saved")
else
local rv = { ["opkg.conf"] = fs.readfile("/etc/opkg.conf") }
local entries = fs.dir("/etc/opkg")
if entries then
local entry
for entry in entries do
if entry:match("%.conf$") then
rv["opkg/%s" % entry] = fs.readfile("/etc/opkg/%s" % entry)
end
end
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
end

View File

@ -1,70 +0,0 @@
{
"admin/network/firewall": {
"title": "Firewall",
"order": 60,
"action": {
"type": "alias",
"path": "admin/network/firewall/zones"
},
"depends": {
"acl": [ "luci-app-firewall" ],
"fs": { "/sbin/fw3": "executable" },
"uci": { "firewall": true }
}
},
"admin/network/firewall/zones": {
"title": "General Settings",
"order": 10,
"action": {
"type": "view",
"path": "firewall/zones"
}
},
"admin/network/firewall/forwards": {
"title": "Port Forwards",
"order": 20,
"action": {
"type": "view",
"path": "firewall/forwards"
}
},
"admin/network/firewall/rules": {
"title": "Traffic Rules",
"order": 30,
"action": {
"type": "view",
"path": "firewall/rules"
}
},
"admin/network/firewall/snats": {
"title": "NAT Rules",
"order": 40,
"action": {
"type": "view",
"path": "firewall/snats"
}
},
"admin/network/firewall/custom": {
"title": "Custom Rules",
"order": 50,
"action": {
"type": "view",
"path": "firewall/custom"
}
},
"admin/network/firewall/customttl": {
"title": "Custom TTL Settings",
"order": 55,
"action": {
"type": "cbi",
"path": "firewall/ttlx"
}
}
}

View File

@ -1,98 +0,0 @@
{
"admin/network/switch": {
"title": "Switch",
"order": 20,
"action": {
"type": "view",
"path": "network/switch"
},
"depends": {
"acl": [ "luci-mod-network-config" ],
"fs": { "/sbin/swconfig": "executable" },
"uci": { "network": { "@switch": true } }
}
},
"admin/network/wireless": {
"title": "Wireless",
"order": 15,
"action": {
"type": "view",
"path": "network/wireless"
},
"depends": {
"acl": [ "luci-mod-network-config" ],
"uci": { "wireless": { "@wifi-device": true } }
}
},
"admin/network/remote_addr/*": {
"action": {
"type": "call",
"module": "luci.controller.admin.network",
"function": "remote_addr"
}
},
"admin/network/network": {
"title": "Interfaces",
"order": 10,
"action": {
"type": "view",
"path": "network/interfaces"
},
"depends": {
"acl": [ "luci-mod-network-config" ]
}
},
"admin/network/dhcp": {
"title": "DHCP and DNS",
"order": 30,
"action": {
"type": "view",
"path": "network/dhcp"
},
"depends": {
"acl": [ "luci-mod-network-dhcp" ],
"uci": { "dhcp": true }
}
},
"admin/network/hosts": {
"title": "Hostnames",
"order": 40,
"action": {
"type": "view",
"path": "network/hosts"
},
"depends": {
"acl": [ "luci-mod-network-dhcp" ],
"uci": { "dhcp": true }
}
},
"admin/network/routes": {
"title": "Static Routes",
"order": 50,
"action": {
"type": "view",
"path": "network/routes"
},
"depends": {
"acl": [ "luci-mod-network-config" ]
}
},
"admin/network/diagnostics": {
"title": "Diagnostics",
"order": 60,
"action": {
"type": "view",
"path": "network/diagnostics"
},
"depends": {
"acl": [ "luci-mod-network-diagnostics" ]
}
}
}

View File

@ -1,38 +0,0 @@
{
"admin/status/overview": {
"title": "Overview",
"order": 1,
"action": {
"type": "template",
"path": "admin_status/index"
},
"depends": {
"acl": [ "luci-mod-status-index" ]
}
},
"admin/status/syslog": {
"title": "System Log",
"order": 4,
"action": {
"type": "view",
"path": "status/syslog"
},
"depends": {
"acl": [ "luci-mod-status-logs" ]
}
},
"admin/status/channel_analysis": {
"title": "Wifi Channel Analysis",
"order": 7,
"action": {
"type": "view",
"path": "status/channel_analysis"
},
"depends": {
"acl": [ "luci-mod-status-channel_analysis" ],
"uci": { "wireless": { "@wifi-device": true } }
}
},
}

View File

@ -1,60 +0,0 @@
{
"admin/system/system": {
"title": "System",
"order": 1,
"action": {
"type": "view",
"path": "system/system"
},
"depends": {
"acl": [ "luci-mod-system-config" ]
}
},
"admin/system/admin": {
"title": "Administration",
"order": 2,
"action": {
"type": "firstchild"
},
"depends": {
"acl": [ "luci-mod-system-config", "luci-mod-system-ssh" ]
}
},
"admin/system/admin/password": {
"title": "Router Password",
"order": 1,
"action": {
"type": "view",
"path": "system/password"
},
"depends": {
"acl": [ "luci-mod-system-config" ]
}
},
"admin/system/flash": {
"title": "Flash Firmware",
"order": 70,
"action": {
"type": "view",
"path": "system/flash"
},
"depends": {
"acl": [ "luci-mod-system-flash" ]
}
},
"admin/system/reboot": {
"title": "Reboot",
"order": 90,
"action": {
"type": "view",
"path": "system/reboot"
},
"depends": {
"acl": [ "luci-mod-system-reboot" ]
}
}
}

View File

@ -1,34 +0,0 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Menu Change" "$@"
}
full=$1
source /etc/openwrt_release
twone=$(echo "$DISTRIB_RELEASE" | grep "21.02")
if [ $full = "0" ]; then
fv="1"
if [ ! -z "$twone" ]; then # 21.02
cp /usr/lib/fullmenu/full21/luci-mod-status.json /usr/share/luci/menu.d
cp /usr/lib/fullmenu/full21/luci-mod-system.json /usr/share/luci/menu.d
cp /usr/lib/fullmenu/full21/luci-app-opkg.json /usr/share/luci/menu.d
else # 19.07.6
cp /usr/lib/fullmenu/full19/luci-mod-status.json /usr/share/luci/menu.d
cp /usr/lib/fullmenu/full19/luci-mod-system.json /usr/share/luci/menu.d
fi
else
fv="0"
if [ ! -z "$twone" ]; then # 21.02
cp /usr/lib/fullmenu/limited21/luci-mod-status.json /usr/share/luci/menu.d
cp /usr/lib/fullmenu/limited21/luci-mod-system.json /usr/share/luci/menu.d
rm -f /usr/share/luci/menu.d/luci-app-opkg.json
else # 19.07.6
cp /usr/lib/fullmenu/limited19/luci-mod-status.json /usr/share/luci/menu.d
cp /usr/lib/fullmenu/limited19/luci-mod-system.json /usr/share/luci/menu.d
fi
fi
uci set custom.menu.full=$fv
uci commit custom

View File

@ -1,28 +0,0 @@
module("luci.controller.fullmenu", package.seeall)
function index()
local fs = require "nixio.fs"
local page
page = entry({"admin", "system", "fullmenu"}, template("fullmenu/fullmenu"), "Menu Selection", 96)
page.dependent = true
entry({"admin", "system", "getmenu"}, call("action_getmenu"))
entry({"admin", "system", "setmenu"}, call("action_setmenu"))
end
function action_getmenu()
local rv = {}
id = luci.model.uci.cursor():get("custom", "menu", "full")
rv["full"] = id
password = luci.model.uci.cursor():get("custom", "menu", "password")
rv["password"] = password
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
function action_setmenu()
local set = luci.http.formvalue("set")
os.execute("/usr/lib/fullmenu/setmenu.sh " .. set)
end

View File

@ -1,166 +0,0 @@
<%+header%>
<%
local sys = require "luci.sys"
local utl = require "luci.util"
local fs = require "nixio.fs"
function showicon(lck)
if lck == 0 then
return resource .. "/icons/unlock1.png"
else
return resource .. "/icons/lock1.png"
end
end
-%>
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
var lockb = 0;
var full;
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "getmenu")%>',
null,
function(x, rv)
{
document.getElementById("password").value=rv.password;
full = rv.full;
if ( full == "0" )
{
document.getElementById("idf").style.visibility="visible";
document.getElementById("idn").style.visibility="hidden";
document.getElementById("idn").style.display = "none";
}
else
{
document.getElementById("idf").style.visibility="hidden";
document.getElementById("idf").style.display = "none";
document.getElementById("idn").style.visibility="visible";
}
}
);
function done() {
document.getElementById("popup").style.display = "none";
passw = document.getElementById("password").value;
var r = document.getElementById("pass").value;
if ( r == null )
{
document.getElementById("pass").value="";
return false;
}
if ( r == passw )
{
// change menu type here
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "setmenu")%>',
{ set: full },
function()
{
document.getElementById("pass").value="";
window.location.reload(false);
}
);
}
else
{
alert("<%:Incorrect Password!!!%>");
document.getElementById("pass").value="";
}
document.getElementById("lockbtn").disabled=false;
document.getElementById("unlockbtn").disabled=false;
return false;
};
function unlock(btn)
{
document.getElementById("popup").style.display = "block";
document.getElementById("lockbtn").disabled=true;
document.getElementById("unlockbtn").disabled=true;
return false;
}
//]]></script>
<form method="post" action="<%=REQUEST_URI%>">
<div class="cbi-map" id="cbi-modem">
<h2><a id="content" name="content"><%:Menu Selection%></a></h2>
<div class="cbi-map-descr"> </div>
<head>
<style>
#popup {
width:560px;
height:190px;
padding:20px;
background-color:gainsboro;
border-style : solid;
position:fixed;
top : 40%;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
text-align: center;
display:none;
}
</style>
</head>
<fieldset class="cbi-section" id="cbi-mod">
<table style="visibility:hidden" width="700" border="0" id="atpass">
<tr>
<td width="10%"><div id="password" align="right"></div></td>
</tr>
</table>
<div id="popup">
<table width="500" border="0">
<tr>
<td width="50px"><div><%:Enter Password to Change Menu Type%></div></td>
</tr>
<tr>
<td width="200px"><input id="pass" type="password"/></td>
</tr>
<tr>
<td><input type="image" src="<%=showicon(0)%>" style="width:48px;height:48px;" onclick="return done()" /></td>
</tr>
</table>
</div>
<table width="465" border="0" id="idf">
<tr>
<td width="15%"></td>
<td width="20%"><div align="center" style="font-size:1.5em" id="netidt"><strong><%:Current Menu is Limited.%></strong></div></td>
<td width="5%"></td>
<td width="60%"></td>
</tr>
<tr>
<td></td>
<td><div align="center" ><strong><%:You must enter a password to change to the full Menu.%></strong></div></td>
<td><input type="image" align="center" id="lockbtn" name="lockbtn" src="<%=showicon(1)%>" style="width:48px;height:48px;" onclick="return unlock(this)" /></td>
<td></td>
</tr>
</table>
<table width="465" border="0" id="idn">
<tr>
<td width="15%"></td>
<td width="20%"><div align="center" style="font-size:1.5em" id="netidt"><strong><%:Current Menu is Full.%></strong></div></td>
<td width="5%"></td>
<td width="60%"></td>
</tr>
<tr>
<td></td>
<td><div align="center"><strong><%:You must enter a password to change to the limited Menu.%></strong></div></td>
<td><input type="image" align="center" id="unlockbtn" name="unlockbtn" src="<%=showicon(1)%>" style="width:48px;height:48px;" onclick="return unlock(this)" /></td>
<td></td>
</tr>
</table>
</fieldset>
</div>
</form>
<%+footer%>

View File

@ -1,11 +1,7 @@
module("luci.controller.speedtest", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
entry({"admin", "speed"}, firstchild(), translate("Speed Test"), 95).dependent=false
page = entry({"admin", "speed", "speedtest"}, template("speedtest/speedtest"), translate("OpenSpeedTest"), 71)
entry({"admin", "speed"}, firstchild(), "Speed Test", 81).dependent=false
page = entry({"admin", "speed", "speedtest"}, template("speedtest/speedtest"), "OpenSpeedTest", 71)
page.dependent = true
end

View File

@ -17,8 +17,8 @@
<form method="post" action="<%=REQUEST_URI%>">
<div class="cbi-map" id="cbi-misc">
<h2><a id="content" name="content"><%:Browser Speed Test%></a></h2>
<div class="cbi-map-descr"><%:A Speed Test using OpenSpeedTest that runs in the browser%></div>
<h2><a id="content" name="content">Browser Speed Test</a></h2>
<div class="cbi-map-descr">A Speed Test using OpenSpeedTest that runs in the browser</div>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="/luci-static/speed/css/iconmoon_splash.css">

View File

@ -1,16 +1,8 @@
module("luci.controller.texting", package.seeall)
function index()
local lock = luci.model.uci.cursor():get("custom", "menu", "full")
local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0"
local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0"
if (multilock == "0") or (multilock == "1" and rootlock == "1") then
if lock == "1" then
if (multilock == "1" and rootlock == "1") then
entry({"admin", "adminmenu", "texting"}, cbi("fullmenu/texting"), "Random Texting", 9)
else
entry({"admin", "adminmenu", "texting"}, cbi("fullmenu/texting"), "---Random Texting", 9)
end
end
if lock == "1" then
entry({"admin", "adminmenu", "texting"}, cbi("fullmenu/texting"), "---Random Texting", 8)
end
entry({"admin", "services", "chksms"}, call("action_chksms"))

View File

@ -1,36 +0,0 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-throttle
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-throttle
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Optional Applications
DEPENDS:=+tc +kmod-sched-core +kmod-ifb +iptables \
+iptables-mod-ipopt +iptables-mod-conntrack-extra \
+kmod-sched-cake
TITLE:=support for Throttle
PKGARCH:=all
endef
define Package/ext-throttle/description
Helper scripts to enable Throttle
endef
define Build/Compile
endef
define Package/ext-throttle/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-throttle))

View File

@ -1,34 +0,0 @@
config queue 'wan'
option enabled '0'
option download '85000'
option upload '10000'
option qdisc 'cake'
option script 'piece_of_cake.qos'
option linklayer 'none'
option interface '0'
option debug_logging '0'
option verbosity '5'
config queue 'wan1'
option enabled '0'
option download '85000'
option upload '10000'
option qdisc 'cake'
option script 'piece_of_cake.qos'
option linklayer 'none'
option debug_logging '0'
option verbosity '5'
option interface '0'
config queue 'wan2'
option enabled '0'
option download '85000'
option upload '10000'
option qdisc 'cake'
option script 'piece_of_cake.qos'
option linklayer 'none'
option interface '0'
option debug_logging '0'
option verbosity '5'

View File

@ -1,27 +0,0 @@
#!/bin/sh
if [ "$ACTION" = ifdown ]; then
if [ $INTERFACE = "wan" -o $INTERFACE = "wan1" -o $INTERFACE = "wan2" ]; then
uci set sqm.$INTERFACE.interface='0'
uci commit sqm
logger -t THROTTLE-DEBUG "$ACTION $INTERFACE"
fi
fi
[ -n "$DEVICE" ] || exit 0
restart_sqm() {
/usr/lib/sqm/run.sh stop ${DEVICE}
/usr/lib/sqm/run.sh start ${DEVICE}
}
if [ "$ACTION" = ifup ]; then
if [ $INTERFACE = "wan" -o $INTERFACE = "wan1" -o $INTERFACE = "wan2" ]; then
uci set sqm.$INTERFACE.interface=$DEVICE
uci commit sqm
/etc/init.d/sqm enabled
restart_sqm
logger -t THROTTLE-DEBUG "$DEVICE $ACTION $INTERFACE"
fi
fi

View File

@ -1,31 +0,0 @@
#!/bin/sh /etc/rc.common
START=50
USE_PROCD=1
service_triggers()
{
procd_add_reload_trigger "sqm"
}
reload_service()
{
stop "$@"
start "$@"
}
start_service()
{
/usr/lib/sqm/run.sh start "$@"
}
stop_service()
{
/usr/lib/sqm/run.sh stop "$@"
}
boot()
{
export SQM_VERBOSITY_MIN=5 # Silence errors
start "$@"
}

View File

@ -1,5 +0,0 @@
SQM_LIB_DIR=/usr/lib/sqm
SQM_STATE_DIR=/var/run/sqm
SQM_QDISC_STATE_DIR=${SQM_STATE_DIR}/available_qdiscs
SQM_CHECK_QDISCS="fq_codel codel pie sfq cake"
SQM_SYSLOG=1

View File

@ -1,12 +0,0 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@sqm[-1]
add ucitrack sqm
set ucitrack.@sqm[-1].init=sqm
del_list ucitrack.@firewall[0].affects=sqm
add_list ucitrack.@firewall[0].affects=sqm
commit ucitrack
EOF
exit 0

View File

@ -1,109 +0,0 @@
# You need to jiggle these parameters. Note limits are tuned towards a <10Mbit uplink <60Mbup down
[ -z "$SCRIPT" ] && SCRIPT=
[ -z "$UPLINK" ] && UPLINK=2302
[ -z "$DOWNLINK" ] && DOWNLINK=14698
[ -z "$IFACE" ] && IFACE=eth0
[ -z "$QDISC" ] && QDISC=fq_codel
[ -z "$LLAM" ] && LLAM="default"
[ -z "$LINKLAYER" ] && LINKLAYER="none"
[ -z "$OVERHEAD" ] && OVERHEAD=0
[ -z "$STAB_MTU" ] && STAB_MTU=2047
[ -z "$STAB_MPU" ] && STAB_MPU=0
[ -z "$STAB_TSIZE" ] && STAB_TSIZE=512
[ -z "$AUTOFLOW" ] && AUTOFLOW=0
[ -z "$LIMIT" ] && LIMIT=1001 # sane global default for *LIMIT for fq_codel on a small memory device
[ -z "$ILIMIT" ] && ILIMIT=
[ -z "$ELIMIT" ] && ELIMIT=
[ -z "$ITARGET" ] && ITARGET=
[ -z "$ETARGET" ] && ETARGET=
[ -z "$IECN" ] && IECN="ECN"
[ -z "$EECN" ] && EECN="ECN"
# These two used to be called something else; preserve backwards compatibility
[ -z "$ZERO_DSCP_INGRESS" ] && ZERO_DSCP_INGRESS="${ZERO_DSCP:-${SQUASH_DSCP:-1}}"
[ -z "$IGNORE_DSCP_INGRESS" ] && IGNORE_DSCP_INGRESS="${IGNORE_DSCP:-${SQUASH_INGRESS:-1}}"
[ -z "$IQDISC_OPTS" ] && IQDISC_OPTS=""
[ -z "$EQDISC_OPTS" ] && EQDISC_OPTS=""
# handling of specific important binaries
[ -z "$TC" ] && TC=tc_wrapper
[ -z "$TC_BINARY" ] && TC_BINARY=$(command -v tc)
[ -z "$IP" ] && IP=ip_wrapper
[ -z "$IP_BINARY" ] && IP_BINARY=$(command -v ip)
[ -z "$IPTABLES" ] && IPTABLES=iptables_wrapper
[ -z "$IPTABLES_BINARY" ] && IPTABLES_BINARY=$(command -v iptables)
[ -z "$IP6TABLES" ] && IP6TABLES=ip6tables_wrapper
[ -z "$IP6TABLES_BINARY" ] && IP6TABLES_BINARY=$(command -v ip6tables)
[ -z "$IPTABLES_ARGS" ] && IPTABLES_ARGS="-w 1"
# Try modprobe first, fall back to insmod
if [ -z "$INSMOD" ]; then
INSMOD=$(command -v modprobe)
if [ -n "$INSMOD" ]; then
INSMOD="${INSMOD} -q"
else
INSMOD=$(command -v insmod)
fi
fi
[ -z "$TARGET" ] && TARGET="5ms"
[ -z "$IPT_MASK" ] && IPT_MASK="0xff" # to disable: set mask to 0xffffffff
#sm: we need the functions above before trying to set the ingress IFB device
#sm: *_CAKE_OPTS should contain the diffserv keyword for cake
[ -z "$INGRESS_CAKE_OPTS" ] && INGRESS_CAKE_OPTS="diffserv3"
[ -z "$EGRESS_CAKE_OPTS" ] && EGRESS_CAKE_OPTS="diffserv3"
[ -z "$CUR_DIRECTION" ] && CUR_DIRECTION="NONE"
# HTB without a sufficiently large burst/cburst value is a bit CPU hungry
# so allow to specify the permitted burst in the time domain (microseconds)
# so the user has a feeling for the associated worst case latency cost
# set to zero to use htb default butst of one MTU
[ -z "$SHAPER_BURST_DUR_US" ] && SHAPER_BURST_DUR_US=1000
[ -z "$ISHAPER_BURST_DUR_US" ] && ISHAPER_BURST_DUR_US=$SHAPER_BURST_DUR_US
[ -z "$ESHAPER_BURST_DUR_US" ] && ESHAPER_BURST_DUR_US=$SHAPER_BURST_DUR_US
# use the same logic for the calculation of htb's quantum
# quantum controlls how many bytes htb tries to deque from the current tier
# before switching tiers.
[ -z "$SHAPER_QUANTUM_DUR_US" ] && SHAPER_QUANTUM_DUR_US=$SHAPER_BURST_DUR_US
[ -z "$ISHAPER_QUANTUM_DUR_US" ] && ISHAPER_QUANTUM_DUR_US=$SHAPER_QUANTUM_DUR_US
[ -z "$ESHAPER_QUANTUM_DUR_US" ] && ESHAPER_QUANTUM_DUR_US=$SHAPER_QUANTUM_DUR_US
# Logging verbosity
VERBOSITY_SILENT=0
VERBOSITY_ERROR=1
VERBOSITY_WARNING=2
VERBOSITY_INFO=5
VERBOSITY_DEBUG=8
VERBOSITY_TRACE=10
[ -z "$SQM_VERBOSITY_MAX" ] && SQM_VERBOSITY_MAX=$VERBOSITY_INFO
# For silencing only errors
[ -z "$SQM_VERBOSITY_MIN" ] && SQM_VERBOSITY_MIN=$VERBOSITY_SILENT
[ -z "$SQM_DEBUG" ] && SQM_DEBUG=0
if [ "$SQM_DEBUG" -eq "1" ]
then
SQM_DEBUG_STEM="${SQM_STATE_DIR}/${IFACE}"
SQM_START_LOG="${SQM_DEBUG_STEM}.start-sqm.log"
SQM_STOP_LOG="${SQM_DEBUG_STEM}.stop-sqm.log"
[ -z "SQM_DEBUG_LOG" ] && SQM_DEBUG_LOG="${SQM_DEBUG_STEM}.debug.log"
OUTPUT_TARGET="${SQM_DEBUG_LOG}"
else
OUTPUT_TARGET="/dev/null"
fi
# Can be overridden by callers that want to silence error output for a
# particular command
SILENT=0
# Transaction log for unwinding ipt rules
IPT_TRANS_LOG="${SQM_STATE_DIR}/${IFACE}.iptables.log"
# These are the modules that do_modules() will attempt to load
ALL_MODULES="act_ipt sch_$QDISC sch_ingress act_mirred cls_fw cls_flow cls_u32 sch_htb sch_hfsc"

View File

@ -1,923 +0,0 @@
################################################################################
# (sqm) functions.sh
#
# These are all helper functions for various parts of SQM scripts. If you want
# to play around with your own shaper-qdisc-filter configuration look here for
# ready made tools, or examples start of on your own.
#
# Please note the SQM logger function is broken down into levels of logging.
# Use only levels appropriate to touch points in your script and realize the
# potential to overflow SYSLOG.
#
################################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Copyright (C) 2012-2019
# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller
# Eric Luehrsen
#
################################################################################
# Logging verbosity
VERBOSITY_SILENT=0
VERBOSITY_ERROR=1
VERBOSITY_WARNING=2
VERBOSITY_INFO=5
VERBOSITY_DEBUG=8
VERBOSITY_TRACE=10
sqm_logger() {
local level_min
local level_max
local debug
case $1 in
''|*[!0-9]*) LEVEL=$VERBOSITY_INFO ;; # empty or non-numbers
*) LEVEL=$1; shift ;;
esac
level_min=${SQM_VERBOSITY_MIN:-$VERBOSITY_SILENT}
level_max=${SQM_VERBOSITY_MAX:-$VERBOSITY_INFO}
debug=${SQM_DEBUG:-0}
if [ "$level_max" -ge "$LEVEL" ] && [ "$level_min" -le "$LEVEL" ] ; then
if [ "$SQM_SYSLOG" -eq "1" ]; then
logger -t SQM -s "$*"
else
echo "$@" >&2
fi
fi
# this writes into SQM_START_LOG or SQM_STOP_LOG, log files are trucated in
# start-sqm/stop-sqm respectively and should only take little space
if [ "$debug" -eq "1" ]; then
echo "$@" >> "${SQM_DEBUG_LOG}"
fi
}
sqm_error() { sqm_logger $VERBOSITY_ERROR ERROR: "$@"; }
sqm_warn() { sqm_logger $VERBOSITY_WARNING WARNING: "$@"; }
sqm_log() { sqm_logger $VERBOSITY_INFO "$@"; }
sqm_debug() { sqm_logger $VERBOSITY_DEBUG "$@"; }
sqm_trace() { sqm_logger $VERBOSITY_TRACE "$@"; }
# Inspired from https://stackoverflow.com/questions/85880/determine-if-a-function-exists-in-bash
#fn_exists() { LC_ALL=C type $1 | grep -q 'is a function'; }
fn_exists() {
local FN_CANDIDATE
local CUR_LC_ALL
local TYPE_OUTPUT
local RET
FN_CANDIDATE=$1
# check that a candidate nme was given
if [ -z "${FN_CANDIDATE}" ]; then
sqm_error "fn_exists: no function name specified as first argument."
return 1
fi
sqm_debug "fn_exists: function candidate name: ${FN_CANDIDATE}"
# extract the textual type description
TYPE_OUTPUT=$( LC_ALL=C type $1 2>&1 )
sqm_debug "fn_exists: TYPE_OUTPUT: $TYPE_OUTPUT"
# OpenWrt (2019) returns 'is a function'
# Debian Buster/raspbian returns 'is a shell function'
# let's just hope no Linux system reurn 'is a shell builtin function'
echo ${TYPE_OUTPUT} | grep -q 'is .*function'
RET=$?
sqm_debug "fn_exists: return value: ${RET}"
return ${RET}
}
# Transaction logging for ipt rules to allow for gracefull final teardown
ipt_log_restart() {
[ -f "$IPT_TRANS_LOG" ] && rm -f "$IPT_TRANS_LOG"
}
# Function to negate iptables commands. Turns addition and insertion into
# deletion, and creation of new chains into deletion
# Its output has quotes around all parameters so we can preserve arguments
# containing whitespace across log file write & re-read
ipt_negate()
{
for var in "$@"; do
case "$var" in
"-A"|"-I") echo -n '"-D" ' ;;
"-N") echo -n '"-X" ' ;;
*) echo -n "\"$var\" " ;;
esac
done
echo ""
}
ipt_log()
{
echo "$@" >> $IPT_TRANS_LOG
}
# Split a string containing an iptables command line parameter invocation, then
# run it through ipt(). This is used to turn lines read from the log file, or
# output from ipt_negate() back into proper parameters contained in $@
ipt_run_split()
{
eval "set -- $1"
ipt "$@"
}
# Read the transaction log in reverse and execute using ipt to undo changes.
# Since we logged only ipt '-D' commands, ipt won't add them again to the
# transaction log, but will include them in the syslog/debug log.
ipt_log_rewind() {
[ -f "$IPT_TRANS_LOG" ] || return 0
sed -n '1!G;h;$p' "$IPT_TRANS_LOG" |
while read line; do
[ -n "$line" ] || continue
ipt_run_split "$line"
done
}
ipt() {
local neg
for var in "$@"; do
case "$var" in
"-A"|"-I"|"-N")
# If the rule is an addition rule, we first run its negation,
# then log that negation to be used by ipt_log_rewind() on
# shutdown
neg="$(ipt_negate "$@")"
ipt_run_split "$neg"
ipt_log "$neg"
;;
esac
done
SILENT=1 ${IPTABLES} $IPTABLES_ARGS "$@"
SILENT=1 ${IP6TABLES} $IPTABLES_ARGS "$@"
}
# wrapper to call iptables to allow debug logging
iptables_wrapper(){
cmd_wrapper iptables ${IPTABLES_BINARY} "$@"
}
# wrapper to call ip6tables to allow debug logging
ip6tables_wrapper(){
cmd_wrapper ip6tables ${IP6TABLES_BINARY} "$@"
}
# wrapper to call tc to allow debug logging
tc_wrapper(){
cmd_wrapper tc ${TC_BINARY} "$@"
}
# wrapper to call ip to allow debug logging
ip_wrapper(){
cmd_wrapper ip ${IP_BINARY} "$@"
}
# the actual command execution wrapper
cmd_wrapper(){
# $1: the symbolic name of the command for informative output
# $2: the name of the binary to call (potentially including the full path)
# $3-$end: the actual arguments for $2
local CALLERID
local CMD_BINARY
local LAST_ERROR
local RET
local ERRLOG
CALLERID=$1 ; shift 1 # extract and remove the id string
CMD_BINARY=$1 ; shift 1 # extract and remove the binary
# Handle silencing of errors from callers
ERRLOG="sqm_error"
if [ "$SILENT" -eq "1" ]; then
ERRLOG="sqm_debug"
sqm_debug "cmd_wrapper: ${CALLERID}: invocation silenced by request, FAILURE either expected or acceptable."
# The busybox shell doesn't understand the concept of an inline variable
# only applying to a single command, so we need to reset SILENT
# afterwards. Ugly, but it works...
SILENT=0
fi
sqm_trace "cmd_wrapper: COMMAND: ${CMD_BINARY} $@"
LAST_ERROR=$( ${CMD_BINARY} "$@" 2>&1 )
RET=$?
if [ "$RET" -eq "0" ] ; then
sqm_debug "cmd_wrapper: ${CALLERID}: SUCCESS: ${CMD_BINARY} $@"
else
# this went south, try to capture & report more detail
$ERRLOG "cmd_wrapper: ${CALLERID}: FAILURE (${RET}): ${CMD_BINARY} $@"
$ERRLOG "cmd_wrapper: ${CALLERID}: LAST ERROR: ${LAST_ERROR}"
fi
return $RET
}
do_modules() {
for m in $ALL_MODULES; do
[ -d /sys/module/${m} ] || ${INSMOD} $m 2>>${OUTPUT_TARGET}
done
}
# Write a state file to the filename given as $1. This version will extract all
# variable names defined in defaults.sh and since defaults.sh should contain all
# used variables this should be the complete set.
write_state_file() {
local filename
local awkscript
awkscript='match($0, /[A-Z0-9_]+=/) {print substr($0, RSTART, RLENGTH-1)}'
filename=$1
shift
awk "$awkscript" ${SQM_LIB_DIR}/defaults.sh | sort -u | while read var; do
val=$(eval echo '$'$var)
echo "$var=\"$val\""
done > $filename
}
check_state_dir() {
local PERM
local OWNER
if [ -z "${SQM_STATE_DIR}" ]; then
SQM_DEBUG=0 sqm_error '$SQM_STATE_DIR is unset - check your config!'
exit 1
fi
[ -d "${SQM_STATE_DIR}" ] || ( umask 077; mkdir -p "$SQM_STATE_DIR" ) || exit 1
if [ ! -w "${SQM_STATE_DIR}" ] || [ ! -x "${SQM_STATE_DIR}" ]; then
SQM_DEBUG=0 sqm_error "Cannot write to state dir '$SQM_STATE_DIR'"
exit 1
fi
# OpenWrt doesn't have stat; for now just skip the remaining tests if it's
# not available
command -v stat >/dev/null 2>&1 || return 0
PERM="0$(stat -L -c '%a' "${SQM_STATE_DIR}")"
if [ "$((PERM & 0002))" -ne 0 ]; then
SQM_DEBUG=0 sqm_error "State dir '$SQM_STATE_DIR' is world writable; this is unsafe, please fix"
exit 1
fi
OWNER="$(stat -L -c '%u' "${SQM_STATE_DIR}")"
if [ "$OWNER" -ne "$(id -u)" ]; then
SQM_DEBUG=0 sqm_error "State dir '$SQM_STATE_DIR' is owned by a different user; this is unsafe, please fix"
exit 1
fi
}
# find the ifb device associated with a specific interface, return nothing of no
# ifb is associated with IF
get_ifb_associated_with_if() {
local CUR_IF
local CUR_IFB
local TMP
CUR_IF=$1
# Stray ' in the comment is a fix for broken editor syntax highlighting
CUR_IFB=$( $TC_BINARY -p filter show parent ffff: dev ${CUR_IF} | grep -o -E ifb'[^)\ ]+' ) # '
sqm_debug "ifb associated with interface ${CUR_IF}: ${CUR_IFB}"
# we could not detect an associated IFB for CUR_IF
if [ -z "${CUR_IFB}" ]; then
TMP=$( $TC_BINARY -p filter show parent ffff: dev ${CUR_IF} )
if [ ! -z "${TMP}" ]; then
# oops, there is output but we failed to properly parse it? Ask for a user report
sqm_error "#---- CUT HERE ----#"
sqm_error "get_ifb_associated_with_if failed to extrect the ifb name from:"
sqm_error $( $TC_BINARY -p filter show parent ffff: dev ${CUR_IF} )
sqm_error "Please report this as an issue at https://github.com/tohojo/sqm-scripts"
sqm_error "Please copy and paste everything below the cut-here line into your issue report, thanks."
else
sqm_debug "Currently no ifb is associated with ${CUR_IF}, this is normal during starting of the sqm system."
fi
fi
echo ${CUR_IFB}
}
ifb_name() {
local CUR_IF
local MAX_IF_NAME_LENGTH
local IFB_PREFIX
local NEW_IFB
CUR_IF=$1
MAX_IF_NAME_LENGTH=15
IFB_PREFIX="ifb4"
NEW_IFB=$( echo -n "${IFB_PREFIX}${CUR_IF}" | head -c $MAX_IF_NAME_LENGTH )
echo ${NEW_IFB}
}
# if required
create_new_ifb_for_if() {
local NEW_IFB
NEW_IFB=$(ifb_name $1)
create_ifb ${NEW_IFB}
RET=$?
echo $NEW_IFB
return $RET
}
# TODO: report failures
create_ifb() {
local CUR_IFB
CUR_IFB=${1}
$IP link add name ${CUR_IFB} type ifb
}
delete_ifb() {
local CUR_IFB
CUR_IFB=${1}
$IP link set dev ${CUR_IFB} down
$IP link delete ${CUR_IFB} type ifb
}
# the best match is either the IFB already associated with the current interface
# or a new named IFB
get_ifb_for_if() {
local CUR_IF
local CUR_IFB
CUR_IF=$1
# if an ifb is already associated return that
CUR_IFB=$( get_ifb_associated_with_if ${CUR_IF} )
[ -z "$CUR_IFB" ] && CUR_IFB=$( create_new_ifb_for_if ${CUR_IF} )
[ -z "$CUR_IFB" ] && sqm_warn "Could not find existing IFB for ${CUR_IF}, nor create a new IFB instead..."
echo ${CUR_IFB}
}
# Verify that a qdisc works, and optionally that it is part of a set of
# supported qdiscs. If passed a $2, this function will first check if $1 is in
# that (space-separated) list and return an error if it's not.
#
# note the ingress qdisc is different in that it requires tc qdisc replace dev
# tmp_ifb ingress instead of "root ingress"
verify_qdisc() {
local qdisc
local supported
local ifb
local root_string
local args
local IFB_MTU
local found
local randnum
qdisc=$1
supported="$2"
randnum=$(tr -cd 0-9a-f < /dev/urandom 2>/dev/null | head -c 5)
ifb=SQM_IFB_$randnum
root_string="root" # this works for most qdiscs
args=""
IFB_MTU=1514
if [ -n "$supported" ]; then
found=0
for q in $supported; do
[ "$qdisc" = "$q" ] && found=1
done
[ "$found" -eq "1" ] || return 1
fi
create_ifb $ifb || return 1
case $qdisc in
#ingress is special
ingress) root_string="" ;;
#cannot instantiate tbf without args
tbf)
IFB_MTU=$( get_mtu $ifb )
IFB_MTU=$(( ${IFB_MTU} + 14 )) # TBF's warning is confused, it says MTU but it checks MTU + 14
args="limit 1 burst ${IFB_MTU} rate 1kbps"
;;
esac
$TC qdisc replace dev $ifb $root_string $qdisc $args
res=$?
if [ "$res" = "0" ] ; then
sqm_debug "QDISC $qdisc is useable."
else
sqm_error "QDISC $qdisc is NOT useable."
fi
delete_ifb $ifb
return $res
}
get_htb_adsll_string() {
ADSLL=""
if [ "$LLAM" = "htb_private" -a "$LINKLAYER" != "none" ]; then
# HTB defaults to MTU 1600 and an implicit fixed TSIZE of 256, but HTB
# as of around 3.10.0 does not actually use a table in the kernel
ADSLL="mpu ${STAB_MPU} linklayer ${LINKLAYER} overhead ${OVERHEAD} mtu ${STAB_MTU}"
sqm_debug "ADSLL: ${ADSLL}"
fi
echo ${ADSLL}
}
get_stab_string() {
local STABSTRING
local TMP_LLAM
STABSTRING=""
TMP_LLAM=${LLAM}
if [ "${LLAM}" = "default" -a "$QDISC" != "cake" ]; then
sqm_debug "LLA: default link layer adjustment method for !cake is tc_stab"
TMP_LLAM="tc_stab"
fi
if [ "${TMP_LLAM}" = "tc_stab" -a "$LINKLAYER" != "none" ]; then
STABSTRING="stab mtu ${STAB_MTU} tsize ${STAB_TSIZE} mpu ${STAB_MPU} overhead ${OVERHEAD} linklayer ${LINKLAYER}"
sqm_debug "STAB: ${STABSTRING}"
fi
echo ${STABSTRING}
}
# cake knows how to handle ATM and per packet overhead, so expose and use this...
get_cake_lla_string() {
local STABSTRING
local TMP_LLAM
STABSTRING=""
TMP_LLAM=${LLAM}
if [ "${LLAM}" = "default" -a "$QDISC" = "cake" ]; then
sqm_debug "LLA: default link layer adjustment method for cake is cake"
TMP_LLAM="cake"
fi
if [ "${TMP_LLAM}" = "cake" -a "${LINKLAYER}" != "none" ]; then
if [ "${LINKLAYER}" = "atm" ]; then
STABSTRING="atm"
fi
STABSTRING="${STABSTRING} overhead ${OVERHEAD} mpu ${STAB_MPU}"
sqm_debug "cake link layer adjustments: ${STABSTRING}"
fi
echo ${STABSTRING}
}
# centralize the implementation for the default sqm_start sqeuence
# the individual sqm_start function only need to do the individually
# necessary checking.
# This expects the calling script to supply both an egress() and ingress() function
# and will warn if they are missing
sqm_start_default() {
#sqm_error "sqm_start_default"
[ -n "$IFACE" ] || return 1
# reset the iptables trace log
ipt_log_restart
if fn_exists sqm_prepare_script ; then
sqm_debug "sqm_start_default: starting sqm_prepare_script"
sqm_prepare_script
else
sqm_debug "sqm_start_default: no sqm_prepare_script function found, proceeding without."
fi
do_modules
verify_qdisc $QDISC || return 1
sqm_debug "sqm_start_default: Starting ${SCRIPT}"
[ -z "$DEV" ] && DEV=$( get_ifb_for_if ${IFACE} )
if [ "${UPLINK}" -ne 0 ];
then
CUR_DIRECTION="egress"
fn_exists egress && egress || sqm_warn "sqm_start_default: ${SCRIPT} lacks an egress() function"
#egress
sqm_debug "sqm_start_default: egress shaping activated"
else
sqm_debug "sqm_start_default: egress shaping deactivated"
SILENT=1 $TC qdisc del dev ${IFACE} root
fi
if [ "${DOWNLINK}" -ne 0 ];
then
CUR_DIRECTION="ingress"
verify_qdisc ingress "ingress" || return 1
fn_exists ingress && ingress || sqm_warn "sqm_start_default: ${SCRIPT} lacks an ingress() function"
#ingress
sqm_debug "sqm_start_default: ingress shaping activated"
else
sqm_debug "sqm_start_default: ingress shaping deactivated"
SILENT=1 $TC qdisc del dev ${DEV} root
SILENT=1 $TC qdisc del dev ${IFACE} ingress
fi
return 0
}
sqm_stop() {
if [ "${DOWNLINK}" -ne 0 ]; then
$TC qdisc del dev $IFACE ingress
$TC qdisc del dev $IFACE root
[ -n "$CUR_IFB" ] && $TC qdisc del dev $CUR_IFB root
[ -n "$CUR_IFB" ] && sqm_debug "${0}: ${CUR_IFB} shaper deleted"
fi
# undo accumulated ipt commands during shutdown
ipt_log_rewind
# reset the iptables trace log
ipt_log_restart
[ -n "$CUR_IFB" ] && $IP link set dev ${CUR_IFB} down
[ -n "$CUR_IFB" ] && $IP link delete ${CUR_IFB} type ifb
[ -n "$CUR_IFB" ] && sqm_debug "${0}: ${CUR_IFB} interface deleted"
}
# Note this has side effects on the prio variable
# and depends on the interface global too
fc() {
$TC filter add dev $interface protocol ip parent $1 prio $prio u32 match ip tos $2 0xfc classid $3
prio=$(($prio + 1))
$TC filter add dev $interface protocol ipv6 parent $1 prio $prio u32 match ip6 priority $2 0xfc classid $3
prio=$(($prio + 1))
}
# allow better control over HTB's quantum variable
# this controlls how many bytes htb ties to deque from the current tier before
# switching to the next, if this is large mixing between pririty tiers will be
# lumpy, but at a lower CPU cost. In first approximation quantum should not be
# larger than burst.
get_htb_quantum() {
local HTB_MTU
local BANDWIDTH
local DURATION_US
local MIN_QUANTUM
local QUANTUM
HTB_MTU=$( get_mtu $1 )
BANDWIDTH=$2
DURATION_US=$3
sqm_debug "get_htb_quantum: 1: ${1}, 2: ${2}, 3: ${3}"
if [ -z "${DURATION_US}" ] ; then
DURATION_US=${SHAPER_QUANTUM_DUR_US} # the duration of the burst in microseconds
sqm_warn "get_htb_quantum (by duration): Defaulting to ${DURATION_US} microseconds."
fi
if [ -n "${HTB_MTU}" -a "${DURATION_US}" -gt "0" ] ; then
QUANTUM=$( get_burst ${HTB_MTU} ${BANDWIDTH} ${DURATION_US} )
fi
if [ -z "$QUANTUM" ]; then
MIN_QUANTUM=$(( ${MTU} + 48 )) # add 48 bytes to MTU for the ovehead
MIN_QUANTUM=$(( ${MIN_QUANTUM} + 47 )) # now do ceil(Min_BURST / 48) * 53 in shell integer arithmic
MIN_QUANTUM=$(( ${MIN_QUANTUM} / 48 ))
MIN_QUANTUM=$(( ${MIN_QUANTUM} * 53 )) # for MTU 1489 to 1536 this will result in MIN_BURST = 1749 Bytes
sqm_warn "get_htb_quantum: 0 bytes quantum will not work, defaulting to one ATM/AAL5 expanded MTU packet with overhead: ${MIN_QUANTUM}"
echo ${MIN_QUANTUM}
else
echo ${QUANTUM}
fi
}
# try to define the burst parameter in the duration required to transmit a burst
# at the configured bandwidth conceptuallly the matching quantum for this burst
# should be BURST/number_of_tiers to give each htb tier a chance to dequeue into
# each burst, but that most likely will end up with a somewhat too small quantum
# note: to get htb to report the configured burst/cburt one needs to issue the
# following command (for ifbpppoe-wan):
# tc -d class show dev ifb4pppoe-wan
get_burst() {
local MTU
local BANDWIDTH
local SHAPER_BURST_US
local MIN_BURST
local BURST
MTU=$1
BANDWIDTH=$2 # note bandwidth is always given in kbps
SHAPER_BURST_US=$3
sqm_debug "get_burst: 1: ${1}, 2: ${2}, 3: ${3}"
if [ -z "${SHAPER_BURST_US}" ] ; then
SHAPER_BURST_US=1000 # the duration of the burst in microseconds
sqm_warn "get_burst (by duration): Defaulting to ${SHAPER_BURST_US} microseconds bursts."
fi
# let's assume ATM/AAL5 to be the worst case encapsulation
# and 48 Bytes a reasonable worst case per packet overhead
MIN_BURST=$(( ${MTU} + 48 )) # add 48 bytes to MTU for the ovehead
MIN_BURST=$(( ${MIN_BURST} + 47 )) # now do ceil(Min_BURST / 48) * 53 in shell integer arithmic
MIN_BURST=$(( ${MIN_BURST} / 48 ))
MIN_BURST=$(( ${MIN_BURST} * 53 )) # for MTU 1489 to 1536 this will result in MIN_BURST = 1749 Bytes
# htb/tbf expect burst to be specified in bytes, while bandwidth is in kbps
BURST=$(( ((${SHAPER_BURST_US} * ${BANDWIDTH}) / 8000) ))
if [ ${BURST} -lt ${MIN_BURST} ] ; then
sqm_log "get_burst (by duration): the calculated burst/quantum size of ${BURST} bytes was below the minimum of ${MIN_BURST} bytes."
BURST=${MIN_BURST}
fi
sqm_debug "get_burst (by duration): BURST [Byte]: ${BURST}, BANDWIDTH [Kbps]: ${BANDWIDTH}, DURATION [us]: ${SHAPER_BURST_US}"
echo ${BURST}
}
# Create optional burst parameters to leap over CPU interupts when the CPU is
# severly loaded. We need to be conservative though.
get_htb_burst() {
local HTB_MTU
local BANDWIDTH
local DURATION_US
local BURST
HTB_MTU=$( get_mtu $1 )
BANDWIDTH=$2
DURATION_US=$3
sqm_debug "get_htb_burst: 1: ${1}, 2: ${2}, 3: ${3}"
if [ -z "${DURATION_US}" ] ; then
DURATION_US=${SHAPER_BURST_DUR_US} # the duration of the burst in microseconds
sqm_warn "get_htb_burst (by duration): Defaulting to ${SHAPER_BURST_DUR_US} microseconds."
fi
if [ -n "${HTB_MTU}" -a "${DURATION_US}" -gt "0" ] ; then
BURST=$( get_burst ${HTB_MTU} ${BANDWIDTH} ${DURATION_US} )
fi
if [ -z "$BURST" ]; then
sqm_debug "get_htb_burst: Default Burst, HTB will use MTU plus shipping and handling"
else
echo burst $BURST cburst $BURST
fi
}
# For a default PPPoE link this returns 1492 just as expected but I fear we
# actually need the wire size of the whole thing not so much the MTU
get_mtu() {
CUR_MTU=$(cat /sys/class/net/$1/mtu)
sqm_debug "IFACE: ${1} MTU: ${CUR_MTU}"
echo ${CUR_MTU}
}
# Set the autoflow variable to 1 if you want to limit the number of flows
# otherwise the default of 1024 will be used for all Xfq_codel qdiscs.
get_flows() {
case $QDISC in
codel|ns2_codel|pie|*fifo|pfifo_fast) ;;
fq_codel|*fq_codel|sfq) echo flows $( get_flows_count ${1} ) ;;
esac
}
get_flows_count() {
if [ "${AUTOFLOW}" -eq "1" ]; then
FLOWS=8
[ $1 -gt 999 ] && FLOWS=16
[ $1 -gt 2999 ] && FLOWS=32
[ $1 -gt 7999 ] && FLOWS=48
[ $1 -gt 9999 ] && FLOWS=64
[ $1 -gt 19999 ] && FLOWS=128
[ $1 -gt 39999 ] && FLOWS=256
[ $1 -gt 69999 ] && FLOWS=512
[ $1 -gt 99999 ] && FLOWS=1024
case $QDISC in
codel|ns2_codel|pie|*fifo|pfifo_fast) ;;
fq_codel|*fq_codel|sfq) echo $FLOWS ;;
esac
else
case $QDISC in
codel|ns2_codel|pie|*fifo|pfifo_fast) ;;
fq_codel|*fq_codel|sfq) echo 1024 ;;
esac
fi
}
# set the target parameter, also try to only take well formed inputs
# Note, the link bandwidth in the current direction (ingress or egress)
# is required to adjust the target for slow links
get_target() {
local CUR_TARGET
local CUR_LINK_KBPS
CUR_TARGET=${1}
CUR_LINK_KBPS=${2}
[ ! -z "$CUR_TARGET" ] && sqm_debug "cur_target: ${CUR_TARGET} cur_bandwidth: ${CUR_LINK_KBPS}"
CUR_TARGET_STRING=
# either e.g. 100ms or auto
CUR_TARGET_VALUE=$( echo ${CUR_TARGET} | grep -o -e \^'[[:digit:]]\+' )
CUR_TARGET_UNIT=$( echo ${CUR_TARGET} | grep -o -e '[[:alpha:]]\+'\$ )
AUTO_TARGET=
UNIT_VALID=
case $QDISC in
*codel|*pie)
if [ ! -z "${CUR_TARGET_VALUE}" -a ! -z "${CUR_TARGET_UNIT}" ];
then
case ${CUR_TARGET_UNIT} in
# permissible units taken from: tc_util.c get_time()
s|sec|secs|ms|msec|msecs|us|usec|usecs)
CUR_TARGET_STRING="target ${CUR_TARGET_VALUE}${CUR_TARGET_UNIT}"
UNIT_VALID="1"
;;
esac
fi
# empty field in GUI or undefined GUI variable now defaults to auto
if [ -z "${CUR_TARGET_VALUE}" -a -z "${CUR_TARGET_UNIT}" ];
then
if [ ! -z "${CUR_LINK_KBPS}" ]; then
TMP_TARGET_US=$( adapt_target_to_slow_link $CUR_LINK_KBPS )
TMP_INTERVAL_STRING=$( adapt_interval_to_slow_link $TMP_TARGET_US )
CUR_TARGET_STRING="target ${TMP_TARGET_US}us ${TMP_INTERVAL_STRING}"
AUTO_TARGET="1"
sqm_debug "get_target defaulting to auto."
else
sqm_warn "required link bandwidth in kbps not passed to get_target()."
fi
fi
# but still allow explicit use of the keyword auto for backward compatibility
case ${CUR_TARGET_UNIT} in
auto|Auto|AUTO)
if [ ! -z "${CUR_LINK_KBPS}" ]; then
TMP_TARGET_US=$( adapt_target_to_slow_link $CUR_LINK_KBPS )
TMP_INTERVAL_STRING=$( adapt_interval_to_slow_link $TMP_TARGET_US )
CUR_TARGET_STRING="target ${TMP_TARGET_US}us ${TMP_INTERVAL_STRING}"
AUTO_TARGET="1"
else
sqm_warn "required link bandwidth in kbps not passed to get_target()."
fi
;;
esac
case ${CUR_TARGET_UNIT} in
default|Default|DEFAULT)
if [ ! -z "${CUR_LINK_KBPS}" ]; then
CUR_TARGET_STRING="" # return nothing so the default target is not over-ridden...
AUTO_TARGET="1"
sqm_debug "get_target using qdisc default, no explicit target string passed."
else
sqm_warn "required link bandwidth in kbps not passed to get_target()."
fi
;;
esac
if [ ! -z "${CUR_TARGET}" ]; then
if [ -z "${CUR_TARGET_VALUE}" -o -z "${UNIT_VALID}" ]; then
[ -z "$AUTO_TARGET" ] && sqm_warn "${CUR_TARGET} is not a well formed tc target specifier; e.g.: 5ms (or s, us), or one of the strings auto or default."
fi
fi
;;
esac
echo $CUR_TARGET_STRING
}
# for low bandwidth links fq_codels default target of 5ms does not work too well
# so increase target for slow links (note below roughly 2500kbps a single packet
# will take more than 5 ms to be tansfered over the wire)
adapt_target_to_slow_link() {
LINK_BW=$1
# for ATM the worst case expansion including overhead seems to be 33 clls of
# 53 bytes each
MAX_DELAY=$(( 1000 * 1000 * 33 * 53 * 8 / 1000 )) # Max delay in us at 1kbps
TARGET=$(( ${MAX_DELAY} / ${LINK_BW} )) # note this truncates the decimals
# do not change anything for fast links
[ "$TARGET" -lt 5000 ] && TARGET=5000
case ${QDISC} in
*codel|pie)
echo "${TARGET}"
;;
esac
}
# codel looks at a whole interval to figure out wether observed latency stayed
# below target if target >= interval that will not work well, so increase
# interval by the same amonut that target got increased
adapt_interval_to_slow_link() {
TARGET=$1
case ${QDISC} in
*codel)
# Note this is not following codel theory to well as target should
# be 5-10% of interval and the simple addition does not conserve
# that relationship
INTERVAL=$(( (100 - 5) * 1000 + ${TARGET} ))
echo "interval ${INTERVAL}us"
;;
pie)
## not sure if pie needs this, probably not
#TUPDATE=$(( (30 - 20) * 1000 + ${TARGET} ))
#echo "tupdate ${TUPDATE}us"
;;
esac
}
# set quantum parameter if available for this qdisc
get_quantum() {
case $QDISC in
*fq_codel|fq_pie|drr) echo quantum $1 ;;
*) ;;
esac
}
# only show limits to qdiscs that can handle them...
# Note that $LIMIT contains the default limit
get_limit() {
CURLIMIT=$1
case $QDISC in
*codel|*pie|pfifo_fast|sfq|pfifo) [ -z ${CURLIMIT} ] && CURLIMIT=${LIMIT} # global default limit
;;
bfifo) [ -z "$CURLIMIT" ] && [ ! -z "$LIMIT" ] && CURLIMIT=$(( ${LIMIT} * $( cat /sys/class/net/${IFACE}/mtu ) )) # bfifo defaults to txquelength * MTU,
;;
*) sqm_warn "qdisc ${QDISC} does not support a limit"
;;
esac
sqm_debug "get_limit: $1 CURLIMIT: ${CURLIMIT}"
if [ ! -z "$CURLIMIT" ]; then
echo "limit ${CURLIMIT}"
fi
}
get_ecn() {
CURECN=$1
case ${CURECN} in
ECN)
case $QDISC in
*codel|*pie|*red)
CURECN=ecn
;;
*)
CURECN=""
;;
esac
;;
NOECN)
case $QDISC in
*codel|*pie|*red)
CURECN=noecn
;;
*)
CURECN=""
;;
esac
;;
*)
sqm_warn "ecn value $1 not handled"
;;
esac
sqm_debug "get_ECN: $1 CURECN: ${CURECN} IECN: ${IECN} EECN: ${EECN}"
echo ${CURECN}
}
# This could be a complete diffserv implementation
diffserv() {
interface=$1
prio=1
# Catchall
$TC filter add dev $interface parent 1:0 protocol all prio 999 u32 \
match ip protocol 0 0x00 flowid 1:12
# Find the most common matches fast
fc 1:0 0x00 1:12 # BE
fc 1:0 0x20 1:13 # CS1
fc 1:0 0x10 1:11 # IMM
fc 1:0 0xb8 1:11 # EF
fc 1:0 0xc0 1:11 # CS3
fc 1:0 0xe0 1:11 # CS6
fc 1:0 0x90 1:11 # AF42 (mosh)
# Arp traffic
$TC filter add dev $interface protocol arp parent 1:0 prio $prio handle 500 fw flowid 1:11
prio=$(($prio + 1))
}
eth_setup() {
ethtool -K $IFACE gso off
ethtool -K $IFACE tso off
ethtool -K $IFACE ufo off
ethtool -K $IFACE gro off
if [ -e /sys/class/net/$IFACE/queues/tx-0/byte_queue_limits ]; then
for i in /sys/class/net/$IFACE/queues/tx-*/byte_queue_limits
do
echo $(( 4 * $( get_mtu ${IFACE} ) )) > $i/limit_max
done
fi
}

View File

@ -1,52 +0,0 @@
# Cero3 Shaper
# A cake shaper and AQM solution that allows several diffserv marking schemes
# for ethernet gateways
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Copyright (C) 2012-5 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller
#sm: TODO pass in the cake diffserv keyword
. ${SQM_LIB_DIR}/defaults.sh
QDISC=cake
# Default traffic classication is passed in INGRESS_CAKE_OPTS and EGRESS_CAKE_OPTS, defined in defaults.sh now
egress() {
SILENT=1 $TC qdisc del dev $IFACE root
$TC qdisc add dev $IFACE root $( get_stab_string ) cake \
bandwidth ${UPLINK}kbit $( get_cake_lla_string ) ${EGRESS_CAKE_OPTS} ${EQDISC_OPTS}
}
ingress() {
SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress
$TC qdisc add dev $IFACE handle ffff: ingress
SILENT=1 $TC qdisc del dev $DEV root
[ "$IGNORE_DSCP_INGRESS" -eq "1" ] && INGRESS_CAKE_OPTS="$INGRESS_CAKE_OPTS besteffort"
[ "$ZERO_DSCP_INGRESS" -eq "1" ] && INGRESS_CAKE_OPTS="$INGRESS_CAKE_OPTS wash"
$TC qdisc add dev $DEV root $( get_stab_string ) cake \
bandwidth ${DOWNLINK}kbit $( get_cake_lla_string ) ${INGRESS_CAKE_OPTS} ${IQDISC_OPTS}
$IP link set dev $DEV up
# redirect all IP packets arriving in $IFACE to ifb0
$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \
match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV
}
sqm_prepare_script() {
do_modules
verify_qdisc $QDISC "cake" || return 1
}

View File

@ -1,4 +0,0 @@
This uses the cake qdisc as a replacement for both htb as shaper and fq_codel as leaf qdisc.
This exercises cake's diffserv profile(s) as different "layers" of priority.
This script requires that cake is selected as qdisc, and forces its usage.
See: http://www.bufferbloat.net/projects/codel/wiki/Cake for more information

View File

@ -1,52 +0,0 @@
# Cero3 Simple Shaper
# A 1 tin cake shaper for
# ethernet gateways. This is nearly the simplest possible
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Copyright (C) 2012-5 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller
. ${SQM_LIB_DIR}/defaults.sh
QDISC=cake
# to keep this as simple as possible we ignore the *_CAKE_OPTS from defaults.sh
INGRESS_CAKE_OPTS="besteffort"
EGRESS_CAKE_OPTS="besteffort"
egress() {
sqm_debug "egress"
SILENT=1 $TC qdisc del dev $IFACE root
$TC qdisc add dev $IFACE root $( get_stab_string ) cake \
bandwidth ${UPLINK}kbit $( get_cake_lla_string ) ${EGRESS_CAKE_OPTS} ${EQDISC_OPTS}
}
ingress() {
sqm_debug "ingress"
SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress
$TC qdisc add dev $IFACE handle ffff: ingress
SILENT=1 $TC qdisc del dev $DEV root
[ "$ZERO_DSCP_INGRESS" -eq "1" ] && INGRESS_CAKE_OPTS="$INGRESS_CAKE_OPTS wash"
$TC qdisc add dev $DEV root $( get_stab_string ) cake \
bandwidth ${DOWNLINK}kbit $( get_cake_lla_string ) ${INGRESS_CAKE_OPTS} ${IQDISC_OPTS}
$IP link set dev $DEV up
# redirect all IP packets arriving in $IFACE to ifb0
$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \
match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV
}
sqm_prepare_script() {
do_modules
verify_qdisc $QDISC "cake" || return 1
}

View File

@ -1,4 +0,0 @@
This just uses the cake qdisc as a replacement for both htb as shaper and fq_codel as leaf qdisc.
It just does not come any simpler than this, in other words it truely is a "piece of cake".
This script requires that cake is selected as qdisc, and forces its usage.
See: http://www.bufferbloat.net/projects/codel/wiki/Cake for more information

View File

@ -1,130 +0,0 @@
#!/bin/sh
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Copyright (C) 2012-4 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller
. /lib/functions.sh
. /etc/sqm/sqm.conf
. ${SQM_LIB_DIR}/functions.sh
ACTION="${1:-start}"
RUN_IFACE="$2"
LOCKDIR="${SQM_STATE_DIR}/sqm-run.lock"
check_state_dir
[ -d "${SQM_QDISC_STATE_DIR}" ] || ${SQM_LIB_DIR}/update-available-qdiscs
stop_statefile() {
local f
f="$1"
# Source the state file prior to stopping; we need the variables saved in
# there.
[ -f "$f" ] && ( . "$f";
IFACE=$IFACE SCRIPT=$SCRIPT SQM_DEBUG=$SQM_DEBUG \
SQM_DEBUG_LOG=$SQM_DEBUG_LOG \
SQM_VERBOSITY_MAX=$SQM_VERBOSITY_MAX \
SQM_VERBOSITY_MIN=$SQM_VERBOSITY_MIN \
OUTPUT_TARGET=$OUTPUT_TARGET ${SQM_LIB_DIR}/stop-sqm )
}
start_sqm_section() {
local section
section="$1"
export IFACE=$(config_get "$section" interface)
[ -z "$RUN_IFACE" -o "$RUN_IFACE" = "$IFACE" ] || return
[ "$(config_get "$section" enabled)" -eq 1 ] || return 0
[ -f "${SQM_STATE_DIR}/${IFACE}.state" ] && return
export UPLINK=$(config_get "$section" upload)
export DOWNLINK=$(config_get "$section" download)
export LLAM=$(config_get "$section" linklayer_adaptation_mechanism)
export LINKLAYER=$(config_get "$section" linklayer)
export OVERHEAD=$(config_get "$section" overhead)
export STAB_MTU=$(config_get "$section" tcMTU)
export STAB_TSIZE=$(config_get "$section" tcTSIZE)
export STAB_MPU=$(config_get "$section" tcMPU)
export ILIMIT=$(config_get "$section" ilimit)
export ELIMIT=$(config_get "$section" elimit)
export ITARGET=$(config_get "$section" itarget)
export ETARGET=$(config_get "$section" etarget)
export IECN=$(config_get "$section" ingress_ecn)
export EECN=$(config_get "$section" egress_ecn)
export IQDISC_OPTS=$(config_get "$section" iqdisc_opts)
export EQDISC_OPTS=$(config_get "$section" eqdisc_opts)
export TARGET=$(config_get "$section" target)
export QDISC=$(config_get "$section" qdisc)
export SCRIPT=$(config_get "$section" script)
# The UCI names for these two variables are confusing and should have been
# changed ages ago. For now, keep the bad UCI names but use meaningful
# variable names in the scripts to not break user configs.
export ZERO_DSCP_INGRESS=$(config_get "$section" squash_dscp)
export IGNORE_DSCP_INGRESS=$(config_get "$section" squash_ingress)
# If SQM_DEBUG or SQM_VERBOSITY_* were passed in via the command line make
# them available to the other scripts this allows to override sqm's log
# level as set in the GUI for quick debugging without GUI accesss.
export SQM_DEBUG=${SQM_DEBUG:-$(config_get "$section" debug_logging)}
export SQM_VERBOSITY_MAX=${SQM_VERBOSITY_MAX:-$(config_get "$section" verbosity)}
export SQM_VERBOSITY_MIN
"${SQM_LIB_DIR}/start-sqm"
}
release_lock() {
PID=$(cat "$LOCKDIR/pid")
if [ "$PID" -ne "$$" ]; then
sqm_error "Trying to release lock with wrong PID $PID != $$"
return 1
fi
rm -rf "$LOCKDIR"
return 0
}
take_lock() {
if mkdir "$LOCKDIR" 2>/dev/null; then
sqm_trace "Acquired run lock"
echo $$ > "$LOCKDIR/pid"
trap release_lock 0
return 0
fi
PID=$(cat "$LOCKDIR/pid")
sqm_warn "Unable to get run lock - already held by $PID"
return 1
}
MAX_TRIES=10
tries=$MAX_TRIES
while ! take_lock; do
sleep 1
tries=$((tries - 1))
if [ "$tries" -eq 0 ]; then
sqm_error "Giving up on getting lock after $MAX_TRIES attempts"
sqm_error "This is a bug; please report it at https://github.com/tohojo/sqm-scripts/issues"
sqm_error "Then, to re-enable sqm-scripts, manually remove $LOCKDIR"
exit 1
fi
done
if [ "$ACTION" = "stop" ]; then
if [ -z "$RUN_IFACE" ]; then
# Stopping all active interfaces
for f in ${SQM_STATE_DIR}/*.state; do
stop_statefile "$f"
done
else
stop_statefile "${SQM_STATE_DIR}/${RUN_IFACE}.state"
fi
else
config_load sqm
config_foreach start_sqm_section
fi

View File

@ -1,234 +0,0 @@
################################################################################
# simple.qos (Cero3 Shaper)
#
# Abstract:
# This is a three band fq_codel and ipv6 enabled shaping script for Ethernet
# gateways. Compared to the complexity that debloat had become this cleanly
# shows a means of going from diffserv marking to prioritization using the
# current tools ip(6)tables and tc. We should note that the complexity of
# debloat exists for a reason, and it is expected that script is run first to
# setup various other parameters such as BQL and ethtool.
#
# (Assume the debloat script has setup the other interfaces.)
#
# Notes:
# This does the right thing with ipv6 traffic. It also tries to leverage
# diffserv to some sane extent. In particular, the 'priority' queue is limited
# to 33% of the total, so EF, and IMM traffic cannot starve other types. The
# rfc suggested 30%. 30% is probably a lot in today's world.
#
# References:
# This alternate shaper attempts to go for 1/u performance in a clever way
# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD
#
################################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Copyright (C) 2012-2016
# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller
#
################################################################################
. ${SQM_LIB_DIR}/defaults.sh
################################################################################
ipt_setup() {
ipt -t mangle -N QOS_MARK_${IFACE}
case $QDISC in
cake*)
sqm_debug "cake does all the diffserv work - no need for iptables rules"
;;
*)
ipt -t mangle -A QOS_MARK_${IFACE} -j MARK --set-mark 0x2/${IPT_MASK}
# You can go further with classification but...
ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class CS1 -j MARK --set-mark 0x3/${IPT_MASK}
ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class CS6 -j MARK --set-mark 0x1/${IPT_MASK}
ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class EF -j MARK --set-mark 0x1/${IPT_MASK}
ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class AF42 -j MARK --set-mark 0x1/${IPT_MASK}
ipt -t mangle -A QOS_MARK_${IFACE} -m tos --tos Minimize-Delay -j MARK --set-mark 0x1/${IPT_MASK}
;;
esac
# Turn it on. Preserve classification if already performed
#
#sm: is it correct to do this in $IFACE? Should ingress not be on $DEV? since HTB acts on $DEV?
#
# ZERO also does not work on $DEV (that is the IFB will still see the
# incoming ToS bits whether we squash or not)
#
# ZERO is still useful to protect internal machines...
if [ "$ZERO_DSCP_INGRESS" = "1" ]; then
sqm_debug "Squashing differentiated services code points (DSCP) from ingress."
ipt -t mangle -I PREROUTING -i $IFACE -m dscp ! --dscp 0 -j DSCP --set-dscp-class be
else
sqm_debug "Keeping differentiated services code points (DSCP) from ingress."
ipt -t mangle -A PREROUTING -i $IFACE -m mark --mark 0x00/${IPT_MASK} -g QOS_MARK_${IFACE}
fi
ipt -t mangle -A POSTROUTING -o $IFACE -m mark --mark 0x00/${IPT_MASK} -g QOS_MARK_${IFACE}
# The Syn optimization was nice but fq_codel does it for us
# ipt -t mangle -A PREROUTING -i s+ -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j MARK --set-mark 0x01
# Not sure if this will work. Encapsulation is a problem period
ipt -t mangle -I PREROUTING -i vtun+ -p tcp -j MARK --set-mark 0x2/${IPT_MASK} # tcp tunnels need ordering
# Emanating from router, do a little more optimization
# but don't bother with it too much.
ipt -t mangle -A OUTPUT -p udp -m multiport --ports 123,53 -j DSCP --set-dscp-class AF42
#Not clear if the second line is needed
#ipt -t mangle -A OUTPUT -o $IFACE -g QOS_MARK_${IFACE}
}
cake_egress()
{
$TC qdisc add dev $IFACE root `get_stab_string` $QDISC bandwidth ${CEIL}kbit `get_cake_lla_string` ${EQDISC_OPTS}
}
egress() {
CEIL=${UPLINK}
PRIO_RATE=`expr $CEIL / 3` # Ceiling for prioirty
BE_RATE=`expr $CEIL / 6` # Min for best effort
BK_RATE=`expr $CEIL / 6` # Min for background
BE_CEIL=`expr $CEIL - 16` # A little slop at the top
LQ="quantum `get_htb_quantum $IFACE $CEIL ${ESHAPER_QUANTUM_DUR_US}`"
BURST="`get_htb_burst $IFACE $CEIL ${ESHAPER_BURST_DUR_US}`"
SILENT=1 $TC qdisc del dev $IFACE root
case $QDISC in
cake*) cake_egress; return;;
esac
$TC qdisc add dev $IFACE root handle 1: `get_stab_string` htb default 12
$TC class add dev $IFACE parent 1: classid 1:1 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit $BURST `get_htb_adsll_string`
$TC class add dev $IFACE parent 1:1 classid 1:11 htb $LQ rate 128kbit ceil ${PRIO_RATE}kbit prio 1 `get_htb_adsll_string`
$TC class add dev $IFACE parent 1:1 classid 1:12 htb $LQ rate ${BE_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 2 `get_htb_adsll_string`
$TC class add dev $IFACE parent 1:1 classid 1:13 htb $LQ rate ${BK_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 3 `get_htb_adsll_string`
$TC qdisc add dev $IFACE parent 1:11 handle 110: $QDISC \
`get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${PRIO_RATE}` ${EQDISC_OPTS}
$TC qdisc add dev $IFACE parent 1:12 handle 120: $QDISC \
`get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${BE_RATE}` ${EQDISC_OPTS}
$TC qdisc add dev $IFACE parent 1:13 handle 130: $QDISC \
`get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${BK_RATE}` ${EQDISC_OPTS}
# Need a catchall rule
$TC filter add dev $IFACE parent 1:0 protocol all prio 999 u32 \
match ip protocol 0 0x00 flowid 1:12
# FIXME should probably change the filter here to do pre-nat
$TC filter add dev $IFACE parent 1:0 protocol ip prio 1 handle 1/${IPT_MASK} fw classid 1:11
$TC filter add dev $IFACE parent 1:0 protocol ip prio 2 handle 2/${IPT_MASK} fw classid 1:12
$TC filter add dev $IFACE parent 1:0 protocol ip prio 3 handle 3/${IPT_MASK} fw classid 1:13
# ipv6 support. Note that the handle indicates the fw mark bucket that is looked for
$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 4 handle 1/${IPT_MASK} fw classid 1:11
$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 5 handle 2/${IPT_MASK} fw classid 1:12
$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 6 handle 3/${IPT_MASK} fw classid 1:13
# Arp traffic
$TC filter add dev $IFACE parent 1:0 protocol arp prio 7 handle 1/${IPT_MASK} fw classid 1:11
# ICMP traffic - Don't impress your friends. Deoptimize to manage ping floods
# better instead
$TC filter add dev $IFACE parent 1:0 protocol ip prio 8 \
u32 match ip protocol 1 0xff flowid 1:13
$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 9 \
u32 match ip protocol 1 0xff flowid 1:13
}
cake_ingress()
{
CAKEARGS=
[ "$IGNORE_DSCP_INGRESS" = "1" ] && CAKEARGS="$CAKEARGS besteffort"
$TC qdisc add dev $DEV root `get_stab_string` $QDISC bandwidth ${DOWNLINK}kbit \
$CAKEARGS `get_cake_lla_string` ${IQDISC_OPTS}
$IP link set dev $DEV up
# redirect all IP packets arriving in $IFACE to $DEV
$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \
match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV
}
ingress() {
CEIL=$DOWNLINK
PRIO_RATE=`expr $CEIL / 3` # Ceiling for prioirty
BE_RATE=`expr $CEIL / 6` # Min for best effort
BK_RATE=`expr $CEIL / 6` # Min for background
BE_CEIL=`expr $CEIL - 16` # A little slop at the top
LQ="quantum `get_htb_quantum $IFACE $CEIL ${ISHAPER_QUANTUM_DUR_US}`"
BURST="`get_htb_burst $IFACE $CEIL ${ISHAPER_BURST_DUR_US}`"
SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress
$TC qdisc add dev $IFACE handle ffff: ingress
SILENT=1 $TC qdisc del dev $DEV root
case $QDISC in
cake*) cake_ingress; return ;;
esac
if [ "$IGNORE_DSCP_INGRESS" = "1" ]; then
sqm_debug "Do not perform DSCP based filtering on ingress. (1-tier classification)"
$TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 10
$TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST `get_htb_adsll_string`
$TC class add dev $DEV parent 1:1 classid 1:10 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST prio 0 `get_htb_adsll_string`
$TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC \
`get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_flows ${DOWNLINK}` ${IQDISC_OPTS}
else
sqm_debug "Perform DSCP based filtering on ingress. (3-tier classification)"
$TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 12
$TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit $BURST `get_htb_adsll_string`
$TC class add dev $DEV parent 1:1 classid 1:11 htb $LQ rate 32kbit ceil ${PRIO_RATE}kbit prio 1 `get_htb_adsll_string`
$TC class add dev $DEV parent 1:1 classid 1:12 htb $LQ rate ${BE_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 2 `get_htb_adsll_string`
$TC class add dev $DEV parent 1:1 classid 1:13 htb $LQ rate ${BK_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 3 `get_htb_adsll_string`
$TC qdisc add dev $DEV parent 1:11 handle 110: $QDISC \
`get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 500` `get_flows ${PRIO_RATE}` ${IQDISC_OPTS}
$TC qdisc add dev $DEV parent 1:12 handle 120: $QDISC \
`get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 1500` `get_flows ${BE_RATE}` ${IQDISC_OPTS}
$TC qdisc add dev $DEV parent 1:13 handle 130: $QDISC \
`get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 300` `get_flows ${BK_RATE}` ${IQDISC_OPTS}
diffserv $DEV
fi
$IP link set dev $DEV up
# redirect all IP packets arriving in $IFACE to $DEV
$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \
match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV
}
sqm_prepare_script() {
do_modules
verify_qdisc "htb" || return 1
ipt_setup
}

View File

@ -1 +0,0 @@
BW-limited three-tier prioritisation scheme with your qdisc on each queue. (default)

View File

@ -1,104 +0,0 @@
################################################################################
# simplest.qos (Cero3 Simple Shaper)
#
# Abstract:
# This is a single band fq_codel and ipv6 enabled shaping script for Ethernet
# gateways. This is nearly the simplest possible. With FQ_CODEL, the sparseness
# priority will work pretty well for a casual network. Flow-hashes should not
# overlap much with only a few users.
#
# References:
# This alternate shaper attempts to go for 1/u performance in a clever way
# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD
#
################################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Copyright (C) 2012-2016
# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller
#
################################################################################
. ${SQM_LIB_DIR}/defaults.sh
################################################################################
cake_egress()
{
$TC qdisc add dev $IFACE root `get_stab_string` cake bandwidth ${UPLINK}kbit besteffort `get_cake_lla_string` ${EQDISC_OPTS}
}
egress() {
LQ="quantum `get_htb_quantum $IFACE ${UPLINK} ${ESHAPER_QUANTUM_DUR_US}`"
BURST="`get_htb_burst $IFACE ${UPLINK} ${ESHAPER_BURST_DUR_US}`"
SILENT=1 $TC qdisc del dev $IFACE root
case $QDISC in
cake*) cake_egress; return ;;
esac
$TC qdisc add dev $IFACE root handle 1: `get_stab_string` htb default 10
$TC class add dev $IFACE parent 1: classid 1:1 htb $LQ rate ${UPLINK}kbit ceil ${UPLINK}kbit $BURST `get_htb_adsll_string`
$TC class add dev $IFACE parent 1:1 classid 1:10 htb $LQ rate ${UPLINK}kbit ceil ${UPLINK}kbit $BURST prio 0 `get_htb_adsll_string`
$TC qdisc add dev $IFACE parent 1:10 handle 110: $QDISC \
`get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_flows ${UPLINK}` ${EQDISC_OPTS}
}
cake_ingress()
{
$TC qdisc add dev $DEV root `get_stab_string` cake bandwidth ${DOWNLINK}kbit besteffort `get_cake_lla_string` ${IQDISC_OPTS}
$IP link set dev $DEV up
# redirect all IP packets arriving in $IFACE to $DEV
$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \
match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV
}
ingress() {
sqm_debug "ingress"
SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress
$TC qdisc add dev $IFACE handle ffff: ingress
LQ="quantum `get_htb_quantum $IFACE ${DOWNLINK} ${ISHAPER_QUANTUM_DUR_US}`"
BURST="`get_htb_burst $IFACE ${DOWNLINK} ${ISHAPER_BURST_DUR_US}`"
SILENT=1 $TC qdisc del dev $DEV root
case $QDISC in
cake*) cake_ingress; return ;;
esac
$TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 10
$TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST `get_htb_adsll_string`
$TC class add dev $DEV parent 1:1 classid 1:10 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST prio 0 `get_htb_adsll_string`
# FIXME: I'd prefer to use a pre-nat filter but we need to detect if nat is on this interface
# AND we need to permute by a random number which we can't do from userspace filters
# Most high rate flows are REALLY close. This stomps on those harder, but hurts on high rate long distance
#$TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC limit $LIMIT $ECN interval 20ms target 3ms `get_flows ${DOWNLINK}`
$TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC \
`get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_flows ${DOWNLINK}` ${IQDISC_OPTS}
$IP link set dev $DEV up
# redirect all IP packets arriving in $IFACE to ifb0
$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \
match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV
}
sqm_prepare_script() {
do_modules
verify_qdisc "htb" || return 1
}
################################################################################

View File

@ -1 +0,0 @@
Simplest possible configuration: HTB rate limiter with your qdisc attached.

View File

@ -1,85 +0,0 @@
################################################################################
# simplest_tbf.qos (Simple TBF shaper)
#
# Abstract:
# This is a single band fq_codel and ipv6 enabled shaping script for Ethernet
# gateways. This is nearly the simplest possible. With FQ_CODEL, the sparseness
# priority will work pretty well for a casual network. Flow-hashes should not
# overlap much with only a few users.
#
# Uses TBF instead of HTB as that may give better performance on some
# architectures.
#
# References:
# This alternate shaper attempts to go for 1/u performance in a clever way
# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD
#
################################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Copyright (C) 2012-2017
# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller
#
################################################################################
. ${SQM_LIB_DIR}/defaults.sh
################################################################################
egress() {
MTU=$(get_mtu $IFACE)
BURST="$(get_burst ${MTU:-1514} ${UPLINK} ${ESHAPER_BURST_DUR_US})"
BURST=${BURST:-1514}
SILENT=1 $TC qdisc del dev $IFACE root
$TC qdisc add dev $IFACE root handle 1: $(get_stab_string) tbf \
rate ${UPLINK}kbit burst $BURST latency 300ms $(get_htb_adsll_string)
$TC qdisc add dev $IFACE parent 1: handle 110: $QDISC \
$(get_limit ${ELIMIT}) $(get_target "${ETARGET}" ${UPLINK}) \
$(get_ecn ${EECN}) $(get_flows ${UPLINK}) ${EQDISC_OPTS}
}
ingress() {
sqm_debug "ingress"
SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress
$TC qdisc add dev $IFACE handle ffff: ingress
MTU=$(get_mtu $IFACE)
BURST="$(get_burst ${MTU:-1514} ${DOWNLINK} ${ISHAPER_BURST_DUR_US})"
BURST=${BURST:-1514}
SILENT=1 $TC qdisc del dev $DEV root
$TC qdisc add dev $DEV root handle 1: $(get_stab_string) tbf \
rate ${DOWNLINK}kbit burst $BURST latency 300ms $(get_htb_adsll_string)
$TC qdisc add dev $DEV parent 1: handle 110: $QDISC \
$(get_limit ${ILIMIT}) $(get_target "${ITARGET}" ${DOWNLINK}) \
$(get_ecn ${IECN}) $(get_flows ${DOWNLINK}) ${IQDISC_OPTS}
$IP link set dev $DEV up
# redirect all IP packets arriving in $IFACE to ifb0
$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \
match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV
}
sqm_prepare_script() {
do_modules
verify_qdisc "tbf" || return 1
case $QDISC in
cake*)
sqm_warn "Cake is not supported with this script; falling back to FQ-CoDel"
QDISC=fq_codel ;;
esac
}
################################################################################

View File

@ -1,2 +0,0 @@
Simplest possible configuration (TBF): TBF rate limiter with your qdisc attached.
TBF may give better performance than HTB on some architectures.

Some files were not shown because too many files have changed in this diff Show More