[Zrouter-src] ZRouter.org: push to ZRouter profiles/lua_web_ui/files/etc/dhcli...

zrouter-src at zrouter.org zrouter-src at zrouter.org
Thu Sep 20 12:54:09 UTC 2012


details:   http://zrouter.org/hg/zrouter//rev/367c29234e4c
changeset: 440:367c29234e4c
user:      Aleksandr Rybalko <ray at ddteam.net>
date:      Thu Sep 20 15:21:54 2012 +0300
description:
Introduce LUA WEB UI.

diffstat:

 profiles/lua_web_ui/files/etc/dhclient-script                         |    66 +
 profiles/lua_web_ui/files/etc/favicon.ico                             |   Bin 
 profiles/lua_web_ui/files/etc/mpd-linkdown                            |    50 +
 profiles/lua_web_ui/files/etc/mpd-linkup                              |    55 +
 profiles/lua_web_ui/files/etc/racoon/phase1-down.sh                   |    28 +
 profiles/lua_web_ui/files/etc/racoon/phase1-up.sh                     |    28 +
 profiles/lua_web_ui/files/etc/racoon/racoon.conf                      |    31 +
 profiles/lua_web_ui/files/etc/rc.d/collector                          |    24 +
 profiles/lua_web_ui/files/etc/rc.d/devd                               |    27 +
 profiles/lua_web_ui/files/etc/rc.d/httpd                              |    27 +
 profiles/lua_web_ui/files/etc/www/collector.lua                       |   268 +
 profiles/lua_web_ui/files/etc/www/collector.sh                        |    19 +
 profiles/lua_web_ui/files/etc/www/config.xml                          |   274 ++
 profiles/lua_web_ui/files/etc/www/devd.lua                            |   263 +
 profiles/lua_web_ui/files/etc/www/devd.sh                             |    14 +
 profiles/lua_web_ui/files/etc/www/htdocs/Administration.config.html   |    19 +
 profiles/lua_web_ui/files/etc/www/htdocs/Administration.firmware.html |    20 +
 profiles/lua_web_ui/files/etc/www/htdocs/Administration.info.html     |    16 +
 profiles/lua_web_ui/files/etc/www/htdocs/Administration.users.html    |    21 +
 profiles/lua_web_ui/files/etc/www/htdocs/Advanced.PPP.html            |     8 +
 profiles/lua_web_ui/files/etc/www/htdocs/Basic.lan.html               |    21 +
 profiles/lua_web_ui/files/etc/www/htdocs/Basic.wan.html               |    46 +
 profiles/lua_web_ui/files/etc/www/htdocs/Basic.wlan.html              |    18 +
 profiles/lua_web_ui/files/etc/www/htdocs/Security.IPSec.html          |    85 +
 profiles/lua_web_ui/files/etc/www/htdocs/Security.OpenVPN.html        |     9 +
 profiles/lua_web_ui/files/etc/www/htdocs/Security.SSH.html            |     9 +
 profiles/lua_web_ui/files/etc/www/htdocs/cmd.xml                      |   125 +
 profiles/lua_web_ui/files/etc/www/htdocs/config.dat                   |    10 +
 profiles/lua_web_ui/files/etc/www/htdocs/css/anim.css                 |   131 +
 profiles/lua_web_ui/files/etc/www/htdocs/css/router.css               |   290 ++
 profiles/lua_web_ui/files/etc/www/htdocs/event.xml                    |   108 +
 profiles/lua_web_ui/files/etc/www/htdocs/footer.html                  |     2 +
 profiles/lua_web_ui/files/etc/www/htdocs/header.html                  |    23 +
 profiles/lua_web_ui/files/etc/www/htdocs/home_sys.html                |    50 +
 profiles/lua_web_ui/files/etc/www/htdocs/img/FreeBSD_logo.png         |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/banner.jpg               |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/config.gif               |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/folder.gif               |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/help.gif                 |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/home.gif                 |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/join.gif                 |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/joinbottom.gif           |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/line.gif                 |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/logout.gif               |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/minus.gif                |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/minusbottom.gif          |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/monitor.gif              |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/open_file.gif            |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/open_folder.gif          |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/plus.gif                 |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/plusbottom.gif           |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/sys.gif                  |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/text.gif                 |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/themespacer.gif          |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/tool.gif                 |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar.jpg             |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar_v.jpg           |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/img/triangle.gif             |   Bin 
 profiles/lua_web_ui/files/etc/www/htdocs/index.html                   |   102 +
 profiles/lua_web_ui/files/etc/www/htdocs/js/ajax.js                   |   107 +
 profiles/lua_web_ui/files/etc/www/htdocs/js/defineMyTree.js           |    77 +
 profiles/lua_web_ui/files/etc/www/htdocs/js/tree.js                   |  1360 ++++++++++
 profiles/lua_web_ui/files/etc/www/htdocs/js/ua.js                     |   116 +
 profiles/lua_web_ui/files/etc/www/htdocs/js/utils.js                  |   475 +++
 profiles/lua_web_ui/files/etc/www/htdocs/js/view.js                   |    18 +
 profiles/lua_web_ui/files/etc/www/htdocs/js/wizard.js                 |    47 +
 profiles/lua_web_ui/files/etc/www/htdocs/jstree_table.html            |    41 +
 profiles/lua_web_ui/files/etc/www/htdocs/vaps.lua                     |   134 +
 profiles/lua_web_ui/files/etc/www/httpd.lua                           |  1290 +++++++++
 profiles/lua_web_ui/files/etc/www/httpd.sh                            |    17 +
 profiles/lua_web_ui/files/etc/www/lib/base64.lua                      |    35 +
 profiles/lua_web_ui/files/etc/www/lib/bit.lua                         |    29 +
 profiles/lua_web_ui/files/etc/www/lib/conf.lua                        |   158 +
 profiles/lua_web_ui/files/etc/www/lib/dhcpd.lua                       |   106 +
 profiles/lua_web_ui/files/etc/www/lib/handler.lua                     |   305 ++
 profiles/lua_web_ui/files/etc/www/lib/hostapd.lua                     |   143 +
 profiles/lua_web_ui/files/etc/www/lib/ipcalc.lua                      |    58 +
 profiles/lua_web_ui/files/etc/www/lib/ltn12.lua                       |   292 ++
 profiles/lua_web_ui/files/etc/www/lib/mime.lua                        |    87 +
 profiles/lua_web_ui/files/etc/www/lib/mpd.lua                         |   315 ++
 profiles/lua_web_ui/files/etc/www/lib/node.lua                        |    68 +
 profiles/lua_web_ui/files/etc/www/lib/pidfile.lua                     |    69 +
 profiles/lua_web_ui/files/etc/www/lib/racoon.lua                      |   368 ++
 profiles/lua_web_ui/files/etc/www/lib/socket.lua                      |   133 +
 profiles/lua_web_ui/files/etc/www/lib/socket/ftp.lua                  |   281 ++
 profiles/lua_web_ui/files/etc/www/lib/socket/http.lua                 |   350 ++
 profiles/lua_web_ui/files/etc/www/lib/socket/smtp.lua                 |   251 +
 profiles/lua_web_ui/files/etc/www/lib/socket/tp.lua                   |   123 +
 profiles/lua_web_ui/files/etc/www/lib/socket/url.lua                  |   297 ++
 profiles/lua_web_ui/files/etc/www/lib/table.save-0.94.lua             |   183 +
 profiles/lua_web_ui/files/etc/www/lib/test.lua                        |    31 +
 profiles/lua_web_ui/files/etc/www/lib/utils.lua                       |   328 ++
 profiles/lua_web_ui/files/etc/www/lib/xml.lua                         |   472 +++
 profiles/lua_web_ui/profile.mk                                        |    13 +
 94 files changed, 10464 insertions(+), 0 deletions(-)

diffs (10791 lines):

diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/dhclient-script
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/dhclient-script	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+#LOG=/tmp/DHCLIENT-SCRIPT.log
+LOG=/dev/null
+
+touch ${LOG}
+echo "DHCLIENT-SCRIPT: $*" >> ${LOG}
+#set >> ${LOG}
+echo >>  ${LOG}
+
+case ${reason} in
+ARPSEND)
+	# TODO
+	;;
+
+ARPCHECK)
+	# TODO
+	;;
+
+EXPIRE)
+	# TODO
+	;;
+
+PREINIT)
+	# TODO
+	;;
+
+REBOOT|BOUND|RENEW)
+        #interface=wan0
+        #new_broadcast_address=192.168.1.255
+        #new_dhcp_lease_time=3600
+        #new_dhcp_message_type=5
+        #new_dhcp_server_identifier=192.168.1.3
+        #new_domain_name_servers='192.168.1.3 192.168.1.3'
+        #new_expiry=4137
+        #new_ip_address=192.168.1.5
+        #new_network_number=192.168.1.0
+        #new_routers=192.168.1.3
+        #new_subnet_mask=255.255.255.0
+        #reason=REBOOT
+        ifconfig ${interface} ${new_ip_address} netmask ${new_subnet_mask}
+        echo "DHCP: iface=${interface} ip=${new_ip_address} netmask=${new_subnet_mask} route=${new_routers} dns=${new_domain_name_servers}" >> ${LOG}
+        query="cmd=event"
+        query="${query}&state=up"
+        query="${query}&iface=${interface}"
+        query="${query}&gw=${new_routers}"
+        query="${query}&ip=${new_ip_address}"
+        query="${query}&netmask=${new_subnet_mask}"
+        query="${query}&dhclient_reason=${reason}"
+        query="${query}&dhclient_lease_time=${new_dhcp_lease_time}"
+        query="${query}&dhclient_message_type=${new_dhcp_message_type}"
+        query="${query}&dhclient_server_identifier=${new_dhcp_server_identifier}"
+        query="${query}&dhclient_expiry=${new_expiry}"
+        i=1
+        for dns in ${new_domain_name_servers} ; do
+    		query="${query}&dns${i}=${dns}"
+		i=$(( ${i} + 1 ))
+        done
+
+        # Notify configuration handler
+        fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+	;;
+*)
+	;;
+esac
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/favicon.ico
Binary file profiles/lua_web_ui/files/etc/favicon.ico has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/mpd-linkdown
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/mpd-linkdown	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+LOG=/tmp/mpd-linkdown.log
+
+touch ${LOG}
+echo "mpd-linkdown $*" >> ${LOG}
+#set >> ${LOG}
+echo >>  ${LOG}
+
+interface=$1
+proto=$2
+localip=$3
+remoteip=$4
+authname=$5
+
+echo $#
+case $# in
+	6)
+	dns1="8.8.8.8"
+	dns2="8.8.4.4"
+	peeraddress=$6
+	;;
+	7)
+	dns1=$6
+	dns2="8.8.8.8"
+	peeraddress=$7
+	;;
+	8)
+	dns1=$6
+	dns2=$7
+	peeraddress=$8
+	;;
+esac
+
+echo "MPD: iface=${interface} proto = ${proto} localip=${localip} remoteip=${remoteip} dns1=${dns1} dns2=${dns2} peeraddress=${peeraddress}" >> ${LOG}
+
+query="cmd=event"
+query="${query}&state=down"
+query="${query}&iface=${interface}"
+query="${query}&proto=${proto}"
+query="${query}&gw=${remoteip}"
+query="${query}&ip=${localip}"
+#query="${query}&dns1=${dns1}"
+#query="${query}&dns2=${dns2}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/mpd-linkup
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/mpd-linkup	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+#
+# mpd-linkup ng0 inet 95.81.35.177/32 195.128.182.55 - dns1 195.128.182.40 dns2 195.128.182.41 [12]
+#
+
+LOG=/tmp/mpd-linkup.log
+
+touch ${LOG}
+echo "mpd-linkup $*" >> ${LOG}
+#set >> ${LOG}
+echo >>  ${LOG}
+
+interface=$1
+proto=$2
+localip=$3
+remoteip=$4
+authname=$5
+
+case $# in
+6)
+	dns1="8.8.8.8"
+	dns2="8.8.4.4"
+	peeraddress=$6
+	;;
+7)
+	dns1=$6
+	dns2="8.8.8.8"
+	peeraddress=$7
+	;;
+8)
+	dns1=$6
+	dns2=$7
+	peeraddress=$8
+	;;
+esac
+
+dns1=${dns1#dns1 }
+dns2=${dns2#dns2 }
+
+echo "MPD: iface=${interface} proto = ${proto} localip=${localip} remoteip=${remoteip} dns1=${dns1} dns2=${dns2} peeraddress=${peeraddress}" >> ${LOG}
+query="cmd=event"
+query="${query}&state=up"
+query="${query}&iface=${interface}"
+query="${query}&proto=${proto}"
+query="${query}&gw=${remoteip}"
+query="${query}&ip=${localip}"
+query="${query}&dns1=${dns1}"
+query="${query}&dns2=${dns2}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/racoon/phase1-down.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/racoon/phase1-down.sh	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+LOG=/tmp/racoon-phase1-down.log
+
+touch ${LOG}
+echo "phase1-down.sh $*" >> ${LOG}
+
+
+echo $@  >>  ${LOG}
+echo "LOCAL_ADDR = ${LOCAL_ADDR} LOCAL_PORT = ${LOCAL_PORT} REMOTE_ADDR = ${REMOTE_ADDR} REMOTE_PORT = ${REMOTE_PORT}" >>  ${LOG}
+
+echo >>  ${LOG}
+
+query="cmd=event"
+query="${query}&state=down"
+query="${query}&iface=IPSec0"	# XXX: should use names for IPSec peers
+query="${query}&gw=${REMOTE_ADDR}:${REMOTE_PORT}"
+query="${query}&ip=${LOCAL_ADDR}:${LOCAL_PORT}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+# XXX: should be handled by httpd/collector
+sh "/var/run/racoon.${REMOTE_ADDR}_down.sh"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/racoon/phase1-up.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/racoon/phase1-up.sh	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+LOG=/tmp/racoon-phase1-up.log
+
+touch ${LOG}
+echo "phase1-up.sh $*" >> ${LOG}
+
+
+echo $@  >>  ${LOG}
+echo "LOCAL_ADDR = ${LOCAL_ADDR} LOCAL_PORT = ${LOCAL_PORT} REMOTE_ADDR = ${REMOTE_ADDR} REMOTE_PORT = ${REMOTE_PORT}" >>  ${LOG}
+
+echo >>  ${LOG}
+
+query="cmd=event"
+query="${query}&state=up"
+query="${query}&iface=IPSec0"	# XXX: should use names for IPSec peers
+query="${query}&gw=${REMOTE_ADDR}:${REMOTE_PORT}"
+query="${query}&ip=${LOCAL_ADDR}:${LOCAL_PORT}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+# XXX: should be handled by httpd/collector
+sh "/var/run/racoon.${REMOTE_ADDR}_up.sh"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/racoon/racoon.conf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/racoon/racoon.conf	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,31 @@
+path    pidfile  "/var/run/racoon.pid";
+path    pre_shared_key  "/var/db/racoon/racoon_psk.txt"; #location of pre-shared key file
+log     notify;  #log verbosity setting: set to 'notify' when testing and debugging is complete
+
+padding # options are not to be changed
+{
+        maximum_length  20;
+        randomize       off;
+        strict_check    off;
+        exclusive_tail  off;
+}
+
+timer   # timing options. change as needed
+{
+        counter         5;
+        interval        20 sec;
+        persend         1;
+#       natt_keepalive  15 sec;
+        phase1          30 sec;
+        phase2          15 sec;
+}
+
+listen  # address [port] that racoon will listening on
+{
+#        isakmp          192.168.90.1 [500];
+#        isakmp_natt     192.168.90.1 [4500];
+	adminsock "/var/db/racoon/racoon.sock" "root" "operator" 0660;
+}
+
+include "/var/run/racoon.links.conf";
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/rc.d/collector
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/rc.d/collector	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# PROVIDE: collector
+# REQUIRE: MAIN
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+#[ -z "${collector_enable}" ] && collector_enable="YES"
+collector_enable="YES"
+name="collector"
+command="/etc/www/${name}.sh"
+rcvar=`set_rcvar`
+
+conf_file="/etc/${name}.conf"
+pidfile="/var/run/${name}.pid"
+
+command_args="-P ${pidfile} -B ${conf_file} &"
+#required_files="${conf_file}"
+#required_modules="wlan_xauth wlan_wep wlan_tkip wlan_ccmp"
+#extra_commands="reload"
+
+load_rc_config ${name}
+run_rc_command "$1"
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/rc.d/devd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/rc.d/devd	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# $FreeBSD: src/etc/rc.d/hostapd,v 1.3.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $
+#
+
+# PROVIDE: devd
+# REQUIRE: MAIN httpd
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+#[ -z "${devd_enable}" ] && devd_enable="YES"
+devd_enable="YES"
+name="devd"
+command="/etc/www/devd.sh"
+rcvar=`set_rcvar`
+
+conf_file="/etc/${name}.conf"
+pidfile="/var/run/${name}.pid"
+
+command_args="-P ${pidfile} -B ${conf_file} &"
+#required_files="${conf_file}"
+#required_modules="wlan_xauth wlan_wep wlan_tkip wlan_ccmp"
+#extra_commands="reload"
+
+load_rc_config ${name}
+run_rc_command "$1"
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/rc.d/httpd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/rc.d/httpd	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# $FreeBSD: src/etc/rc.d/hostapd,v 1.3.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $
+#
+
+# PROVIDE: httpd
+# REQUIRE: MAIN collector
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+#[ -z "${httpd_enable}" ] && httpd_enable="YES"
+httpd_enable="YES"
+name="httpd"
+command="/etc/www/${name}.sh"
+rcvar=`set_rcvar`
+
+conf_file="/etc/${name}.conf"
+pidfile="/var/run/${name}.pid"
+
+command_args="-P ${pidfile} -B ${conf_file} &"
+#required_files="${conf_file}"
+#required_modules="wlan_xauth wlan_wep wlan_tkip wlan_ccmp"
+#extra_commands="reload"
+
+load_rc_config ${name}
+run_rc_command "$1"
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/collector.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/collector.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,268 @@
+#!/usr/bin/lua
+
+package.path = "./?.lua;/etc/www/lib/?.lua;./lib/?.lua";
+package.cpath =
+	"/lib/?.so;/usr/lib/?.so;/usr/lib/lua/?.so;" ..
+	"/lib/lua?.so;/usr/lib/lua?.so;/usr/lib/lua/lua?.so;" ..
+	"/lib/?-core.so;/usr/lib/?-core.so;/usr/lib/lua/?-core.so;" ..
+	"/lib/?/core.so;/usr/lib/?/core.so;/usr/lib/lua/?/core.so;";
+
+host = host or "127.0.0.1";
+port = port or "8";
+
+serverhost = serverhost or "127.0.0.1";
+serverport = serverport or "80";
+
+-- Globals
+r = {};		-- Runtime varibles structure
+rquery = {};
+queue = {};
+local internet_led = nil;
+
+--
+-- Utility function:  URL encoding function
+--
+function urlEncode(str)
+    if (str) then
+        str = string.gsub (str, "\n", "\r\n")
+        str = string.gsub (str, "([^%w ])",
+            function (c) return string.format ("%%%02X", string.byte(c)) end)
+        str = string.gsub (str, " ", "+")
+    end
+    return str
+end
+
+
+--
+-- Utility function:  URL decode function
+--
+function urlDecode(str)
+    str = string.gsub (str, "+", " ")
+    str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end)
+    str = string.gsub (str, "\r\n", "\n")
+    return str
+end
+
+-- convert name1=value1&name2=val+ue%2F2
+-- to table {"name1"="value1", "name2"="val ue/2"}
+function parse_query(query)
+    local parsed = {};
+    local pos = 0;
+
+    query = string.gsub(query, "&", "&");
+    query = string.gsub(query, "<", "<");
+    query = string.gsub(query, ">", ">");
+
+    local function ginsert(qstr)
+        local first, last = string.find(qstr, "=");
+        if first then
+            local key = urlDecode(string.sub(qstr, 0, first-1));
+            local value = urlDecode(string.sub(qstr, first+1));
+            parsed[key] = value;
+        end
+    end
+
+    while true do
+        local first, last = string.find(query, "&", pos);
+        if first then
+            ginsert(string.sub(query, pos, first-1));
+            pos = last+1;
+        else
+            ginsert(string.sub(query, pos));
+            break;
+        end
+    end
+    return parsed;
+end
+
+function process(q, queryline)
+
+    if q["cmd"] == "event" then
+	    q["timestamp"] = os.date("%Y-%m-%d %H:%M:%S");
+
+	    local iface = q["iface"];
+
+	    if not iface then
+		return ("collector.lua: ERROR: Interface not defined");
+	    end
+
+	    if type(r[iface]) ~= "table" then r[iface] = {}; end
+--	    rquery[iface] = queryline;
+	    -- First element processed last (implement FIFO)
+	    table.insert(queue, 1, {handled=false, query=queryline, qt=q});
+
+	    for k,v in pairs(q) do
+		if (k ~= "iface") and (k ~= "cmd") then
+		    r[iface][k] = v;
+		end
+	    end
+	    if q["state"] == "up" then
+		-- XXX: should not be here
+		-- XXX: must check exit code
+		if r[iface]["gw"] then
+		    exitcode = os.execute(
+			"route change default  " .. r[iface]["gw"] .." > /dev/null 2>&1 || " ..
+			"route add default  " .. r[iface]["gw"] .." > /dev/null 2>&1"
+		    );
+		    if internet_led then
+			internet_led:set(1);
+		    end
+		end
+		local dns = {};
+		if q["dns1"] and q["dns1"]:len() >= 7 then
+		    table.insert(dns, q["dns1"]);
+		end
+		if q["dns2"] and q["dns2"]:len() >= 7 then
+		    table.insert(dns, q["dns2"]);
+		end
+		if table.getn(dns) > 0 then
+		    resolv_conf = io.open("/etc/resolv.conf", "w");
+		    for i,v in ipairs(dns) do
+			-- print("nameserver	" .. v);
+			resolv_conf:write("nameserver	" .. v .. "\n");
+		    end
+		    resolv_conf:close();
+		end
+	    end
+	    if q["state"] == "down" then
+		if r[iface]["gw"] then
+		    if internet_led then
+			internet_led:set(0);
+		    end
+		end
+	    end
+
+	return "OK";
+
+    elseif q["cmd"] == "revent" then
+
+	iface = q["iface"];
+
+	if r[iface] then
+	    local ret = nil;
+
+	    for k,v in pairs(r[iface]) do
+		if ret then
+		    ret = ret .. "&" .. urlEncode(k) .. "=" .. urlEncode(v);
+		else
+		    ret = urlEncode(k) .. "=" .. urlEncode(v);
+		end
+	    end
+
+	    return (ret);
+	else
+	    return ("ERROR: no data for interface " .. iface);
+	end
+    else
+	return ("ERROR: unknown command");
+    end
+end
+
+function call_server(http, q)
+    local query = "http://127.0.0.1:80/event.xml?" .. q;
+
+    local body, code, headers = http.request(query);
+
+    if code == 200 then
+	return (true);
+    else
+	return (nil);
+    end
+
+end
+
+function getopt(args, opts)
+    i=1;
+    while i < table.getn(arg) do
+	if arg[i]:match("^-") then
+	    opts[arg[i]] = arg[i+1];
+	    i = i + 1;
+	end
+	i = i + 1;
+    end
+    return (opts);
+end
+
+
+
+opts = {};
+opts["-P"] = "/var/run/collector.pid";
+
+if arg then
+    opts = getopt(arg, opts);
+end
+
+
+-- Check pidfile
+dofile("lib/pidfile.lua");
+pidfile(opts["-P"]);
+
+dofile("lib/led.lua");
+
+internet_led = Led:new_from_env("INTERNET_LED");
+
+socket = require("socket");
+http = require("socket.http");
+server = assert(socket.bind(host, port));
+server:settimeout(5);
+
+
+while 1 do
+    local method, path, query, major, minor;
+
+    local control = server:accept();
+
+    if control then
+	while 1 do
+    	    local data, err = control:receive();
+    	    if not err then
+    		local q;
+	        _, _, method, path, q, major, minor  = string.find(data, "([A-Z]+) (.-)%?(.-) HTTP/(%d).(%d)");
+		if not query and q then
+		    query = q;
+		    break;
+		end
+    	    else
+    		break;
+    	    end
+	end
+
+	if query then
+	    local q = parse_query(query);
+	    if q and q.cmd then
+		assert(control:send(
+		    "HTTP/1.0 200 OK\r\n" ..
+		    "Server: simple-lua\r\n" ..
+		    "Content-type: text/xml\r\n" ..
+		    "Connection: close\r\n" ..
+		    "\r\n" ..
+		    process(q, query)
+		));
+    	    end
+        end
+
+	assert(control:close());
+    end
+
+    local n = table.getn(queue);
+    if n > 0 then
+	for i = n,1,-1 do
+	    if queue[i].handled ~= true then
+		-- print("queue[" .. i .. "] Will send " .. queue[i].query .. " to main server");
+		if (call_server(http, queue[i].query) == true) then
+		    -- print("queue[" .. i .. "] Will delete " .. queue[i].query .. " from queue");
+		    queue[i].handled = true;
+		    table.remove(queue, i);
+		end
+	    end
+	end
+    end
+
+end
+
+os.exit(0);
+
+
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/collector.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/collector.sh	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+
+cd /etc/www
+
+echo $$ > /var/run/collector.sh.pid
+
+INTERNET_LED=$(kenv -q INTERNET_LED)
+INTERNET_LED_INVERT=$(kenv -q INTERNET_LED_INVERT)
+
+export INTERNET_LED INTERNET_LED_INVERT
+
+./collector.lua > /var/log/collector.sh.log 2>&1
+exit 1
+
+while true; do
+    ./collector.lua > /var/log/collector.sh.log 2>&1
+done
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/config.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/config.xml	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,274 @@
+<interfaces>
+    <wan0>
+        <PPPoE enable="false" type="pppoe" onchange="iface_changed('interfaces.wan0.PPPoE')">
+            <action>
+                <create target="socket:127.0.0.1:5005" type="socket">
+                    <message></message>
+                </create>
+            </action>
+            <nat enable="true"></nat>
+            <name>PPPoE</name>
+            <username>pppoe1</username>
+            <password>test</password>
+            <service_name></service_name>
+            <device>wan0</device>
+            <default_route>true</default_route>
+            <!-- flags -> FORCE='overwrite received', DEFAULT='used if no received' -->
+            <ipaddr flags="DEFAULT,FORCE">10.0.0.1/32</ipaddr>
+            <gateway flags="DEFAULT">10.0.0.2</gateway>
+            <!-- <ip6addr></ip6addr> -->
+            <!-- Values holders -->
+            <dns1></dns1>
+            <dns2></dns2>
+            <name>wan0pppoe</name>
+            <group>WAN</group>
+            <cost>10</cost>
+        </PPPoE>
+        <PPP enable="false" type="modem" onchange="iface_changed('interfaces.wan0.PPP')">
+            <action>
+                <up target="socket:127.0.0.1:5005" type="socket"></up>
+                <destroy target="socket:127.0.0.1:5005" type="socket"></destroy>
+                <down target="socket:127.0.0.1:5005" type="socket"></down>
+                <create target="socket:127.0.0.1:5005" type="socket"></create>
+                <destroy target="socket:127.0.0.1:5005" type="socket"></destroy>
+            </action>
+            <name>3G</name>
+            <nat enable="true"></nat>
+            <username>IT</username>
+            <password>IT</password>
+            <phone>#777</phone>
+            <init_string></init_string>
+            <device>/dev/cuaU0.0</device>
+            <default_route>true</default_route>
+            <!-- flags -> FORCE='overwrite received', DEFAULT='used if no received' -->
+            <ipaddr flags="DEFAULT,FORCE">10.0.0.1/32</ipaddr>
+            <gateway flags="DEFAULT">10.0.0.2</gateway>
+            <!-- <ip6addr></ip6addr> -->
+            <!-- Values holders -->
+            <dns1></dns1>
+            <dns2></dns2>
+            <name>PPP</name>
+            <group>WAN</group>
+            <cost>1000</cost>
+        </PPP>
+        <Static enable="true" type="hw">
+            <nat enable="true"></nat>
+            <dhcp enable="true"></dhcp>
+            <device>wan0</device>
+            <default_route>true</default_route>
+            <!-- flags -> FORCE='overwrite received', DEFAULT='used if no received' -->
+            <ipaddr flags="DEFAULT,FORCE">10.0.0.10/24</ipaddr>
+            <!-- Values holders -->
+            <gateway>10.0.0.1</gateway>
+            <dns1>10.0.0.1</dns1>
+            <dns2>10.0.0.2</dns2>
+            <name>wan0</name>
+            <group>WAN</group>
+            <cost>100</cost>
+        </Static>
+    </wan0>
+    <wlan0 enable="true" type="wlan">
+        <create>
+            <exec>ifconfig wlan0 create wlandev wifi0 wlanmode hostap</exec>
+        </create>
+        <init>
+            <exec>ifconfig wlan0</exec>
+        </init>
+        <wlan_interface>wifi0</wlan_interface>
+        <channel>6</channel>
+        <mode>11ng</mode>
+        <ht40>true</ht40>
+    </wlan0>
+    <wifi0>
+        <init>
+            <exec>ifconfig wifi0 up</exec>
+        </init>
+    </wifi0>
+    <lan0>
+        <init>
+            <!-- exec>ifconfig lan0 up</exec -->
+        </init>
+    </lan0>
+    <bridge0 type="bridge">
+        <create>
+            <exec>ifconfig wlan0 down</exec>
+            <exec>ifconfig lan0 down</exec>
+            <exec>ifconfig bridge0 create addm lan0 addm wlan0 up</exec>
+            <exec>ifconfig bridge0 down</exec>
+            <exec>ifconfig bridge0 ether `kenv LAN_MAC_ADDR`</exec>
+            <exec>ifconfig lan0 up</exec>
+            <exec>ifconfig wlan0 up</exec>
+            <exec>ifconfig bridge0 up</exec>
+        </create>
+        <init>
+        </init>
+        <ipaddr>192.168.0.1/24</ipaddr>
+        <lagg_interfaces>lan0,wlan0</lagg_interfaces>
+    </bridge0>
+</interfaces>
+<switch>
+    <ports>
+        <port id="0" pvid="1" tagged="false"></port>
+        <port id="1" pvid="1" tagged="false"></port>
+        <port id="2" pvid="1" tagged="false"></port>
+        <port id="3" pvid="1" tagged="false"></port>
+        <port id="4" pvid="2" tagged="false"></port>
+        <port id="5" pvid="1" tagged="true"></port>
+        <port id="6" pvid="1" tagged="false"></port>
+    </ports>
+    <vlans>
+        <vlan id="0" vid="1">0,1,2,3,5</vlan>
+        <vlan id="1" vid="2">4,5</vlan>
+    </vlans>
+</switch>
+<dnsrelay enable="false"></dnsrelay>
+<dhcpd>
+    <instances>
+        <instance id="0" enable="true">
+            <interface>bridge0</interface>
+            <domain>dlink.ua</domain>
+            <!-- <domainservers>192.168.0.1</domainservers> -->
+            <default-lease-time>600</default-lease-time>
+            <max-lease-time>7200</max-lease-time>
+            <range>
+                <start>192.168.0.100</start>
+                <end>192.168.0.200</end>
+            </range>
+        </instance>
+    </instances>
+</dhcpd>
+<routes>
+    <default>
+        <source priority="10">interfaces.wan0.DHCP.gateway</source>
+        <source priority="11">interfaces.wan0.PPPoE.gateway</source>
+        <source priority="12">interfaces.wan0.PPP.gateway</source>
+        <source priority="13">interfaces.wan0.Static.gateway</source>
+        <source priority="14">interfaces.wan0.PPTP.gateway</source>
+        <source priority="15">interfaces.wan0.L2TP.gateway</source>
+    </default>
+    <route id="1" enable="false">
+        <net>172.16.0.0/12</net>
+        <gw>192.168.0.2</gw>
+    </route>
+</routes>
+<resolve>
+    <search>dlink.ua</search>
+    <domain>dlink.ua dlink.ru</domain>
+    <options>attempts:5 timeout:10</options>
+    <nameserver order="100">8.8.8.8</nameserver>
+    <nameserver order="101">8.8.4.4</nameserver>
+</resolve>
+<igmp>
+    <instance id="0" enable="false">
+	<up>wan0</up>
+	<down>wlan0</down>
+    </instance>
+    <instance id="0" enable="false">
+	<up>wan0</up>
+	<down>lan0</down>
+    </instance>
+</igmp>
+<info>
+    <hostname>zrouter</hostname>
+    <location>home</location>
+    <firmware>
+	<!-- XXX: version and build date should be here -->
+        <version>???</version>
+        <date>????</date>
+        <update_url>http://www.dlink.ua/files/products/ftp/pub/Router/DIR-620/Firmware/FreeBSD/D-Link_DIR-620-last.txt</update_url>
+    </firmware>
+</info>
+<hostapd>
+    <instance id="0" enable="true">
+        <ieee80211d>1</ieee80211d>
+        <country_code>UA</country_code>
+        <interface>wlan0</interface>
+        <macaddr_acl>0</macaddr_acl>
+        <auth_algs>1</auth_algs>
+        <debug>0</debug>
+        <hw_mode>g</hw_mode>
+        <ctrl_interface>/var/run/hostapd</ctrl_interface>
+        <ctrl_interface_group>wheel</ctrl_interface_group>
+        <ssid>zrouter</ssid>
+        <channel>6</channel>
+        <!-- Open -->
+        <wpa>3</wpa>
+        <!-- WPA -->
+        <!-- <wpa>1</wpa> -->
+        <!-- RSN/WPA2 -->
+        <!-- <wpa>2</wpa> -->
+        <wpa_passphrase>freebsdmall</wpa_passphrase>
+        <wpa_key_mgmt>WPA-PSK</wpa_key_mgmt>
+        <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+    </instance>
+    <instance id="1" enable="false">
+        <ieee80211d>1</ieee80211d>
+        <country_code>UA</country_code>
+        <interface>wlan0</interface>
+        <macaddr_acl>0</macaddr_acl>
+        <auth_algs>1</auth_algs>
+        <debug>0</debug>
+        <hw_mode>g</hw_mode>
+        <ctrl_interface>/var/run/hostapd</ctrl_interface>
+        <ctrl_interface_group>wheel</ctrl_interface_group>
+        <ssid>zrouter</ssid>
+        <!-- WPA -->
+        <!-- <wpa>1</wpa> -->
+        <!-- RSN/WPA2 -->
+        <wpa>2</wpa>
+        <wpa_passphrase>freebsdmall</wpa_passphrase>
+        <wpa_key_mgmt>WPA-PSK</wpa_key_mgmt>
+        <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+    </instance>
+</hostapd>
+<http>
+    <users>
+        <user username="admin" password="admin" group="admin"></user>
+        <user username="user" password="123" group="stat"></user>
+    </users>
+    <!-- host>192.168.0.1</host
+	bind to all, because we need local access also.
+	XXX: we should take care about ipfw deny for that. -->
+    <host>192.168.0.1</host>
+    <port>80</port>
+</http>
+<ipsec>
+    <remote id="0" enable="false">
+	<gateway>10.0.0.2:500</gateway>
+        <exchange_mode>main,aggressive</exchange_mode>
+        <my_identifier>address 10.0.0.1</my_identifier>
+        <peers_identifier>address 10.0.0.2</peers_identifier>
+        <lifetime>time 28800 sec</lifetime>
+	<initial_contact>on</initial_contact>
+        <passive>off</passive>
+        <proposal_check>obey</proposal_check>
+	<nat_traversal>off</nat_traversal>
+        <generate_policy>off</generate_policy>
+        <proposal>
+            <encryption_algorithm>3des</encryption_algorithm>
+            <hash_algorithm>md5</hash_algorithm>
+            <authentication_method>pre_shared_key</authentication_method>
+            <dh_group>5</dh_group>
+            <psk>pskpskpsk</psk>
+	</proposal>
+    </remote>
+    <sainfo id="0" enable="true">
+	<src>address 192.168.0.0/24 any</src>
+	<dst>address 192.168.2.0/24 any</dst>
+	<pfs_group>5</pfs_group>
+	<lifetime>time 3600 sec</lifetime>
+	<encryption_algorithm>3des</encryption_algorithm>
+	<authentication_algorithm>hmac_md5</authentication_algorithm>
+	<compression_algorithm>deflate</compression_algorithm>
+    </sainfo>
+    <setkey>
+	<line>spdadd 192.168.0.0/24 192.168.2.0/24 any -P out ipsec esp/tunnel/10.0.0.1-10.0.0.2/use</line>
+	<line>spdadd 192.168.2.0/24 192.168.0.0/24 any -P in ipsec esp/tunnel/10.0.0.2-10.0.0.1/use</line>
+	<line></line>
+	<line></line>
+    </setkey>
+</ipsec>
+<ntp enable="true">
+    <server id="1">ntp.dlink.com.tw</server>
+    <server id="2">ntp1.dlink.com</server>
+</ntp>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/devd.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/devd.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,263 @@
+#!/usr/bin/lua
+
+package.path = "./?.lua;/etc/www/lib/?.lua;./lib/?.lua";
+package.cpath =
+	"/lib/?.so;/usr/lib/?.so;/usr/lib/lua/?.so;" ..
+	"/lib/lua?.so;/usr/lib/lua?.so;/usr/lib/lua/lua?.so;" ..
+	"/lib/?-core.so;/usr/lib/?-core.so;/usr/lib/lua/?-core.so;" ..
+	"/lib/?/core.so;/usr/lib/?/core.so;/usr/lib/lua/?/core.so;";
+
+serverhost = serverhost or "127.0.0.1";
+serverport = serverport or "80";
+
+-- redirect print to /dev/console
+-- dofile("lib/print_to_console.lua");
+
+-- redirect print to syslog
+dofile("lib/lsyslog.lua");
+syslog_init("devd.lua");
+
+-- urlEncode/urlDecode
+dofile("lib/urlXxcode.lua");
+
+function tab_to_query(t)
+    local ret = "event=devd";
+
+    for k,v in pairs(t) do
+	ret = ret .. "&" .. urlEncode(k) .. "=" .. urlEncode(v);
+    end
+
+    return (ret);
+end
+
+function call_server(config, q)
+    local query = "http://127.0.0.1:80/event.xml?" .. q;
+
+    local body, code, headers = config.http.request(query);
+
+    if code == 200 then
+	return (true);
+    else
+	return (nil);
+    end
+
+end
+
+function exec_output(cmd)
+	fp = io.popen(cmd, "r");
+	data = fp:read("*a");
+	fp:close();
+	return data;
+end
+
+function system_event(config, msg)
+    -- !system=IFNET subsystem=rt0 type=ATTACH
+    -- !system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.1.1
+    -- !system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.1 cdev=ugen0.1 \
+    --		vendor=0x0000 product=0x0000 devclass=0x09 devsubclass=0x00 \
+    --		sernum= release=0x0100 mode=host port=1 parent=dotg0
+    -- !system=GPIO subsystem=pin14 type=PIN_LOW bus=gpiobus0 period=0
+    -- !system=GPIO subsystem=pin14 type=PIN_HIGH bus=gpiobus0 period=0
+
+    function generic_event(m, msg)
+	-- Relay to main control logic
+	local query = "cmd=event" ..
+	    "&system=" .. m.system ..
+	    "&subsystem=" .. m.subsystem ..
+	    "&type=" .. m.type ..
+	    "&data=" .. urlEncode(msg);
+	-- cmd=event&iface=wan0&state=linkup;
+	print("devd.lua: query master with \"" .. query .. "\"");
+	if call_server(config, query) == false then
+	    -- XXX error handling
+	end
+    end
+
+    local m = {};
+
+    if not msg then
+	return (nil);
+    end
+
+    for k, v in msg:gmatch("(%w+)=(%S+)") do
+        m[k] = v;
+        -- print(k,v);
+    end
+
+    if m.system and m.subsystem and m.type then
+	if     m.system == "IFNET" then
+	    -- Interfaces
+	    -- system=IFNET subsystem=lan0 type=LINK_UP
+	    local linkstate;
+	    if m.type == "LINK_UP" then
+		if m.subsystem == "lan0" then
+		    -- XXX: bug workaround, we have to check why UP does not unplumb iface
+		    os.execute("ifconfig lan0 down");
+		    os.execute("ifconfig lan0 up");
+		end
+		linkstate = "linkup";
+	    elseif m.type == "LINK_DOWN" then
+		linkstate = "linkdown";
+	    else
+		generic_event(m, msg);
+		return (nil);
+	    end
+	    local query = "cmd=event" ..
+		"&iface=" .. urlEncode(m.subsystem) ..
+		"&state=" .. linkstate;
+	    -- cmd=event&iface=wan0&state=linkup;
+	    if call_server(config, query) == false then
+		-- XXX error handling
+	    end
+	elseif m.system == "DEVFS" then
+	    -- Device nodes
+	    generic_event(m, msg);
+
+	elseif m.system == "USB" then
+	    -- USB messages
+	    generic_event(m, msg);
+	    -- !system=USB subsystem=INTERFACE type=ATTACH ugen=ugen0.2 cdev=ugen0.2 vendor=0x1f28 product=0x0021
+	    -- devclass=0x00 devsubclass=0x00 sernum="216219360300" release=0x0000
+	    -- mode=host interface=0 endpoints=2 intclass=0x08 intsubclass=0x06 intprotocol=0x50
+
+	    -- system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.2 cdev=ugen0.2 vendor=0x1f28 product=0x0021
+	    -- devclass=0x00 devsubclass=0x00 sernum=%22216219360300%22 release=0x0000 mode=host port=1 parent=ugen0.1
+
+	    -- Our usb_modeswitch :)
+	    if m.subsystem == "DEVICE" and m.type == "ATTACH" then
+		-- XXX: get that from config
+		m.vendor = m.vendor - 0;
+		m.product = m.product - 0;
+		-- ugen0.2 -> 0.2
+		devid = m.ugen:gsub("ugen", "");
+		if m.vendor == 0x1f28 and m.product == 0x0021 then
+	    	    os.execute("hex2bin " ..
+	    		"55534243b82e238c24000000800108df200000000000000000000000000000" ..
+	    		" > /dev/usb/" .. devid .. ".8"); -- EndPoint 8
+		end
+	    end
+
+	elseif m.system == "GPIO" then
+	    -- GPIO messages
+	    generic_event(m, msg);
+
+	    -- XXX: should not be hardcoded
+	    if m.subsystem == reset_pin and m.bus == "gpiobus0" then
+		if     m.type == "PIN_LOW" then
+		    -- Pin return to normal state
+		    time = tonumber(m.period);
+		    -- if hold time between 10 and 15 sec, call httpd to reset to default
+		    -- XXX better to send event to httpd, then httpd will decide what to do
+		    -- XXX2 but if httpd have wrong config, then he can't start
+		    if 10 < time and time < 15 then
+			-- XXX: always do restore config here, because wrong config break httpd yet
+			-- if call_server(config, "restore=config") == false then
+			    -- If we can't get success from httpd, then we restore default manualy
+			    os.execute("mv /tmp/etc/www/config.xml /tmp/etc/www/config.xml.bak");
+			    os.execute("/etc/rc.save_config");
+			    os.execute("reboot");
+			-- end
+			os.execute("echo \"devd.lua: User request Reset to Default\" > /dev/console");
+		    end
+		elseif m.type == "PIN_HIGH" then
+		    -- User push the reset button
+		    -- Nothing to do yet
+		else
+		    -- Unknown type
+		end
+	    end
+	else
+	    -- Unknown system
+	end
+    end
+end
+
+function unknown_device(config, msg)
+-- "? at pins=?  on gpiobus0"
+end
+
+function device_attached(config, msg)
+-- "+nvram2env0 at   on nexus0"
+end
+
+function device_detached(config, msg)
+-- "-nvram2env0 at   on nexus0"
+end
+
+
+
+local run = true;
+local config = {};
+config.http = require("socket.http");
+
+reset_pin = exec_output("kenv -q RESET_PIN");
+if not reset_pin then
+    reset_pin = 10;
+end
+reset_pin = string.format("pin%03d", reset_pin);
+
+while run do
+    if not config.d then
+	config.d = io.open("/dev/devctl", "r");
+    end
+    local line = config.d:read("*l");
+    if line then
+	print("devd.lua:DEBUG: got \"" .. line .. "\"");
+	local m, _, t, msg = line:find("^(.)(.*)");
+	if m and t and msg then
+		if     t == "!" then
+		    system_event(config, msg);
+		elseif t == "?" then
+		    unknown_device(config, msg);
+		elseif t == "+" then
+		    device_attached(config, msg);
+		elseif t == "-" then
+		    device_detached(config, msg);
+		else
+			os.execute("echo \" Message with unknown type received " .. line .. "\" > /dev/console");
+		end
+	end
+    end
+end
+
+
+--[[
+!system=IFNET subsystem=rt0 type=ATTACH
+!system=IFNET subsystem=usbus0 type=ATTACH
+!system=IFNET subsystem=rt28600 type=ATTACH
+!system=IFNET subsystem=lo0 type=ATTACH
+
++nvram2env0 at   on nexus0
++clock0 at   on nexus0
++rt0 at   on nexus0
++rt305x_sysctl0 at   on obio0
++rt305x_ic0 at   on obio0
++gpioc0 at pins=?  on gpiobus0
++gpioreset0 at pins=?  on gpiobus0
+? at pins=?  on gpiobus0
++gpioled1 at pins=?  on gpiobus0
++gpiobus0 at   on gpio0
++gpio0 at   on obio0
++uart1 at   on obio0
++cfid0 at   on cfi0
++cfi0 at   on obio0
++usbus0 at   on dotg0
++dotg0 at   on obio0
++rt28600 at   on nexus0
++nexus0 at   on root0
+
+-- New device node
+!system=DEVFS subsystem=CDEV type=CREATE cdev=usbctl
+!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.1.0
+!system=DEVFS subsystem=CDEV type=CREATE cdev=ugen0.1
+!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.1.1
+
+!system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.1 cdev=ugen0.1 vendor=0x0000 product=0x0000 devclass=0x09 devsubclass=0x00 sernum= release=0x0100 mode=host port=1 parent=dotg0
+!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen0.1 cdev=ugen0.1 vendor=0x0000 product=0x0000 devclass=0x09 devsubclass=0x00 sernum= release=0x0100 mode=host interface=0 endpoints=1 intclass=0x09 intsubclass=0x00 intprotocol=0x00
+!system=DEVFS subsystem=CDEV type=CREATE cdev=cfid0
+!system=DEVFS subsystem=CDEV type=CREATE cdev=map/bootloader
+
+-- Reported GPIO pins
+!system=GPIO subsystem=pin14 type=PIN_LOW bus=gpiobus0 period=0
+!system=GPIO subsystem=pin14 type=PIN_HIGH bus=gpiobus0 period=0
+]]
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/devd.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/devd.sh	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+
+cd /etc/www
+
+echo $$ > /var/run/devd.sh.pid
+
+./devd.lua > /var/log/devd.sh.log 2>&1
+exit 1
+
+while true; do
+    ./devd.lua
+done
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.config.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.config.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,19 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>Device Configuration</h1>
+
+    <h4>Upload Configuration</h4>
+    <form method="post" action="/cmd.xml" enctype="multipart/form-data">
+	<input type="hidden" name="cmd" value="upload_config">
+	<input type="file" name="config" value="">
+	<input type="submit" name="Upload Config" value="Upload Config">
+    </form>
+    <h4>Download Configuration</h4>
+    <form method="post" action="/config.dat" enctype="application/x-www-form-urlencoded">
+	<input type="hidden" name="cmd" value="download_config">
+	<input type="submit" name="Download Config" value="Download Config">
+    </form>
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.firmware.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.firmware.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,20 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>Device Firmware</h1>
+Current Version: <strong>$$$info.firmware.version$$$</strong><br/>
+Build Date:<strong>$$$info.firmware.date$$$</strong><br/>
+
+$$$code:conf_table("Firmware", "Firmware", "info.firmware",
+{
+    { label = "Update URL", 		type = "node", htmltype = "text", 	node = "update_url" 	},
+})$$$
+
+    <h4>Upgrade Firmware</h4>
+    <form method="post" action="/cmd.xml" enctype="application/x-www-form-urlencoded">
+	<input type="hidden" name="cmd" value="upgrade">
+	<input type="submit" name="Start Upgrade" value="Start Upgrade">
+    </form>
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.info.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.info.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,16 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>Device Information</h1>
+Vendor:<strong>$$$info.device.vendor$$$</strong><br/>
+Model:<strong>$$$info.device.model$$$</strong><br/>
+Hardware Revision:<strong>$$$info.device.revision$$$</strong><br/>
+
+$$$code:conf_table("DevInfo", "Device Information", "info",
+{
+    { label = "Hostname", 	type = "node", htmltype = "text", 	node = "hostname" 	},
+    { label = "Location", 	type = "node", htmltype = "text", 	node = "location" 	},
+})$$$
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.users.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.users.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,21 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>Users</h1>
+TODO: Access groups
+$$$code:conf_table("User1Auth", "User 1 auth", "http.users.user[1]",
+{
+    { label = "Username", 	type = "attr", htmltype = "text", 	node = ":username" 	},
+    { label = "Password", 	type = "attr", htmltype = "text", 	node = ":password" 	},
+--[[    { label = "Group", 		type = "attr", htmltype = "text", 	node = ":group" 		},]]
+})$$$
+
+$$$code:conf_table("User2Auth", "User 2 auth", "http.users.user[2]",
+{
+    { label = "Username", 	type = "attr", htmltype = "text", 	node = ":username" 	},
+    { label = "Password", 	type = "attr", htmltype = "text", 	node = ":password" 	},
+--[[    { label = "Group", 		type = "attr", htmltype = "text", 	node = ":group" 		},]]
+})$$$
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Advanced.PPP.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Advanced.PPP.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,8 @@
+$$$code:inc("htdocs/header.html")$$$
+
+    <h1>Advanced PPP options</h1>
+    <h1>Advanced 3G modems options</h1>
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Basic.lan.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Basic.lan.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,21 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>LAN configuration</h1>
+
+$$$code:conf_table("LAN", "LAN", "interfaces.bridge0",
+{
+    { label = "IP Address", 		type = "node", htmltype = "text", 	node = "ipaddr" 	},
+})$$$
+
+$$$code:conf_table("DHCPD", "DHCP server configuration", "dhcpd.instances.instance[1]",
+{
+    { label = "Enabled", 		type = "attr", htmltype = "checkbox", 	node = ":enable" 	},
+    { label = "First IP Address", 	type = "node", htmltype = "text", 	node = "range.start" 	},
+    { label = "Last IP Address", 	type = "node", htmltype = "text", 	node = "range.end" 	},
+    { label = "Default Lease Time", 	type = "node", htmltype = "text", 	node = "default-lease-time"},
+    { label = "Max Lease Time", 	type = "node", htmltype = "text", 	node = "max-lease-time" },
+})$$$
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Basic.wan.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Basic.wan.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,46 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>Internet connections configuration</h1>
+
+$$$code:conf_table("Static", "Ethernet Interface", "interfaces.wan0.Static",
+{
+    { label = "Enabled", 		type = "attr", htmltype = "checkbox", 	node = ":enable" 	},
+    { label = "Automatic (DHCP)",	type = "attr", htmltype = "checkbox", 	node = "dhcp:enable" 	},
+    { label = "IP Address", 		type = "node", htmltype = "text", 	node = "ipaddr" 	},
+    { label = "Gateway Address", 	type = "node", htmltype = "text", 	node = "gateway" 	},
+    { label = "DNS Primary", 		type = "node", htmltype = "text", 	node = "dns1" 		},
+    { label = "DNS Secondary", 		type = "node", htmltype = "text", 	node = "dns2" 		},
+    { label = "NAT Enabled", 		type = "attr", htmltype = "checkbox", 	node = "nat:enable" 	}
+})$$$
+
+$$$code:conf_table("PPPoE", "PPPoE", "interfaces.wan0.PPPoE",
+{
+    { label = "Enabled", 		type = "attr", htmltype = "checkbox", 	node = ":enable" 	},
+    { label = "Username", 		type = "node", htmltype = "text", 	node = "username" 	},
+    { label = "Password", 		type = "node", htmltype = "text", 	node = "password" 	},
+    { label = "Service name", 		type = "node", htmltype = "text", 	node = "service_name" 	},
+    { label = "Device", 		type = "node", htmltype = "text", 	node = "device" 	},
+    { label = "IP Address", 		type = "node", htmltype = "text", 	node = "ipaddr" 	},
+    { label = "Gateway Address", 	type = "node", htmltype = "text", 	node = "gateway" 	},
+    { label = "DNS Primary", 		type = "node", htmltype = "text", 	node = "dns1" 		},
+    { label = "DNS Secondary", 		type = "node", htmltype = "text", 	node = "dns2" 		},
+    { label = "NAT Enabled", 		type = "attr", htmltype = "checkbox", 	node = "nat:enable" 	}
+})$$$
+
+$$$code:conf_table("PPP", "PPP (3G)", "interfaces.wan0.PPP",
+{
+    { label = "Enabled", 		type = "attr", htmltype = "checkbox", 	node = ":enable" 	},
+    { label = "Username", 		type = "node", htmltype = "text", 	node = "username" 	},
+    { label = "Password", 		type = "node", htmltype = "text", 	node = "password" 	},
+    { label = "Phone", 			type = "node", htmltype = "text", 	node = "phone" 		},
+    { label = "Init String",		type = "node", htmltype = "text", 	node = "init_string"	},
+    { label = "Device", 		type = "node", htmltype = "text", 	node = "device" 	},
+    { label = "IP Address", 		type = "node", htmltype = "text", 	node = "ipaddr" 	},
+    { label = "Gateway Address", 	type = "node", htmltype = "text", 	node = "gateway" 	},
+    { label = "DNS Primary", 		type = "node", htmltype = "text", 	node = "dns1" 		},
+    { label = "DNS Secondary", 		type = "node", htmltype = "text", 	node = "dns2" 		},
+    { label = "NAT Enabled", 		type = "attr", htmltype = "checkbox", 	node = "nat:enable" 	}
+})$$$
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Basic.wlan.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Basic.wlan.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,18 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>Wireless configuration</h1>
+
+$$$code:conf_table("WLAN", "Wireless Access Point configuration", "hostapd.instance[1]",
+{
+    { label = "Enabled", 			type = "attr", htmltype = "checkbox", 	node = ":enable" 	},
+    { label = "Country code (UA)", 		type = "node", htmltype = "text", 	node = "country_code" 	},
+    { label = "wireless iface (wlan0)", 	type = "node", htmltype = "text", 	node = "interface" 	},
+    { label = "Channel (6)", 			type = "node", htmltype = "text", 	node = "channel" 	},
+    { label = "SSID", 				type = "node", htmltype = "text", 	node = "ssid"		},
+    { label = "WPA mode, 1-WPA, 2-RSN, 3-WPA+RSN", 	type = "node", htmltype = "text", 	node = "wpa"	},
+    { label = "WPA key", 			type = "node", htmltype = "text", 	node = "wpa_passphrase" },
+})$$$
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Security.IPSec.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Security.IPSec.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,85 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>IPSec configuration</h1>
+
+
+<!-- ipsec>
+    <remote id="0" enable="true">
+	<gateway>10.0.0.2:500</gateway>
+        <exchange_mode>main,aggressive</exchange_mode>
+        <my_identifier>address 10.0.0.1</my_identifier>
+        <peers_identifier>address 10.0.0.2</peers_identifier>
+        <lifetime>time 28800 sec</lifetime>
+	<initial_contact>on</initial_contact>
+        <passive>off</passive>
+        <proposal_check>obey</proposal_check>
+	<nat_traversal>off</nat_traversal>
+        <generate_policy>off</generate_policy>
+        <proposal>
+            <encryption_algorithm>3des</encryption_algorithm>
+            <hash_algorithm>md5</hash_algorithm>
+            <authentication_method>pre_shared_key</authentication_method>
+            <dh_group>5</dh_group>
+	</proposal>
+    </remote>
+    <sainfo id="0" enable="true">
+	<src>address 192.168.0.0/24 any</src>
+	<dst>address 192.168.2.0/24 any</dst>
+	<pfs_group>5</pfs_group>
+	<lifetime>time 3600 sec</lifetime>
+	<encryption_algorithm>3des</encryption_algorithm>
+	<authentication_algorithm>hmac_md5</authentication_algorithm>
+	<compression_algorithm>deflate</compression_algorithm>
+    </sainfo>
+    <setkey>
+	<line>spdadd 192.168.0.0/24 192.168.2.0/24 any -P out ipsec esp/tunnel/10.0.0.1-10.0.0.2/use</line>
+	<line>spdadd 192.168.2.0/24 192.168.0.0/24 any -P in ipsec esp/tunnel/10.0.0.2-10.0.0.1/use</line>
+    <setkey>
+</ipsec -->
+
+
+$$$code:conf_table("IPSec", "IPSec link configuration", "ipsec.remote[1]",
+{
+    { label = "Enabled", 		type = "attr", htmltype = "checkbox", 	node = ":enable" 	},
+    { label = "Gateway", 		type = "node", htmltype = "text", 	node = "gateway"		},
+    { label = "Exchange Mode", 		type = "node", htmltype = "text", 	node = "exchange_mode"		},
+    { label = "My ID", 			type = "node", htmltype = "text", 	node = "my_identifier"		},
+    { label = "Peer ID", 		type = "node", htmltype = "text", 	node = "peers_identifier"	},
+    { label = "Lifetime", 		type = "node", htmltype = "text", 	node = "lifetime"		},
+    { label = "Initial Contact", 	type = "node", htmltype = "text", 	node = "initial_contact"	},
+    { label = "Passive", 		type = "node", htmltype = "text", 	node = "passive"		},
+    { label = "Proposal Check", 	type = "node", htmltype = "text", 	node = "proposal_check"		},
+    { label = "NAT Traversal", 		type = "node", htmltype = "text", 	node = "nat_traversal"		},
+    { label = "Generate Policy", 	type = "node", htmltype = "text", 	node = "generate_policy"	},
+})$$$
+$$$code:conf_table("IPSecProposal", "IPSec link1 proposal configuration", "ipsec.remote[1].proposal",
+{
+    { label = "Encryption Algorithm", 	type = "node", htmltype = "text", 	node = "encryption_algorithm"	},
+    { label = "HASH Algorithm", 	type = "node", htmltype = "text", 	node = "hash_algorithm"		},
+    { label = "DH Group", 		type = "node", htmltype = "text", 	node = "dh_group"		},
+    { label = "Pre Shared Key", 	type = "node", htmltype = "text", 	node = "psk"			},
+})$$$
+
+$$$code:conf_table("IPSecTunnel", "IPSec link1 Tunnel configuration", "ipsec.sainfo[1]",
+{
+    { label = "Source Address",		type = "node", htmltype = "text", 	node = "src"			},
+    { label = "Destination Address",	type = "node", htmltype = "text", 	node = "dst"			},
+    { label = "PFS Group", 		type = "node", htmltype = "text", 	node = "pfs_group"		},
+    { label = "Lifetime", 		type = "node", htmltype = "text", 	node = "lifetime"		},
+    { label = "Encryption Algorithm", 	type = "node", htmltype = "text", 	node = "encryption_algorithm"	},
+    { label = "Auth Algorithm", 	type = "node", htmltype = "text", 	node = "authentication_algorithm"},
+    { label = "Compression Algorithm", 	type = "node", htmltype = "text", 	node = "compression_algorithm"	},
+})$$$
+
+$$$code:conf_table("SPD", "IPSec Policy (setkey) configuration", "ipsec.setkey",
+{
+    { label = "Line1",	type = "node", htmltype = "text", node = "line[1]"},
+    { label = "Line2",	type = "node", htmltype = "text", node = "line[2]"},
+    { label = "Line3",	type = "node", htmltype = "text", node = "line[3]"},
+    { label = "Line4",	type = "node", htmltype = "text", node = "line[4]"},
+})$$$
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Security.OpenVPN.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Security.OpenVPN.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,9 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>OpenVPN configuration</h1>
+
+    Empty
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Security.SSH.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Security.SSH.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,9 @@
+$$$code:inc("htdocs/header.html")$$$
+    <h1>SSH tunnels configuration</h1>
+
+    Empty
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/cmd.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/cmd.xml	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,125 @@
+function process()
+
+    if rq.POST["cmd"] == "get" then
+
+	return (c:getNode(rq.POST["key"]):value());
+
+    elseif rq.POST["cmd"] == "set" then
+
+	c:getNode(rq.POST["key"]):value(rq.POST["value"]);
+	return (c:getNode(rq.POST["key"]):value());
+
+    elseif rq.POST["cmd"] == "upload_config" then
+
+	print(tdump(rq.POST));
+	return ("OK");
+
+    elseif rq.POST["cmd"] == "upgrade" then
+
+	os.execute("LAST=`fetch -o - " .. c:getNode("info.firmware.update_url"):value() .."` ; /etc/upgrade ${LAST} > /dev/console 2>&1");
+	return ("OK");
+
+    elseif rq.POST["cmd"] == "setmany" then
+
+	path = rq.POST["path"];
+	if not path then
+	    return ("path missing");
+	end
+	-- print(rq.RequestBody);
+
+	-- if name like "sm:key" do c:getNode(path .. "key"):value(rq.POST["value"]);
+	-- if name like "smattr:key:attr" do c:getNode(path .. "key"):attr("attr", rq.POST["value"]);
+	for k,v in pairs(rq.POST) do
+	    attr, _, subpath, attrname = string.find(k, "^smattr:(.-):(.*)");
+	    if not v then v = ""; end
+	    if (attr) then
+		if string.len(subpath) > 0 then
+		    subpath = path .. "." .. subpath;
+		else
+		    subpath = path;
+		end
+
+		local n = c:getOrCreateNode(subpath);
+		if not n then
+		    print ("ERROR: can't find/create node \"" .. subpath .. "\"");
+		    return ("ERROR: can't find/create node \"" .. subpath .. "\"");
+		end
+		n:attr(attrname, v);
+		print(subpath .." ".. attrname .. " newval=" .. c:getNode(subpath):attr(attrname));
+    	    elseif string.find(k, "^sm:") then
+    		_, _, subpath = string.find(k, "^sm:(.*)");
+		if string.len(subpath) > 0 then
+		    subpath = path .. "." .. subpath;
+		else
+		    subpath = path;
+		end
+		local n = c:getOrCreateNode(subpath);
+		if not n then
+		    print ("ERROR: can't find/create node \"" .. subpath .. "\"");
+		    return ("ERROR: can't find/create node \"" .. subpath .. "\"");
+		end
+		n:value(v or "");
+		print(subpath .. " newval=" .. n:value());
+    	    end
+	end
+	return ("OK");
+
+    elseif rq.POST["save"] == "config" then
+
+	print("Saving configuration to config.xml");
+	if not save_file("config.xml", xmldump(c:gettree())) then
+	    return ("Error saving configuration");
+	end
+	if os.execute("/etc/rc.save_config") ~= 0 then
+	    return ("Error saving configuration block to flash");
+	end
+	return ("Configuration saved successful");
+
+    elseif rq.POST["restore"] == "config" then
+
+	print("Restoring factory default setting");
+	os.execute("echo '(sleep 5 ; rm /tmp/etc/www/config.xml ; /etc/rc.save_config ; /sbin/reboot ) & ' >> /tmp/restore_scrip.sh");
+	if os.execute("sh /tmp/restore_scrip.sh &") ~= 0 then
+	    return ("Run restore script fail");
+	end
+	return ("Configuration restore procedure started");
+
+    elseif rq.POST["system"] == "reboot" then
+
+	print("Reboot device");
+	os.execute("echo '(sleep 5 ; /sbin/reboot) &' > /tmp/reboot_scrip.sh");
+	os.execute("echo 'Run /tmp/reboot_scrip.sh' > /dev/console");
+	if os.execute("sh /tmp/reboot_scrip.sh &") ~= 0 then
+	    return ("Can't execute reboot script");
+	end
+	os.execute("echo 'Return \"Reboot in progress\" to parent' > /dev/console");
+	return ("Reboot in progress");
+
+    elseif rq.POST["telnet"] == "enable" then
+
+	print("Enabling telnet service");
+	os.execute("echo 'Enabling telnet service' > /dev/console");
+	os.execute("/usr/libexec/telnetd -4 -debug 23 &");
+	return ("telnet service started");
+
+    else
+
+--	print(tdump(rq));
+--	print(tdump(rq.POST));
+	return ("Unknow command");
+
+    end
+end
+
+
+
+    return ([[
+<?xml version="1.0" encoding="utf-8" ?>
+<data>
+]] ..
+process() ..
+[[
+</data>
+]]);
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/config.dat
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/config.dat	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,10 @@
+
+
+if rq.POST["cmd"] == "download_config" then
+	return (xmldump(c:gettree()));
+else
+	return ("Unknow command");
+end
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/css/anim.css
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/css/anim.css	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,131 @@
+/* color and iteration examples */
+a.boxitem {
+    background:#8dd5e7;
+    border:1px solid #004c6d;
+    color:#004c6d;
+    display:block;
+    height:2em;
+    line-height:2em;
+    width:6em;
+    text-align:center;
+}
+
+/* xy and curve examples */
+span.boxitem {
+    background:#ffa928;
+    display:block;
+    height:10px;
+    width:10px;
+}
+
+/* module examples */
+div.boxitem {
+    /*width:34em;*/
+    width:100%;
+    overflow:hidden;
+}
+
+div.boxitem {
+    border-bottom:1px solid #7a97bb;
+}
+
+div.boxitem .yui3-hd {
+    background: url(../img/tool_bar.jpg) repeat-x;
+    cursor:pointer;
+    cursor:hand;
+    /*border:1px solid #243356;*/
+    border:0;
+    zoom:1;
+}
+
+div.boxitem .yui3-hd h4 {
+    border:0;
+    color:#fff;
+    margin:0;
+}
+
+div.boxitem .yui3-bd {
+    background:#abceff;
+    border:solid #7a97bb;
+    border-width:0 1px;
+    clear: both;
+    overflow:hidden;
+    zoom:1;
+}
+
+div.boxitem .yui3-hd,
+div.boxitem .yui3-bd p {
+    margin:0;
+    padding:0.1em 1em;
+}
+
+div.boxitem div.yui3-bd p {
+    margin:0.3em 10px 0 0; /* right margin for scrollbar space */
+}
+
+div.boxitem .yui3-bd p em {
+    font-weight:bold;
+}
+
+/* basic example */
+div.boxitem a.yui3-remove {
+    background-position:0 -300px;
+    height:16px;
+    width:26px;
+}
+
+/* scroll example */
+.boxitem.yui3-scroll {
+    position: relative;
+}
+
+.yui3-scroll .yui3-hd {
+    position: relative;
+}
+.yui3-scroll .yui3-bd {
+    height:10em;
+    overflow:hidden;
+}
+
+.boxitem .yui3-hd .yui3-scroll-controls { /* fake scrollbar */
+    background:#dfdfdf;
+    border-left:1px solid #7a97bb;
+    height:10em;
+    width:13px;
+    position:absolute;
+    right:0;
+    bottom:-10.1em;
+    overflow:hidden;
+}
+
+.boxitem .yui3-hd .yui3-scroll-controls a {
+    margin: 0;
+    position:absolute;
+    top:0;
+    right:0;
+    height:14px;
+    width:14px;
+    Xborder:1px solid #000;
+}
+
+.boxitem .yui3-scroll-controls a.yui3-scrollup {
+    background-position:-12px -752px; /* scroll up icon */
+}
+
+.boxitem .yui3-scroll-controls a.yui3-scrolldown {
+    background-position:-12px -804px; /* scroll down icon */
+    top:auto;
+    bottom:0;
+}
+
+/* reverse and easing examples */
+.boxitem a.yui3-toggle {
+    background-position:0 -400px; /* close (minus) icon */
+    height:15px;
+    width:15px;
+}
+
+.boxitem
+.yui3-closed a.yui3-toggle {
+    background-position:0 -350px; /* open (plus) icon */
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/css/router.css
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/css/router.css	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,290 @@
+html, div, h1, h2, h3, h4, p, ul, ol, li, dl, dt, dd, td, input, select, textarea
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 12px;
+}
+
+body
+{
+	background: #CCDCE2;
+	font-size: 12px; font-family:
+	Arial; margin: 0px;
+}
+
+body.body_fw{
+	background: #ffffff;
+}
+
+input, select, textarea
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 11px;
+}
+
+input.text
+{
+	text-align: left;
+	border: solid;
+	border-width: 1px;
+	border-color: steelblue;
+}
+
+.style6
+{
+	font-size: 14px;
+	font-weight: bold;
+}
+.r_tb
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 12px;
+	text-align:right;
+}
+.c_tb
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 12px;
+	text-align:center;
+}
+.l_tb
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 12px;
+	text-align:left;
+}
+.br_tb
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 12px;
+	text-align:right;
+	font-weight: bold;
+}
+.bc_tb
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 12px;
+	text-align:center;
+	font-weight: bold;
+}
+.bl_tb
+{
+	font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+	font-size: 12px;
+	text-align:left;
+	font-weight: bold;
+}
+
+h1
+{
+	color: #000000;
+	font-size: 12px;
+	font-weight: bold;
+	letter-spacing: 1px;
+	text-transform: uppercase;
+	margin: 0 -10px 5px -10px;
+	padding: 5px 5px 5px 10px;
+	background: url(img/light_blue1.jpg);
+}
+
+#table_tree{
+	font-family: Arial;
+	font-size: 22px;
+	height: 514px;
+	width: 200px;
+	margin: 5px 4px 3px 1px;
+	border-top-color:#808080;
+	border-left-color:#808080;
+	background:#FFFFFF;
+}
+
+#table_page{
+	width:555px;
+	height: 514px;
+	margin: 5px 5px 5px 3px;
+	border-width: 2px;
+	border-top:solid 2 #ffffff;
+	border-bottom:solid 2 #808080;
+	border-left:solid 2 #ffffff;
+	border-right:solid 2 #808080;
+	background:#CCDCE2;
+}
+
+#table_frame{
+	width:547px;
+	height: 504px;
+	margin: 2px 2px 2px 3px;
+	border: 1px solid #136393;
+	background:#E4EAEB;
+}
+
+#alink_tree a:link, #alink_tree a:visited, #alink_tree a:active{
+	text-decoration: none;
+	font-size: 11px;
+	color: #000000;
+}
+
+#td_header
+{
+	font-family: Arial;
+	height: 30px;
+	color: #000000;
+	font-size: 18px;
+	background: url(img/light_blue1.jpg);
+	padding-left: 15px;
+}
+
+#table_header{
+	height: 30px;
+	width: 100%;
+	background:#CCDCE2;
+}
+
+#table_set_main{
+	width: 100%;
+	margin-top: 1px;
+	border-top: solid 1px  #136393;
+	background: #E4EAEB;
+	padding-left: 5px;
+	padding-top: 5px;
+}
+
+#td_left{
+	font-family: Arial;
+	text-align:left;
+	margin: 2px;
+	height:25px;
+}
+
+#td_right{
+	font-family: Arial;
+	text-align:left;
+}
+
+span.word{
+	vertical-align: 3px;
+	padding: 0px 3px 0px 3px;
+}
+
+span.img{
+	vertical-align: 5px;
+}
+
+a.logout{
+	font-family: Arial;
+	font-size: 11px;
+	margin: 0px 0px 0px 0px;
+	padding: 6px 8px 6px 8px;
+	width:200px;
+}
+
+a.logout:link, a.logout:visited, a.logout:active{
+	color: #000000;
+	background: #FFFFCC;
+}
+
+a.logout:hover {
+	color: #0000FF;
+	background: #FFFFCC;
+	text-decoration: underline;
+}
+
+.list_head{
+	background: #4D4D4D;
+	color: #FFFFFF;
+}
+
+.div_tab {
+	background: #ffffff;
+	border-color: #c0c0c0 #ffffff #ffffff #c0c0c0;
+	border-style: inset;
+	border-width: 2px;
+	overflow: auto;
+	height: 125px;
+}
+
+.div_tab td{
+	height: 20px;
+}
+
+.div_tab tr{
+	height: auto;
+}
+
+.div_client_tab{
+	background: #E4EAEB;
+	border-color: #c0c0c0 #ffffff #ffffff #c0c0c0;
+	border-style: inset;
+	border-width: 1px;
+	overflow: auto;
+}
+
+.div_client_tab td{
+	height: 20px;
+}
+
+.div_client_tab tr{
+	height: auto;
+}
+
+.table_tool{
+	width: 99%;
+	background: #E4EAEB;
+	border: 1px solid #136393;
+
+}
+
+.table_tool_td{
+	font-family: Arial;
+	height: 25px;
+	color: #ffffff;
+	font-size: 15px;
+	background: #6595b9;
+	padding-left: 5px;
+}
+
+.table_tool td{
+	padding: 3px;
+}
+
+.sec_n {
+  	background-color: #EEEEEE;
+  	color: #000000;
+  	border-left: 1px solid #FFFFFF;
+  	border-top: 1px solid #FFFFFF;
+  	border-right: 1px solid gray;
+  	border-bottom: 1px solid #FFFFFF
+}
+
+.sec_s {
+  	background-color: #D4D0C8;
+  	color: #000000;
+  	border-left: 1px solid #FFFFFF;
+  	border-top: 1px solid #FFFFFF;
+ 	 border-right: 1px solid gray;
+ 	font-weight: bold;
+}
+
+.TabPane_body {
+  	background-color: #D4D0C8;
+  	color: #000000;
+  	border-left:1px solid #FFFFFF;
+  	border-right: 1px solid gray;
+  	border-bottom: 1px solid gray;
+  	width:99%;
+  	height:350px;
+}
+
+.edit_vlan_table{
+
+	background-color: #E4EAEB;
+	margin:20px 10px 0px 10px;
+	border: 1px solid #136393;
+}
+
+.help_title_td
+{
+	font-size: 14px;
+	text-decoration: underline;
+	font-weight:bold;
+
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/event.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/event.xml	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,108 @@
+-- rq = {};
+-- rq.GET = {};
+
+-- rq.GET["cmd"	] = "event";
+-- rq.GET["gw"	] = "192.168.1.3";
+-- rq.GET["dns2"	] = "192.168.1.3";
+-- rq.GET["dns1"	] = "192.168.1.3";
+-- rq.GET["iface"	] = "PPP";
+-- rq.GET["state"] = "up";
+
+-- r = {};
+
+-- function doit()
+
+function process()
+    if not c then
+	print("Configuration structure 'c' is missing");
+    end
+    if not rq then
+	print("Request structure 'rq' is missing");
+    end
+
+    if     rq.GET["cmd"] == "get" then
+
+	return (c:getNode(rq.GET["key"]):value());
+
+    elseif rq.GET["cmd"] == "set" then
+
+	c:getNode(rq.GET["key"]):value(rq.GET["value"]);
+	return (c:getNode(rq.GET["key"]):value());
+
+    elseif rq.GET["restore"] == "config" then
+
+	os.execute("echo \"event.xml: " .. rq.QueryString .."\" > /dev/console");
+	if os.execute("rm /tmp/etc/www/config.xml") ~= 0 then
+	    return ("Can't remove current config");
+	end
+	if os.execute("/etc/rc.save_config") ~= 0 then
+	    return ("Error saving configuration block to flash");
+	end
+	if os.execute("reboot &") ~= 0 then
+	    return ("Error when trying reboot");
+	end
+	return ("Configuration restored successful");
+
+    elseif rq.GET["cmd"] == "event" then
+	    -- print(rq.RequestHeader);
+	    -- cmd=event&iface=wan0&state=linkup
+	    local iface = rq.GET["iface"];
+	    local newstate = rq.GET["state"];
+
+	    if not iface then
+		return ("event.lua: ERROR: Interface not defined");
+	    end
+
+	    if type(r[iface]) ~= "table" then r[iface] = {}; end
+
+	    print("echo \"event.xml: " .. rq.QueryString .."\" > /dev/console");
+	    if newstate == "up" then
+		-- Update NAT alias address for Static/DHCP
+		if iface == "wan0" then
+		    local ip = rq.GET["ip"];
+		    ip = ip:gsub("/%d+", "");
+		    os.execute("ngctl msg wan0nat: setaliasaddr " .. ip);
+		end
+	    elseif newstate == "linkup" then
+		--
+		run_dhclient(c, iface); -- if DHCP enabled.
+	    elseif newstate == "down" then
+		--
+	    elseif newstate == "linkdown" then
+		--
+	    end
+
+	    for k,v in pairs(rq.GET) do
+		if (k ~= "iface") and (k ~= "cmd") then
+		    r[iface][k] = v;
+		end
+	    end
+
+	return "OK";
+
+    elseif rq.GET["cmd"] == "revent" then
+
+	iface = rq.GET["iface"];
+
+	if r[iface] then
+	    return (tdump(r[iface]));
+	else
+	    return ("ERROR: no data for interface " .. iface);
+	end
+    else
+	return ("ERROR: unknown command");
+    end
+end
+
+return ([[
+<?xml version="1.0" encoding="utf-8" ?>
+<data>]] ..
+process() ..
+[[
+</data>
+]]);
+
+-- end
+
+-- print(doit());
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/footer.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/footer.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,2 @@
+</body>
+</html>
\ No newline at end of file
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/header.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/header.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+    <head>
+	<meta http-equiv="content-type" content="text/html; charset=utf-8">
+	<title></title>
+	<style type="text/css"> body {	margin:0; padding:0; } 	</style>
+	<link href="css/anim.css" rel="stylesheet" type="text/css">
+    </head>
+    <body class="yui3-skin-sam  yui-skin-sam">
+<script type="text/javascript" src="js/ajax.js"></script>
+<script>
+function send_update(form, proc)
+{
+    var query = getValuesAsArray(form);
+    if (!proc) {
+	proc = function (x) { };
+    }
+    ajax("POST", "/cmd.xml", query, true, proc);
+
+    return false;
+}
+</script>
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/home_sys.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/home_sys.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+
+<HTML XMLNS="http://www.w3.org/1999/xhtml">
+  <HEAD>
+    <LINK REL="stylesheet" HREF="index_files/router.css" TYPE="text/css">
+    <META http-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
+    <TITLE>$$$info.device.vendor$$$   $$$info.device.model$$$   $$$info.device.revision$$$</TITLE>
+    <script type="text/javascript" src="js/utils.js"></script>
+    <script type="text/javascript" src="js/ajax.js"></script>
+  </HEAD>
+  <BODY LEFTMARGIN="0" TOPMARGIN="0" STYLE="overflow:auto;" BGCOLOR="#ccdce2" MARGINHEIGHT="0" MARGINWIDTH="0">
+    <TABLE ID="table_frame" BORDER="0" CELLPADDING="0" CELLSPACING="0">
+      <TBODY>
+        <TR>
+          <TD VALIGN="top">
+            <TABLE ID="table_header" CELLPADDING="0" CELLSPACING="0">
+              <TBODY>
+                <TR><TD ID="td_header" VALIGN="middle">System Information</TD></TR>
+              </TBODY>
+            </TABLE>
+            <TABLE ID="table_set_main" BORDER="0" CELLPADDING="0" CELLSPACING="0">
+              <!-- ________________________________ Main Content Start ______________________________ -->
+              <TBODY>
+                <TR><TD ID="td_left" HEIGHT="25" WIDTH="150">Device</TD>
+            	    <TD ID="td_right">$$$info.device.vendor$$$   $$$info.device.model$$$   $$$info.device.revision$$$</TD>
+            	</TR>
+                <TR><TD ID="td_left" HEIGHT="25" WIDTH="150">SoC</TD>
+            	    <TD ID="td_right">$$$info.soc.vendor$$$   $$$info.soc.model$$$   $$$info.soc.revision$$$</TD>
+            	</TR>
+                <TR><TD ID="td_left" HEIGHT="25">Firmware Version</TD><TD ID="td_right">$$$info.firmware.version$$$</TD></TR>
+                <TR><TD ID="td_left" HEIGHT="25">Code revision</TD><TD ID="td_right">$$$code: r.zrouter_version.revision $$$</TD></TR>
+                <TR><TD ID="td_left" HEIGHT="25">Firmware build date</TD><TD ID="td_right">$$$code: r.zrouter_version.build $$$</TD></TR>
+                <TR><TD ID="td_left" HEIGHT="25">System Name</TD><TD ID="td_right">$$$info.hostname$$$</TD></TR>
+                <TR><TD ID="td_left" HEIGHT="25">Location</TD><TD ID="td_right">$$$info.location$$$</TD></TR>
+                <TR><TD ID="td_left" HEIGHT="25">System Time</TD><TD ID="td_right">$$$code:os.date("%Y-%m-%d %H:%M:%S")$$$</TD></TR>
+                <!--TR><TD ID="td_left" HEIGHT="25">Up Time</TD><TD ID="td_right"></TD></TR-->
+                <!-- TR><TD ID="td_left" HEIGHT="25">Operation Mode</TD><TD ID="td_right">Access Point</TD></TR -->
+                <!-- TR><TD ID="td_left" HEIGHT="25">MAC Address</TD><TD ID="td_right">00:21:91:5a:86:f2</TD></TR-->
+                <!-- TR><TD ID="td_left" HEIGHT="25">SSID 1~3</TD><TD ID="td_right">02:21:91:5a:86:f2 ~ 06:21:91:5a:86:f2</TD></TR-->
+                <TR><TD ID="td_left" HEIGHT="25">IP Address</TD><TD ID="td_right">$$$interfaces.bridge0.ipaddr$$$</TD></TR>
+
+              </TBODY>
+    	      <!-- ________________________________  Main Content End _______________________________ -->
+            </TABLE>
+          </TD>
+        </TR>
+      </TBODY>
+    </TABLE>
+  </BODY>
+</HTML>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/FreeBSD_logo.png
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/FreeBSD_logo.png has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/banner.jpg
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/banner.jpg has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/config.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/config.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/folder.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/folder.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/help.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/help.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/home.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/home.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/join.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/join.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/joinbottom.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/joinbottom.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/line.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/line.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/logout.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/logout.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/minus.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/minus.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/minusbottom.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/minusbottom.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/monitor.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/monitor.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/open_file.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/open_file.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/open_folder.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/open_folder.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/plus.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/plus.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/plusbottom.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/plusbottom.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/sys.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/sys.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/text.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/text.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/themespacer.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/themespacer.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/tool.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/tool.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar.jpg
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar.jpg has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar_v.jpg
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar_v.jpg has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/triangle.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/triangle.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/index.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/index.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,102 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <link rel="stylesheet" href="css/router.css" type="text/css" />
+  <link rel="stylesheet" href="css/toolbar.css" type="text/css" />
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+  <title>$$$info.device.vendor$$$   $$$info.device.model$$$   $$$info.device.revision$$$</title>
+  <script type="text/javascript" src="js/utils.js"></script>
+  <script type="text/javascript" src="js/wizard.js"></script>
+  <!-- script type="text/javascript" src="js/tree.js"></script -->
+  <script type="text/javascript" src="js/view.js"></script>
+  <script type="text/javascript" src="js/ajax.js"></script>
+</head>
+<body leftmargin="0" topmargin="0" style="overflow: auto;" bgcolor="#ccdce2" marginheight="0" marginwidth="0">
+    <center>
+      <table id="MainTable" border="1" bordercolor="#1e4c7d" cellpadding="0" cellspacing="0">
+        <tbody>
+          <tr>
+            <td colspan="2">
+              <table background="img/banner.jpg" border="0" cellpadding="0" cellspacing="0" height="71" width="1000">
+                <tbody>
+                  <tr>
+                    <td align="right" valign="middle">
+                      <font style="color: white; font-family: Arial; font-style: normal; font-variant: normal; font-weight: normal; font-size: 12pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">
+                        <b>$$$info.device.vendor$$$   $$$info.device.model$$$   $$$info.device.revision$$$</b>
+                      </font>
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
+            </td>
+          </tr>
+          <tr>
+            <td colspan="2">
+              <div class='toolbar'>
+                <ul>
+                  <li><a href='home_sys.html' target='ifrMain'><span>Home<img src='img/home.gif' width='16' border='0' hspace='10'></span></a></li>
+                  <li class='separator'> </li>
+                  <li><a href='#'><span>Maintenance<img src='img/tool.gif' width='16' border='0' hspace='10'></span></a>
+                    <ul>
+                      <li><a href='#' onClick="tryget('system=reboot'); return false;"><span>Reboot</span></a></li>
+                    </ul>
+                  </li>
+                  <li class='separator'> </li>
+                  <li><a href='#'><span>Configuration</span></a>
+                    <ul>
+                       <li><a href='#' onClick="tryget('save=config'); return false;"><span>Save Configuration</span></a></li>
+                       <li><a href='#' onClick="tryget('restore=config'); return false;"><span>Restore to Default</span></a></li>
+                       <li><a href='#' onClick="tryget('telnet=enable'); return false;"><span>Run telnet service</span></a></li>
+                    </ul>
+                  </li>
+                  <li class='separator'> </li>
+                  <li><a href='http://www.dlink.ua/files/products/ftp/pub/Router/DIR-632/Help/'><span>Help</span></a></li>
+                </ul>
+              </div>
+              <div style="clear:both; height: 0px; margin: 0px 0px 0px 0px;"> </div>
+            </td>
+          </tr>
+
+
+          <tr>
+            <td bordercolor="ccdce2" valign="top">
+              <table id="table_tree" style="margin: 3px; width: 256px;" border="1" cellpadding="0" cellspacing="0" frame="box" width="261">
+                <tbody>
+                  <tr>
+                    <td id="link_tree" valign="top">
+                      <iframe id="ifrMenu" class="ifrMenu" src="tv.html" frameborder="0" height="100%" scrolling="no" width="100%"></iframe>
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
+            </td>
+            <td bordercolor="ccdce2" valign="top" style="padding: 5px;">
+              <table id="table_page" style="margin: 3px; width: 720px; padding: 5px;" border="0" cellpadding="0" cellspacing="0" frame="box" width="750">
+                <tbody>
+                  <tr>
+                    <td>
+                      <iframe id="ifrMain" name="ifrMain" src="home_sys.html" onload="" frameborder="0" height="100%" scrolling="auto" width="100%"></iframe>
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
+            </td>
+          </tr>
+          <tr>
+            <td colspan="2">
+              <table background="img/FreeBSD_logo.png" border="0" cellpadding="0" cellspacing="0" height="75" width="1000">
+                <tbody>
+                  <tr>
+                    <td align="right" valign="middle">
+                       
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </center>
+</body>
+</html>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/ajax.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/ajax.js	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,107 @@
+
+function getXmlHttp()
+{
+	var xmlhttp;
+	try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
+	catch (e) {
+		try {  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP.6.0"); }
+		catch (E) { }
+		try {  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP.3.0"); }
+		catch (E) { }
+		try {  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
+		catch (E) { xmlhttp = false; }
+	}
+	if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
+		xmlhttp = new XMLHttpRequest();
+	}
+	return xmlhttp;
+}
+
+var xmlhttp = getXmlHttp()
+var xmlhttptimeout = 0;
+
+function ajax(method, target, msg, async, handler)
+{
+
+	if (handler != "ignore") {
+		xmlhttptimeout = setTimeout( function(){ xmlhttp.abort(); alert("Timeout") }, 10000);
+	}
+
+	xmlhttp.onreadystatechange = function()
+	{
+		if (xmlhttp.readyState != 4) return;
+
+		clearTimeout(xmlhttptimeout);
+
+		if (xmlhttp.status == 200) {
+	    		handler(xmlhttp);
+		} else {
+	    		alert("Error: " + xmlhttp.statusText);
+		}
+	}
+
+	xmlhttp.open(method, target, async);
+	xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
+	xmlhttp.send(msg);
+}
+
+function getValuesAsArray(formRef)
+{
+	var ret = "r=" + encodeURIComponent(Math.random());
+	var els = formRef.elements;
+	for(var no=0; no < els.length; no++)
+	{
+		if(els[no].disabled)
+		    continue;
+		var tag = els[no].tagName.toLowerCase();
+
+		switch(tag){
+			case "input":
+				var type = els[no].type.toLowerCase();
+
+				if(!type)
+				    type='text';
+
+				switch(type){
+					case "text":
+					case "image":
+					case "hidden":
+					case "password":
+						ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(els[no].value);
+						break;
+					case "checkbox":
+						if(els[no].checked)
+						    ret += '&' + encodeURIComponent(els[no].name) + '=true';
+						else
+						    ret += '&' + encodeURIComponent(els[no].name) + '=false';
+						break;
+					case "radio":
+						if(els[no].checked)
+						    ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(els[no].value);
+						break;
+				}
+				break;
+			case "select":
+				var string = '';
+				var mult = els[no].getAttribute('multiple');
+				if(mult || mult===''){
+					ops = els[no].options;
+
+					for(var no2=0;no2<ops.length;no2++)
+					{
+						var index = retArray[els[no].name].length;
+						if(ops[no2].selected)
+						    ret += '&' + encodeURIComponent(els[no].name + index) + '=' + encodeURIComponent(ops[no2].value);
+					}
+				}else{
+					ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(ops[els[no].selectedIndex].value);
+				}
+				break;
+			case "textarea":
+				ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(els[no].value);
+				break;
+		}
+	}
+	return ret;
+}
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/defineMyTree.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/defineMyTree.js	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,77 @@
+/* You can find instructions for this file here:
+/ http://www.geocities.com/marcelino_martins/ftv2instructions.html
+*/
+
+// Decide if the names are links or just the icons
+var USETEXTLINKS = 1;  //replace 0 with 1 for hyperlinks
+
+// Decide if the tree is to start all open or just showing the root folders
+var STARTALLOPEN = 0; //replace 0 with 1 to show the whole tree
+
+var ICONPATH = 'img/';
+
+var deviceType="Router";
+
+var  band=0;
+
+
+if(band==0)
+{
+	var x="CfgWLanParam.html?0";
+}
+else
+{
+	var x="CfgWLanParam.html?1";
+}
+
+
+var foldersTree = gHeader(deviceType, "/home_sys.html");
+var aux1, aux2;
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Basic Settings </font>", ""));
+insDoc(aux1, gLnk("R"," Internet", "/Basic.wan.html"));
+insDoc(aux1, gLnk("R"," Wireless", "/Basic.wlan.html"));
+insDoc(aux1, gLnk("R"," LAN", "/Basic.lan.html"));
+insDoc(aux1, gLnk("R"," IPTV", "/Basic.iptv.html"));
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Security Links </font>", ""));
+insDoc(aux1, gLnk("R"," IPSec", "/Security.IPSec.html"));
+insDoc(aux1, gLnk("R"," OpenVPN", "/Security.OpenVPN.html"));
+insDoc(aux1, gLnk("R"," SSH Tunnels", "/Security.SSH.html"));
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Administration </font>", ""));
+insDoc(aux1, gLnk("R"," Device Info", "/Administration.info.html"));
+insDoc(aux1, gLnk("R"," Users", "/Administration.users.html"));
+insDoc(aux1, gLnk("R"," Firmware", "/Administration.firmware.html"));
+
+//aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Advanced Settings </font>", ""));
+//insDoc(aux1, gLnk("R"," Performance", "/home_sys.html?page=adv_perf.html"));
+//insDoc(aux1, gLnk("R"," Multi-SSID", "/home_sys.html?page=adv_mssid.html"));
+//insDoc(aux1, gLnk("R"," VLAN ", "/home_sys.html?page=adv_8021q.html"));
+//insDoc(aux1, gLnk("R"," Instrusion", "/home_sys.html?page=adv_rogue.html"));
+//insDoc(aux1, gLnk("R"," Schedule", "/home_sys.html?page=adv_schedule.html"));
+//insDoc(aux1, gLnk("R"," QOS", "/home_sys.html?page=adv_qos.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2> DHCP Server</font>", ""));
+//insDoc(aux2, gLnk("R"," Dynamic Pool Setting", "/home_sys.html?page=adv_dhcpd.html"));
+//insDoc(aux2, gLnk("R"," Static Pool Setting", "/home_sys.html?page=adv_dhcps.html"));
+//insDoc(aux2, gLnk("R"," Current IP Mapping List", "/home_sys.html?page=adv_dhcpl.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2> Filters</font>", ""));
+//insDoc(aux2, gLnk("R"," Wireless MAC ACL", "/home_sys.html?page=adv_acl.html"));
+//insDoc(aux2, gLnk("R"," WLAN Partition", "/home_sys.html?page=adv_partition.html"));
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Status</font>", ""));
+insDoc(aux1, gLnk("R"," Device Information", "/status.lua"));
+insDoc(aux1, gLnk("R"," System Log", "/log.lua"));
+//insDoc(aux1, gLnk("R"," Client Information", "/home_sys.html?page=st_info.html"));
+//insDoc(aux1, gLnk("R"," WDS Information", "/home_sys.html?page=st_wds_info.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2> Stats</font>", ""));
+//insDoc(aux2, gLnk("R"," Ethernet", "/home_sys.html?page=st_stats_lan.html"));
+//insDoc(aux2, gLnk("R"," WLAN", "/home_sys.html?page=st_stats_wl.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2>Log</font>", ""));
+//insDoc(aux2, gLnk("R"," View Log", "/home_sys.html?page=st_log.html"));
+//insDoc(aux2, gLnk("R"," Log Settings", "/home_sys.html?page=st_logs.html"));
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/tree.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/tree.js	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,1360 @@
+/******************************************************************
+ Definition of class Folder
+******************************************************************/
+function Header(folderDescription, hreference) /* constructor */
+{
+	/* constant data */
+	this.desc = folderDescription;
+	this.hreference = hreference;
+	this.id = -1;
+	this.navObj = 0;
+	this.iconImg = 0;
+	this.nodeImg = 0;
+	this.isLastNode = 0;
+	this.iconSrc = ICONPATH + "monitor.gif";
+	this.iconSrcClosed = ICONPATH + "monitor.gif";
+	this.children = new Array;
+	this.nChildren = 0;
+	this.level = 0;
+	this.leftSideCoded = "";
+	this.isLastNode=false;
+	this.parentObj = null;
+	this.maySelect=true;
+	this.prependHTML = "";
+
+	/* dynamic data */
+	this.isOpen = false;
+	this.isLastOpenedFolder = false;
+	this.isRendered = 0;
+
+	/* methods */
+	this.initialize = initializeFolder;
+	this.setState = setStateFolder;
+	this.addChild = addChild;
+	this.createIndex = createEntryIndex;
+	this.escondeBlock = escondeBlock;
+	this.esconde = escondeFolder;
+	this.folderMstr = folderMstr;
+	this.renderOb = drawFolder;
+	this.totalHeight = totalHeight;
+	this.subEntries = folderSubEntries;
+	this.linkHTML = linkFolderHTML;
+	this.blockStartHTML = blockStartHTML;
+	this.blockEndHTML = blockEndHTML;
+	this.nodeImageSrc = nodeImageSrc;
+	this.iconImageSrc = iconImageSrc;
+	this.getID = getID;
+	this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders;
+}
+
+function Folder(folderDescription, hreference) /* constructor */
+{
+	/* constant data */
+	this.desc = folderDescription;
+	this.hreference = hreference;
+	this.id = -1;
+	this.navObj = 0;
+	this.iconImg = 0;
+	this.nodeImg = 0;
+	this.isLastNode = 0;
+	this.iconSrc = ICONPATH + "open_folder.gif";
+	this.iconSrcClosed = ICONPATH + "folder.gif";
+	this.children = new Array;
+	this.nChildren = 0;
+	this.level = 0;
+	this.leftSideCoded = "";
+	this.isLastNode=false;
+	this.parentObj = null;
+	this.maySelect=true;
+	this.prependHTML = "";
+
+	/* dynamic data */
+	this.isOpen = false;
+	this.isLastOpenedFolder = false;
+	this.isRendered = 0;
+
+	/* methods */
+	this.initialize = initializeFolder;
+	this.setState = setStateFolder;
+	this.addChild = addChild;
+	this.createIndex = createEntryIndex;
+	this.escondeBlock = escondeBlock;
+	this.esconde = escondeFolder;
+	this.folderMstr = folderMstr;
+	this.renderOb = drawFolder;
+	this.totalHeight = totalHeight;
+	this.subEntries = folderSubEntries;
+	this.linkHTML = linkFolderHTML;
+	this.blockStartHTML = blockStartHTML;
+	this.blockEndHTML = blockEndHTML;
+	this.nodeImageSrc = nodeImageSrc;
+	this.iconImageSrc = iconImageSrc;
+	this.getID = getID;
+	this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders;
+}
+
+function initializeFolder(level, lastNode, leftSide)
+{
+	var j=0;
+	var i=0;
+	nc = this.nChildren;
+
+	this.createIndex();
+	this.level = level;
+	this.leftSideCoded = leftSide;
+
+	if(browserVersion == 0 || STARTALLOPEN==1)
+		this.isOpen=true;
+
+	if(level>0)
+ 	if(lastNode)
+ 		/* the last child in the children array */
+ 		leftSide = leftSide + "0";
+	else
+		leftSide = leftSide + "1";
+
+	this.isLastNode = lastNode;
+
+	if(nc > 0)
+	{
+ 		level = level + 1;
+ 		for (i = 0; i < this.nChildren; i++)
+ 		{
+  			if (i == this.nChildren-1)
+				this.children[i].initialize(level, 1, leftSide);
+  			else
+				this.children[i].initialize(level, 0, leftSide);
+ 		}
+	}
+}
+
+function drawFolder(insertAtObj)
+{
+ 	var nodeName = "";
+ 	var auxEv = "";
+ 	var docW = "";
+
+ 	var leftSide = leftSideHTML(this.leftSideCoded);
+
+ 	if (browserVersion > 0)
+  	auxEv = "<span onClick='clickOnNode(\""+this.getID()+"\")' onMouseOver='showCursor(this);'>";
+ 	else
+  	auxEv = "<span>";
+
+ 	nodeName = this.nodeImageSrc();
+
+ 	if (this.level>0)
+  	if (this.isLastNode)
+  		/* the last child in the children array */
+  		leftSide = leftSide + "<td valign=top>" + auxEv +
+  		    "<img name='nodeIcon" + this.id + "' id='nodeIcon" +
+  		    this.id + "' src='" + nodeName + "' height=16 border=0></span></td>";
+  	else
+   		leftSide = leftSide + "<td valign=top background=" + ICONPATH + "line.gif>" + auxEv +
+   		    "<img name='nodeIcon" + this.id + "' id='nodeIcon" +
+   		    this.id + "' src='" + nodeName + "' height=16 border=0></span></td>";
+
+ 	this.isRendered = 1;
+
+ 	if (browserVersion == 2)
+ 	{
+  	if (!doc.yPos)
+   	doc.yPos=20;
+ 	}
+
+ 	docW = this.blockStartHTML("folder");
+
+ 	docW = docW + "<tr>" + leftSide + "<td valign=top>";
+ 	if (USEICONS)
+ 	{
+  		docW = docW + auxEv;/* this.linkHTML(false) */
+  	 	docW = docW + "<img id='folderIcon" + this.id + "' name='folderIcon" + this.id + "' src='" + this.iconImageSrc() + "' border=0></span>";
+  	}
+  	else
+  	{
+		if (this.prependHTML == "")
+  		docW = docW + "<img src=" + ICONPATH + "themespacer.gif height=2 width=2>";
+  	}
+
+  	if (WRAPTEXT)
+		docW = docW + "</td>"+this.prependHTML+"<td valign=middle width=100%>";
+  	else
+	  	docW = docW + "</td>"+this.prependHTML+"<td valign=middle nowrap width=100%>";
+  	if (USETEXTLINKS)
+  	{
+ 		if(this.linkHTML(true)=="<a>" && (this.getID()!=0))
+			docW = docW + auxEv + this.desc + "</span>";
+		else
+ 			docW = docW + this.linkHTML(true) + this.desc + "</a>";
+  	}
+ 	else
+ 	docW = docW + auxEv + this.desc + "</span>";
+
+  	docW = docW + "</td>";
+  	docW = docW + this.blockEndHTML();
+
+  	if (insertAtObj == null)
+  	{
+		if (supportsDeferral)
+		{
+			doc.write("<div id=domRoot></div>"); /* transition between regular flow HTML, and node-insert DOM DHTML */
+			insertAtObj = getElById("domRoot");
+		  	insertAtObj.insertAdjacentHTML("beforeEnd", docW);
+	  	}
+	  	else
+		  	doc.write(docW);
+  	}
+  	else
+  	{
+   	insertAtObj.insertAdjacentHTML("afterEnd", docW);
+  	}
+
+  	if (browserVersion == 2)
+  	{
+ 	this.navObj = doc.layers["folder"+this.id];
+ 	if (USEICONS)
+   		this.iconImg = this.navObj.document.images["folderIcon"+this.id]
+ 	this.nodeImg = this.navObj.document.images["nodeIcon"+this.id];
+   	 doc.yPos=doc.yPos+this.navObj.clip.height;
+  	}
+  	else if (browserVersion != 0)
+  	{
+  		this.navObj = getElById("folder"+this.id);
+   		if (USEICONS)
+   		this.iconImg = getElById("folderIcon"+this.id);
+ 	this.nodeImg = getElById("nodeIcon"+this.id);
+  	}
+}
+
+function setStateFolder(isOpen)
+{
+  	var subEntries;
+  	var totalHeight;
+  	var fIt = 0;
+  	var i=0;
+  	var currentOpen;
+
+  	if (isOpen == this.isOpen)
+ 	return;
+
+  	if (browserVersion == 2)
+  	{
+ 	totalHeight = 0;
+ 	for (i=0; i < this.nChildren; i++)
+  		totalHeight = totalHeight + this.children[i].navObj.clip.height;
+   	subEntries = this.subEntries();
+ 	if (this.isOpen)
+   		totalHeight = 0 - totalHeight;
+ 	for (fIt = this.id + subEntries + 1; fIt < nEntries; fIt++)
+  		indexOfEntries[fIt].navObj.moveBy(0, totalHeight);
+  	}
+  	this.isOpen = isOpen;
+
+ 	if (this.getID()!=foldersTree.getID() && PERSERVESTATE && !this.isOpen) /* closing */
+ 	{
+ 		currentOpen = GetCookie("clickedFolder");
+  		if (currentOpen != null)
+  		{
+  			currentOpen = currentOpen.replace(this.getID()+cookieCutter, "");
+   			SetCookie("clickedFolder", currentOpen);
+  		}
+  	}
+
+  	if (!this.isOpen && this.isLastOpenedfolder)
+  	{
+		lastOpenedFolder = null;
+		this.isLastOpenedfolder = false;
+  	}
+ 	propagateChangesInState(this);
+}
+
+function propagateChangesInState(folder)
+{
+  	var i=0;
+
+  	/* Change icon */
+  	if (folder.nChildren > 0 && folder.level>0)  /* otherwise the one given at render stays */
+  		folder.nodeImg.src = folder.nodeImageSrc();
+
+  	/* Change node */
+  	if (USEICONS)
+ 		folder.iconImg.src = folder.iconImageSrc();
+
+  	/* Propagate changes */
+  	for (i=folder.nChildren-1; i>=0; i--)
+ 		if (folder.isOpen)
+   			folder.children[i].folderMstr(folder.navObj);
+ 		else
+  	  		folder.children[i].esconde();
+}
+
+function escondeFolder()
+{
+  	this.escondeBlock();
+
+  	this.setState(0);
+}
+
+function linkFolderHTML(isTextLink)
+{
+  	var docW = "";
+
+  	if (this.hreference)
+  	{
+		if (USEFRAMES)
+	  		docW = docW + "<a href='" + this.hreference + "' TARGET=\"ifrMain\" ";
+		else
+	  		docW = docW + "<a href='" + this.hreference + "' TARGET=_top ";
+
+ 	if (isTextLink)
+ 	{
+ 		docW += "id=\"itemTextLink"+this.id+"\" ";
+ 	}
+
+ 	if (browserVersion > 0)
+   		docW = docW + "onClick='javascript:clickOnFolder(\""+this.getID()+"\")'";
+
+ 	docW = docW + ">";
+  	}
+  	else
+  	{
+ 	docW = docW + "<a>";
+  	}
+
+  	return docW;
+}
+
+function addChild(childNode)
+{
+  	this.children[this.nChildren] = childNode;
+  	childNode.parentObj = this;
+  	this.nChildren++;
+  	return childNode;
+}
+
+function folderSubEntries()
+{
+  	var i = 0;
+  	var se = this.nChildren;
+
+  	for (i=0; i < this.nChildren; i++)
+  	{
+ 		if (this.children[i].children) /* is a folder */
+   			se = se + this.children[i].subEntries();
+  	}
+  	return se;
+}
+
+function nodeImageSrc()
+{
+  	var srcStr = "";
+  	if (this.isLastNode) /* the last child in the children array */
+  	{
+ 		if (this.nChildren == 0)
+   			srcStr = ICONPATH + "joinbottom.gif";
+ 		else if (this.isOpen)
+  			srcStr = ICONPATH + "minusbottom.gif";
+		else
+  			srcStr = ICONPATH + "plusbottom.gif";
+  	}
+  	else
+  	{
+ 		if (this.nChildren == 0)
+   			srcStr = ICONPATH + "join.gif";
+ 		else if (this.isOpen)
+  			srcStr = ICONPATH + "minus.gif";
+   		else
+  			srcStr = ICONPATH + "plus.gif";
+  	}
+  	return srcStr;
+}
+
+function iconImageSrc()
+{
+  	if (this.isOpen)
+ 	return(this.iconSrc);
+  	else
+ 	return(this.iconSrcClosed);
+}
+
+/*
+ * Definition of class Item (a document or link inside a Folder)
+ */
+function Item(itemDescription, itemLink, target) /*  Constructor */
+{
+  	/*  constant data */
+  	this.desc = itemDescription;
+  	this.link = ""+itemLink;
+  	this.id = -1; /* initialized in initalize() */
+  	this.navObj = 0 ;/* initialized in render() */
+  	this.iconImg = 0; /* initialized in render() */
+  	this.iconSrc = ICONPATH + "text.gif";
+  	this.isRendered = 0;
+  	this.isLastNode = false;
+  	this.level = 0;
+  	this.leftSideCoded = "";
+  	this.nChildren = 0;
+  	this.target = target;
+  	this.parentObj = null;
+  	this.maySelect=true;
+  	this.prependHTML = "";
+
+  	/*  methods */
+  	this.initialize = initializeItem;
+  	this.createIndex = createEntryIndex;
+  	this.escondeBlock = escondeBlock;
+  	this.esconde = escondeBlock;
+  	this.folderMstr = folderMstr;
+  	this.renderOb = drawItem;
+  	this.totalHeight = totalHeight;
+  	this.blockStartHTML = blockStartHTML;
+  	this.blockEndHTML = blockEndHTML;
+  	this.getID = getID;
+  	this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders;
+}
+
+function initializeItem(level, lastNode, leftSide)
+{
+  	this.createIndex();
+  	this.level = level;
+  	this.leftSideCoded = leftSide;
+  	this.isLastNode = lastNode;
+}
+
+function drawItem(insertAtObj)
+{
+  	var leftSide = leftSideHTML(this.leftSideCoded);
+  	var docW = "";
+
+	/*
+	 * In Netscape, it will calling onclick function first and open new window, but it's wrong!
+	 * We don't really know this onclick function use for what and remove it!
+	 * var fullLink = "href=\""+this.link+"\" target=\""+this.target+"\"
+	 * onClick=\"clickOnLink('"+this.getID()+"\', '"+this.link+"','"+this.target+"');return false;\"";
+	 */
+  	var fullLink = 'href=\"'+this.link+'\" target=\"'+this.target+'\"';
+
+ 	this.isRendered = 1;
+
+  	if (this.level>0)
+ 		if (this.isLastNode) /* the last 'brother' in the children array */
+ 		{
+  			leftSide = leftSide + "<td valign=top><img src='" + ICONPATH + "joinbottom.gif' height=16 ></td>";
+ 		}
+ 		else
+ 		{
+  			leftSide = leftSide + "<td valign=top background=" + ICONPATH + "line.gif><img src='" + ICONPATH + "join.gif' height=16 ></td>";
+ 		}
+
+  	docW = docW + this.blockStartHTML("item");
+
+  	docW = docW + "<tr>" + leftSide + "<td valign=top>";
+  	if (USEICONS)
+ 		docW = docW + "<a " + fullLink  + " id=\"itemIconLink"+this.id+"\">" +
+ 		    "<img id='itemIcon"+this.id+"' " + "src='"+this.iconSrc+"' border=0>" + "</a>";
+  	else if (this.prependHTML == "")
+    		docW = docW + "<img src=" + ICONPATH + "themespacer.gif height=2 width=3>";
+
+  	if (WRAPTEXT)
+ 		docW = docW + "</td>"+this.prependHTML+"<td valign=middle width=100%>";
+  	else
+ 		docW = docW + "</td>"+this.prependHTML+"<td valign=middle nowrap width=100%>";
+
+  	if (USETEXTLINKS)
+ 		docW = docW + "<a " + fullLink + " id=\"itemTextLink"+this.id+"\">" + this.desc + "</a>";
+  	else
+ 		docW = docW + this.desc;
+
+  	docW = docW + "</td>";
+
+  	docW = docW + this.blockEndHTML();
+
+  	if (insertAtObj == null)
+  	{
+		doc.write(docW);
+  	}
+  	else
+  	{
+ 		insertAtObj.insertAdjacentHTML("afterEnd", docW);
+  	}
+
+  	if (browserVersion == 2)
+  	{
+ 		this.navObj = doc.layers["item"+this.id];
+ 		if (USEICONS)
+ 			this.iconImg = this.navObj.document.images["itemIcon"+this.id];
+ 		doc.yPos=doc.yPos+this.navObj.clip.height;
+  	}
+  	else if (browserVersion != 0)
+  	{
+ 		this.navObj = getElById("item"+this.id);
+ 		if (USEICONS)
+ 			this.iconImg = getElById("itemIcon"+this.id);
+  	}
+}
+
+
+/*
+ * Methods common to both objects (pseudo-inheritance)
+ */
+function forceOpeningOfAncestorFolders()
+{
+  	if (this.parentObj == null || this.parentObj.isOpen)
+ 		return;
+  	else
+  	{
+ 		this.parentObj.forceOpeningOfAncestorFolders();
+ 		clickOnNodeObj(this.parentObj);
+  	}
+}
+
+function escondeBlock()
+{
+  	if (browserVersion == 1 || browserVersion == 3)
+  	{
+ 		if (this.navObj.style.display == "none")
+   			return;
+ 		this.navObj.style.display = "none";
+  	}
+  	else
+  	{
+ 		if (this.navObj.visibility == "hidden")
+   			return;
+ 		this.navObj.visibility = "hidden";
+  	}
+}
+
+function folderMstr(domObj)
+{
+  	if (browserVersion == 1 || browserVersion == 3)
+  	{
+   		if (t==-1)
+   		return;
+  	}
+
+  	if (!this.isRendered)
+  		this.renderOb(domObj);
+  	else if (browserVersion == 1 || browserVersion == 3)
+   		this.navObj.style.display = "block";
+	else
+   		this.navObj.visibility = "show";
+}
+
+function blockStartHTML(idprefix)
+{
+  	var idParam = "id='" + idprefix + this.id + "'";
+  	var docW = "";
+
+  	if (browserVersion == 2)
+ 	docW = "<layer "+ idParam + " top=" + doc.yPos + " visibility=show>";
+  	else if (browserVersion != 0)
+ 	docW = "<div " + idParam + " style='display:block; position:block;'>";
+
+  	docW = docW + "<table border=0 cellspacing=0 cellpadding=0 width=100% >";
+
+  	return docW;
+}
+
+function blockEndHTML()
+{
+  	var docW = "";
+
+  	docW = "</table>";
+
+  	if (browserVersion == 2)
+ 	docW = docW + "</layer>";
+  	else if (browserVersion != 0)
+ 	docW = docW + "</div>";
+
+  	return docW;
+}
+
+function createEntryIndex()
+{
+  	this.id = nEntries;
+  	indexOfEntries[nEntries] = this;
+  	nEntries++;
+}
+
+/*
+ * total height of subEntries open
+ */
+function totalHeight() /* used with browserVersion == 2 */
+{
+  	var h = this.navObj.clip.height;
+  	var i = 0;
+
+  	if (this.isOpen) /* is a folder and _is_ open */
+  		for (i=0 ; i < this.nChildren; i++)
+   			h = h + this.children[i].totalHeight();
+
+  	return h;
+}
+
+
+function leftSideHTML(leftSideCoded)
+{
+	var i;
+	var retStr = "";
+
+	for (i=0; i<leftSideCoded.length; i++)
+	{
+		if (leftSideCoded.charAt(i) == "1")
+		{
+			retStr = retStr + "<td valign=top background=" + ICONPATH + "line.gif><img src='" + ICONPATH + "line.gif' height=16 ></td>";
+		}
+		if (leftSideCoded.charAt(i) == "0")
+		{
+			retStr = retStr + "<td valign=top><img src='" + ICONPATH + "themespacer.gif' height=16 ></td>";
+		}
+	}
+	return retStr;
+}
+
+function getID()
+{
+	/*
+	 * define a .xID in all nodes (folders and items) if you want to PERVESTATE that
+	 * work when the tree changes. The value eXternal value must be unique for each
+	 * node and must node change when other nodes are added or removed
+	 * The value may be numeric or string, but cannot have the same char used in cookieCutter */
+	if (typeof this.xID != "undefined")
+ 		return this.xID;
+  	else
+ 		return this.id;
+}
+
+
+/*  Events */
+function clickOnFolder(folderId)
+{
+	var clicked = findObj(folderId);
+
+	if (!clicked.isOpen)
+	{
+ 		clickOnNodeObj(clicked);
+	}
+
+	if (lastOpenedFolder != null && lastOpenedFolder != folderId)
+ 		/* sets lastOpenedFolder to null */
+ 		clickOnNode(lastOpenedFolder);
+	if (clicked.nChildren==0)
+	{
+   		lastOpenedFolder = folderId;
+   		clicked.isLastOpenedfolder = true;
+	}
+
+	if (isLinked(clicked.hreference))
+	{
+		highlightObjLink(clicked);
+	}
+}
+
+function clickOnNode(folderId)
+{
+  	clickOnNodeObj(findObj(folderId));
+}
+
+function clickOnNodeObj(folderObj)
+{
+  	var state = 0;
+  	var currentOpen;
+
+  	if(folderObj.getID() == 0)
+  	{
+  		state = false; /* Header */
+  	}
+  	else
+  	{
+  		state = folderObj.isOpen;
+  	}
+
+  	folderObj.setState(!state); /* open<->close */
+
+  	if (folderObj.id!=foldersTree.id && PERSERVESTATE)
+  	{
+ 		currentOpen = GetCookie("clickedFolder");
+ 		if (currentOpen == null)
+   			currentOpen = "";
+
+ 		if (!folderObj.isOpen) /* closing */
+ 		{
+  			currentOpen = currentOpen.replace(folderObj.getID()+cookieCutter, "");
+   			SetCookie("clickedFolder", currentOpen);
+ 		}
+ 		else
+   			SetCookie("clickedFolder", currentOpen+folderObj.getID()+cookieCutter);
+  	}
+}
+
+function clickOnLink(clickedId, target, windowName)
+{
+ 	highlightObjLink(findObj(clickedId));
+
+ 	if (isLinked(target))
+ 	{
+  		window.open(target,windowName);
+ 	}
+}
+
+function ld()
+{
+	/* return document.links.length-1  original */
+	return 0;
+}
+
+
+/* Auxiliary Functions */
+function findObj(id)
+{
+  	var i=0;
+ 	var nodeObj;
+
+  	if (typeof foldersTree.xID != "undefined")
+  	{
+ 		nodeObj = indexOfEntries[i];
+ 		for(i=0;i<nEntries&&indexOfEntries[i].xID!=id;i++)
+ 			/* may need optimization */
+ 			;
+ 		id = i;
+  	}
+ 	if (id >= nEntries)
+ 		return null; /* example: node removed in DB */
+ 	else
+ 		return indexOfEntries[id];
+}
+
+function isLinked(hrefText)
+{
+	var result = true;
+	result = (result && hrefText !=null);
+	result = (result && hrefText != '');
+	result = (result && hrefText.indexOf('undefined') < 0);
+	result = (result && hrefText.indexOf('parent.op') < 0);
+	return result;
+}
+
+/* Do highlighting by changing background and foreg. colors of folder or doc text */
+function highlightObjLink(nodeObj)
+{
+  	if (!HIGHLIGHT || nodeObj==null || nodeObj.maySelect==false)
+  	{
+  		/* node deleted in DB */
+  		return;
+  	}
+
+  	if (browserVersion == 1 || browserVersion == 3)
+  	{
+ 		var clickedDOMObj = getElById('itemTextLink'+nodeObj.id);
+ 		if (clickedDOMObj != null)
+ 		{
+  			if (lastClicked != null)
+  			{
+     				var prevClickedDOMObj = getElById('itemTextLink'+lastClicked.id);
+   				prevClickedDOMObj.style.color=lastClickedColor;
+   				prevClickedDOMObj.style.backgroundColor=lastClickedBgColor;
+  			}
+
+  			lastClickedColor = clickedDOMObj.style.color;
+  			lastClickedBgColor  = clickedDOMObj.style.backgroundColor;
+  			clickedDOMObj.style.color=HIGHLIGHT_COLOR;
+  			clickedDOMObj.style.backgroundColor=HIGHLIGHT_BG;
+ 		}
+  	}
+
+  	lastClicked = nodeObj;
+  	if (PERSERVESTATE)
+ 		SetCookie('highlightedTreeviewLink', nodeObj.getID());
+}
+
+function gFld(description, hreference)
+{
+  	folder = new Folder(description, hreference);
+  	return folder;
+}
+
+function gHeader(description, hreference)
+{
+  	header = new Header(description, hreference);
+  	return header ;
+}
+
+function gLnk(optionFlags, description, linkData)
+{
+  	var fullLink = "";
+  	var targetFlag = "";
+  	var target = "";
+  	var protocolFlag = "";
+  	var protocol = "";
+
+  	if (optionFlags>=0) /* is numeric (old style) or empty (error) */
+  	{
+ 		return oldGLnk(optionFlags, description, linkData);
+  	}
+
+  	targetFlag = optionFlags.charAt(0);
+  	if (targetFlag=="B")
+ 		target = "_blank";
+  	if (targetFlag=="P")
+ 		target = "_parent";
+ 	if (targetFlag=="R")
+ 		target = "ifrMain";
+  	if (targetFlag=="S")
+ 		target = "_self";
+  	if (targetFlag=="T")
+ 		target = "_top";
+
+  	if (optionFlags.length > 1)
+  	{
+ 		protocolFlag = optionFlags.charAt(1);
+ 		if (protocolFlag=="h")
+   			protocol = "http://";
+ 		if (protocolFlag=="s")
+   			protocol = "https://";
+ 		if (protocolFlag=="f")
+   			protocol = "ftp://";
+ 		if (protocolFlag=="m")
+   			protocol = "mailto:";
+  	}
+
+  	fullLink = "'" + protocol + linkData + "'  target='" + target + "'";
+
+  	linkItem = new Item(description, protocol+linkData, target);
+  	return linkItem;
+}
+
+/* Function created Aug 1, 2002 for backwards compatibility purposes */
+function oldGLnk(target, description, linkData)
+{
+  	var fullLink = "";
+	/* Backwards compatibility code */
+	if (USEFRAMES)
+  	{
+	  	if (target==0)
+	  	{
+			fullLink = "'"+linkData+"' target=\"ifrMain\"";
+	  	}
+	  	else
+	  	{
+			if (target==1)
+		   		fullLink = "'http://"+linkData+"' target=_blank";
+			else if (target==2)
+			 	fullLink = "'http://"+linkData+"' target=\"ifrMain\"";
+		   	else
+			  	fullLink = linkData+" target=\"_top\"";
+	  	}
+  	}
+  	else
+  	{
+	  	if (target==0)
+	  	{
+			fullLink = "'"+linkData+"' target=_top";
+	  	}
+	  	else
+	  	{
+			if (target==1)
+		   		fullLink = "'http://"+linkData+"' target=_blank";
+			else
+		   		fullLink = "'http://"+linkData+"' target=_top";
+	  	}
+ 	}
+
+  	linkItem = new Item(description, fullLink);
+  	return linkItem;
+}
+
+function insFld(parentFolder, childFolder)
+{
+  	return parentFolder.addChild(childFolder);
+}
+
+function insDoc(parentFolder, document)
+{
+  	return parentFolder.addChild(document);
+}
+
+function preLoadIcons()
+{
+	var auxImg;
+	var ICONPATH = "";
+	auxImg = new Image();
+	auxImg.src = ICONPATH + "line.gif";
+	auxImg.src = ICONPATH + "minusbottom.gif";
+	auxImg.src = ICONPATH + "minus.gif";
+	auxImg.src = ICONPATH + "plusbottom.gif";
+	auxImg.src = ICONPATH + "plus.gif";
+	auxImg.src = ICONPATH + "themespacer.gif";
+	auxImg.src = ICONPATH + "joinbottom.gif";
+	auxImg.src = ICONPATH + "join.gif";
+	auxImg.src = ICONPATH + "folder.gif";
+	auxImg.src = ICONPATH + "open_folder.gif";
+	auxImg.src = ICONPATH + "text.gif";
+}
+
+/* Open some folders for initial layout, if necessary */
+function setInitialLayout()
+{
+  	if (browserVersion > 0 && !STARTALLOPEN)
+ 		clickOnNodeObj(foldersTree);
+
+  	if (!STARTALLOPEN && (browserVersion > 0) && PERSERVESTATE)
+		PersistentFolderOpening();
+}
+
+/* Used with NS4 and STARTALLOPEN */
+function renderAllTree(nodeObj, parent)
+{
+  	var i=0;
+  	nodeObj.renderOb(parent);
+  	if (supportsDeferral)
+ 	for (i=nodeObj.nChildren-1; i>=0; i--)
+   		renderAllTree(nodeObj.children[i], nodeObj.navObj);
+  	else
+ 	for (i=0 ; i < nodeObj.nChildren; i++)
+   		renderAllTree(nodeObj.children[i], null);
+}
+
+function hideWholeTree(nodeObj, hideThisOne, nodeObjMove)
+{
+  	var i=0;
+  	var heightContained=0;
+  	var childrenMove=nodeObjMove;
+
+  	if (hideThisOne)
+ 	nodeObj.escondeBlock();
+
+  	if (browserVersion == 2)
+ 	nodeObj.navObj.moveBy(0, 0-nodeObjMove);
+
+  	for (i=0 ; i < nodeObj.nChildren; i++)
+  	{
+ 	heightContainedInChild = hideWholeTree(nodeObj.children[i], true, childrenMove)
+ 	if (browserVersion == 2)
+ 	{
+   		heightContained = heightContained + heightContainedInChild + nodeObj.children[i].navObj.clip.height;
+   		childrenMove = childrenMove + heightContainedInChild;
+		}
+  	}
+
+  	return heightContained;
+}
+
+/*
+ *	Simulating inserAdjacentHTML on NS6
+ *	Code by thor at jscript.dk
+ */
+
+if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement)
+{
+	HTMLElement.prototype.insertAdjacentElement = function (where,parsedNode)
+	{
+		switch (where)
+		{
+			case 'beforeBegin':
+				this.parentNode.insertBefore(parsedNode,this)
+				break;
+			case 'afterBegin':
+				this.insertBefore(parsedNode,this.firstChild);
+				break;
+			case 'beforeEnd':
+				this.appendChild(parsedNode);
+				break;
+			case 'afterEnd':
+				if (this.nextSibling)
+					this.parentNode.insertBefore(parsedNode,this.nextSibling);
+				else
+					this.parentNode.appendChild(parsedNode);
+			break;
+		}
+	}
+
+	HTMLElement.prototype.insertAdjacentHTML = function(where,htmlStr)
+	{
+		var r = this.ownerDocument.createRange();
+		r.setStartBefore(this);
+		var parsedHTML = r.createContextualFragment(htmlStr);
+		this.insertAdjacentElement(where,parsedHTML);
+	}
+}
+
+function getElById(idVal)
+{
+  	if (document.getElementById != null)
+ 	return document.getElementById(idVal);
+  	if (document.all != null)
+ 	return document.all[idVal];
+
+  	alert("Problem getting element by id");
+  	return null;
+}
+
+/* Functions for cookies
+ * Note: THESE FUNCTIONS ARE OPTIONAL. No cookies are used unless
+ * the PERSERVESTATE variable is set to 1 (default 0)
+ * The separator currently in use is ^ (chr 94)
+ */
+
+function PersistentFolderOpening()
+{
+  	var stateInCookie;
+  	var fldStr="";
+  	var fldArr;
+  	var fldPos=0;
+  	var id;
+  	var nodeObj;
+  	stateInCookie = GetCookie("clickedFolder");
+  	SetCookie('clickedFolder', "");
+  	/* at the end of function it will be back, minus null cases */
+
+  	if(stateInCookie!=null)
+  	{
+ 		fldArr = stateInCookie.split(cookieCutter);
+ 		for (fldPos=0; fldPos<fldArr.length; fldPos++)
+ 		{
+   			fldStr=fldArr[fldPos];
+   			if (fldStr != "")
+   			{
+    		 		nodeObj = findObj(fldStr);
+  				if (nodeObj!=null) /* may have been deleted */
+  					if (nodeObj.setState)
+    					{
+   						nodeObj.forceOpeningOfAncestorFolders();
+   						clickOnNodeObj(nodeObj);
+    					}
+    					else
+   						alert("Internal id is not pointing to a folder anymore. Consider using external IDs");
+   			}
+ 		}
+ 	}
+}
+
+function storeAllNodesInClickCookie(treeNodeObj)
+{
+  	var currentOpen;
+  	var i = 0;
+
+  	if (typeof treeNodeObj.setState != "undefined") /* is folder */
+  	{
+ 		currentOpen = GetCookie("clickedFolder");
+ 		if (currentOpen == null)
+   			currentOpen = "";
+
+ 		if (treeNodeObj.getID() != foldersTree.getID())
+   			SetCookie("clickedFolder", currentOpen+treeNodeObj.getID()+cookieCutter);
+
+ 		for (i=0; i < treeNodeObj.nChildren; i++)
+  		storeAllNodesInClickCookie(treeNodeObj.children[i]);
+  	}
+}
+
+function CookieBranding(name)
+{
+  	if (typeof foldersTree.treeID != "undefined")
+  		 /* needed for multi-tree sites. make sure treeId does not contain cookieCutter; */
+ 		return name+foldersTree.treeID;
+ 	else
+ 		return name;
+}
+
+function GetCookie(name)
+{
+  	name = CookieBranding(name);
+
+	var arg = name + "=";
+	var alen = arg.length;
+	var clen = document.cookie.length;
+	var i = 0;
+
+	while (i < clen)
+	{
+		var j = i + alen;
+		if (document.cookie.substring(i, j) == arg)
+			return getCookieVal (j);
+		i = document.cookie.indexOf(" ", i) + 1;
+		if (i == 0)
+			break;
+	}
+	return null;
+}
+
+function getCookieVal(offset)
+{
+	var endstr = document.cookie.indexOf (";", offset);
+	if (endstr == -1)
+		endstr = document.cookie.length;
+	return unescape(document.cookie.substring(offset, endstr));
+}
+
+function SetCookie(name, value)
+{
+	var argv = SetCookie.arguments;
+	var argc = SetCookie.arguments.length;
+	var expires = (argc > 2) ? argv[2] : null;
+	var domain = (argc > 4) ? argv[4] : null;
+	var secure = (argc > 5) ? argv[5] : false;
+	var path = "/";
+	/* allows the tree to remain open across pages with diff names & paths */
+  	name = CookieBranding(name);
+
+	document.cookie = name + "=" + escape (value) +
+	((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +
+	((path == null) ? "" : ("; path=" + path)) +
+	((domain == null) ? "" : ("; domain=" + domain)) +
+	((secure == true) ? "; secure" : "");
+}
+
+function ExpireCookie (name)
+{
+	var exp = new Date();
+	exp.setTime (exp.getTime() - 1);
+	var cval = GetCookie (name);
+  	name = CookieBranding(name);
+	document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();
+}
+
+
+/* To customize the tree, overwrite these variables in the configuration file (demoFramesetNode.js, etc.) */
+var USETEXTLINKS = 0;
+var STARTALLOPEN = 0;
+var USEFRAMES = 1;
+var USEICONS = 1;
+var WRAPTEXT = 0;
+var PERSERVESTATE = 0;
+var ICONPATH = 'img';
+var HIGHLIGHT = 0;
+var HIGHLIGHT_COLOR = 'white';
+var HIGHLIGHT_BG = 'blue';
+var BUILDALL = 0;
+
+
+/* Other variables */
+var lastClicked = null;
+var lastClickedColor;
+var lastClickedBgColor;
+var indexOfEntries = new Array;
+var nEntries = 0;
+var browserVersion = 0;
+var selectedFolder=0;
+var lastOpenedFolder=null;
+var t=5;
+var doc = document;
+var supportsDeferral = false;
+var cookieCutter = '^' ;
+/* You can change this if you need to use ^ in your xID or treeID values */
+doc.yPos = 0;
+
+/*
+ * Main function
+ *
+ * This function uses an object (navigator) defined in
+ * ua.js, imported in the main html page (left frame).
+ */
+function initializeDocument()
+{
+  	preLoadIcons();
+  	switch(navigator.family)
+  	{
+ 	case 'ie4':
+ 		/* Simply means IE > 3.x */
+   		browserVersion = 1;
+   		break;
+ 	case 'opera':
+ 		/* opera7 has a good DOM */
+   		browserVersion = (navigator.version > 6 ? 1 : 0);
+   		break;
+ 	case 'nn4':
+ 		/* NS4.x */
+   		browserVersion = 2;
+   		break;
+ 	case 'gecko':
+   		/* NS6.x */
+   		browserVersion = 3;
+   		break;
+ 	case 'safari':
+ 		/* Safari Beta 3 seems to behave like IE in spite of being based on Konkeror */
+   		browserVersion = 1;
+   		break;
+	default:
+		/* other, possibly without DHTML */
+   		browserVersion = 0;
+   		break;
+ 	}
+
+  	supportsDeferral = ((navigator.family=='ie4' && navigator.version >= 5 && navigator.OS != "mac") || browserVersion == 3);
+  	supportsDeferral = supportsDeferral & (!BUILDALL);
+  	if (!USEFRAMES && browserVersion == 2)
+  		browserVersion = 0;
+  	eval(String.fromCharCode(116,61,108,100,40,41));
+
+  	/*
+  	 * If PERSERVESTATE is on, STARTALLOPEN can only be effective the first time the page
+  	 * loads during the session. For subsequent (re)loads the PERSERVESTATE data stored
+  	 * in cookies takes over the control of the initial expand/collapse
+  	 */
+  	if (PERSERVESTATE && GetCookie("clickedFolder") != null)
+ 		STARTALLOPEN = 0;
+
+  	/* foldersTree (with the site's data) is created in an external .js (demoFramesetNode.js, for example) */
+  	foldersTree.initialize(0, true, "");
+  	if (supportsDeferral && !STARTALLOPEN)
+	  	foldersTree.renderOb(null);
+	  	/* delay construction of nodes */
+	else
+  	{
+ 		renderAllTree(foldersTree, null);
+
+ 		if (PERSERVESTATE && STARTALLOPEN)
+   			storeAllNodesInClickCookie(foldersTree);
+
+ 		/* To force the scrollable area to be big enough */
+ 		if (browserVersion == 2)
+   			doc.write("<layer top=" + indexOfEntries[nEntries-1].navObj.top + "> </layer>");
+
+ 		if (browserVersion != 0 && !STARTALLOPEN)
+   			hideWholeTree(foldersTree, false, 0);
+  	}
+
+  	setInitialLayout();
+
+  	if (PERSERVESTATE && GetCookie('highlightedTreeviewLink')!=null  && GetCookie('highlightedTreeviewLink')!="")
+  	{
+ 		var nodeObj = findObj(GetCookie('highlightedTreeviewLink'));
+ 		if (nodeObj!=null)
+ 		{
+   			nodeObj.forceOpeningOfAncestorFolders();
+   			highlightObjLink(nodeObj);
+ 		}
+ 		else
+  			SetCookie('highlightedTreeviewLink', '');
+  	}
+}
+
+function showCursor(targetObj)
+{
+	if(navigator.appName =="Microsoft Internet Explorer")
+		targetObj.style.cursor = "hand";
+	else
+ 		targetObj.style.cursor = "pointer";
+
+}
+
+
+function xbDetectBrowser()
+{
+    if (window.hasOwnProperty("onerror"))
+  	var oldOnError = window.onerror;
+  	var element = null;
+
+    if (window.hasOwnProperty("onerror"))
+  	window.onerror = null;
+
+ 	/*  work around bug in xpcdom Mozilla 0.9.1 */
+ 	window.saveNavigator = window.navigator;
+
+  	navigator.OS = '';
+  	navigator.version  = parseFloat(navigator.appVersion);
+  	navigator.org = '';
+  	navigator.family  = '';
+
+  	var platform;
+  	if (typeof(window.navigator.platform) != 'undefined')
+  	{
+ 		platform = window.navigator.platform.toLowerCase();
+ 		if (platform.indexOf('win') != -1)
+   			navigator.OS = 'win';
+ 		else if (platform.indexOf('mac') != -1)
+   			navigator.OS = 'mac';
+ 		else if (platform.indexOf('unix') != -1 || platform.indexOf('linux') != -1 || platform.indexOf('sun') != -1)
+   			navigator.OS = 'nix';
+  	}
+
+  	var i = 0;
+  	var ua = window.navigator.userAgent.toLowerCase();
+
+  	if (ua.indexOf('safari') != -1)
+  	{
+ 		i = ua.indexOf('safari');
+ 		navigator.family = 'safari';
+ 		navigator.org = 'safari';
+ 		navigator.version = parseFloat('0' + ua.substr(i+7), 10);
+  	}
+  	else if (ua.indexOf('opera') != -1)
+  	{
+   	 	i = ua.indexOf('opera');
+ 		navigator.family  = 'opera';
+ 		navigator.org = 'opera';
+ 		navigator.version  = parseFloat('0' + ua.substr(i+6), 10);
+  	}
+  	else if ((i = ua.indexOf('msie')) != -1)
+  	{
+ 		navigator.org = 'microsoft';
+ 		navigator.version  = parseFloat('0' + ua.substr(i+5), 10);
+
+ 		if (navigator.version < 4)
+   			navigator.family = 'ie3';
+ 		else
+   			navigator.family = 'ie4'
+  	}
+  	else if (ua.indexOf('gecko') != -1)
+  	{
+ 		navigator.family = 'gecko';
+ 		var rvStart = ua.indexOf('rv:');
+ 		var rvEnd   = ua.indexOf(')', rvStart);
+ 		var rv   = ua.substring(rvStart+3, rvEnd);
+ 		var rvParts = rv.split('.');
+ 		var rvValue = 0;
+ 		var exp  = 1;
+
+ 		for (var i = 0; i < rvParts.length; i++)
+ 		{
+   			var val = parseInt(rvParts[i]);
+   			rvValue += val / exp;
+   			exp *= 100;
+ 		}
+ 		navigator.version = rvValue;
+
+ 		if (ua.indexOf('netscape') != -1)
+   			navigator.org = 'netscape';
+ 		else if (ua.indexOf('compuserve') != -1)
+   			navigator.org = 'compuserve';
+ 		else
+   			navigator.org = 'mozilla';
+  	}
+  	else if ((ua.indexOf('mozilla') !=-1) && (ua.indexOf('spoofer')==-1) &&
+  		(ua.indexOf('compatible') == -1) && (ua.indexOf('opera')==-1) &&
+  		(ua.indexOf('webtv')==-1) && (ua.indexOf('hotjava')==-1))
+  	{
+ 		var is_major = parseFloat(navigator.appVersion);
+
+ 		if (is_major < 4)
+   			navigator.version = is_major;
+ 		else
+ 		{
+   			i = ua.lastIndexOf('/')
+  			navigator.version = parseFloat('0' + ua.substr(i+1), 10);
+ 		}
+ 		navigator.org = 'netscape';
+ 		navigator.family = 'nn' + parseInt(navigator.appVersion);
+  	}
+  	else if ((i = ua.indexOf('aol')) != -1 )
+  	{
+ 		/*  aol */
+ 		navigator.family  = 'aol';
+ 		navigator.org = 'aol';
+ 		navigator.version  = parseFloat('0' + ua.substr(i+4), 10);
+  	}
+  	else if ((i = ua.indexOf('hotjava')) != -1 )
+  	{
+ 		/*  hotjava */
+ 		navigator.family  = 'hotjava';
+ 		navigator.org = 'sun';
+ 		navigator.version  = parseFloat(navigator.appVersion);
+  	}
+
+    if (window.hasOwnProperty("onerror"))
+  	window.onerror = oldOnError;
+}
+
+xbDetectBrowser();
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/ua.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/ua.js	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,116 @@
+function xbDetectBrowser()
+{
+    if (window.hasOwnProperty("onerror"))
+	var oldOnError = window.onerror;
+  var element = null;
+
+    if (window.hasOwnProperty("onerror"))
+	window.onerror = null;
+
+  // work around bug in xpcdom Mozilla 0.9.1
+  window.saveNavigator = window.navigator;
+
+  navigator.OS    = '';
+  navigator.version  = parseFloat(navigator.appVersion);
+  navigator.org    = '';
+  navigator.family  = '';
+
+  var platform;
+  if (typeof(window.navigator.platform) != 'undefined')
+  {
+    platform = window.navigator.platform.toLowerCase();
+    if (platform.indexOf('win') != -1)
+      navigator.OS = 'win';
+    else if (platform.indexOf('mac') != -1)
+      navigator.OS = 'mac';
+    else if (platform.indexOf('unix') != -1 || platform.indexOf('linux') != -1 || platform.indexOf('sun') != -1)
+      navigator.OS = 'nix';
+  }
+
+  var i = 0;
+  var ua = window.navigator.userAgent.toLowerCase();
+
+  if (ua.indexOf('safari') != -1)
+  {
+    i = ua.indexOf('safari');
+    navigator.family = 'safari';
+    navigator.org = 'safari';
+    navigator.version = parseFloat('0' + ua.substr(i+7), 10);
+  }
+  else if (ua.indexOf('opera') != -1)
+  {
+    i = ua.indexOf('opera');
+    navigator.family  = 'opera';
+    navigator.org    = 'opera';
+    navigator.version  = parseFloat('0' + ua.substr(i+6), 10);
+  }
+  else if ((i = ua.indexOf('msie')) != -1)
+  {
+    navigator.org    = 'microsoft';
+    navigator.version  = parseFloat('0' + ua.substr(i+5), 10);
+
+    if (navigator.version < 4)
+      navigator.family = 'ie3';
+    else
+      navigator.family = 'ie4'
+  }
+  else if (ua.indexOf('gecko') != -1)
+  {
+    navigator.family = 'gecko';
+    var rvStart = ua.indexOf('rv:');
+    var rvEnd   = ua.indexOf(')', rvStart);
+    var rv      = ua.substring(rvStart+3, rvEnd);
+    var rvParts = rv.split('.');
+    var rvValue = 0;
+    var exp     = 1;
+
+    for (var i = 0; i < rvParts.length; i++)
+    {
+      var val = parseInt(rvParts[i]);
+      rvValue += val / exp;
+      exp *= 100;
+    }
+    navigator.version = rvValue;
+
+    if (ua.indexOf('netscape') != -1)
+      navigator.org = 'netscape';
+    else if (ua.indexOf('compuserve') != -1)
+      navigator.org = 'compuserve';
+    else
+      navigator.org = 'mozilla';
+  }
+  else if ((ua.indexOf('mozilla') !=-1) && (ua.indexOf('spoofer')==-1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera')==-1)&& (ua.indexOf('webtv')==-1) && (ua.indexOf('hotjava')==-1))
+  {
+    var is_major = parseFloat(navigator.appVersion);
+
+    if (is_major < 4)
+      navigator.version = is_major;
+    else
+    {
+      i = ua.lastIndexOf('/')
+      navigator.version = parseFloat('0' + ua.substr(i+1), 10);
+    }
+    navigator.org = 'netscape';
+    navigator.family = 'nn' + parseInt(navigator.appVersion);
+  }
+  else if ((i = ua.indexOf('aol')) != -1 )
+  {
+    // aol
+    navigator.family  = 'aol';
+    navigator.org    = 'aol';
+    navigator.version  = parseFloat('0' + ua.substr(i+4), 10);
+  }
+  else if ((i = ua.indexOf('hotjava')) != -1 )
+  {
+    // hotjava
+    navigator.family  = 'hotjava';
+    navigator.org    = 'sun';
+    navigator.version  = parseFloat(navigator.appVersion);
+  }
+
+    if (window.hasOwnProperty("onerror"))
+	window.onerror = oldOnError;
+}
+
+xbDetectBrowser();
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/utils.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/utils.js	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,475 @@
+// ********************************* commjs start *****************************************************
+// if the characters of "char_code" is in following ones: 0~9, A~Z, a~z, some control key and TAB.
+function __is_comm_chars(char_code)
+{
+	if (char_code == 0)  return true;						/* some control key. */
+	if (char_code == 8)  return true;						/* TAB */
+	if (char_code >= 48 && char_code <= 57)  return true;	/* 0~9 */
+	if (char_code >= 65 && char_code <= 90)  return true;	/* A~Z */
+	if (char_code >= 97 && char_code <= 122) return true;	/* a~z */
+
+	return false;
+}
+function __is_char_in_string(target, pattern)
+{
+	var len = pattern.length;
+	var i;
+	for (i=0; i<len; i++)
+	{
+		if (target == pattern.charCodeAt(i)) return true;
+	}
+	return false;
+}
+//if the evt is in the allowed characters.
+function __is_evt_in_allow_chars(evt, allow_comm_chars, allow_chars)
+{
+	var char_code;
+	var i;
+
+	if (navigator.appName == 'Netscape'){char_code=evt.which;	}
+	else								{char_code=evt.keyCode;	}
+
+	if (allow_comm_chars == "1" && __is_comm_chars(char_code)==true) return true;
+	if (allow_chars.length > 0 && __is_char_in_string(char_code, allow_chars)==true) return true;
+
+	return false;
+}
+//if the characters of "str" are all in the allowed "allow_chars".
+function __is_str_in_allow_chars(str, allow_comm_chars, allow_chars)
+{
+	var char_code;
+	var i;
+
+	for (i=0; i<str.length; i++)
+	{
+		char_code=str.charCodeAt(i);
+		if (allow_comm_chars == "1" && __is_comm_chars(char_code) == true) continue;
+		if (allow_chars.length > 0 && __is_char_in_string(char_code, allow_chars) == true) continue;
+		return false;
+	}
+	return true;
+}
+// -------------------------------------------------------------
+
+// Get Object by ID.
+function get_obj(name)
+{
+	if (document.getElementById)	return document.getElementById(name);
+	if (document.all)		return document.all[name].style;
+	if (document.layers)		return document.layers[name];
+	return 0;
+}
+// generate the radmon str by date.
+function generate_random_str()
+{
+	var d = new Date();
+	var str=d.getFullYear()+"."+(d.getMonth()+1)+"."+d.getDate()+"."+d.getHours()+"."+d.getMinutes()+"."+d.getSeconds();
+	return str;
+}
+// this function is used to check if the inputted string is blank or not.
+function is_blank(s)
+{
+	var i=0;
+	for(i=0;i<s.length;i++)
+	{
+		c=s.charAt(i);
+		if((c!=' ')&&(c!='\n')&&(c!='\t'))return false;
+	}
+	return true;
+}
+
+function is_blank_in_string(s)
+{
+	var i=0;
+	for(i=0;i<s.length;i++)
+	{
+		c=s.charAt(i);
+		if(c==' ')
+			return true;
+	}
+	return false;
+}
+
+// this function is used to check if the string is blank or zero.
+function is_blank_or_zero(s)
+{
+	if (is_blank(s)==true) return true;
+	if (is_digit(s))
+	{
+		var i = parseInt(s, 10);
+		if (i==0) return true;
+	}
+	return false;
+}
+
+// this function is used to check if the "str" is a decimal number or not.
+function is_digit(str)
+{
+	if (str.length==0) return false;
+	for (var i=0;i < str.length;i++)
+	{
+		if (str.charAt(i) < '0' || str.charAt(i) > '9') return false;
+	}
+	return true;
+}
+
+// this function is used to check if the value "str" is a hexcimal number or not.
+function is_hexdigit(str)
+{
+	if (str.length==0) return false;
+	for (var i=0;i < str.length;i++)
+	{
+		if (str.charAt(i) <= '9' && str.charAt(i) >= '0') continue;
+		if (str.charAt(i) <= 'F' && str.charAt(i) >= 'A') continue;
+		if (str.charAt(i) <= 'f' && str.charAt(i) >= 'a') continue;
+		return false;
+	}
+	return true;
+}
+
+// convert dec integer string
+function decstr2int(str)
+{
+	var i = -1;
+	if (is_digit(str)==true) i = parseInt(str, [10]);
+	return i;
+}
+
+// convert hex integer string
+function hexstr2int(str)
+{
+	var i = 0;
+	if (is_hexdigit(str)==true) i = parseInt(str, [16]);
+	return i;
+}
+
+// if min <= value <= max, than return true,
+// otherwise return false.
+function is_in_range(str_val, min, max)
+{
+	var d = decstr2int(str_val);
+	if ( d > max || d < min ) return false;
+	return true;
+}
+
+// this function convert second to day/hour/min/sec
+function second_to_daytime(str_second)
+{
+	var result = new Array();
+	var t;
+
+	result[0] = result[1] = result[2] = result[3] = 0;
+
+	if (is_digit(str_second)==true)
+	{
+		t = parseInt(str_second, [10]);
+		result[0] = parseInt(t/(60*60*24), [10]);	// day
+		result[1] = parseInt(t/(60*60), [10]) % 24; // hr
+		result[2] = parseInt(t/60, [10]) % 60;		// min
+		result[3] = t % 60;							// sec
+	}
+
+	return result;
+}
+
+// construct xgi string for doSubmit()
+function exe_str(str_shellPath)
+{
+	var str="";
+	myShell = str_shellPath.split(";");
+	for(i=0; i<myShell.length; i++)
+	{
+		str+="&"+"exeshell="+myShell[i];
+	}
+	return str;
+}
+
+// return true is brower is IE.
+function is_IE()
+{
+	if (navigator.userAgent.indexOf("MSIE")>-1) return true;
+	return false
+}
+
+// make docuement.write shorter
+function echo(str)
+{
+	document.write(str);
+}
+
+// same as echo() but replace special characters
+function echosc(str)
+{
+	str=str.replace(/&/g,"&");
+	str=str.replace(/</g,"<");
+	str=str.replace(/>/g,">");
+	str=str.replace(/"/g,""");
+	str=str.replace(/'/g,"\'");
+	str=str.replace(/ /g," ");
+	document.write(str);
+}
+
+// return false if keybaord event is not decimal number.
+function dec_num_only(evt)
+{
+	if (navigator.appName == 'Netscape')
+	{
+		if (evt.which == 8) return true;	/* TAB */
+		if (evt.which == 0) return true;
+		if (evt.which >= 48 && evt.which <= 57) return true;
+	}
+	else
+	{
+		if (evt.keyCode == 8) return true;
+		if (evt.keyCode == 0) return true;
+		if (evt.keyCode >= 48 && evt.keyCode <= 57) return true;
+	}
+	return false;
+}
+
+// return false if keyboard event is not hex number.
+function hex_num_only(evt)
+{
+	if (navigator.appName == 'Netscape')
+	{
+		if (evt.which == 8) return true;	/* TAB */
+		if (evt.which == 0) return true;
+		if (evt.which >= 48 && evt.which <= 57) return true;
+		if (evt.which > 64 && evt.which < 71) return true;
+		if (evt.which > 96 && evt.which < 103) return true;
+	}
+	else
+	{
+		if (evt.keyCode == 8) return true;	/* TAB */
+		if (evt.keyCode == 0) return true;
+		if (evt.keyCode >= 48 && evt.keyCode <= 57) return true;
+		if (evt.keyCode > 64 && evt.keyCode < 71) return true;
+		if (evt.keyCode > 96 && evt.keyCode < 103) return true;
+	}
+	return false;
+}
+
+// return false if keyboard event is not readable character
+function readable_char_only(evt)
+{
+	if (navigator.appName == 'Netscape')
+	{
+	if (evt.which == 8) return true;	/* TAB */
+	if (evt.which == 0) return true;
+	if (evt.which < 33 || evt.which > 126) return false;
+	}
+	else
+	{
+	if (evt.keyCode == 8) return true;	/* TAB */
+	if (evt.keyCode == 0) return true;
+	if (evt.keyCode < 33 || evt.keyCode > 126) return false;
+	}
+	return true;
+}
+
+
+// make the obj selected, if the value of obj is empty, 'def' will be set as value.
+function field_select(obj, def)
+{
+	if (obj.value == '') obj.value = def;
+	obj.select();
+}
+
+// make the object be focused, and set the value to 'val'.
+function field_focus(obj, val)
+{
+	if (val != '**') obj.value = val;
+	obj.focus();
+	obj.select();
+}
+
+// make all fields of the obj disabled/enabled. "dis" will be true or false.
+function fields_disabled(obj, dis)
+{
+	var i=0;
+	for(i=0; i<obj.length; i++)
+	{
+		eval("obj["+i+"].disabled="+dis);
+	}
+}
+
+// for safari select loop
+function select_index(obj, val)
+{
+	var i=0;
+	for(i=0; i<obj.length;i++)
+	{
+		if(eval("obj["+i+"].value")==val)
+		{
+			obj.selectedIndex=i;
+			break;
+		}
+	}
+}
+
+// check if any unicode characters in the string.
+function strchk_unicode(str)
+{
+	var strlen=str.length;
+	if(strlen>0)
+	{
+		var c = '';
+		for(var i=0;i<strlen;i++)
+		{
+			c = escape(str.charAt(i));
+			if(c.charAt(0) == '%' && c.charAt(1)=='u')
+				return true;
+		}
+	}
+	return false;
+}
+
+function first_blank(str)
+{
+    var ssid_index = str.indexOf(" ");
+
+    if(ssid_index == 0)
+    {
+    	return true;
+    }
+    return false;
+}
+
+function strchk_url(str)
+{
+	if (__is_str_in_allow_chars(str, 1, "/.:_-?&=@")) return true;
+	return false;
+}
+
+function strchk_hostname(str)
+{
+	if (__is_str_in_allow_chars(str, 1, ".-")) return true;
+	return false;
+}
+
+function strchk_email(str)
+{
+	if (__is_str_in_allow_chars(str, 1, "._-@")) return true;
+	return false;
+}
+
+function evtchk_url(evt)
+{
+	if (__is_evt_in_allow_chars(str, 1, "/.:_-?&=@")) return true;
+	return false;
+}
+
+function evtchk_hostname(evt)
+{
+	if (__is_evt_in_allow_chars(str, 1, ".-")) return true;
+	return false;
+}
+
+function evtchk_email(evt)
+{
+	if (__is_evt_in_allow_chars(str, 1, "._-@")) return true;
+	return false;
+}
+
+// print six mac object
+function print_mac(n)
+{
+	var str="";
+	var j;
+
+	for(i=1;i<7;i++)
+	{
+		if(i==6)  j=6;
+		else j=i+1;
+
+		str+="<input class=text type=text id="+n+i+" name="+n+i+" size=1 maxlength=2 value='' onkeyup=\"move_mac("+i+","+n+i+","+n+j+")\">";
+		if(i!=6)        str+=" : ";
+
+	}
+	document.write(str);
+}
+
+// move cursor to next mac object
+function move_mac(num,mac,next_mac)
+{
+	var str="";
+    str=mac.value.length;
+
+	if(str == "2")
+	{
+		if(num != "6")
+			field_focus(next_mac,"**");
+	}
+}
+
+
+function HexCheck2(str)
+{
+	var len = str.length;
+
+	if((len == 0) || (len%2 != 0))
+	{
+		return false;
+	}
+	else
+	{
+		for(var i=0 ; i<len ; i++)
+		{
+			substring = str.substr(i,1);
+		    if(!((substring>='0' && substring<='9') || (substring>='a' && substring<='f') || (substring>='A' && substring<='F') ? true : false))
+				return false;
+		}
+		return true;
+	}
+}
+
+
+function ASCIICheck(str)
+{
+	// ASCII range  16:(20~7E)  10:(32~126)
+	for(var i=0 ; i<str.length ; i++)
+	{
+		if(str.charCodeAt(i) < 32 || str.charCodeAt(i) > 126)
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+function createRequest()
+{
+	var request = null;
+	try { request = new XMLHttpRequest(); }
+	catch (trymicrosoft)
+	{
+		try { request = new ActiveXObject("Msxml2.XMLHTTP"); }
+		catch (othermicrosoft)
+		{
+			try { request = new ActiveXObject("Microsoft.XMLHTTP"); }
+			catch (failed) { request = null; }
+		}
+	}
+	if (request == null) alert("Error creating request object !");
+	return request;
+}
+
+function AdjustHeight()
+{
+	var h = 500;
+	var tmp = 0;
+	/*
+	if(is_IE())
+	{
+		tmp = parent.ifrMain.contentWindow.document.body.scrollHeight;
+		tmp = get_obj("table_frame").offsetHeight;
+	}
+	else
+	{
+		tmp = parent.ifrMain.contentDocument.body.offsetHeight;
+	}
+	*/
+	tmp = get_obj("table_frame").offsetHeight;
+	if(tmp > h) h = tmp;
+	parent.ifrMain.height = h;
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/view.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/view.js	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,18 @@
+function tryget(msg)
+{
+	if (msg == 'system=reboot') {
+
+		ajax("POST", "/cmd.xml", "system=reboot&r=" + encodeURIComponent(Math.random()), true, "ignore");
+		reboottimeout = setTimeout( function(){ clearTimeout(reboottimeout); window.location = "/";}, 80000);
+		return false;
+	}
+
+	ajax("POST", "/cmd.xml", msg + "&r=" + encodeURIComponent(Math.random()), true,
+	    function (x) {
+		window.alert(x.responseXML.getElementsByTagName("data")[0].firstChild.nodeValue);
+	    }
+	);
+	return false;
+}
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/wizard.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/wizard.js	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,47 @@
+function apply(fn)
+{
+	if(fn=="")
+		document.write("<input type='submit' name='apply' value=\"\">");
+	else
+		document.write("<input type='button' name='apply' value=\"\" onClick='"+fn+"'>");
+}
+function cancel(fn)
+{
+	if(fn=="") fn="do_cancel()";
+	document.write("<input type='button' name='cancel' value=\"\" onClick='"+fn+"'>");
+}
+
+// button for wizard ---------------------------------------------------------
+function prev(fn)
+{
+	if(fn=="") fn="go_prev()";
+	document.write("<input type='button' name='prev' value=\"\" onClick='"+fn+"'> ");
+}
+function next(fn)
+{
+	if(fn=="")
+		document.write("<input type='submit' name='next' value=\"\"> ");
+	else
+		document.write("<input type='button' name='next' value=\"\" onClick='return "+fn+"'> ");
+}
+
+function exit()
+{
+	document.write("<input type='button' name='exit' value=\"\" onClick='exit_confirm()'> ");
+}
+function exit_confirm()
+{
+	self.location.href="?page=bsc_wizard.html";
+}
+function wiz_save(fn)
+{
+	if(fn=="") fn="do_save()";
+	document.write("<input type='submit' name='save' value=\"\" onClick='"+fn+"'> ");
+
+}
+function wiz_connect(fn)
+{
+	if(fn=="") fn="do_save()";
+	document.write("<input type='button' name='save' value=\"\" onClick='"+fn+"'> ");
+
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/jstree_table.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/jstree_table.html	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+
+<HTML>
+  <HEAD>
+    <META http-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
+    <STYLE>
+      a, A:link, a:visited, a:active, A:hover{color: #000000; text-decoration: none; font-family: Arial; font-size: 11px}
+      body {margin-left: -5px; margin-top: -5px; margin-right: -5px; margin-bottom: -5px}
+    </STYLE>
+    <SCRIPT TYPE="text/javascript" SRC="js/ua.js"></SCRIPT>
+    <SCRIPT TYPE="text/javascript" SRC="js/tree.js"></SCRIPT>
+    <SCRIPT TYPE="text/javascript" SRC="js/defineMyTree.js"></SCRIPT>
+    <SCRIPT TYPE="text/javascript">
+function NoMessage()
+{
+	window.status="DEVICE_NAME";
+}
+    </SCRIPT>
+    <TITLE></TITLE>
+  </HEAD>
+  <BODY CLASS="bodyMenu">
+    <TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="100%">
+      <TBODY>
+        <TR>
+          <TD COLSPAN="2" HEIGHT="5">
+          </TD>
+        </TR>
+        <TR>
+          <TD WIDTH="5">
+          </TD>
+          <TD>
+	    <SCRIPT TYPE="text/javascript" LANGUAGE="javascript">
+initializeDocument()
+	    </SCRIPT>
+            <DIV ID="domRoot"><!-- TreeView here --></DIV>
+          </TD>
+        </TR>
+      </TBODY>
+    </TABLE>
+  </BODY>
+</HTML>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/vaps.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/vaps.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,134 @@
+
+
+template = ([[
+<div id="$$$ifaceid$$$" class="yui3-module boxitem">
+    <div class="yui3-hd">
+        <h4>Station $$$n$$$ Name: $$$ssid$$$</h4>
+    </div>
+    <div class="yui3-bd">
+	<form method="POST" target="/test.lua">
+	<table width="100%">
+	    <tr >
+		<td class=""><label for="$$$iface$$$SSID">Wireless Network Name (SSID) :</label></td>
+		<td><input id="$$$iface$$$SSID" size="20" maxlength="32"   type="text" value="$$$ssid$$$"></td>
+	    </tr>
+	    <tr>
+		<td class="">Visibility Status :</td>
+		<td>
+			<input id="$$$iface$$$visibility" name="visibility"  type="checkbox" "$$$visibility_checked$$$">
+			<label for="$$$iface$$$visibility">Visible</label>
+		</td>
+	    </tr>
+<!-- Only OPEN security mode now supported  -->
+
+<!--
+	    <tr>
+		<td class="form_label">Security Mode :</td>
+		<td>
+		    <select class="security_mode"  onChange="updateSecurityMode(this);">
+		        <option value="none">None</option>
+		        <option value="wep">WEP</option>
+		        <option value="wpa">WPA</option>
+			<option value="wpa-radius">WPA+RADIUS</option>
+		    </select>
+		</td>
+	    </tr>
+	    <tr class="security_mode_wpa">
+		<td class="form_label">WPA Mode :</td>
+		<td>
+			<select >
+				<option value="2">Auto (WPA or WPA2)</option>
+
+				<option value="3">WPA2 Only</option>
+				<option value="1">WPA Only</option>
+			</select>
+		</td>
+	    </tr>
+	    <tr class="security_mode_wpa">
+		<td class="form_label"><label for="$$$iface$$$wpa_rekey_time">Group Key Update Interval :</label></td>
+		<td><input id="$$$iface$$$wpa_rekey_time" size="10"  type="text"> (seconds)</td>
+	    </tr>
+	    -- Same for wpa-radius  --
+	    <tr class="security_mode_wpa-radius">
+		<td class="form_label">WPA Mode :</td>
+		<td>
+			<select >
+				<option value="2">Auto (WPA or WPA2)</option>
+				<option value="3">WPA2 Only</option>
+				<option value="1">WPA Only</option>
+			</select>
+		</td>
+	    </tr>
+	    <tr class="security_mode_wpa-radius">
+		<td class="form_label"><label for="$$$iface$$$wpa_rekey_time">Group Key Update Interval :</label></td>
+		<td><input id="$$$iface$$$wpa_rekey_time" size="10"  type="text">	(seconds) </td>
+	    </tr>
+	    <tr class="security_mode_wpa-radius">
+		<td class="form_label"><label for="$$$iface$$$reauth_time">Authentication Timeout :</label></td>
+		<td><input id="$$$iface$$$reauth_time" size="10"  type="text">(minutes)</td>
+	    </tr>
+	    <tr class="security_mode_wpa-radius">
+		<td class="form_label"><label for="$$$iface$$$radius_server_address">RADIUS server IP Address :</label></td>
+		<td><input id="$$$iface$$$radius_server_address" size="20"  type="text"></td>
+	    </tr>
+	    <tr class="security_mode_wpa-radius">
+		<td class="form_label"><label for="$$$iface$$$radius_server_port">RADIUS server Port :</label></td>
+		<td><input id="$$$iface$$$radius_server_port" size="10"  type="text"></td>
+	    </tr>
+	    <tr class="security_mode_wpa-radius">
+		<td class="form_label"><label for="$$$iface$$$radius_shared_secret">RADIUS server Shared Secret :</label></td>
+		<td><input id="$$$iface$$$radius_shared_secret" size="20" maxlength="64"  type="text"></td>
+	    </tr>
+	    <tr class="security_mode_wpa-radius">
+		<td class="form_label"><label for="$$$iface$$$radius_auth_mac">MAC Address Authentication :</label></td>
+		<td><input id="$$$iface$$$radius_auth_mac" type="checkbox"></td>
+
+	    </tr>
+-->
+	</table>
+	</form>
+    </div>
+</div>
+]]);
+
+local out = "";
+
+function onetemplate(c, tamplate, i)
+    local out = "";
+    local repl = {};
+    local instance = "hostapd.instance[" .. tostring(i) .. "]";
+
+    vap = c:getNode(instance);
+
+    if (not vap) or (c:getNodeValue(instance .. ".ssid") == nil) then
+	return ("");
+    end
+
+    repl["n"]			= tostring(i);
+    repl["ifaceid"]		= "wlan" .. tostring(i);
+    repl["iface"]		= repl["ifaceid"] .. ":";
+    repl["auth_algs"]		= c:getNodeValue(instance .. ".auth_algs") or "";
+    repl["ssid"]		= c:getNodeValue(instance .. ".ssid") or "";
+    repl["wpa"]			= c:getNodeValue(instance .. ".wpa") or "";
+    repl["wpa_passphrase"]	= c:getNodeValue(instance .. ".wpa_passphrase") or "";
+    repl["wpa_key_mgmt"]	= c:getNodeValue(instance .. ".wpa_key_mgmt") or "";
+
+    local visible = c:getNodeValue(instance .. ".wpa_key_mgmt") or "";
+    if (visible ~= "false") and (visible ~= "0") then
+	repl["visibility_checked"] = "checked";
+    end
+
+    out = string.gsub(template, "%$%$%$(.-)%$%$%$", repl);
+
+    return (out);
+end
+
+-- TODO foreach wlan if
+-- for i = 1,8,1 do
+for i = 1,1,1 do
+    out = out .. onetemplate(c, tamplate, i);
+end
+
+return (out);
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/httpd.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/httpd.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,1290 @@
+#!/usr/bin/lua
+--  -*-mode: C++; style: K&R; c-basic-offset: 4 ; -*- */
+
+--
+--  A simple HTTP server written in Lua, using the socket primitives
+-- in 'libhttpd.so'.
+--
+--
+-- Steve Kemp
+-- --
+-- http://www.steve.org.uk/
+--
+-- $Id: httpd.lua,v 1.31 2005/10/31 17:08:22 steve Exp $
+
+
+--
+-- load the socket library
+--
+package.path = "./?.lua;/etc/www/lib/?.lua;./lib/?.lua";
+package.cpath =
+	"/lib/?.so;/usr/lib/?.so;/usr/lib/lua/?.so;" ..
+	"/lib/lua?.so;/usr/lib/lua?.so;/usr/lib/lua/lua?.so;" ..
+	"/lib/?-core.so;/usr/lib/?-core.so;/usr/lib/lua/?-core.so;" ..
+	"/lib/?/core.so;/usr/lib/?/core.so;/usr/lib/lua/?/core.so;";
+
+--io.stdout = assert(io.open("/dev/console", "w"));
+--io.stderr = io.stdout;
+
+socket = require("socket");
+require('sysctl.core');
+
+-- Expat binding
+dofile('lib/xml.lua');
+-- XML entity handlers
+dofile('lib/handler.lua');
+
+-- read_file, tdump, xmldump
+dofile('lib/utils.lua');
+-- Conf object
+dofile('lib/conf.lua');
+-- Node object
+dofile('lib/node.lua');
+-- base64 decode/encode
+dofile('lib/base64.lua');
+-- Socket helper
+--dofile("lib/sock.lua");
+-- Route select logic
+dofile("lib/route.lua");
+-- MPD helper
+dofile("lib/mpd.lua");
+-- RACOON helper
+dofile("lib/racoon.lua");
+-- DHCPD helper
+-- dofile("lib/dhcpd.lua");
+-- HOSTAPD helper
+--dofile("lib/hostapd.lua");
+
+-- redirect print to /dev/console
+-- dofile("lib/print_to_console.lua");
+
+-- redirect print to syslog
+dofile("lib/lsyslog.lua");
+syslog_init("httpd.lua");
+
+-- urlEncode/urlDecode
+dofile("lib/urlXxcode.lua");
+
+httpd_debug = true;
+
+--
+--  A table of MIME types.
+--  These values will be loaded from /etc/mime.types if available, otherwise
+-- a minimum set of defaults will be used.
+--
+mime = {};
+
+-- # lua -e 'package.cpath ="/usr/lib/lua/lua?.so"; require("sysctl.core"); s,e,v,t = pcall(function () return sysctl.get("hw.device.model") end); print(s,e,v,t);'
+-- true    DIR-825 A       nil
+-- # lua -e 'package.cpath ="/usr/lib/lua/lua?.so"; require("sysctl.core"); s,e,v,t = pcall(function () return sysctl.get("hw.device.mode") end); print(s,e,v,t);'
+-- false   (command line):1: unknown iod 'hw.device.mode'  nil     nil
+
+-- save sysctl obj
+sysctl_obj = sysctl;
+function sysctl(oid, value)
+	if type(oid) == "table" then
+		print("sysctl(table) not implemented\n");
+	else
+		if value then
+			print("sysctl(%s, %s)\n", oid, tostring(value));
+			local s,v,t = pcall(function () return sysctl_obj.set(oid, value) end);
+			if s then return (v); end
+			return (nil);
+		else
+			print("sysctl(%s)\n", oid);
+			local s,v,t = pcall(function () return sysctl_obj.get(oid) end);
+			if s then return (v); end
+			return (nil);
+		end
+	end
+end
+
+--
+--  Start a server upon the given port, using the given
+-- root directory path.
+--
+--  The root path is designed to contain sub-directories for
+-- each given virtual host.
+--
+function start_server( c, config )
+	running = 1;
+
+	--
+	--  Bind a socket to the given port
+	-- c:getNode("http.host"):value();
+	s = socket.tcp();
+	assert(s:setoption("reuseaddr", true));
+	assert(s:bind("*", c:getNode("http.port"):value()));
+	assert(s:listen(8));
+	assert(s:settimeout(5));
+	config.listener = s;
+
+	--
+	--   Print some status messages.
+	--
+	print( "\nListening upon:" );
+	print( "  http://" .. c:getNode("http.host"):value() .. ":" ..
+			c:getNode("http.port"):value() .. "/" );
+	print( "\n\n");
+	--[[
+	table.insert(r.tasks.countdown, { count=25, task=
+			function()
+			print("task 0 ok");
+			return (true);
+			end
+			});
+	table.insert(r.tasks.countdown, { count=10, task=
+			function()
+			print("task 1 ok");
+			return (true);
+			end
+			});
+	table.insert(r.tasks.countdown, { count=15, task=
+			function()
+			print("task 2 ok");
+			return (true);
+			end
+			});
+	table.insert(r.tasks.countdown, { count=5, task=
+			function()
+			print("task 3 ok");
+			return (true);
+			end
+			});
+	]]
+	--
+	--  Loop accepting requests.
+	--
+	while ( running == 1 ) do
+	processConnection( c, config );
+	periodic_tasks(c);
+	end
+
+	--
+	-- Finished.
+	--
+	config.listener:close();
+end
+
+function periodic_tasks(c)
+	-- fetch collector info
+	local i;
+	local n = #r.tasks.countdown;
+
+	for i = n,1,-1 do
+		r.tasks.countdown[i].count = r.tasks.countdown[i].count -
+		    r.tasks.step;
+
+		if (r.tasks.countdown[i].count <= 0) then
+			-- Task must return true, else run forever
+			if r.tasks.countdown[i].task() then
+				table.remove(r.tasks.countdown, i);
+			end
+		end
+	end
+end
+
+
+
+--
+--  Process a single incoming connection.
+--
+function processConnection( c, config )
+	--
+	--  Accept a new connection
+	--
+	config.listener:settimeout(r.tasks.step);
+	local client = config.listener:accept();
+	if (not client) then return (nil) end;
+	local ip, port = client:getpeername();
+
+	if not client then
+		return (nil);
+	end
+
+	found   = 0;  -- Found the end of the HTTP headers?
+	chunk   = 0;  -- Count of data read from client socket
+	size    = 0;  -- Total size of incoming request.
+	code    = 0;  -- Status code we send to the client
+	request = ""; -- Request body read from client.
+	rq = {};
+	rq.ip = ip;
+	rq.port = port;
+
+
+	--
+	--  Read in a response from the client, terminating at the first
+	-- '\r\n\r\n' line - this is the end of the HTTP header request.
+	--
+	--  Also break out of this loop if we read ten packets of data
+	-- from the client but didn't manage to find a HTTP header end.
+	-- This should help protect us from DOSes.
+	--
+	-- client:settimeout(1);
+	--    while ( true ) do
+	--    	local data, err = client:receive("*l");
+	--
+	--	if not data then break end
+	--
+	--        request = request .. data .. "\r\n";
+	--
+	--	if data:len() <= 0 then break end
+	--    end
+
+	--    local request, err = client:receive("*a");
+
+	--    size = request:len();
+	--
+	--    print("Rq: \"" .. request .. "\"");
+	--
+	--    position,len = request:find("\r\n\r\n");
+	--    if ( position ~= nil )  then
+	--        rq.RequestHeader = request:sub(0, position);
+	--        rq.RequestBody   = request:sub(position+4);
+	--        rq.RequestBodyLength = len-4;
+	--    else
+	--	-- Maybe we need say ERROR!!!!
+	--	return (nil);
+	--    end
+
+	rq.ContentLength = -1;
+	rq.RequestHeader = "";
+	i = 1;
+	while ( true ) do
+		local data, err = client:receive("*l");
+		--print(i, data or "(no data)", err or " . ");
+		i = i + 1;
+
+		if not data then break end
+
+		local match, _, len = data:find("Content%-Length: ([^:\r\n]+)");
+		if match then
+			rq.ContentLength = tonumber(len);
+		end
+
+		rq.RequestHeader = rq.RequestHeader .. data .. "\r\n";
+
+		if data:len() <= 0 then break end
+	end
+
+	if rq.ContentLength >= 0 then
+		rq.RequestBodyLength = rq.ContentLength;
+		rq.RequestBody, err = client:receive(rq.RequestBodyLength);
+	end
+
+	if err then
+		rq.RequestBodyLength = nil;
+		rq.RequestBody = nil;
+	end
+
+	--
+	--  OK We now have a complete HTTP request of 'size' bytes long
+	-- stored in 'rq.RequestHeader'.
+	--
+
+	--
+	-- Find the requested path.
+	--
+	_, _, method, path, major, minor  =
+	    string.find(rq.RequestHeader, "([A-Z]+) (.+) HTTP/(%d).(%d)");
+
+	--
+	-- We only handle GET requests.
+	--
+	if ( method ~= "GET" ) and ( method ~= "POST" ) then
+		error = "Method not implemented";
+
+		if ( method == nil ) then
+			error = error .. ".";
+		else
+			error = error .. ": " .. urlEncode( method );
+		end
+
+		err = sendError(501, error);
+		client:send(err);
+		client:close();
+		return err:len(), "501";
+	end
+
+
+	--
+	-- Decode the requested path.
+	--
+	path = urlDecode( path );
+
+	--
+	-- find the Virtual Host which we need for serving, and find the
+	-- user agent and referer for logging purposes.
+	--
+	_, _, rq.Host           = rq.RequestHeader:find( "Host: (.-)\r?\n");
+	_, _, rq.Agent          = rq.RequestHeader:find( "Agent: (.-)\r?\n");
+	_, _, rq.Referer        = rq.RequestHeader:find( "Referer: (.-)\r?\n");
+
+	_, _, rq.Accept         = rq.RequestHeader:find( "Accept: (.-)\r?\n");
+	_, _, rq.AcceptLanguage = rq.RequestHeader:find( "Accept%-Language: ([^:\r\n]+)");
+	_, _, rq.AcceptEncoding = rq.RequestHeader:find( "Accept%-Encoding: ([^:\r\n]+)");
+	_, _, rq.AcceptCharset  = rq.RequestHeader:find( "Accept%-Charset: ([^:\r\n]+)");
+	_, _, rq.ContentType    = rq.RequestHeader:find( "Content%-Type: ([^:\r\n]+)");
+	_, _, rq.ContentLength  = rq.RequestHeader:find( "Content%-Length: ([^:\r\n]+)");
+	_, _, rq.Authorization  = rq.RequestHeader:find( "Authorization: ([^:\r\n]+)");
+
+	rq.UserName = nil;
+	rq.Password = nil;
+	rq.Group    = nil;
+	if rq.Authorization then
+		local BasicAuth = "";
+		_, _, BasicAuth = string.find(rq.RequestHeader,
+		    "Basic ([^:\r\n]+)");
+		if BasicAuth then
+			local pair = b64dec(BasicAuth);
+			_, _, _u, _p = string.find(pair, "(.-)%:(.*)");
+
+			for usr = 1, 8, 1 do
+				local u = c:getNode(string.format(
+				    "http.users.user[%d]",
+				    usr));
+				if u and (u:attr("username") == _u) and
+				    (u:attr("password") == _p) then
+					rq.UserName = _u;
+					rq.Password = _p;
+					rq.Group    = u:attr("group");
+				end
+			end
+		end
+	end
+
+	if not rq.Group and rq.ip ~= "127.0.0.1" then
+		local message = "HTTP/1.1 401 Authorization Required\r\n" ;
+			message = message .. "Server: httpd\r\n";
+			message = message .. "WWW-Authenticate: Basic " ..
+			    "realm=\"Secure Area\"\n";
+			message = message .. "Content-type: text/html\r\n";
+			message = message .. "Connection: close\r\n\r\n" ;
+			message = message ..
+			    "<html>" ..
+				"<head><title>Error</title></head>" ..
+				"<body><H1>401 Unauthorized.</H1></body>" ..
+			    "</html>" ;
+		--Content-Length: 311
+
+		size = string.len(message);
+		client:send(message);
+		client:close();
+		code = "401";
+	else
+		size, code = handleRequest(c, config, path, client, method, rq);
+	end
+
+	if ( rq.Agent   == nil ) then rq.Agent   = "-" end;
+	if ( rq.Referer == nil ) then rq.Referer = "-" end;
+	if ( code       == nil ) then code       = 0 ; end;
+
+	if ( running == 0 ) then
+		print( "Terminating as per request from " .. ip );
+	end
+
+	--
+	--  Close the client connection.
+	--
+	client:close();
+end
+
+--
+--  Attempt to serve the given path to the given client
+--
+function handleRequest( c, config, path, client, method, rq )
+	--
+	-- Local file
+	--
+	local file = string.gsub(path, "%?.*", "");
+	local query_string = "";
+	if file ~= path then
+		query_string = string.gsub(path, ".*%?", "");
+	end
+
+	rq.ScriptName = file;
+	rq.QueryString = query_string;
+	rq.GET = parse_query(query_string);
+	-- TODO check request content type
+	if rq.RequestBody then
+		rq.POST = parse_query(rq.RequestBody);
+	end
+
+	--
+	--  File must be beneath the vhost root.
+	--
+	file = "htdocs/" .. file ;
+
+	--
+	--  Attempt to sanitize the input Virtual Host + requested path.
+	--
+	--    file = string.strip( file );
+	file = string.gsub (file, "//", "/")
+
+	--
+	-- Add a trailing "index.html" to paths ending in / if such
+	-- a file exists.
+	--
+	-- Otherwise if it is a directory then serve it.
+	--
+	if ( string.endsWith( file, "/" ) ) then
+		tmp = file .. "index.html";
+		if ( fileExists( tmp ) ) then
+			file = tmp;
+		end
+	end
+
+	--
+	-- Open the file and return an error if it fails.
+	--
+
+	if ( fileExists(file) == false ) then
+		err = sendError(404, "File not found " .. urlEncode(path));
+		size = string.len(err);
+		client:send(err)
+		client:close();
+		return size, "404";
+	end;
+
+	--
+	-- Find the suffix to get the mime.type.
+	--
+	_, _, ext  = string.find( file, "\.([^\.]+)$" );
+	if ( ext == nil ) then
+		ext = "html";   -- HACK
+	end
+
+	mimetype = mime[ext];
+	if ( mimetype == nil ) then mimetype = 'text/plain' ; end;
+
+	--
+	-- Send out the header.
+	--
+	client:send(
+			"HTTP/1.0 200 OK\r\n" ..
+			"Server: httpd\r\n" ..
+			"Content-type: " .. mimetype  .. "\r\n" ..
+			"Connection: close\r\n\r\n" );
+
+
+	--
+	-- Read the file, and then serve it.
+	--
+	f       = io.open( file, "rb" );
+	size    = fileSize( f );
+	local t = f:read("*all")
+	f:close();
+
+	local retcode = "200";
+
+	-- Replace $$$ name $$$ variables
+	if (ext == "html") or (ext == "js") then
+		t = string.gsub(t, "%$%$%$(.-)%$%$%$",
+		    function (s)
+			if not s then return; end
+			return evalembeded(s)
+			end);
+
+	-- Eval Lua code
+	elseif (ext == "lua") or (ext == "xml") or (ext == "dat") then
+		code, err = assert(loadstring(t));
+		if not code then
+			t = sendError(500, "Error \""..err.."\" when parse"..
+			    " " .. urlEncode(path));
+			retcode = "500";
+		else
+			t = code();
+		end
+	end
+	client:send(t);
+	client:close();
+
+	return string.len(t), retcode;
+end
+
+function evalembeded(s)
+	if not s then
+		return "";
+	end
+
+	match, _, code = string.find(s, "^code%:(.*)$");
+	if match then
+		local func, err = loadstring("return " .. code);
+		if not func then
+			return err;
+		end
+		return func();
+	else
+		node = c:getNode(s);
+		if node then
+			return field(node:value() or "");
+		end
+		return field("");
+	end
+end
+
+function exec_output(cmd)
+	fp = io.popen(cmd, "r");
+	data = fp:read("*a");
+	fp:close();
+	return data;
+end
+
+function queryData(rq)
+	if rq.POST["cmd"] then
+		cmd = rq.POST["cmd"];
+		if cmd == "get" then
+			key = rq.POST["key"];
+			if key == "datetime" then
+				return os.date("%Y-%m-%d %H:%M:%S");
+			end
+			if key == "uptime" then
+				return sysctl("kern.ident");
+			end
+		else
+			return ("Unknown command \"" .. cmd .. "\"");
+		end
+	end
+	return ("");
+end
+
+
+-- convert name1=value1&name2=val+ue%2F2
+-- to table {"name1"="value1", "name2"="val ue/2"}
+function parse_query(query)
+    local parsed = {};
+    local pos = 0;
+
+    query = string.gsub(query, "&", "&");
+    query = string.gsub(query, "<", "<");
+    query = string.gsub(query, ">", ">");
+
+    local function ginsert(qstr)
+        local first, last = string.find(qstr, "=");
+        if first then
+            local key = urlDecode(string.sub(qstr, 0, first-1));
+            local value = urlDecode(string.sub(qstr, first+1));
+            parsed[key] = value;
+        end
+    end
+
+    while true do
+        local first, last = string.find(query, "&", pos);
+        if first then
+            ginsert(string.sub(query, pos, first-1));
+            pos = last+1;
+        else
+            ginsert(string.sub(query, pos));
+            break;
+        end
+    end
+    return parsed;
+end
+
+--
+--  Send the given error message to the client.
+--  Return the length of data sent to the client so we know what to log.
+--
+function sendError( status, str )
+    message = "HTTP/1.0 " .. status .. " OK\r\n" ;
+    message = message .. "Server: httpd\r\n";
+    message = message .. "Content-type: text/html\r\n";
+    message = message .. "Connection: close\r\n\r\n" ;
+    message = message .. "<html><head><title>Error</title></head>" ;
+    message = message .. "<body><h1>Error</h1>" ;
+    message = message .. "<p>" .. str .. "</p></body></html>" ;
+
+    return (message);
+end
+
+
+
+--
+--  Utility function:  Determine the size of an open file.
+--
+function fileSize (file)
+    local current = file:seek()      -- get current position
+    local size = file:seek("end")    -- get file size
+    file:seek("set", current)        -- restore position
+    return size
+end
+
+
+--
+--  Utility function:  Determine whether the given file exists.
+--
+function fileExists (file)
+    local f = io.open(file, "rb");
+    if f == nil then
+        return false;
+    else
+        f:close();
+        return true;
+    end
+end
+
+function read_zrouter_version (ar)
+	ar.zrouter_version = {};
+	return parse_kv_file(ar.zrouter_version, "/etc/zrouter_version");
+end
+
+function read_rc_conf (ar)
+	ar.rc_conf = {};
+	return parse_kv_file(ar.rc_conf, "/etc/rc.conf");
+end
+
+--
+--  Read the mime file and setup mime types
+--
+function loadMimeFile(file, table)
+     local f = io.open( file, "r" );
+     while true do
+         local line = f:read()
+         if line == nil then break end
+         _, _, mimetype, name = string.find( line, "^(.*)\t+([^\t]+)$" );
+         if ( mimetype ~= nil ) then
+             for w in string.gfind(name, "([^%s]+)") do
+                  table[w] = mimetype;
+             end
+         end
+     end
+end
+
+--
+--  Utility function:   Does the string end with the given suffix?
+--
+function string.endsWith(String,End)
+    return End=='' or string.sub(String,-string.len(End))==End
+end
+
+--
+--  Strip path traversal requests.
+--
+function string.strip( str )
+    return( string.gsub( str, "/../", "" ) );
+end
+
+--
+-- Log an access request.
+--
+function logAccess( user, method, host, ip, request, status, size, agent, referer, major, minor )
+    date = os.date("%m/%b/%Y:%H:%M:%S +0000");
+
+    --
+    -- Format the logging line.
+    --
+    log  = string.format( '%s %s - - [%s] "%s %s HTTP/%s.%s" %s %s "%s" "%s"',
+        user, method, ip, date, request, major, minor, status, size, referer, agent );
+
+    logfile = "logs/access.log"
+
+    --
+    -- Open logfile for appending.
+    --
+    file = io.open( logfile , "a" );
+    if ( file ~= nil ) then
+        file:write( log .. "\n" );
+        file:close();
+    else
+        print( "WARNING : Unable to open logfile for writing : " .. logfile );
+    end
+
+    print( log );
+end
+
+--
+-----
+---
+--
+--  This is the start of the real code.  Now that our functions have been
+-- defined we actually execute from this point onwards.
+--
+---
+----
+--
+
+--
+--  Setup the MIME types our server will use for serving files.
+--
+if ( fileExists( "/etc/mime.types" ) ) then
+    loadMimeFile( "/etc/mime.types",  mime );
+else
+    --
+    --  The global MIME types file does not exist.
+    --  Setup minimal defaults.
+    --
+--    print( "WARNING: /etc/mime.types could not be read." );
+--    print( "         Running with minimal MIME types." );
+
+    -- TODO: lua scripts can be able to set content type
+    mime[ "lua" ]  = "text/html";
+    mime[ "xml" ]  = "application/xml";
+    mime[ "html"]  = "text/html";
+    mime[ "txt" ]  = "text/plain";
+    mime[ "js"  ]  = "text/plain";
+    mime[ "css" ]  = "text/css";
+    mime[ "jpg" ]  = "image/jpeg";
+    mime[ "jpeg"]  = "image/jpeg";
+    mime[ "gif" ]  = "image/gif";
+    mime[ "png" ]  = "image/png";
+    mime[ "dat" ]  = "application/octet-stream";
+end
+
+function checkIface(name)
+	local ret = os.execute("ifconfig " .. name .. " > /dev/null");
+	if ret ~= 0 then
+	    return (nil);
+	end
+	return (true);
+end
+--[[
+        <create>
+            <exec order="1">ifconfig wlan0 ether `kenv WAN_MAC_ADDR`</exec>
+            <exec order="2">ifconfig lan0 ether `kenv WAN_MAC_ADDR`</exec>
+            <exec order="3">ifconfig bridge0 create addm lan0 addm wlan0 up</exec>
+        </create>
+        <init>
+            <exec order="1">ifconfig bridge0</exec>
+        </init>
+]]
+
+function doexec(c, path)
+    if ((not c) or (not path)) then
+	return (nil);
+    end
+
+    local block = c:getNode(path);
+
+    if not block then
+	return (nil);
+    end
+
+    local function execone(c, path)
+	local exec = c:getNode(path);
+	if exec then
+	    exec = exec:value();
+	    if exec then
+		print("Run:" .. exec)
+		print(exec_output(exec));
+	    end
+	end
+    end
+
+    for i = 1,16,1 do
+	execone(c, path .. ".exec[" .. i .. "]");
+    end
+
+    return (true);
+
+end
+
+
+function configure_lan(c)
+
+    local function config_iface(c, name)
+        if not checkIface(name) then
+	    doexec(c, "interfaces." .. name ..".create");
+	end
+	doexec(c, "interfaces." .. name ..".init");
+
+	ipnode = c:getNode("interfaces." .. name .. ".ipaddr");
+	if (ipnode) then
+	    local ip = ipnode:value();
+	    if ip then
+		local cmd = "ifconfig " .. name .. " " .. " inet " .. ip;
+		print("Run:" .. cmd)
+		print(exec_output(cmd));
+	    end
+	end
+    end
+
+    config_iface(c, "lan0");
+    config_iface(c, "wlan0");
+    config_iface(c, "bridge0");
+
+end
+
+mpd = 0;
+
+function configure_mpd_link(c, path, bundle, link)
+    if mpd == 0 then
+	mpd = MPD:new(c, "127.0.0.1", 5005);
+    end
+
+--    local bundle = "PPP";
+--    local path = "interfaces.wan0.PPP";
+
+    mpd:config_bundle(path, bundle);
+    mpd:config_link(path, link, bundle);
+end
+
+function run_dhclient(c, iface)
+    local path = "interfaces." .. iface .. ".Static";
+
+    -- return if no iface.Static node.
+    if not c:getNode(path) then
+	return (nil);
+    end
+
+    -- return if Static mode not enabled.
+    if c:getNode(path):attr("enable") ~= "true" then
+	return (nil);
+    end
+
+    -- return if no DHCP enabled.
+    local dhcp = c:getNode(path .. ".dhcp");
+    if not dhcp or dhcp:attr("enable") ~= "true" then
+	return (nil);
+    end
+
+    -- Run dhclient
+    print("Run dhclient on " .. iface);
+    os.execute(string.format("kill `cat /var/run/dhclient.%s.pid`", iface));
+
+    -- Do not execute dhclient if interface is down
+    if exec_output("ifconfig -v " .. iface .." | grep 'status: active'") ~= "" then
+	os.execute(string.format("/sbin/dhclient -b %s", iface));
+	-- XXX, hack to "unplumb" iface if it was not up on boot
+	os.execute(string.format("ifconfig %s `ifconfig %s | grep 'ether '`", iface, iface));
+    end
+end
+
+
+function configure_wan(c)
+    -- TODO: auto enumerate wan links
+    --[[
+kldload ng_nat
+kldload ng_ipfw
+
+ngctl mkpeer ipfw: nat 60 out
+ngctl name ipfw:60 nat
+ngctl connect ipfw: nat: 61 in
+ngctl msg nat: setaliasaddr 192.168.101.204
+
+ipfw add 98 netgraph 61 all from any to any in via wan0
+ipfw add 99 netgraph 60 all from any to any out via wan0
+
+sysctl net.inet.ip.fw.one_pass=0
+    ]]
+
+    kldload({"ng_nat", "ng_ipfw"});
+    sysctl("net.inet.ip.fw.one_pass", 0);
+
+    local sub = "";
+    for _, sub in ipairs({"Static", "PPPoE", "PPP", "PTPP", "L2TP"}) do
+	print("sub=" .. sub);
+	local path = "interfaces.wan0." .. sub;
+	local ifnode = c:getNode(path);
+
+	if ifnode and ifnode:attr("enable") == "true" then
+	    local subtype = c:getNode(path):attr("type");
+	    print("subtype=" .. subtype);
+	    if (subtype == "l2tp") then
+		-- TODO: multilink have different link names
+	    elseif (subtype == "pppoe") then
+		kldload({"ng_pppoe"});
+		os.execute("sleep 1");
+		configure_mpd_link(c, path, sub, sub);
+		-- Add interface to route select logic
+		r.route:f(sub,
+		    safeValue(c, path .. ".group", "WAN"),
+		    safeValue(c, path .. ".cost", "1000") - 0,
+		    "down",
+		    "LINKDOWN")
+	    elseif (subtype == "pptp") then
+		-- TODO: multilink have different link names
+	    elseif (subtype == "modem") then
+		kldload({"umodem", "u3g"});
+		os.execute("sleep 1");
+		configure_mpd_link(c, path, sub, sub);
+		r.route:f(sub,
+		    safeValue(c, path .. ".group", "WAN"),
+		    safeValue(c, path .. ".cost", "1000") - 0,
+		    "down",
+		    "LINKDOWN")
+	    elseif (subtype == "hw") then
+		local dev = c:getNode(path .. ".device"):value();
+		local dhcp = c:getNode(path .. ".dhcp");
+		local dhcpenabled = 0;
+		if dhcp and dhcp:attr("enable") == "true" then
+			dhcpenabled = true;
+		end
+
+		os.execute(string.format("ifconfig %s up", dev));
+		r.route:f(sub,
+		    safeValue(c, path .. ".group", "WAN"),
+		    safeValue(c, path .. ".cost", "1000") - 0,
+		    "up",
+		    "LINKDOWN")
+
+    		local query = "cmd=event";
+        	query = query .. "&state=up";
+        	query = query .. "&iface=" .. 	urlEncode(dev);
+        	query = query .. "&gw=" .. 	urlEncode(c:getNode(path .. ".gateway"):value());
+        	query = query .. "&ip=" .. 	urlEncode(c:getNode(path .. ".ipaddr"):value());
+        	query = query .. "&netmask=" .. urlEncode(c:getNode(path .. ".ipaddr"):value());
+    		query = query .. "&dns1=" .. 	urlEncode(c:getNode(path .. ".dns1"):value());
+    		query = query .. "&dns2=" .. 	urlEncode(c:getNode(path .. ".dns2"):value());
+
+		-- Call collector, to let him know about static config, and assign route+dns's
+		cmdline = "fetch -qo - \"http://127.0.0.1:8/event.xml?" .. query .. "\"";
+    		print("Exec: " .. cmdline);
+    		os.execute(cmdline);
+
+		-- Config static first
+		local ip = c:getNode(path .. ".ipaddr"):value();
+		local dhcp = c:getNode(path .. ".dhcp");
+		print("Run: \"ifconfig " .. dev .. " " .. ip .. "\"");
+		if os.execute(string.format("ifconfig %s %s", dev, ip)) ~= 0 then
+		    print("\"ifconfig " .. dev .. " " .. ip .. "\" - failed");
+		end
+
+		run_dhclient(c, dev); -- if DHCP enabled.
+
+		-- XXX temporary FIX for wan0 with static address
+		-- if not dhcpenabled and dev == "wan0" then
+		    os.execute(string.format("route add default %s",
+			c:getNode(path .. ".gateway"):value()));
+		-- end
+
+
+		local nat = c:getNode(path .. ".nat");
+		if nat and nat:attr("enable") == "true" then
+		    local ip = c:getNode(path .. ".ipaddr"):value();
+		    ip = ip:gsub("/%d+", "");
+		    os.execute("ngctl mkpeer ipfw: nat 60 out");
+		    os.execute("ngctl name ipfw:60 wan0nat");
+		    os.execute("ngctl connect ipfw: wan0nat: 61 in");
+		    os.execute("ngctl msg wan0nat: setaliasaddr " .. ip);
+
+		    if dhcpenabled then
+			-- pass DHCP via iface
+			os.execute("ipfw add 96 allow all from any 67 to any 68 out via " .. dev);
+			os.execute("ipfw add 97 allow all from any 68 to any 67 out via " .. dev);
+		    end
+		    os.execute("ipfw add 98 netgraph 61 all from any to any in via " .. dev);
+		    os.execute("ipfw add 99 netgraph 60 all from any to any out via " .. dev);
+		else
+		    if dhcpenabled then
+			os.execute("ipfw delete 96");
+			os.execute("ipfw delete 97");
+		    end
+		    os.execute("ipfw delete 98");
+		    os.execute("ipfw delete 99");
+		end
+	    else
+		print("Unsupported interface type " .. subtype);
+	    end
+	else
+	    print("Skiping disabled iface " .. path);
+	end
+    end
+end
+
+dhcpd = 0;
+function start_dhcpd(c)
+    if c:getNode("dhcpd.instances.instance[1]"):attr("enable") == "true" then
+	if dhcpd == 0 then
+	    dhcpd = DHCPD:new(c, "dhcpd.instances.instance[1]");
+	end
+	dhcpd:make_conf();
+	dhcpd:write();
+	print("Start DHCPD");
+	dhcpd:run();
+    end
+end
+
+function getopt(args, opts)
+    i=1;
+    while i < table.getn(arg) do
+	if arg[i]:match("^-") then
+	    opts[arg[i]] = arg[i+1];
+	    i = i + 1;
+	end
+	i = i + 1;
+    end
+    return (opts);
+end
+
+function update_board_info(c)
+    for _, oid in pairs({"device.vendor", "device.model", "device.revision", "soc.vendor", "soc.model"}) do
+	n = c:getOrCreateNode("info." .. oid);
+	n:value(sysctl("hw." .. oid));
+	if not n:value() then
+	    n:value("__NO_DATA__");
+	end
+	print(tostring(oid) .. "=" .. n:value());
+    end
+end
+
+function safeValue(c, name, default)
+	node = c:getNode(name);
+	if not node then
+		if default then
+			return default;
+		else
+			return "";
+		end
+	end
+	return node:value();
+end
+
+function start_dnsmasq(c)
+	-- TODO: if DNS-Relay enabled
+	-- XXX: dnsmasq able to do DHCPD also
+	-- dhcp-range=[interface:<inter-face>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
+	-- # --domain=zrouter,192.168.0.100,192.168.0.200
+	-- # --dhcp-range=192.168.0.100,192.168.0.200,1h
+	-- # --dhcp-authoritative - don't wait for other DHCPDs
+	-- # --bogus-priv - NXDOMAIN for private nets
+	local_domain = "";
+	local_dhcp_range = "";
+	if c:getNode("dhcpd.instances.instance[1]"):attr("enable") == "true" then
+
+		dhcproot = "dhcpd.instances.instance[1].";
+		domain = safeValue(c, dhcproot .. "domain", "zrouter");
+		dltime = safeValue(c, dhcproot .. "default-lease-time", 3600);
+		mltime = safeValue(c, dhcproot .. "max-lease-time");
+		ranges = safeValue(c, dhcproot .. "range.start");
+		rangee = safeValue(c, dhcproot .. "range.end");
+
+		local_domain = " --domain=" .. domain .."," .. ranges .. "," .. rangee;
+		local_dhcp_range = " --dhcp-range=" .. ranges .. "," .. rangee .. "," .. dltime;
+
+	end
+	dnsmasq_cmd =
+	    "/sbin/dnsmasq" ..
+	    " -i bridge0" ..
+	    local_domain ..
+	    local_dhcp_range ..
+	    " --dhcp-authoritative" ..
+	    " --bogus-priv";
+
+	print("Start " .. dnsmasq_cmd);
+	os.execute(dnsmasq_cmd);
+end
+
+function start_hostapd(c)
+	if c:getNode("hostapd.instance[1]"):attr("enable") == "true" then
+		kldload({"wlan_xauth", "wlan_tkip", "wlan_ccmp"});
+		aproot = "hostapd.instance[1].";
+		driver = "bsd";
+		--        <ieee80211d>1</ieee80211d>
+		--        <country_code>UA</country_code>
+		channel = safeValue(c, aproot .. "channel", 6);
+		country_code = safeValue(c, aproot .. "country_code", "UA");
+		--        <interface>wlan0</interface>
+		interface = safeValue(c, aproot .. "interface", "wlan0");
+
+		commandline = string.format("ifconfig %s down",interface);
+		if os.execute(commandline) ~= 0 then
+		    print("Exec: " .. commandline .. " - FAILED");
+		end
+		commandline = string.format(
+		    "ifconfig %s country %s channel %s up",
+		    interface, country_code, channel);
+		if os.execute(commandline) ~= 0 then
+		    print("Exec: " .. commandline .. " - FAILED");
+		end
+		--        <macaddr_acl>0</macaddr_acl>
+		--        <auth_algs>1</auth_algs>
+		--        <debug>0</debug>
+		--        <hw_mode>g</hw_mode>
+		--        <ctrl_interface>/var/run/hostapd</ctrl_interface>
+		--        <ctrl_interface_group>wheel</ctrl_interface_group>
+		--        <ssid>zrouter</ssid>
+		ssid = safeValue(c, aproot .. "ssid", "zrouter");
+		--        <!-- Open -->
+		--        <wpa>0</wpa>
+		wpa = safeValue(c, aproot .. "wpa", 3);
+		--        <!-- WPA -->
+		--        <!-- <wpa>1</wpa> -->
+		--        <!-- RSN/WPA2 -->
+		-- <!-- <wpa>2</wpa> -->
+    		-- <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+		wpa_key_mgmt = safeValue(c, aproot .. "wpa_key_mgmt", "WPA-PSK");
+		wpa_passphrase = safeValue(c, aproot .. "wpa_passphrase", "freebsdmall");
+		wpa_pairwise = safeValue(c, aproot .. "wpa_pairwise", "CCMP");
+		ctrl_interface = "/var/run/hostapd";
+
+		-- # TARGET
+		-- interface=wlan0
+		-- driver=bsd
+		-- ssid=CACHEBOY_11N_1
+		-- wpa=3
+		-- wpa_key_mgmt=WPA-PSK
+		-- wpa_passphrase=Sysinit891234
+		-- wpa_pairwise=CCMP
+		-- ctrl_interface=/var/run/hostapd
+		hostapd_conf = "/tmp/hostapd." .. interface ..".conf";
+
+		hostapd_conf_data = 
+		    "interface=" ..		interface .. "\n" ..
+		    "driver=" ..		driver .. "\n" ..
+		    "country_code=" .. 		country_code .. "\n" ..
+		    "channel=" ..		channel .. "\n" ..
+		    "ssid=" ..			ssid .. "\n" ..
+		    "wpa=" ..			wpa .. "\n" ..
+		    "wpa_key_mgmt=" ..		wpa_key_mgmt .. "\n" ..
+		    "wpa_passphrase=" ..	wpa_passphrase .. "\n" ..
+		    "wpa_pairwise=" ..		wpa_pairwise .. "\n" ..
+		    "ctrl_interface=" ..	ctrl_interface .. "\n";
+
+		local f = assert(io.open(hostapd_conf, "w"));
+		f:write(hostapd_conf_data);
+		f:close();
+
+		hostapd_cmd = "/usr/sbin/hostapd -B " .. hostapd_conf;
+
+		print("Start " .. hostapd_cmd);
+		os.execute(hostapd_cmd);
+
+	end
+end
+
+function start_igmp_fwd(c)
+	if not c:getNode("igmp.instance[1]") then
+		return;
+	end
+	if c:getNode("igmp.instance[1]"):attr("enable") == "true" then
+		upif   = safeValue(c, aproot .. "up", "wan0");
+		downif = safeValue(c, aproot .. "down", "lan0");
+
+		cmd = "/etc/rc.d/ng_igmpproxy start " .. upif .. " " .. downif;
+
+		print("Start " .. cmd);
+		os.execute(cmd);
+	end
+end
+
+-- Globals
+config = {};	-- Unused now
+c = {}; 	-- XML tree from config.xml
+r = {};		-- Runtime varibles structure
+
+r.routes = {};
+r.routes["default"] = "127.0.0.1";
+r.routes["224.0.0.0/4"] = "-iface bridge0"
+r.tasks = {};
+r.tasks.step = 5; -- Seconds
+r.tasks.periodic = {};
+r.tasks.onetime  = {}; -- At some time
+r.tasks.countdown= {}; -- when counter expired
+r.ver = {};
+
+opts = {};
+opts["-P"] = "/var/run/httpd.pid";
+
+if arg then
+    opts = getopt(arg, opts);
+end
+
+-- Check pidfile
+dofile("lib/pidfile.lua");
+pidfile(opts["-P"]);
+
+
+print("Parse config ...");
+c = Conf:new(load_file("config.xml"));
+
+update_board_info(c);
+read_zrouter_version(r);
+read_rc_conf(r);
+
+print("Initialize board ...");
+
+print("Initialize route select logic ...");
+r.route = ROUTE:new(c, 0);
+
+print("Enable LAN ports ...");
+os.execute("/etc/rc.d/switchctl enablelan");
+print("Init LAN ...");
+configure_lan(c);
+
+print("Start DHCP/DNS Relay ...");
+start_dnsmasq(c);
+-- start_dhcpd(c);
+
+-- print("Init AP");
+-- ap = HOSTAPD:new(c, 1);
+-- ap:run();
+
+print("Init AP ...");
+start_hostapd(c);
+
+print("Init IGMP/Multicast forwarding ...");
+start_igmp_fwd(c);
+
+os.execute("ipfw add 100 allow ip from any to any via lo0");
+-- os.execute("ipfw add 200 deny ip from any to 127.0.0.0/8");
+-- os.execute("ipfw add 300 deny ip from 127.0.0.0/8 to any");
+
+-- Hide Web-UI from WAN links
+os.execute("ipfw add 400 allow tcp from any to me 80 via lan0");
+os.execute("ipfw add 500 allow tcp from any to me 80 via bridge0");
+-- TODO: If not enabled WAN administration
+os.execute("ipfw add 600 deny tcp from any to me 80");
+-- check w/ ipfw NAT-ed packets
+sysctl("net.inet.ip.forwarding", 1);
+sysctl("net.inet.ip.fastforwarding", 1);
+sysctl("net.inet.tcp.blackhole", 2);
+sysctl("net.inet.udp.blackhole", 0);
+sysctl("net.inet.icmp.drop_redirect", 1);
+sysctl("net.inet.icmp.log_redirect", 0);
+sysctl("net.inet.ip.redirect", 0);
+sysctl("net.inet.ip.sourceroute", 0);
+sysctl("net.inet.ip.accept_sourceroute", 0);
+sysctl("net.inet.icmp.bmcastecho", 0);
+sysctl("net.inet.icmp.maskrepl", 0);
+sysctl("net.link.ether.inet.max_age", 30);
+sysctl("net.inet.ip.ttl", 226);
+sysctl("net.inet.tcp.drop_synfin", 1);
+sysctl("net.inet.tcp.syncookies", 1);
+-- sysctl("kern.ipc.somaxconn", 32768);
+-- sysctl("kern.maxfiles", 204800);
+-- sysctl("kern.maxfilesperproc", 200000);
+-- ??? -- sysctl("kern.ipc.nmbclusters", 524288);
+-- sysctl("kern.ipc.maxsockbuf", 2097152);
+sysctl("kern.random.sys.harvest.ethernet", 0);
+sysctl("kern.random.sys.harvest.interrupt", 0);
+-- sysctl("net.inet.ip.dummynet.io_fast", 1);
+-- sysctl("net.inet.ip.dummynet.max_chain_len", 2048);
+-- sysctl("net.inet.ip.dummynet.hash_size", 65535);
+-- sysctl("net.inet.ip.dummynet.pipe_slot_limit", 2048);
+-- ?? -- sysctl("net.inet.carp.preempt", 1);
+-- ?? -- sysctl("net.inet.carp.log", 2);
+-- ?? -- sysctl("kern.ipc.shmmax", 67108864);
+sysctl("net.inet.ip.intr_queue_maxlen", 8192);
+sysctl("net.inet.ip.fw.one_pass", 0);
+sysctl("net.inet.ip.portrange.randomized", 0);
+sysctl("net.inet.tcp.nolocaltimewait", 1);
+
+racoon = 0;
+if racoon == 0 then
+	racoon = RACOON:new(c);
+end
+
+-- WAN links tasks
+table.insert(r.tasks.countdown, { count=2, task=
+	function()
+	    print("Init WAN links ...");
+	    configure_wan(c);
+	    return (true);
+	end
+    });
+-- IPSec links tasks
+table.insert(r.tasks.countdown, { count=10, task=
+	function()
+	    print("Run racoon ...");
+	    racoon:run();
+	    return (true);
+	end
+    });
+
+print("Run server ...");
+start_server( c, config );
+
+
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/httpd.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/httpd.sh	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+
+cd /etc/www
+
+echo $$ > /var/run/httpd.sh.pid
+
+./httpd.lua > /var/log/httpd.sh.log 2>&1
+echo -n "./httpd.lua exit with status code $? at " >> /var/log/httpd.sh.log 2>&1
+date >> /var/log/httpd.sh.log 2>&1
+echo "./httpd.lua exit " > /dev/console
+exit 1
+
+while true; do
+    ./httpd.lua
+done
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/base64.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/base64.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,35 @@
+
+
+
+-- encoding
+function b64enc(data)
+    local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+    return ((data:gsub('.', function(x)
+        local r,b='',x:byte()
+        for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
+        return r;
+    end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
+        if (#x < 6) then return '' end
+        local c=0
+        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
+        return b:sub(c+1,c+1)
+    end)..({ '', '==', '=' })[#data%3+1])
+end
+
+-- decoding
+function b64dec(data)
+    local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+    data = string.gsub(data, '[^'..b..'=]', '')
+    return (data:gsub('.', function(x)
+        if (x == '=') then return '' end
+        local r,f='',(b:find(x)-1)
+        for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
+        return r;
+    end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
+        if (#x ~= 8) then return '' end
+        local c=0
+        for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
+        return string.char(c)
+    end))
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/bit.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/bit.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,29 @@
+function bit(p)
+    return 2 ^ (p - 1);
+    -- 1-based indexing
+end
+-- Typical call: if hasbit(x, bit(3)) then ...
+function hasbit(x, p)
+    return x % (p + p) >= p;
+end
+
+function setbit(x, p)
+    return hasbit(x, p) and x or x + p;
+end
+
+function clearbit(x, p)
+    return hasbit(x, p) and x - p or x;
+end
+
+-- &(0x12345678 & 0xfffff000) = 0x12345000
+function andL(x, y)
+    local o = 0;
+
+    for i = 1,32,1 do
+	if hasbit(x, bit(i)) and hasbit(y, bit(i)) then
+	    o = o + bit(i);
+	end
+    end
+
+    return (o);
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/conf.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/conf.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,158 @@
+-----------------------------------
+----------- Conf Class ------------
+-----------------------------------
+Conf = {};
+local mt = {};
+
+function Conf:new(s)
+    return setmetatable({ tree = s or '' }, mt)
+end
+
+function Conf:gettree()
+    return (self.tree);
+end
+
+function Conf:getNodeValue(path)
+    local node = self:getNode(path);
+    if type(node) == "table" then
+	return (node:value());
+    end
+    return (nil);
+end
+
+function Conf:getNode(path)
+    local function getNodeL(node, lpath)
+        local match, name, rpath, id = nil;
+	local matched = 0;
+
+	if not node then return (nil) end
+	if (not lpath) or (string.len(lpath) == 0) then
+	    return (node);
+	end
+
+	match, _, name, _, rpath = string.find(lpath, "^([%w%_%-%[%]]+)(%.*)(%S*)$");
+	if not match then
+	    print("Wrong lpath " .. lpath);
+	    return (nil);
+	end
+
+	rmatch, _, idname, id = string.find(name, "^([%w%_%-]+)%[(%d+)%]$");
+	if rmatch then
+	    name = idname;
+	end
+
+	if not name then
+	    print("Empty name");
+	    return (nil);
+	end
+
+	if node._children then
+    	    for _, v in ipairs(node._children) do
+    		if v._type == "ELEMENT" and v._name == name then
+    		    matched = matched + 1;
+    		    if (not id or (matched == tonumber(id))) then
+    			if string.len(rpath) > 0 then
+    			    return getNodeL(v, rpath);
+    			end
+    			return (v);
+    		    end
+    		end
+    	    end
+    	end
+	return (nil);
+    end
+
+    local ret = getNodeL(self.tree, path);
+    return (Node:new(ret, path));
+end
+
+--      node = { _name = <Element Name>,
+--              _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD,
+--              _attr = { Node attributes - see callback API },
+--              _parent = <Parent Node>
+--              _children = { List of child nodes - ROOT/NODE only }
+--            }
+
+function createNode(_name, _type, _attr, _children, _parent)
+    -- TODO: check for "^(ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD)$"
+    if not _name or not _type then
+	print(_name or "(no name)", _type or "(no type)");
+
+	return (nil);
+    end
+
+    local t = {};
+    t._name = _name;
+    t._type = _type;
+    t._attr = _attr or {};
+    t._parent = _parent;
+    t._children = _children or {};
+    return (t);
+end
+
+function attachNode(parent, node)
+    if not parent or not node then
+	return (nil);
+    end
+
+    if not parent._children then
+	parent._children = {};
+    end
+
+    table.insert(parent._children, node);
+    node._parent = parent;
+
+    return (node);
+end
+
+function Conf:getOrCreateNode(path)
+    local node = self:getNode(path);
+    if node then
+	return (node);
+    end
+
+    node = self.tree;
+    for part in string.gmatch(path, "([^\.]+)%.?") do
+	local rmatch, _, idname, id = string.find(part, "^([%w%_%-]+)%[(%d+)%]$");
+	if rmatch then
+	    part = idname;
+	end
+
+	local matched = 0;
+	if type(node) == "table" and type(node._children) == "table" then
+    	    for _, v in ipairs(node._children) do
+
+    		if v._type == "ELEMENT" and v._name == part then
+		    matched = matched + 1;
+
+		    if id then
+			if id == matched then
+			    node = v;
+			    break;
+			end
+		    else
+			node = v;
+			break;
+		    end
+    		end
+    	    end
+    	end
+
+	if matched == 0 or (id and matched < tonumber(id)) then
+	    local new = createNode(part, "ELEMENT");
+	    attachNode(node, new);
+	    node = new;
+	end
+    end
+    return (Node:new(node, path));
+end
+
+function Conf:get(path)
+    print(tostring(self.tree), path);
+    return (path);
+end
+
+mt.__index = Conf;
+-----------------------------------
+-------- End of Conf Class --------
+-----------------------------------
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/dhcpd.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/dhcpd.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,106 @@
+--[[
+option domain-name "fugue.com";
+option domain-name-servers toccata.fugue.com;
+
+option subnet-mask 255.255.255.224;
+default-lease-time 600;
+max-lease-time 7200;
+
+
+subnet 192.5.5.0 netmask 255.255.255.224 {
+  range 192.5.5.26 192.5.5.30;
+  option name-servers bb.home.vix.com, gw.home.vix.com;
+  option domain-name "vix.com";
+  option routers 192.5.5.1;
+  option subnet-mask 255.255.255.224;
+  option broadcast-address 192.5.5.31;
+  default-lease-time 600;
+  max-lease-time 7200;
+}
+
+host fantasia {
+  hardware ethernet 08:00:07:26:c0:a5;
+  fixed-address fantasia.fugue.com;
+}
+]]
+
+require("ipcalc");
+
+DHCPD = {};
+local mt = {};
+
+--DHCPD.instances.instance[1]
+
+
+function DHCPD:new(c, path, debug)
+    t = {};
+    t.path = path;
+    t.c = c;
+    t.iface = c:getNode(path .. "." .. "interface"):value()
+    t.configfile = "/tmp/dhcpd_" .. t.iface .. ".conf";
+    t.pidfile = "/tmp/dhcpd_" .. t.iface .. ".pid";
+    t.debug = debug;
+    return setmetatable(t, mt);
+end
+
+function DHCPD:make_conf()
+
+    self.get  = function (var      ) return self.c:getNode(self.path .. "." .. var):value()    end;
+    self.attr = function (var, attr) return self.c:getNode(self.path .. "." .. var):attr(attr) end;
+    self.conf_data = "";
+
+    local function a(txt)
+	if not txt then
+	    return (nil);
+	end
+	self.conf_data = self.conf_data .. txt .. "\n";
+	if self.debug then print(txt); end
+    end
+
+
+
+
+    local function perhost(name, macaddr, ip)
+	return  "host " .. name .." {\n\thardware ethernet " .. macaddr ..
+	    ";\n\tfixed-address " .. ip ..";\n}\n";
+    end
+--    for i = 1,16,1 do
+--	-- TODO: static entrys
+--    end
+
+    local if_ipaddr = self.c:getNode("interfaces." .. self.iface .. ".ipaddr"):value();
+    local r = cidr_to_net(if_ipaddr);
+    a("option domain-name \"".. self.get("domain") .."\";");
+    a("option domain-name-servers " .. r.ip ..";");
+    a("default-lease-time " .. self.get("default-lease-time") ..";");
+    a("max-lease-time ".. self.get("max-lease-time") ..";");
+    a("subnet " .. r.net .." netmask " .. r.mask .." {");
+    a("\trange " .. self.get("range.start") .. " " .. self.get("range.end") ..";");
+    a("\toption routers " .. r.ip ..";");
+    a("\toption broadcast-address " .. r.broadcast ..";");
+    a("}");
+
+end
+
+function DHCPD:write()
+
+    local f = assert(io.open(self.configfile, "w"));
+    f:write(self.conf_data);
+    f:close();
+end
+
+function DHCPD:run()
+
+    os.execute("mkdir -p /var/run/");
+    os.execute("mkdir -p /var/db/");
+    os.execute("touch /var/db/dhcpd.leases");
+    os.execute("/sbin/dhcpd -lf /var/db/dhcpd.leases -cf " .. self.configfile .. " " .. self.iface);
+end
+
+function DHCPD:stop()
+
+    os.execute("kill `cat /var/run/dhcpd.pid`");
+end
+
+mt.__index = DHCPD;
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/handler.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/handler.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,305 @@
+---
+--  Overview:
+--  =========
+--      Standard XML event handler(s) for XML parser module (xml.lua)
+--
+--  Features:
+--  =========
+--      printHandler        - Generate XML event trace
+--      domHandler          - Generate DOM-like node tree
+--      simpleTreeHandler   - Generate 'simple' node tree
+--
+--  API:
+--  ====
+--      Must be called as handler function from xmlParser
+--      and implement XML event callbacks (see xmlParser.lua
+--      for callback API definition)
+--
+--      printHandler:
+--      -------------
+--
+--      printHandler prints event trace for debugging
+--
+--      domHandler:
+--      -----------
+--
+--      domHandler generates a DOM-like node tree  structure with
+--      a single ROOT node parent - each node is a table comprising
+--      fields below.
+--
+--      node = { _name = <Element Name>,
+--              _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD,
+--              _attr = { Node attributes - see callback API },
+--              _parent = <Parent Node>
+--              _children = { List of child nodes - ROOT/NODE only }
+--            }
+--
+--      The dom structure is capable of representing any valid XML document
+--
+--      simpleTreeHandler
+--      -----------------
+--
+--      simpleTreeHandler is a simplified handler which attempts
+--      to generate a more 'natural' table based structure which
+--      supports many common XML formats.
+--
+--      The XML tree structure is mapped directly into a recursive
+--      table structure with node names as keys and child elements
+--      as either a table of values or directly as a string value
+--      for text. Where there is only a single child element this
+--      is inserted as a named key - if there are multiple
+--      elements these are inserted as a vector (in some cases it
+--      may be preferable to always insert elements as a vector
+--      which can be specified on a per element basis in the
+--      options).  Attributes are inserted as a child element with
+--      a key of '_attr'.
+--
+--      Only Tag/Text & CDATA elements are processed - all others
+--      are ignored.
+--
+--      This format has some limitations - primarily
+--
+--      * Mixed-Content behaves unpredictably - the relationship
+--        between text elements and embedded tags is lost and
+--        multiple levels of mixed content does not work
+--      * If a leaf element has both a text element and attributes
+--        then the text must be accessed through a vector (to
+--        provide a container for the attribute)
+--
+--      In general however this format is relatively useful.
+--
+--      It is much easier to understand by running some test
+--      data through 'textxml.lua -simpletree' than to read this)
+--
+--  Options
+--  =======
+--      simpleTreeHandler.options.noReduce = { <tag> = bool,.. }
+--
+--          - Nodes not to reduce children vector even if only
+--            one child
+--
+--      domHandler.options.(comment|pi|dtd|decl)Node = bool
+--
+--          - Include/exclude given node types
+--
+--  Usage
+--  =====
+--      Pased as delegate in xmlParser constructor and called
+--      as callback by xmlParser:parse(xml) method.
+--
+--      See textxml.lua for examples
+--  License:
+--  ========
+--
+--      This code is freely distributable under the terms of the Lua license
+--      (<a href="http://www.lua.org/copyright.html">http://www.lua.org/copyright.html</a>)
+--
+--  History
+--  =======
+--  $Id: handler.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $
+--
+--  $Log: handler.lua,v $
+--  Revision 1.1.1.1  2001/11/28 06:11:33  paulc
+--  Initial Import
+-- at author Paul Chakravarti (paulc at passtheaardvark.com)<p/>
+
+
+---Handler to generate a string prepresentation of a table
+--Convenience function for printHandler (Does not support recursive tables).
+-- at param t Table to be parsed
+-- at returns Returns a string representation of table
+function showTable(t)
+    local sep = ''
+    local res = ''
+    if type(t) ~= 'table' then
+        return t
+    end
+    for k,v in pairs(t) do
+        if type(v) == 'table' then
+            v = showTable(v)
+        end
+        res = res .. sep .. string.format("%s=%s",k,v)
+        sep = ','
+    end
+    res = '{'..res..'}'
+    return res
+end
+
+---Handler to generate a simple event trace
+printHandler = function()
+    local obj = {}
+    obj.starttag = function(self,t,a,s,e)
+        io.write("Start    : "..t.."\n")
+        if a then
+            for k,v in pairs(a) do
+                io.write(string.format(" + %s='%s'\n",k,v))
+            end
+        end
+    end
+    obj.endtag = function(self,t,s,e)
+        io.write("End      : "..t.."\n")
+    end
+    obj.text = function(self,t,s,e)
+        io.write("Text     : "..t.."\n")
+    end
+    obj.cdata = function(self,t,s,e)
+        io.write("CDATA    : "..t.."\n")
+    end
+    obj.comment = function(self,t,s,e)
+        io.write("Comment  : "..t.."\n")
+    end
+    obj.dtd = function(self,t,a,s,e)
+        io.write("DTD      : "..t.."\n")
+        if a then
+            for k,v in pairs(a) do
+                io.write(string.format(" + %s='%s'\n",k,v))
+            end
+        end
+    end
+    obj.pi = function(self,t,a,s,e)
+        io.write("PI       : "..t.."\n")
+        if a then
+            for k,v in pairs(a) do
+               io. write(string.format(" + %s='%s'\n",k,v))
+            end
+        end
+    end
+    obj.decl = function(self,t,a,s,e)
+        io.write("XML Decl : "..t.."\n")
+        if a then
+            for k,v in pairs(a) do
+                io.write(string.format(" + %s='%s'\n",k,v))
+            end
+        end
+    end
+    return obj
+end
+
+---Handler to generate a lua table from a XML content string
+function simpleTreeHandler()
+    local obj = {}
+
+    obj.root = {}
+    obj.stack = {obj.root;n=1}
+    obj.options = {noreduce = {}}
+
+    obj.reduce = function(self,node,key,parent)
+        -- Recursively remove redundant vectors for nodes
+        -- with single child elements
+        for k,v in pairs(node) do
+            if type(v) == 'table' then
+                self:reduce(v,k,node)
+            end
+        end
+        if table.getn(node) == 1 and not self.options.noreduce[key] and
+            node._attr == nil then
+            parent[key] = node[1]
+        else
+            node.n = nil
+        end
+    end
+
+    obj.starttag = function(self,t,a)
+        local node = {}
+        if self.parseAttributes == true then
+           node._attr=a
+        end
+
+        local current = self.stack[table.getn(self.stack)]
+        if current[t] then
+            table.insert(current[t],node)
+        else
+            current[t] = {node;n=1}
+        end
+        table.insert(self.stack,node)
+    end
+
+    obj.endtag = function(self,t,s)
+        local current = self.stack[table.getn(self.stack)]
+        local prev = self.stack[table.getn(self.stack)-1]
+        if not prev[t] then
+            error("XML Error - Unmatched Tag ["..s..":"..t.."]\n")
+        end
+        if prev == self.root then
+            -- Once parsing complete recursively reduce tree
+            self:reduce(prev,nil,nil)
+        end
+        table.remove(self.stack)
+    end
+
+    obj.text = function(self,t)
+        local current = self.stack[table.getn(self.stack)]
+        table.insert(current,t)
+    end
+
+    obj.cdata = obj.text
+
+    return obj
+end
+
+--- domHandler
+function domHandler()
+    local obj = {}
+    obj.options = {commentNode=1,piNode=1,dtdNode=1,declNode=1}
+    obj.root = { _children = {n=0}, _type = "ROOT" }
+    obj.current = obj.root
+    obj.starttag = function(self,t,a)
+            local node = { _type = 'ELEMENT',
+                           _name = t,
+                           _attr = a,
+                           _parent = self.current,
+                           _children = {n=0} }
+            table.insert(self.current._children,node)
+            self.current = node
+    end
+    obj.endtag = function(self,t,s)
+            if t ~= self.current._name then
+                error("XML Error - Unmatched Tag ["..s..":"..t.."]\n")
+            end
+            self.current = self.current._parent
+    end
+    obj.text = function(self,t)
+            local node = { _type = "TEXT",
+                           _parent = self.current,
+                           _text = t }
+            table.insert(self.current._children,node)
+    end
+    obj.comment = function(self,t)
+            if self.options.commentNode then
+                local node = { _type = "COMMENT",
+                               _parent = self.current,
+                               _text = t }
+                table.insert(self.current._children,node)
+            end
+    end
+    obj.pi = function(self,t,a)
+            if self.options.piNode then
+                local node = { _type = "PI",
+                               _name = t,
+                               _attr = a,
+                               _parent = self.current }
+                table.insert(self.current._children,node)
+            end
+    end
+    obj.decl = function(self,t,a)
+            if self.options.declNode then
+                local node = { _type = "DECL",
+                               _name = t,
+                               _attr = a,
+                               _parent = self.current }
+                table.insert(self.current._children,node)
+            end
+    end
+    obj.dtd = function(self,t,a)
+            if self.options.dtdNode then
+                local node = { _type = "DTD",
+                               _name = t,
+                               _attr = a,
+                               _parent = self.current }
+                table.insert(self.current._children,node)
+            end
+    end
+    obj.cdata = obj.text
+    return obj
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/hostapd.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/hostapd.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,143 @@
+--[[
+ieee80211d=1
+country_code=UA
+interface=wlan0
+macaddr_acl=0
+auth_algs=1
+debug=1
+hw_mode=g
+ctrl_interface=/var/run/hostapd
+ctrl_interface_group=wheel
+ssid=freebsdap
+wpa=2
+wpa_passphrase=freebsdmall
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP TKIP
+
+<hostapd>
+    <instance id="0" enable="true">
+        <ieee80211d>1</ieee80211d>
+        <country_code>UA</country_code>
+        <interface>wlan0</interface>
+        <macaddr_acl>0</macaddr_acl>
+        <auth_algs>1</auth_algs>
+        <debug>0</debug>
+        <hw_mode>g</hw_mode>
+        <ctrl_interface>/var/run/hostapd</ctrl_interface>
+        <ctrl_interface_group>wheel</ctrl_interface_group>
+        <ssid>DIR-620</ssid>
+        <!-- Open -->
+        <wpa>0</wpa>
+        <!-- WPA -->
+        <!-- <wpa>1</wpa> -->
+        <!-- RSN/WPA2 -->
+        <!-- <wpa>2</wpa> -->
+    </instance>
+    <instance id="1" enable="false">
+        <ieee80211d>1</ieee80211d>
+        <country_code>UA</country_code>
+        <interface>wlan0</interface>
+        <macaddr_acl>0</macaddr_acl>
+        <auth_algs>1</auth_algs>
+        <debug>0</debug>
+        <hw_mode>g</hw_mode>
+        <ctrl_interface>/var/run/hostapd</ctrl_interface>
+        <ctrl_interface_group>wheel</ctrl_interface_group>
+        <ssid>DIR-620</ssid>
+        <!-- WPA -->
+        <!-- <wpa>1</wpa> -->
+        <!-- RSN/WPA2 -->
+        <wpa>2</wpa>
+        <wpa_passphrase>freebsdmall</wpa_passphrase>
+        <wpa_key_mgmt>WPA-PSK</wpa_key_mgmt>
+        <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+    </instance>
+</hostapd>
+
+]]
+
+HOSTAPD = {};
+local mt = {};
+
+--hostapd.instance[1]
+
+
+function HOSTAPD:new(c, debug)
+    t = {};
+    t.c = c;
+    t.debug = debug;
+    t.configfile = {};
+    t.conf_data = {};
+    t.pidfile = "/var/run/hostapd.pid";
+    return setmetatable(t, mt);
+end
+
+function HOSTAPD:make_conf(i)
+
+    if self.debug == 1 then print("HOSTAPD:make_conf(".. tostring(i) .. ")"); end
+
+    local path = "hostapd.instance[" .. i .. "]";
+
+    self.conf_data[i] = "";
+
+    local function a(txt)
+	if not txt then
+	    return (nil);
+	end
+	self.conf_data[i] = self.conf_data[i] .. txt .. "\n";
+	if self.debug then print(txt); end
+    end
+
+	local iface = self.c:getNode(path .. ".interface"):value();
+	self.configfile[i] = "/tmp/hostapd_" .. iface .. ".conf";
+
+	a("ieee80211d=1");
+	a("country_code=UA");
+	a("interface=" .. iface);
+	a("macaddr_acl=0");
+	a("auth_algs=1");
+	a("debug=0");
+	a("hw_mode=g");
+	a("ctrl_interface=/var/run/hostapd");
+	a("ctrl_interface_group=wheel");
+	a("ssid=" .. self.c:getNode(path .. ".ssid"):value() .. "");
+	-- TODO: crypto support
+	a("wpa=2");
+	a("wpa_passphrase=freebsdmall");
+	a("wpa_key_mgmt=WPA-PSK");
+	a("wpa_pairwise=CCMP");
+
+end
+
+function HOSTAPD:write(i)
+
+    local f = assert(io.open(self.configfile[i], "w"));
+    f:write(self.conf_data[i]);
+    f:close();
+end
+
+function HOSTAPD:run()
+    local configs = "";
+    local i;
+    for i = 1,8,1 do
+	local vap = self.c:getNode("hostapd.instance[" .. i .. "]");
+	if vap and vap:attr("enable") == "true" then
+	    if self.debug == 1 then print("CALL self.make_conf(".. tostring(i) .. ")"); end
+	    self:make_conf(i);
+	    if self.debug == 1 then print("CALL self.write(".. tostring(i) .. ")"); end
+	    self:write(i);
+	    configs = configs .. " " .. self.configfile[i];
+	end
+    end
+
+    os.execute("mkdir -p /var/run/");
+    os.execute("/usr/sbin/hostapd -B -P " .. self.pidfile .. " " .. configs);
+end
+
+function HOSTAPD:stop()
+
+    os.execute("kill `cat " .. self.pidfile .."`");
+end
+
+mt.__index = HOSTAPD;
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/ipcalc.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/ipcalc.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,58 @@
+require("bit");
+
+function bits_to_hostmask(b)
+    return (2 ^ (32-b) - 1);
+end
+
+function bits_to_netmask(b)
+    return ((2 ^ 32 - 1) - bits_to_hostmask(b));
+end
+
+
+function cidr_to_net(cidr)
+    local r = {};
+    r.cidr	= cidr;
+
+    local function dotted(i)
+	local l1,l2,l3,r1,r2,r3,r4;
+	r1 =  i % 256; l1 =  i / 256;
+	r2 = l1 % 256; l2 = l1 / 256;
+	r3 = l2 % 256; l3 = l2 / 256;
+	r4 = l3 % 256;
+	return string.format("%d.%d.%d.%d", r4, r3, r2, r1);
+    end
+
+    local function toint(i1, i2, i3, i4)
+	return
+	    ((tonumber(i1) * (2^24)) +
+	     (tonumber(i2) * (2^16)) +
+	     (tonumber(i3) * ( 2^8)) +
+	     (tonumber(i4)         ));
+    end
+
+    local i1, i2, i3, i4;
+
+    i1, i2, i3, i4, r.bits = string.match(cidr, "^(%d+)%.(%d+)%.(%d+)%.(%d+)%/(%d+)$");
+
+    if r.bits then
+	r.ip = toint(i1, i2, i3, i4);
+    else
+	local i1, i2, i3, i4, m1, m2, m3, m4 = string.match(cidr,
+	    "^(%d+)%.(%d+)%.(%d+)%.(%d+)%/(%d+)%.(%d+)%.(%d+)%.(%d+)$");
+	if m4 then
+	    r.ip  = toint(i1, i2, i3, i4);
+	    r.net = toint(m1, m2, m3, m4);
+	else
+	    return nil, "Failed to parse";
+	end
+    end
+
+    r.mask 	= dotted(           bits_to_netmask (r.bits));
+    r.net 	= dotted(andL(r.ip, bits_to_netmask (r.bits)));
+    r.host 	= dotted(andL(r.ip, bits_to_hostmask(r.bits)));
+    r.broadcast = dotted(andL(r.ip, bits_to_netmask (r.bits)) + (2 ^ (32-r.bits) - 1) );
+    r.ip 	= dotted(     r.ip);
+
+    return r;
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/ltn12.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/ltn12.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,292 @@
+-----------------------------------------------------------------------------
+-- LTN12 - Filters, sources, sinks and pumps.
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module
+-----------------------------------------------------------------------------
+local string = require("string")
+local table = require("table")
+local base = _G
+module("ltn12")
+
+filter = {}
+source = {}
+sink = {}
+pump = {}
+
+-- 2048 seems to be better in windows...
+BLOCKSIZE = 2048
+_VERSION = "LTN12 1.0.1"
+
+-----------------------------------------------------------------------------
+-- Filter stuff
+-----------------------------------------------------------------------------
+-- returns a high level filter that cycles a low-level filter
+function filter.cycle(low, ctx, extra)
+    base.assert(low)
+    return function(chunk)
+        local ret
+        ret, ctx = low(ctx, chunk, extra)
+        return ret
+    end
+end
+
+-- chains a bunch of filters together
+-- (thanks to Wim Couwenberg)
+function filter.chain(...)
+    local n = table.getn(arg)
+    local top, index = 1, 1
+    local retry = ""
+    return function(chunk)
+        retry = chunk and retry
+        while true do
+            if index == top then
+                chunk = arg[index](chunk)
+                if chunk == "" or top == n then return chunk
+                elseif chunk then index = index + 1
+                else
+                    top = top+1
+                    index = top
+                end
+            else
+                chunk = arg[index](chunk or "")
+                if chunk == "" then
+                    index = index - 1
+                    chunk = retry
+                elseif chunk then
+                    if index == n then return chunk
+                    else index = index + 1 end
+                else base.error("filter returned inappropriate nil") end
+            end
+        end
+    end
+end
+
+-----------------------------------------------------------------------------
+-- Source stuff
+-----------------------------------------------------------------------------
+-- create an empty source
+local function empty()
+    return nil
+end
+
+function source.empty()
+    return empty
+end
+
+-- returns a source that just outputs an error
+function source.error(err)
+    return function()
+        return nil, err
+    end
+end
+
+-- creates a file source
+function source.file(handle, io_err)
+    if handle then
+        return function()
+            local chunk = handle:read(BLOCKSIZE)
+            if not chunk then handle:close() end
+            return chunk
+        end
+    else return source.error(io_err or "unable to open file") end
+end
+
+-- turns a fancy source into a simple source
+function source.simplify(src)
+    base.assert(src)
+    return function()
+        local chunk, err_or_new = src()
+        src = err_or_new or src
+        if not chunk then return nil, err_or_new
+        else return chunk end
+    end
+end
+
+-- creates string source
+function source.string(s)
+    if s then
+        local i = 1
+        return function()
+            local chunk = string.sub(s, i, i+BLOCKSIZE-1)
+            i = i + BLOCKSIZE
+            if chunk ~= "" then return chunk
+            else return nil end
+        end
+    else return source.empty() end
+end
+
+-- creates rewindable source
+function source.rewind(src)
+    base.assert(src)
+    local t = {}
+    return function(chunk)
+        if not chunk then
+            chunk = table.remove(t)
+            if not chunk then return src()
+            else return chunk end
+        else
+            table.insert(t, chunk)
+        end
+    end
+end
+
+function source.chain(src, f)
+    base.assert(src and f)
+    local last_in, last_out = "", ""
+    local state = "feeding"
+    local err
+    return function()
+        if not last_out then
+            base.error('source is empty!', 2)
+        end
+        while true do
+            if state == "feeding" then
+                last_in, err = src()
+                if err then return nil, err end
+                last_out = f(last_in)
+                if not last_out then
+                    if last_in then
+                        base.error('filter returned inappropriate nil')
+                    else
+                        return nil
+                    end
+                elseif last_out ~= "" then
+                    state = "eating"
+                    if last_in then last_in = "" end
+                    return last_out
+                end
+            else
+                last_out = f(last_in)
+                if last_out == "" then
+                    if last_in == "" then
+                        state = "feeding"
+                    else
+                        base.error('filter returned ""')
+                    end
+                elseif not last_out then
+                    if last_in then
+                        base.error('filter returned inappropriate nil')
+                    else
+                        return nil
+                    end
+                else
+                    return last_out
+                end
+            end
+        end
+    end
+end
+
+-- creates a source that produces contents of several sources, one after the
+-- other, as if they were concatenated
+-- (thanks to Wim Couwenberg)
+function source.cat(...)
+    local src = table.remove(arg, 1)
+    return function()
+        while src do
+            local chunk, err = src()
+            if chunk then return chunk end
+            if err then return nil, err end
+            src = table.remove(arg, 1)
+        end
+    end
+end
+
+-----------------------------------------------------------------------------
+-- Sink stuff
+-----------------------------------------------------------------------------
+-- creates a sink that stores into a table
+function sink.table(t)
+    t = t or {}
+    local f = function(chunk, err)
+        if chunk then table.insert(t, chunk) end
+        return 1
+    end
+    return f, t
+end
+
+-- turns a fancy sink into a simple sink
+function sink.simplify(snk)
+    base.assert(snk)
+    return function(chunk, err)
+        local ret, err_or_new = snk(chunk, err)
+        if not ret then return nil, err_or_new end
+        snk = err_or_new or snk
+        return 1
+    end
+end
+
+-- creates a file sink
+function sink.file(handle, io_err)
+    if handle then
+        return function(chunk, err)
+            if not chunk then
+                handle:close()
+                return 1
+            else return handle:write(chunk) end
+        end
+    else return sink.error(io_err or "unable to open file") end
+end
+
+-- creates a sink that discards data
+local function null()
+    return 1
+end
+
+function sink.null()
+    return null
+end
+
+-- creates a sink that just returns an error
+function sink.error(err)
+    return function()
+        return nil, err
+    end
+end
+
+-- chains a sink with a filter
+function sink.chain(f, snk)
+    base.assert(f and snk)
+    return function(chunk, err)
+        if chunk ~= "" then
+            local filtered = f(chunk)
+            local done = chunk and ""
+            while true do
+                local ret, snkerr = snk(filtered, err)
+                if not ret then return nil, snkerr end
+                if filtered == done then return 1 end
+                filtered = f(done)
+            end
+        else return 1 end
+    end
+end
+
+-----------------------------------------------------------------------------
+-- Pump stuff
+-----------------------------------------------------------------------------
+-- pumps one chunk from the source to the sink
+function pump.step(src, snk)
+    local chunk, src_err = src()
+    local ret, snk_err = snk(chunk, src_err)
+    if chunk and ret then return 1
+    else return nil, src_err or snk_err end
+end
+
+-- pumps all data from a source to a sink, using a step function
+function pump.all(src, snk, step)
+    base.assert(src and snk)
+    step = step or pump.step
+    while true do
+        local ret, err = step(src, snk)
+        if not ret then
+            if err then return nil, err
+            else return 1 end
+        end
+    end
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/mime.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/mime.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,87 @@
+-----------------------------------------------------------------------------
+-- MIME support for the Lua language.
+-- Author: Diego Nehab
+-- Conforming to RFCs 2045-2049
+-- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local ltn12 = require("ltn12")
+local mime = require("mime.core")
+local io = require("io")
+local string = require("string")
+module("mime")
+
+-- encode, decode and wrap algorithm tables
+encodet = {}
+decodet = {}
+wrapt = {}
+
+-- creates a function that chooses a filter by name from a given table
+local function choose(table)
+    return function(name, opt1, opt2)
+        if base.type(name) ~= "string" then
+            name, opt1, opt2 = "default", name, opt1
+        end
+        local f = table[name or "nil"]
+        if not f then
+            base.error("unknown key (" .. base.tostring(name) .. ")", 3)
+        else return f(opt1, opt2) end
+    end
+end
+
+-- define the encoding filters
+encodet['base64'] = function()
+    return ltn12.filter.cycle(b64, "")
+end
+
+encodet['quoted-printable'] = function(mode)
+    return ltn12.filter.cycle(qp, "",
+        (mode == "binary") and "=0D=0A" or "\r\n")
+end
+
+-- define the decoding filters
+decodet['base64'] = function()
+    return ltn12.filter.cycle(unb64, "")
+end
+
+decodet['quoted-printable'] = function()
+    return ltn12.filter.cycle(unqp, "")
+end
+
+local function format(chunk)
+    if chunk then
+        if chunk == "" then return "''"
+        else return string.len(chunk) end
+    else return "nil" end
+end
+
+-- define the line-wrap filters
+wrapt['text'] = function(length)
+    length = length or 76
+    return ltn12.filter.cycle(wrp, length, length)
+end
+wrapt['base64'] = wrapt['text']
+wrapt['default'] = wrapt['text']
+
+wrapt['quoted-printable'] = function()
+    return ltn12.filter.cycle(qpwrp, 76, 76)
+end
+
+-- function that choose the encoding, decoding or wrap algorithm
+encode = choose(encodet)
+decode = choose(decodet)
+wrap = choose(wrapt)
+
+-- define the end-of-line normalization filter
+function normalize(marker)
+    return ltn12.filter.cycle(eol, 0, marker)
+end
+
+-- high level stuffing filter
+function stuff()
+    return ltn12.filter.cycle(dot, 2)
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/mpd.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/mpd.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,315 @@
+-----------------------------------
+----------- MPD Class ------------
+-----------------------------------
+--[[
+
+create bundle static B1
+bundle B1
+
+set bundle links L1
+
+set iface addrs 1.1.1.1 2.2.2.2
+set iface route default
+set iface enable on-demand
+set iface idle 900
+set iface enable nat
+set iface up-script /etc/mpd5-up.sh
+set iface down-script /etc/mpd5-down.sh
+
+set ipcp ranges 0.0.0.0/0 0.0.0.0/0
+set ipcp enable req-pri-dns
+set ipcp enable req-sec-dns
+
+open iface
+
+
+
+create link static L1 modem
+create link static L1 pppoe
+create link static L1 pptp
+create link static L1 ltp
+
+set auth authname adbrd****@dsl.ukrtel.net
+set auth password *******
+
+set modem device /dev/cuaU0.0
+set modem var $DialPrefix "DT"
+set modem var $Telephone "#777"
+set modem var $TryPPPEarly "yes"
+set modem var $InitString "+CGDCONT=1,\"IP\",\"internet\""
+set modem script DialPeer
+set modem idle-script Ringback
+set modem watch -cd
+
+set pppoe iface nfe0
+set pppoe service ""
+
+set pptp self 10.1.3.3
+set pptp peer 10.1.0.1
+set pptp disable windowing
+
+set l2tp peer 10.10.10.10
+
+set link disable chap pap
+set link accept chap pap
+set link action bundle B1
+set link enable incoming
+set link max-redial 0
+set link mtu 1460
+set link keep-alive 10 60
+set link bandwidth 14194304
+
+open
+
+
+
+
+
+
+]]
+
+--require("sleep");
+
+MPD = {};
+mt = {};
+
+function MPD:new(tree, host, port, debug)
+	local t = {};
+	if not host or not port then
+		print("No host or port");
+		return (nil);
+	end
+
+--	t.socket = socket.connect(host, port);
+--	if not t.socket then
+--		print("Can't connect to " .. host .. ":" .. port);
+--		return (nil);
+--	end
+	t.host = host;
+	t.port = port;
+	t.c = tree;
+	t.debug = 1;
+	return setmetatable(t, mt);
+end
+
+function MPD:msg(s, wait)
+
+    if self.debug then print("DEBUG MPD:msg: " .. s); end
+    self.socket:settimeout(0.1);
+    self.socket:send(s .. "\n");
+
+    local err = nil;
+    local ret = "";
+--    while not err do
+	local data, err = self.socket:receive("*a");
+	ret = ret .. (data or "");
+--    end
+    if self.debug then print("DEBUG MPD:msg:return = [[" .. ret .. "]]"); end
+
+    return (ret);
+end
+
+function MPD:config_bundle(path, bundle)
+    local pathl = path .. ".";
+    local node;
+
+    self.socket = socket.connect(self.host, self.port);
+	if not self.socket then
+		print("Can't connect to " .. self.host .. ":" .. self.port);
+		return (nil);
+	end
+    -- Create or select bundle
+    self:msg("create bundle static " .. bundle);
+    self:msg("bundle " .. bundle);
+
+    -- Multilink only
+--    self:msg("set bundle links L1");
+
+    -- TODO
+--    local ip = c:getNode(pathl .. "ipaddr")
+--    if ip then
+--	string.match(ip:value(), "%d+%.%d+%.%d+%.%d+%/(%d+)")
+--    end
+
+    local def_local_addr = "0.0.0.0";
+    local def_perr_addr = "10.254.254.2";
+    if self.c:getNode(pathl .. "gateway"):value() then
+	def_perr_addr = self.c:getNode(pathl .. "gateway"):value();
+    end
+
+    self:msg("set iface addrs " .. def_local_addr .. " " .. def_perr_addr);
+    self:msg("set iface up-script /etc/mpd-linkup");
+    self:msg("set iface down-script /etc/mpd-linkdown");
+    self:msg("set ipcp ranges " .. def_local_addr .. "/0 " .. def_perr_addr .."/0");
+
+    -- We should apply default on a up-script run
+--     self:msg("set iface route default");
+
+    local dod = self.c:getNode(pathl .. "on-demand")
+    if dod and dod:attr("enable") == "true" then
+	self:msg("set iface enable on-demand");
+        self:msg("set iface idle " .. self.c:getNode(pathl .. "idle-time"):value());
+    end
+
+    self:msg("set iface name " .. bundle);
+
+    node = self.c:getNode(pathl .. "nat")
+    if node and node:attr("enable") == "true" then
+	self:msg("set iface enable nat");
+    end
+
+    self:msg("set ipcp enable req-pri-dns");
+    self:msg("set ipcp enable req-sec-dns");
+
+    self:msg("open iface");
+
+    self:msg("exit");
+    self.socket:close();
+
+    return (true);
+end
+
+function MPD:config_link(path, link, bundle)
+    local pathl = path .. ".";
+    self.socket = socket.connect(self.host, self.port);
+	if not self.socket then
+		print("Can't connect to " .. self.host .. ":" .. self.port);
+		return (nil);
+	end
+
+    local mpdtype = self.c:getNode(path);
+    if mpdtype and mpdtype:attr("type") then
+	mpdtype = mpdtype:attr("type");
+    else
+	return (nil);
+    end
+
+    self:msg("create link static " .. link .. " " .. mpdtype);
+    self:msg("link " .. link);
+
+    local user = self.c:getNode(pathl .. "username");
+    if user and user:value() and string.len(user:value()) > 0 then
+	self:msg("set auth authname " .. user:value());
+	local passwd = self.c:getNode(pathl .. "password");
+	if passwd and passwd:value() then
+	    self:msg("set auth password \"" .. passwd:value() .. "\"");
+	else
+	    self:msg("set auth password \"\"");
+	end
+    end
+
+    if mpdtype == "modem" then
+	self:msg("set modem device " ..
+	    self.c:getNode(pathl .. "device"):value() .. "");
+	self:msg("set modem var $DialPrefix \"DT\"");
+	-- Try to send PPP request, for cases when modem stick at data mode
+	-- Leased Line.
+	self:msg("set modem var $TryPPPEarly \"yes\"");
+	self:msg("set modem var $Telephone \"" ..
+	    self.c:getNode(pathl .. "phone"):value() .. "\"");
+	local initstring = self.c:getNode(pathl .. "init_string");
+	if initstring then -- If node
+	    initstring = initstring:value();
+	    if initstring and initstring ~= "" then -- If value not empty
+		-- Escape double quotes
+		initstring = initstring:gsub("\"", "\\\"");
+		print("set modem var $InitString \"" .. initstring .. "\"");
+		self:msg("set modem var $InitString \"" .. initstring .. "\"");
+	    end
+	end
+	self:msg("set modem script DialPeer");
+	self:msg("set modem idle-script Ringback");
+	self:msg("set modem watch -cd");
+    elseif mpdtype == "pppoe" then
+	self:msg("set pppoe iface " .. self.c:getNode(pathl .. "device"):value() .. "");
+	local service_node = self.c:getNode(pathl .. "service_name");
+	if service_node and service_node:value() then
+	    self:msg("set pppoe service \"" .. service_node:value() .. "\"");
+	end
+    elseif mpdtype == "pptp" then
+	-- TODO:
+	self:msg("set pptp self 10.1.3.3");
+	self:msg("set pptp peer 10.1.0.1");
+	self:msg("set pptp disable windowing");
+    end
+
+
+    -- TODO
+    self:msg("set link disable chap pap");
+    self:msg("set link accept chap pap");
+    self:msg("set link action bundle " .. bundle);
+    self:msg("set link enable incoming");
+    self:msg("set link max-redial 0");
+    self:msg("set link mtu 1460");
+    self:msg("set link keep-alive 10 60");
+--    self:msg("set link bandwidth 14194304");
+
+    -- Open link
+    self:msg("open");
+    self:msg("exit");
+    self.socket:close();
+
+
+
+    return (true);
+end
+
+function MPD:show_bundle(path, bundle)
+--    self.socket:refresh();
+    self.socket = socket.connect(self.host, self.port);
+
+    self:msg("bundle " .. bundle);
+    local info = self:msg("show bundle " .. bundle, 500);
+    self:msg("exit");
+    self.socket:close();
+
+    return (true);
+end
+
+function MPD:close()
+--    self.socket:close();
+end
+
+mt.__index = MPD;
+-----------------------------------
+-------- End of MPD Class --------
+-----------------------------------
+
+--[[
+Bundle 'PPP' (static):
+	Links          : PPP[Opened/UP]
+	Status         : OPEN
+	Session time   : 1119 seconds
+	MultiSession Id: 249-PPP
+	Total bandwidth: 28800 bits/sec
+	Avail bandwidth: 28800 bits/sec
+	Peer authname  : ""
+Configuration:
+	Retry timeout  : 2 seconds
+	BW-manage:
+	  Period       : 60 seconds
+	  Low mark     : 20%
+	  High mark    : 80%
+	  Min conn     : 30 seconds
+	  Min disc     : 90 seconds
+	  Links        :
+Bundle level options:
+	ipcp      	enable
+	ipv6cp    	disable
+	compression	disable
+	encryption	disable
+	crypt-reqd	disable
+	bw-manage 	disable
+	round-robin	disable
+Multilink PPP:
+	Status         : Inactive
+Traffic stats:
+	Input octets   : 1322
+	Input frames   : 19
+	Output octets  : 1270
+	Output frames  : 18
+	Bad protocols  : 0
+	Runts          : 0
+	Dup fragments  : 0
+	Drop fragments : 0
+]]
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/node.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/node.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,68 @@
+-----------------------------------
+----------- Node Class ------------
+-----------------------------------
+Node = {};
+mtNode = {};
+
+function Node:new(s, path)
+
+    if type(s) ~= "table" then return (nil); end
+    local node = setmetatable({ node = s or '' }, mtNode);
+    node.path = path;
+    return (node);
+end
+
+function Node:dump(f, v)
+    if self.node then
+	if (not f) or f == "txt" then
+	    if v then print("TEXT dump of \"" .. self.path .. "\"") end
+	    return tdump(self.node);
+	elseif f == "xml" then
+	    if v then print("XML dump of \"" .. self.path .. "\"") end
+	    return xmldump(self.node);
+	else
+	    print("Unknow format " .. f);
+	end
+    end
+end
+
+function Node:attr(attr, value)
+    if self.node._attr and type(self.node._attr) == "table" then
+	if value then
+	    self.node._attr[attr] = value;
+	    return (true);
+	else
+	    return (self.node._attr[attr] or "");
+	end
+    end
+    return (nil);
+end
+
+function Node:value(_value)
+    if self.node._children and
+	self.node._children[1] and
+	self.node._children[1]._text then
+
+	if _value then
+	    self.node._children[1]._text = _value;
+	    return (true);
+	else
+	    return (self.node._children[1]._text or "");
+	end
+
+    end
+
+    if _value then
+	if not self.node._children then
+	    self.node._children = {};
+	end
+	table.insert(self.node._children, { _text = _value, _type = "TEXT" });
+    end
+
+    return (nil);
+end
+
+mtNode.__index = Node;
+-----------------------------------
+-------- End of Node Class --------
+-----------------------------------
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/pidfile.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/pidfile.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,69 @@
+
+function readpid(pidfilename)
+    local pidfile = io.open(pidfilename, "r");
+    if pidfile then
+	local pid = assert(pidfile:read("*n"));
+	pidfile:close();
+	return (pid);
+    end
+    -- TODO: rise error on read/open failures
+    return (nil);
+end
+
+
+--
+-- check(pidfilename)
+-- check for pid file and runnig process
+-- return ( 1) if process runnning
+-- return (-1) if stale pid file
+-- return ( 0) if no pid file
+--
+
+function checkpid(pidfilename)
+    local oldpid = readpid(pidfilename);
+    if oldpid and oldpid > 0 then
+	local ret = os.execute("ps -axo command= " .. oldpid);
+	if ret == 0 then
+	    return (1); -- Process running
+	end
+	return (-1); -- Stale pid file, no process
+    end
+    return (0); -- No pid file found
+end
+
+--
+-- pidfile(pidfilename)
+-- check for runnig process and create new pid file otherwise
+-- if exit process if checked proccess running
+--
+
+function pidfile(pidfilename)
+    local psx = require("posix");
+    local pid = psx.getprocessid("pid");
+
+    if checkpid(pidfilename) == 1 then
+	print("pid file ".. pidfilename .. " locked")
+	os.exit(1);
+    end
+
+    pidfile = assert(io.open(pidfilename, "w"));
+    assert(pidfile:write(pid));
+    pidfile:close();
+
+    return (true);
+end
+
+
+function pidfile_signal(pidfilename, signal)
+    return (false);
+end
+
+--
+--
+-- Terminate running holder of pidfile, and write new pidfile
+--
+
+function pidfile_replace_stop()
+end
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/racoon.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/racoon.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,368 @@
+--[[
+
+file /etc/racoon/racoon.conf:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+path    pidfile  "/var/run/racoon.pid";
+path    pre_shared_key  "/var/db/racoon/racoon_psk.txt"; #location of pre-shared key file
+log     notify;  #log verbosity setting: set to 'notify' when testing and debugging is complete
+
+padding # options are not to be changed
+{
+        maximum_length  20;
+        randomize       off;
+        strict_check    off;
+        exclusive_tail  off;
+}
+
+timer   # timing options. change as needed
+{
+        counter         5;
+        interval        20 sec;
+        persend         1;
+#       natt_keepalive  15 sec;
+        phase1          30 sec;
+        phase2          15 sec;
+}
+
+listen  # address [port] that racoon will listening on
+{
+        isakmp          192.168.90.1 [500];
+        isakmp_natt     192.168.90.1 [4500];
+}
+
+include /var/run/racoon.links.conf
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+Generated /var/run/racoon.links.conf:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+include /var/run/racoon.10.0.0.2:500.conf
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+Generated /var/run/racoon.10.0.0.2:500.conf:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+remote  10.0.0.2 [500]
+{
+        exchange_mode   	main,aggressive;
+        doi             	ipsec_doi;
+        situation       	identity_only;
+        my_identifier   	address 10.0.0.1;
+        peers_identifier        address 10.0.0.2;
+        lifetime        	time 28800 sec;
+	initial_contact 	on;
+        passive         	off;
+        proposal_check  	obey;
+        generate_policy 	off;
+
+                        proposal {
+                                encryption_algorithm    3des;
+                                hash_algorithm          md5;
+                                authentication_method   pre_shared_key;
+                                dh_group                5;
+			}
+}
+sainfo  (address 192.168.0.0/24 any address 192.168.2.0/24 any)
+{
+	pfs_group			5;
+	lifetime			time 3600 sec;
+	encryption_algorithm		3des;
+	authentication_algorithm	hmac_md5;
+	compression_algorithm		deflate;
+}
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+usage: racoon [-BdFv] [-a (port)] [-f (file)] [-l (file)] [-p (port)]
+   -B: install SA to the kernel from the file specified by the configuration file.
+   -d: debug level, more -d will generate more debug message.
+   -C: dump parsed config file.
+   -L: include location in debug messages
+   -F: run in foreground, do not become daemon.
+   -v: be more verbose
+   -a: port number for admin port.
+   -f: pathname for configuration file.
+   -l: pathname for log file.
+   -p: port number for isakmp (default: 500).
+   -P: port number for NAT-T (default: 4500).
+
+<ipsec>
+    <remote id="0" enable="true">
+	<gateway>10.0.0.2:500</gateway>
+        <exchange_mode>main,aggressive</exchange_mode>
+        <my_identifier>address 10.0.0.1</my_identifier>
+        <peers_identifier>address 10.0.0.2</peers_identifier>
+        <lifetime>time 28800 sec</lifetime>
+	<initial_contact>on</initial_contact>
+        <passive>off</passive>
+        <proposal_check>obey</proposal_check>
+	<nat_traversal>off</nat_traversal>
+        <generate_policy>off</generate_policy>
+        <proposal>
+            <encryption_algorithm>3des</encryption_algorithm>
+            <hash_algorithm>md5</hash_algorithm>
+            <authentication_method>pre_shared_key</authentication_method>
+            <dh_group>5</dh_group>
+            <psk>pskpskpsk</psk>
+	</proposal>
+    </remote>
+    <sainfo id="0" enable="true">
+	<src>address 192.168.0.0/24 any</src>
+	<dst>address 192.168.2.0/24 any</dst>
+	<pfs_group>5</pfs_group>
+	<lifetime>time 3600 sec</lifetime>
+	<encryption_algorithm>3des</encryption_algorithm>
+	<authentication_algorithm>hmac_md5</authentication_algorithm>
+	<compression_algorithm>deflate</compression_algorithm>
+    </sainfo>
+    <setkey>
+	<line>spdadd 192.168.0.0/24 192.168.2.0/24 any -P out ipsec esp/tunnel/10.0.0.1-10.0.0.2/use</line>
+	<line>spdadd 192.168.2.0/24 192.168.0.0/24 any -P in ipsec esp/tunnel/10.0.0.2-10.0.0.1/use</line>
+	<line></line>
+	<line></line>
+    </setkey>
+</ipsec>
+
+
+]]
+
+-- require("ipcalc");
+
+RACOON = {};
+local mt = {};
+
+
+function RACOON:new(c, debug)
+    t = {};
+    t.c = c;
+    t.remote_count = 0;
+    t.pidfile = "/var/run/racoon.pid";
+    t.logfile = "/var/log/racoon.log";
+    t.configfile = "/etc/racoon/racoon.conf";
+    t.linksfile = "/var/run/racoon.links.conf";
+    t.psk = "/var/db/racoon/racoon_psk.txt";
+
+    t.debug = debug;
+    return setmetatable(t, mt);
+end
+
+function RACOON:make_conf()
+
+    -- Generate linksfile
+    local f = assert(io.open(self.linksfile, "w"));
+    for i = 1,16,1 do
+	local ppath = "ipsec.remote[" ..i.. "]";
+	local node = self.c:getNode(ppath);
+	if node and node:attr("enable") == "true" then
+	    local gw = self.c:getNode(ppath .. ".gateway"):value();
+	    if gw then
+		f:write("include \"/var/run/racoon." .. gw .. ".conf\";\n");
+		t.remote_count = t.remote_count + 1;
+	    else
+		print("Can't get " .. ppath .. ".gateway value");
+		return (nil);
+	    end
+	end
+    end
+    if self.remote_count == 0 then
+	-- No remote targets, so nothing todo
+	print("No remote targets, so nothing todo");
+	return (nil);
+    end
+
+    for i = 1,16,1 do
+	local ppath = "ipsec.sainfo[" ..i.. "]";
+	local node = self.c:getNode(ppath);
+	if node and node:attr("enable") == "true" then
+	    f:write("include \"/var/run/racoon.sainfo" .. i .. ".conf\";\n");
+	end
+    end
+    f:close();
+
+
+
+    local function addline(ppath, item, prep, confitem)
+	local ret = "";
+	    local val = self.c:getNode(ppath .. "." .. (confitem or item)):value();
+	    if val then
+		ret = (prep or "") .. item .. "\t" .. val .. ";\n";
+	    else
+		print("Can't get " .. ppath .. "." .. (confitem or item) .." value");
+	    end
+	return (ret);
+    end
+
+    -- XXX: We need setup routes per IPSec tunnel
+    local last_gw = nil;
+
+    for i = 1,16,1 do
+	local ppath = "ipsec.remote[" ..i.. "]";
+	local node = self.c:getNode(ppath);
+	if node and node:attr("enable") == "true" then
+	    local gw = self.c:getNode(ppath .. ".gateway"):value();
+	    local file = "/var/run/racoon." .. gw .. ".conf";
+	    local remote = gw:gsub(":", " [") .. "]";
+	    last_gw = gw:gsub(":.*", "");
+
+	    local conf = "remote\t" .. remote .. "\n";
+
+	    conf = conf .. "{\n";
+	    conf = conf .. addline(ppath, "exchange_mode"	, "\t");
+	    conf = conf .. "\tdoi	ipsec_doi;\n";
+	    conf = conf .. "\tsituation	identity_only;\n";
+	    conf = conf .. "\tscript \"/etc/racoon/phase1-up.sh\" phase1_up;\n";
+	    conf = conf .. "\tscript \"/etc/racoon/phase1-down.sh\" phase1_down;\n";
+
+	    conf = conf .. addline(ppath, "my_identifier"	, "\t");
+	    conf = conf .. addline(ppath, "peers_identifier"	, "\t");
+	    conf = conf .. addline(ppath, "lifetime"		, "\t");
+	    conf = conf .. addline(ppath, "initial_contact"	, "\t");
+	    conf = conf .. addline(ppath, "passive"		, "\t");
+	    conf = conf .. addline(ppath, "proposal_check"	, "\t");
+	    conf = conf .. addline(ppath, "generate_policy"	, "\t");
+	    conf = conf .. "\tproposal {\n";
+            conf = conf .. addline(ppath, "encryption_algorithm", "\t\t", "proposal.encryption_algorithm");
+            conf = conf .. addline(ppath, "hash_algorithm"	, "\t\t", "proposal.hash_algorithm");
+            conf = conf .. addline(ppath, "authentication_method","\t\t", "proposal.authentication_method");
+            conf = conf .. addline(ppath, "dh_group"		, "\t\t", "proposal.dh_group");
+	    conf = conf .. "\t}\n";
+	    conf = conf .. "}\n";
+
+	    print("IPsec Remote config file " .. file .. ":\n" ..
+		conf ..
+		"=======================================\n");
+
+	    local f = assert(io.open(file, "w"));
+	    f:write(conf);
+	    f:close();
+
+	end
+    end
+
+    local route_up = nil;
+    local route_down = nil;
+
+    if last_gw then
+	local route_up_file = "/var/run/racoon." .. last_gw .. "_up.sh";
+	local route_down_file = "/var/run/racoon." .. last_gw .. "_down.sh";
+
+	route_up = assert(io.open(route_up_file, "w"));
+	route_down = assert(io.open(route_down_file, "w"));
+
+	route_up:write("#!/bin/sh\n");
+	route_down:write("#!/bin/sh\n");
+    end
+
+    for i = 1,16,1 do
+	local ppath = "ipsec.sainfo[" ..i.. "]";
+	local node = self.c:getNode(ppath);
+	if node and node:attr("enable") == "true" then
+	    local file = "/var/run/racoon.sainfo" .. i .. ".conf";
+	    local src = self.c:getNode(ppath .. ".src"):value();
+	    local dst = self.c:getNode(ppath .. ".dst"):value();
+
+	    dst_cidr = dst:gsub("^%S+%s+(%S+)%s+%S+", "%1");
+	    if dst_cidr:match("%d+%.%d+%.%d+%.%d+%/%d+") then
+		-- Preinstall routes of secured remote nets
+		-- "already in table" ignored
+		local cmd = string.format(
+		    "/sbin/route add %s -iface lo0 -reject", dst_cidr);
+		print(cmd);
+		os.execute(cmd);
+		if last_gw then
+		    route_up:write(string.format("/sbin/route change %s %s\n", dst_cidr, last_gw));
+		    route_down:write(string.format("/sbin/route change %s -iface lo0 -reject\n", dst_cidr));
+		end
+	    end
+
+	    local conf = "sainfo (" .. src .. " " .. dst .. ")\n";
+	    conf = conf .. "{\n";
+	    conf = conf .. addline(ppath, "pfs_group"			, "\t");
+	    conf = conf .. addline(ppath, "lifetime"			, "\t");
+	    conf = conf .. addline(ppath, "encryption_algorithm"	, "\t");
+	    conf = conf .. addline(ppath, "authentication_algorithm"	, "\t");
+	    conf = conf .. addline(ppath, "compression_algorithm"	, "\t");
+	    conf = conf .. "}\n";
+
+	    print("IPsec SA info config file " .. file .. ":\n" ..
+		conf ..
+		"=======================================\n");
+
+	    local f = assert(io.open(file, "w"));
+	    f:write(conf);
+	    f:close();
+	end
+    end
+    if last_gw then
+	route_up:close();
+	route_down:close();
+    end
+
+end
+
+function RACOON:make_psk()
+
+    -- Generate linksfile
+    local f = assert(io.open(self.psk, "w"));
+    for i = 1,16,1 do
+	local ppath = "ipsec.remote[" ..i.. "]";
+	local node = self.c:getNode(ppath);
+	if node and node:attr("enable") == "true" then
+	    local gw = self.c:getNode(ppath .. ".gateway"):value();
+	    if gw then
+		gw = gw:gsub(":.*", "");
+		local psk = self.c:getNode(ppath .. ".proposal.psk");
+		if psk then
+		    f:write(gw .. "\t" .. psk:value() .. "\n");
+		end;
+	    else
+		print("Can't get " .. ppath .. ".gateway value");
+		return (nil);
+	    end
+	end
+    end
+    f:close();
+    os.execute("/bin/chmod 700 " .. self.psk);
+end
+
+function RACOON:setkey()
+    local setkey = "";
+
+    for i = 1,16,1 do
+	local ppath = "ipsec.setkey.line[" ..i.. "]";
+	local node = self.c:getNode(ppath);
+	if node then
+	    local val  = node:value();
+	    if val and string.len(val) > 0 then
+		setkey = setkey .. val .. ";\n";
+	    end
+	end
+    end
+
+    if string.len(setkey) > 0 then
+	local sk = io.popen("/sbin/setkey -c ", "w");
+        sk:write(setkey);
+	sk:close();
+    end
+end
+
+function RACOON:run()
+    -- FIXME install routes to remote nets via his IPSec gates
+    --os.execute("route add 192.168.2.0/24 10.0.0.1");
+    os.execute("mkdir -p /var/run/");
+    os.execute("mkdir -p /var/db/racoon");
+    self:setkey();
+    self:make_psk();
+    self:make_conf();
+    if self.remote_count > 0 then
+--	os.execute("echo 'WARNING: RACOON run in DEBUG mode' > /dev/console");
+--	os.execute("/sbin/racoon -ddddf " .. self.configfile .. " -l " .. self.logfile);
+	os.execute("/sbin/racoon -f " .. self.configfile .. " -l " .. self.logfile);
+    end
+end
+
+function RACOON:stop()
+
+    os.execute("kill `cat /var/run/racoon.pid`");
+end
+
+mt.__index = RACOON;
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,133 @@
+-----------------------------------------------------------------------------
+-- LuaSocket helper module
+-- Author: Diego Nehab
+-- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local string = require("string")
+local math = require("math")
+local socket = require("socket.core")
+module("socket")
+
+-----------------------------------------------------------------------------
+-- Exported auxiliar functions
+-----------------------------------------------------------------------------
+function connect(address, port, laddress, lport)
+    local sock, err = socket.tcp()
+    if not sock then return nil, err end
+    if laddress then
+        local res, err = sock:bind(laddress, lport, -1)
+        if not res then return nil, err end
+    end
+    local res, err = sock:connect(address, port)
+    if not res then return nil, err end
+    return sock
+end
+
+function bind(host, port, backlog)
+    local sock, err = socket.tcp()
+    if not sock then return nil, err end
+    sock:setoption("reuseaddr", true)
+    local res, err = sock:bind(host, port)
+    if not res then return nil, err end
+    res, err = sock:listen(backlog)
+    if not res then return nil, err end
+    return sock
+end
+
+try = newtry()
+
+function choose(table)
+    return function(name, opt1, opt2)
+        if base.type(name) ~= "string" then
+            name, opt1, opt2 = "default", name, opt1
+        end
+        local f = table[name or "nil"]
+        if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
+        else return f(opt1, opt2) end
+    end
+end
+
+-----------------------------------------------------------------------------
+-- Socket sources and sinks, conforming to LTN12
+-----------------------------------------------------------------------------
+-- create namespaces inside LuaSocket namespace
+sourcet = {}
+sinkt = {}
+
+BLOCKSIZE = 2048
+
+sinkt["close-when-done"] = function(sock)
+    return base.setmetatable({
+        getfd = function() return sock:getfd() end,
+        dirty = function() return sock:dirty() end
+    }, {
+        __call = function(self, chunk, err)
+            if not chunk then
+                sock:close()
+                return 1
+            else return sock:send(chunk) end
+        end
+    })
+end
+
+sinkt["keep-open"] = function(sock)
+    return base.setmetatable({
+        getfd = function() return sock:getfd() end,
+        dirty = function() return sock:dirty() end
+    }, {
+        __call = function(self, chunk, err)
+            if chunk then return sock:send(chunk)
+            else return 1 end
+        end
+    })
+end
+
+sinkt["default"] = sinkt["keep-open"]
+
+sink = choose(sinkt)
+
+sourcet["by-length"] = function(sock, length)
+    return base.setmetatable({
+        getfd = function() return sock:getfd() end,
+        dirty = function() return sock:dirty() end
+    }, {
+        __call = function()
+            if length <= 0 then return nil end
+            local size = math.min(socket.BLOCKSIZE, length)
+            local chunk, err = sock:receive(size)
+            if err then return nil, err end
+            length = length - string.len(chunk)
+            return chunk
+        end
+    })
+end
+
+sourcet["until-closed"] = function(sock)
+    local done
+    return base.setmetatable({
+        getfd = function() return sock:getfd() end,
+        dirty = function() return sock:dirty() end
+    }, {
+        __call = function()
+            if done then return nil end
+            local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
+            if not err then return chunk
+            elseif err == "closed" then
+                sock:close()
+                done = 1
+                return partial
+            else return nil, err end
+        end
+    })
+end
+
+
+sourcet["default"] = sourcet["until-closed"]
+
+source = choose(sourcet)
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/ftp.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/ftp.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,281 @@
+-----------------------------------------------------------------------------
+-- FTP support for the Lua language
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: ftp.lua,v 1.45 2007/07/11 19:25:47 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local table = require("table")
+local string = require("string")
+local math = require("math")
+local socket = require("socket")
+local url = require("socket.url")
+local tp = require("socket.tp")
+local ltn12 = require("ltn12")
+module("socket.ftp")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+-- timeout in seconds before the program gives up on a connection
+TIMEOUT = 60
+-- default port for ftp service
+PORT = 21
+-- this is the default anonymous password. used when no password is
+-- provided in url. should be changed to your e-mail.
+USER = "ftp"
+PASSWORD = "anonymous at anonymous.org"
+
+-----------------------------------------------------------------------------
+-- Low level FTP API
+-----------------------------------------------------------------------------
+local metat = { __index = {} }
+
+function open(server, port, create)
+    local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create))
+    local f = base.setmetatable({ tp = tp }, metat)
+    -- make sure everything gets closed in an exception
+    f.try = socket.newtry(function() f:close() end)
+    return f
+end
+
+function metat.__index:portconnect()
+    self.try(self.server:settimeout(TIMEOUT))
+    self.data = self.try(self.server:accept())
+    self.try(self.data:settimeout(TIMEOUT))
+end
+
+function metat.__index:pasvconnect()
+    self.data = self.try(socket.tcp())
+    self.try(self.data:settimeout(TIMEOUT))
+    self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
+end
+
+function metat.__index:login(user, password)
+    self.try(self.tp:command("user", user or USER))
+    local code, reply = self.try(self.tp:check{"2..", 331})
+    if code == 331 then
+        self.try(self.tp:command("pass", password or PASSWORD))
+        self.try(self.tp:check("2.."))
+    end
+    return 1
+end
+
+function metat.__index:pasv()
+    self.try(self.tp:command("pasv"))
+    local code, reply = self.try(self.tp:check("2.."))
+    local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
+    local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
+    self.try(a and b and c and d and p1 and p2, reply)
+    self.pasvt = {
+        ip = string.format("%d.%d.%d.%d", a, b, c, d),
+        port = p1*256 + p2
+    }
+    if self.server then
+        self.server:close()
+        self.server = nil
+    end
+    return self.pasvt.ip, self.pasvt.port
+end
+
+function metat.__index:port(ip, port)
+    self.pasvt = nil
+    if not ip then
+        ip, port = self.try(self.tp:getcontrol():getsockname())
+        self.server = self.try(socket.bind(ip, 0))
+        ip, port = self.try(self.server:getsockname())
+        self.try(self.server:settimeout(TIMEOUT))
+    end
+    local pl = math.mod(port, 256)
+    local ph = (port - pl)/256
+    local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
+    self.try(self.tp:command("port", arg))
+    self.try(self.tp:check("2.."))
+    return 1
+end
+
+function metat.__index:send(sendt)
+    self.try(self.pasvt or self.server, "need port or pasv first")
+    -- if there is a pasvt table, we already sent a PASV command
+    -- we just get the data connection into self.data
+    if self.pasvt then self:pasvconnect() end
+    -- get the transfer argument and command
+    local argument = sendt.argument or
+        url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
+    if argument == "" then argument = nil end
+    local command = sendt.command or "stor"
+    -- send the transfer command and check the reply
+    self.try(self.tp:command(command, argument))
+    local code, reply = self.try(self.tp:check{"2..", "1.."})
+    -- if there is not a a pasvt table, then there is a server
+    -- and we already sent a PORT command
+    if not self.pasvt then self:portconnect() end
+    -- get the sink, source and step for the transfer
+    local step = sendt.step or ltn12.pump.step
+    local readt = {self.tp.c}
+    local checkstep = function(src, snk)
+        -- check status in control connection while downloading
+        local readyt = socket.select(readt, nil, 0)
+        if readyt[tp] then code = self.try(self.tp:check("2..")) end
+        return step(src, snk)
+    end
+    local sink = socket.sink("close-when-done", self.data)
+    -- transfer all data and check error
+    self.try(ltn12.pump.all(sendt.source, sink, checkstep))
+    if string.find(code, "1..") then self.try(self.tp:check("2..")) end
+    -- done with data connection
+    self.data:close()
+    -- find out how many bytes were sent
+    local sent = socket.skip(1, self.data:getstats())
+    self.data = nil
+    return sent
+end
+
+function metat.__index:receive(recvt)
+    self.try(self.pasvt or self.server, "need port or pasv first")
+    if self.pasvt then self:pasvconnect() end
+    local argument = recvt.argument or
+        url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
+    if argument == "" then argument = nil end
+    local command = recvt.command or "retr"
+    self.try(self.tp:command(command, argument))
+    local code = self.try(self.tp:check{"1..", "2.."})
+    if not self.pasvt then self:portconnect() end
+    local source = socket.source("until-closed", self.data)
+    local step = recvt.step or ltn12.pump.step
+    self.try(ltn12.pump.all(source, recvt.sink, step))
+    if string.find(code, "1..") then self.try(self.tp:check("2..")) end
+    self.data:close()
+    self.data = nil
+    return 1
+end
+
+function metat.__index:cwd(dir)
+    self.try(self.tp:command("cwd", dir))
+    self.try(self.tp:check(250))
+    return 1
+end
+
+function metat.__index:type(type)
+    self.try(self.tp:command("type", type))
+    self.try(self.tp:check(200))
+    return 1
+end
+
+function metat.__index:greet()
+    local code = self.try(self.tp:check{"1..", "2.."})
+    if string.find(code, "1..") then self.try(self.tp:check("2..")) end
+    return 1
+end
+
+function metat.__index:quit()
+    self.try(self.tp:command("quit"))
+    self.try(self.tp:check("2.."))
+    return 1
+end
+
+function metat.__index:close()
+    if self.data then self.data:close() end
+    if self.server then self.server:close() end
+    return self.tp:close()
+end
+
+-----------------------------------------------------------------------------
+-- High level FTP API
+-----------------------------------------------------------------------------
+local function override(t)
+    if t.url then
+        local u = url.parse(t.url)
+        for i,v in base.pairs(t) do
+            u[i] = v
+        end
+        return u
+    else return t end
+end
+
+local function tput(putt)
+    putt = override(putt)
+    socket.try(putt.host, "missing hostname")
+    local f = open(putt.host, putt.port, putt.create)
+    f:greet()
+    f:login(putt.user, putt.password)
+    if putt.type then f:type(putt.type) end
+    f:pasv()
+    local sent = f:send(putt)
+    f:quit()
+    f:close()
+    return sent
+end
+
+local default = {
+	path = "/",
+	scheme = "ftp"
+}
+
+local function parse(u)
+    local t = socket.try(url.parse(u, default))
+    socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
+    socket.try(t.host, "missing hostname")
+    local pat = "^type=(.)$"
+    if t.params then
+        t.type = socket.skip(2, string.find(t.params, pat))
+        socket.try(t.type == "a" or t.type == "i",
+            "invalid type '" .. t.type .. "'")
+    end
+    return t
+end
+
+local function sput(u, body)
+    local putt = parse(u)
+    putt.source = ltn12.source.string(body)
+    return tput(putt)
+end
+
+put = socket.protect(function(putt, body)
+    if base.type(putt) == "string" then return sput(putt, body)
+    else return tput(putt) end
+end)
+
+local function tget(gett)
+    gett = override(gett)
+    socket.try(gett.host, "missing hostname")
+    local f = open(gett.host, gett.port, gett.create)
+    f:greet()
+    f:login(gett.user, gett.password)
+    if gett.type then f:type(gett.type) end
+    f:pasv()
+    f:receive(gett)
+    f:quit()
+    return f:close()
+end
+
+local function sget(u)
+    local gett = parse(u)
+    local t = {}
+    gett.sink = ltn12.sink.table(t)
+    tget(gett)
+    return table.concat(t)
+end
+
+command = socket.protect(function(cmdt)
+    cmdt = override(cmdt)
+    socket.try(cmdt.host, "missing hostname")
+    socket.try(cmdt.command, "missing command")
+    local f = open(cmdt.host, cmdt.port, cmdt.create)
+    f:greet()
+    f:login(cmdt.user, cmdt.password)
+    f.try(f.tp:command(cmdt.command, cmdt.argument))
+    if cmdt.check then f.try(f.tp:check(cmdt.check)) end
+    f:quit()
+    return f:close()
+end)
+
+get = socket.protect(function(gett)
+    if base.type(gett) == "string" then return sget(gett)
+    else return tget(gett) end
+end)
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/http.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/http.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,350 @@
+-----------------------------------------------------------------------------
+-- HTTP/1.1 client support for the Lua language.
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: http.lua,v 1.71 2007/10/13 23:55:20 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-------------------------------------------------------------------------------
+local socket = require("socket")
+local url = require("socket.url")
+local ltn12 = require("ltn12")
+local mime = require("mime")
+local string = require("string")
+local base = _G
+local table = require("table")
+module("socket.http")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+-- connection timeout in seconds
+TIMEOUT = 60
+-- default port for document retrieval
+PORT = 80
+-- user agent field sent in request
+USERAGENT = socket._VERSION
+
+-----------------------------------------------------------------------------
+-- Reads MIME headers from a connection, unfolding where needed
+-----------------------------------------------------------------------------
+local function receiveheaders(sock, headers)
+    local line, name, value, err
+    headers = headers or {}
+    -- get first line
+    line, err = sock:receive()
+    if err then return nil, err end
+    -- headers go until a blank line is found
+    while line ~= "" do
+        -- get field-name and value
+        name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
+        if not (name and value) then return nil, "malformed reponse headers" end
+        name = string.lower(name)
+        -- get next line (value might be folded)
+        line, err  = sock:receive()
+        if err then return nil, err end
+        -- unfold any folded values
+        while string.find(line, "^%s") do
+            value = value .. line
+            line = sock:receive()
+            if err then return nil, err end
+        end
+        -- save pair in table
+        if headers[name] then headers[name] = headers[name] .. ", " .. value
+        else headers[name] = value end
+    end
+    return headers
+end
+
+-----------------------------------------------------------------------------
+-- Extra sources and sinks
+-----------------------------------------------------------------------------
+socket.sourcet["http-chunked"] = function(sock, headers)
+    return base.setmetatable({
+        getfd = function() return sock:getfd() end,
+        dirty = function() return sock:dirty() end
+    }, {
+        __call = function()
+            -- get chunk size, skip extention
+            local line, err = sock:receive()
+            if err then return nil, err end
+            local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
+            if not size then return nil, "invalid chunk size" end
+            -- was it the last chunk?
+            if size > 0 then
+                -- if not, get chunk and skip terminating CRLF
+                local chunk, err, part = sock:receive(size)
+                if chunk then sock:receive() end
+                return chunk, err
+            else
+                -- if it was, read trailers into headers table
+                headers, err = receiveheaders(sock, headers)
+                if not headers then return nil, err end
+            end
+        end
+    })
+end
+
+socket.sinkt["http-chunked"] = function(sock)
+    return base.setmetatable({
+        getfd = function() return sock:getfd() end,
+        dirty = function() return sock:dirty() end
+    }, {
+        __call = function(self, chunk, err)
+            if not chunk then return sock:send("0\r\n\r\n") end
+            local size = string.format("%X\r\n", string.len(chunk))
+            return sock:send(size ..  chunk .. "\r\n")
+        end
+    })
+end
+
+-----------------------------------------------------------------------------
+-- Low level HTTP API
+-----------------------------------------------------------------------------
+local metat = { __index = {} }
+
+function open(host, port, create)
+    -- create socket with user connect function, or with default
+    local c = socket.try((create or socket.tcp)())
+    local h = base.setmetatable({ c = c }, metat)
+    -- create finalized try
+    h.try = socket.newtry(function() h:close() end)
+    -- set timeout before connecting
+    h.try(c:settimeout(TIMEOUT))
+    h.try(c:connect(host, port or PORT))
+    -- here everything worked
+    return h
+end
+
+function metat.__index:sendrequestline(method, uri)
+    local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
+    return self.try(self.c:send(reqline))
+end
+
+function metat.__index:sendheaders(headers)
+    local h = "\r\n"
+    for i, v in base.pairs(headers) do
+        h = i .. ": " .. v .. "\r\n" .. h
+    end
+    self.try(self.c:send(h))
+    return 1
+end
+
+function metat.__index:sendbody(headers, source, step)
+    source = source or ltn12.source.empty()
+    step = step or ltn12.pump.step
+    -- if we don't know the size in advance, send chunked and hope for the best
+    local mode = "http-chunked"
+    if headers["content-length"] then mode = "keep-open" end
+    return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
+end
+
+function metat.__index:receivestatusline()
+    local status = self.try(self.c:receive(5))
+    -- identify HTTP/0.9 responses, which do not contain a status line
+    -- this is just a heuristic, but is what the RFC recommends
+    if status ~= "HTTP/" then return nil, status end
+    -- otherwise proceed reading a status line
+    status = self.try(self.c:receive("*l", status))
+    local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
+    return self.try(base.tonumber(code), status)
+end
+
+function metat.__index:receiveheaders()
+    return self.try(receiveheaders(self.c))
+end
+
+function metat.__index:receivebody(headers, sink, step)
+    sink = sink or ltn12.sink.null()
+    step = step or ltn12.pump.step
+    local length = base.tonumber(headers["content-length"])
+    local t = headers["transfer-encoding"] -- shortcut
+    local mode = "default" -- connection close
+    if t and t ~= "identity" then mode = "http-chunked"
+    elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
+    return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
+        sink, step))
+end
+
+function metat.__index:receive09body(status, sink, step)
+    local source = ltn12.source.rewind(socket.source("until-closed", self.c))
+    source(status)
+    return self.try(ltn12.pump.all(source, sink, step))
+end
+
+function metat.__index:close()
+    return self.c:close()
+end
+
+-----------------------------------------------------------------------------
+-- High level HTTP API
+-----------------------------------------------------------------------------
+local function adjusturi(reqt)
+    local u = reqt
+    -- if there is a proxy, we need the full url. otherwise, just a part.
+    if not reqt.proxy and not PROXY then
+        u = {
+           path = socket.try(reqt.path, "invalid path 'nil'"),
+           params = reqt.params,
+           query = reqt.query,
+           fragment = reqt.fragment
+        }
+    end
+    return url.build(u)
+end
+
+local function adjustproxy(reqt)
+    local proxy = reqt.proxy or PROXY
+    if proxy then
+        proxy = url.parse(proxy)
+        return proxy.host, proxy.port or 3128
+    else
+        return reqt.host, reqt.port
+    end
+end
+
+local function adjustheaders(reqt)
+    -- default headers
+    local lower = {
+        ["user-agent"] = USERAGENT,
+        ["host"] = reqt.host,
+        ["connection"] = "close, TE",
+        ["te"] = "trailers"
+    }
+    -- if we have authentication information, pass it along
+    if reqt.user and reqt.password then
+        lower["authorization"] =
+            "Basic " ..  (mime.b64(reqt.user .. ":" .. reqt.password))
+    end
+    -- override with user headers
+    for i,v in base.pairs(reqt.headers or lower) do
+        lower[string.lower(i)] = v
+    end
+    return lower
+end
+
+-- default url parts
+local default = {
+    host = "",
+    port = PORT,
+    path ="/",
+    scheme = "http"
+}
+
+local function adjustrequest(reqt)
+    -- parse url if provided
+    local nreqt = reqt.url and url.parse(reqt.url, default) or {}
+    -- explicit components override url
+    for i,v in base.pairs(reqt) do nreqt[i] = v end
+    if nreqt.port == "" then nreqt.port = 80 end
+    socket.try(nreqt.host and nreqt.host ~= "",
+        "invalid host '" .. base.tostring(nreqt.host) .. "'")
+    -- compute uri if user hasn't overriden
+    nreqt.uri = reqt.uri or adjusturi(nreqt)
+    -- ajust host and port if there is a proxy
+    nreqt.host, nreqt.port = adjustproxy(nreqt)
+    -- adjust headers in request
+    nreqt.headers = adjustheaders(nreqt)
+    return nreqt
+end
+
+local function shouldredirect(reqt, code, headers)
+    return headers.location and
+           string.gsub(headers.location, "%s", "") ~= "" and
+           (reqt.redirect ~= false) and
+           (code == 301 or code == 302) and
+           (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
+           and (not reqt.nredirects or reqt.nredirects < 5)
+end
+
+local function shouldreceivebody(reqt, code)
+    if reqt.method == "HEAD" then return nil end
+    if code == 204 or code == 304 then return nil end
+    if code >= 100 and code < 200 then return nil end
+    return 1
+end
+
+-- forward declarations
+local trequest, tredirect
+
+function tredirect(reqt, location)
+    local result, code, headers, status = trequest {
+        -- the RFC says the redirect URL has to be absolute, but some
+        -- servers do not respect that
+        url = url.absolute(reqt.url, location),
+        source = reqt.source,
+        sink = reqt.sink,
+        headers = reqt.headers,
+        proxy = reqt.proxy,
+        nredirects = (reqt.nredirects or 0) + 1,
+        create = reqt.create
+    }
+    -- pass location header back as a hint we redirected
+    headers = headers or {}
+    headers.location = headers.location or location
+    return result, code, headers, status
+end
+
+function trequest(reqt)
+    -- we loop until we get what we want, or
+    -- until we are sure there is no way to get it
+    local nreqt = adjustrequest(reqt)
+    local h = open(nreqt.host, nreqt.port, nreqt.create)
+    -- send request line and headers
+    h:sendrequestline(nreqt.method, nreqt.uri)
+    h:sendheaders(nreqt.headers)
+    -- if there is a body, send it
+    if nreqt.source then
+        h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
+    end
+    local code, status = h:receivestatusline()
+    -- if it is an HTTP/0.9 server, simply get the body and we are done
+    if not code then
+        h:receive09body(status, nreqt.sink, nreqt.step)
+        return 1, 200
+    end
+    local headers
+    -- ignore any 100-continue messages
+    while code == 100 do
+        headers = h:receiveheaders()
+        code, status = h:receivestatusline()
+    end
+    headers = h:receiveheaders()
+    -- at this point we should have a honest reply from the server
+    -- we can't redirect if we already used the source, so we report the error
+    if shouldredirect(nreqt, code, headers) and not nreqt.source then
+        h:close()
+        return tredirect(reqt, headers.location)
+    end
+    -- here we are finally done
+    if shouldreceivebody(nreqt, code) then
+        h:receivebody(headers, nreqt.sink, nreqt.step)
+    end
+    h:close()
+    return 1, code, headers, status
+end
+
+local function srequest(u, b)
+    local t = {}
+    local reqt = {
+        url = u,
+        sink = ltn12.sink.table(t)
+    }
+    if b then
+        reqt.source = ltn12.source.string(b)
+        reqt.headers = {
+            ["content-length"] = string.len(b),
+            ["content-type"] = "application/x-www-form-urlencoded"
+        }
+        reqt.method = "POST"
+    end
+    local code, headers, status = socket.skip(1, trequest(reqt))
+    return table.concat(t), code, headers, status
+end
+
+request = socket.protect(function(reqt, body)
+    if base.type(reqt) == "string" then return srequest(reqt, body)
+    else return trequest(reqt) end
+end)
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/smtp.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/smtp.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,251 @@
+-----------------------------------------------------------------------------
+-- SMTP client support for the Lua language.
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: smtp.lua,v 1.46 2007/03/12 04:08:40 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local coroutine = require("coroutine")
+local string = require("string")
+local math = require("math")
+local os = require("os")
+local socket = require("socket")
+local tp = require("socket.tp")
+local ltn12 = require("ltn12")
+local mime = require("mime")
+module("socket.smtp")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+-- timeout for connection
+TIMEOUT = 60
+-- default server used to send e-mails
+SERVER = "localhost"
+-- default port
+PORT = 25
+-- domain used in HELO command and default sendmail
+-- If we are under a CGI, try to get from environment
+DOMAIN = os.getenv("SERVER_NAME") or "localhost"
+-- default time zone (means we don't know)
+ZONE = "-0000"
+
+---------------------------------------------------------------------------
+-- Low level SMTP API
+-----------------------------------------------------------------------------
+local metat = { __index = {} }
+
+function metat.__index:greet(domain)
+    self.try(self.tp:check("2.."))
+    self.try(self.tp:command("EHLO", domain or DOMAIN))
+    return socket.skip(1, self.try(self.tp:check("2..")))
+end
+
+function metat.__index:mail(from)
+    self.try(self.tp:command("MAIL", "FROM:" .. from))
+    return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:rcpt(to)
+    self.try(self.tp:command("RCPT", "TO:" .. to))
+    return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:data(src, step)
+    self.try(self.tp:command("DATA"))
+    self.try(self.tp:check("3.."))
+    self.try(self.tp:source(src, step))
+    self.try(self.tp:send("\r\n.\r\n"))
+    return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:quit()
+    self.try(self.tp:command("QUIT"))
+    return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:close()
+    return self.tp:close()
+end
+
+function metat.__index:login(user, password)
+    self.try(self.tp:command("AUTH", "LOGIN"))
+    self.try(self.tp:check("3.."))
+    self.try(self.tp:command(mime.b64(user)))
+    self.try(self.tp:check("3.."))
+    self.try(self.tp:command(mime.b64(password)))
+    return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:plain(user, password)
+    local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
+    self.try(self.tp:command("AUTH", auth))
+    return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:auth(user, password, ext)
+    if not user or not password then return 1 end
+    if string.find(ext, "AUTH[^\n]+LOGIN") then
+        return self:login(user, password)
+    elseif string.find(ext, "AUTH[^\n]+PLAIN") then
+        return self:plain(user, password)
+    else
+        self.try(nil, "authentication not supported")
+    end
+end
+
+-- send message or throw an exception
+function metat.__index:send(mailt)
+    self:mail(mailt.from)
+    if base.type(mailt.rcpt) == "table" then
+        for i,v in base.ipairs(mailt.rcpt) do
+            self:rcpt(v)
+        end
+    else
+        self:rcpt(mailt.rcpt)
+    end
+    self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
+end
+
+function open(server, port, create)
+    local tp = socket.try(tp.connect(server or SERVER, port or PORT,
+        TIMEOUT, create))
+    local s = base.setmetatable({tp = tp}, metat)
+    -- make sure tp is closed if we get an exception
+    s.try = socket.newtry(function()
+        s:close()
+    end)
+    return s
+end
+
+-- convert headers to lowercase
+local function lower_headers(headers)
+    local lower = {}
+    for i,v in base.pairs(headers or lower) do
+        lower[string.lower(i)] = v
+    end
+    return lower
+end
+
+---------------------------------------------------------------------------
+-- Multipart message source
+-----------------------------------------------------------------------------
+-- returns a hopefully unique mime boundary
+local seqno = 0
+local function newboundary()
+    seqno = seqno + 1
+    return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
+        math.random(0, 99999), seqno)
+end
+
+-- send_message forward declaration
+local send_message
+
+-- yield the headers all at once, it's faster
+local function send_headers(headers)
+    local h = "\r\n"
+    for i,v in base.pairs(headers) do
+        h = i .. ': ' .. v .. "\r\n" .. h
+    end
+    coroutine.yield(h)
+end
+
+-- yield multipart message body from a multipart message table
+local function send_multipart(mesgt)
+    -- make sure we have our boundary and send headers
+    local bd = newboundary()
+    local headers = lower_headers(mesgt.headers or {})
+    headers['content-type'] = headers['content-type'] or 'multipart/mixed'
+    headers['content-type'] = headers['content-type'] ..
+        '; boundary="' ..  bd .. '"'
+    send_headers(headers)
+    -- send preamble
+    if mesgt.body.preamble then
+        coroutine.yield(mesgt.body.preamble)
+        coroutine.yield("\r\n")
+    end
+    -- send each part separated by a boundary
+    for i, m in base.ipairs(mesgt.body) do
+        coroutine.yield("\r\n--" .. bd .. "\r\n")
+        send_message(m)
+    end
+    -- send last boundary
+    coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
+    -- send epilogue
+    if mesgt.body.epilogue then
+        coroutine.yield(mesgt.body.epilogue)
+        coroutine.yield("\r\n")
+    end
+end
+
+-- yield message body from a source
+local function send_source(mesgt)
+    -- make sure we have a content-type
+    local headers = lower_headers(mesgt.headers or {})
+    headers['content-type'] = headers['content-type'] or
+        'text/plain; charset="iso-8859-1"'
+    send_headers(headers)
+    -- send body from source
+    while true do
+        local chunk, err = mesgt.body()
+        if err then coroutine.yield(nil, err)
+        elseif chunk then coroutine.yield(chunk)
+        else break end
+    end
+end
+
+-- yield message body from a string
+local function send_string(mesgt)
+    -- make sure we have a content-type
+    local headers = lower_headers(mesgt.headers or {})
+    headers['content-type'] = headers['content-type'] or
+        'text/plain; charset="iso-8859-1"'
+    send_headers(headers)
+    -- send body from string
+    coroutine.yield(mesgt.body)
+end
+
+-- message source
+function send_message(mesgt)
+    if base.type(mesgt.body) == "table" then send_multipart(mesgt)
+    elseif base.type(mesgt.body) == "function" then send_source(mesgt)
+    else send_string(mesgt) end
+end
+
+-- set defaul headers
+local function adjust_headers(mesgt)
+    local lower = lower_headers(mesgt.headers)
+    lower["date"] = lower["date"] or
+        os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
+    lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
+    -- this can't be overriden
+    lower["mime-version"] = "1.0"
+    return lower
+end
+
+function message(mesgt)
+    mesgt.headers = adjust_headers(mesgt)
+    -- create and return message source
+    local co = coroutine.create(function() send_message(mesgt) end)
+    return function()
+        local ret, a, b = coroutine.resume(co)
+        if ret then return a, b
+        else return nil, a end
+    end
+end
+
+---------------------------------------------------------------------------
+-- High level SMTP API
+-----------------------------------------------------------------------------
+send = socket.protect(function(mailt)
+    local s = open(mailt.server, mailt.port, mailt.create)
+    local ext = s:greet(mailt.domain)
+    s:auth(mailt.user, mailt.password, ext)
+    s:send(mailt)
+    s:quit()
+    return s:close()
+end)
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/tp.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/tp.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,123 @@
+-----------------------------------------------------------------------------
+-- Unified SMTP/FTP subsystem
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local string = require("string")
+local socket = require("socket")
+local ltn12 = require("ltn12")
+module("socket.tp")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+TIMEOUT = 60
+
+-----------------------------------------------------------------------------
+-- Implementation
+-----------------------------------------------------------------------------
+-- gets server reply (works for SMTP and FTP)
+local function get_reply(c)
+    local code, current, sep
+    local line, err = c:receive()
+    local reply = line
+    if err then return nil, err end
+    code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
+    if not code then return nil, "invalid server reply" end
+    if sep == "-" then -- reply is multiline
+        repeat
+            line, err = c:receive()
+            if err then return nil, err end
+            current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
+            reply = reply .. "\n" .. line
+        -- reply ends with same code
+        until code == current and sep == " "
+    end
+    return code, reply
+end
+
+-- metatable for sock object
+local metat = { __index = {} }
+
+function metat.__index:check(ok)
+    local code, reply = get_reply(self.c)
+    if not code then return nil, reply end
+    if base.type(ok) ~= "function" then
+        if base.type(ok) == "table" then
+            for i, v in base.ipairs(ok) do
+                if string.find(code, v) then
+                    return base.tonumber(code), reply
+                end
+            end
+            return nil, reply
+        else
+            if string.find(code, ok) then return base.tonumber(code), reply
+            else return nil, reply end
+        end
+    else return ok(base.tonumber(code), reply) end
+end
+
+function metat.__index:command(cmd, arg)
+    if arg then
+        return self.c:send(cmd .. " " .. arg.. "\r\n")
+    else
+        return self.c:send(cmd .. "\r\n")
+    end
+end
+
+function metat.__index:sink(snk, pat)
+    local chunk, err = c:receive(pat)
+    return snk(chunk, err)
+end
+
+function metat.__index:send(data)
+    return self.c:send(data)
+end
+
+function metat.__index:receive(pat)
+    return self.c:receive(pat)
+end
+
+function metat.__index:getfd()
+    return self.c:getfd()
+end
+
+function metat.__index:dirty()
+    return self.c:dirty()
+end
+
+function metat.__index:getcontrol()
+    return self.c
+end
+
+function metat.__index:source(source, step)
+    local sink = socket.sink("keep-open", self.c)
+    local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
+    return ret, err
+end
+
+-- closes the underlying c
+function metat.__index:close()
+    self.c:close()
+	return 1
+end
+
+-- connect with server and return c object
+function connect(host, port, timeout, create)
+    local c, e = (create or socket.tcp)()
+    if not c then return nil, e end
+    c:settimeout(timeout or TIMEOUT)
+    local r, e = c:connect(host, port)
+    if not r then
+        c:close()
+        return nil, e
+    end
+    return base.setmetatable({c = c}, metat)
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/url.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/url.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,297 @@
+-----------------------------------------------------------------------------
+-- URI parsing, composition and relative URL resolution
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: url.lua,v 1.38 2006/04/03 04:45:42 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module
+-----------------------------------------------------------------------------
+local string = require("string")
+local base = _G
+local table = require("table")
+module("socket.url")
+
+-----------------------------------------------------------------------------
+-- Module version
+-----------------------------------------------------------------------------
+_VERSION = "URL 1.0.1"
+
+-----------------------------------------------------------------------------
+-- Encodes a string into its escaped hexadecimal representation
+-- Input
+--   s: binary string to be encoded
+-- Returns
+--   escaped representation of string binary
+-----------------------------------------------------------------------------
+function escape(s)
+    return string.gsub(s, "([^A-Za-z0-9_])", function(c)
+        return string.format("%%%02x", string.byte(c))
+    end)
+end
+
+-----------------------------------------------------------------------------
+-- Protects a path segment, to prevent it from interfering with the
+-- url parsing.
+-- Input
+--   s: binary string to be encoded
+-- Returns
+--   escaped representation of string binary
+-----------------------------------------------------------------------------
+local function make_set(t)
+	local s = {}
+	for i,v in base.ipairs(t) do
+		s[t[i]] = 1
+	end
+	return s
+end
+
+-- these are allowed withing a path segment, along with alphanum
+-- other characters must be escaped
+local segment_set = make_set {
+    "-", "_", ".", "!", "~", "*", "'", "(",
+	")", ":", "@", "&", "=", "+", "$", ",",
+}
+
+local function protect_segment(s)
+	return string.gsub(s, "([^A-Za-z0-9_])", function (c)
+		if segment_set[c] then return c
+		else return string.format("%%%02x", string.byte(c)) end
+	end)
+end
+
+-----------------------------------------------------------------------------
+-- Encodes a string into its escaped hexadecimal representation
+-- Input
+--   s: binary string to be encoded
+-- Returns
+--   escaped representation of string binary
+-----------------------------------------------------------------------------
+function unescape(s)
+    return string.gsub(s, "%%(%x%x)", function(hex)
+        return string.char(base.tonumber(hex, 16))
+    end)
+end
+
+-----------------------------------------------------------------------------
+-- Builds a path from a base path and a relative path
+-- Input
+--   base_path
+--   relative_path
+-- Returns
+--   corresponding absolute path
+-----------------------------------------------------------------------------
+local function absolute_path(base_path, relative_path)
+    if string.sub(relative_path, 1, 1) == "/" then return relative_path end
+    local path = string.gsub(base_path, "[^/]*$", "")
+    path = path .. relative_path
+    path = string.gsub(path, "([^/]*%./)", function (s)
+        if s ~= "./" then return s else return "" end
+    end)
+    path = string.gsub(path, "/%.$", "/")
+    local reduced
+    while reduced ~= path do
+        reduced = path
+        path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
+            if s ~= "../../" then return "" else return s end
+        end)
+    end
+    path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
+        if s ~= "../.." then return "" else return s end
+    end)
+    return path
+end
+
+-----------------------------------------------------------------------------
+-- Parses a url and returns a table with all its parts according to RFC 2396
+-- The following grammar describes the names given to the URL parts
+-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
+-- <authority> ::= <userinfo>@<host>:<port>
+-- <userinfo> ::= <user>[:<password>]
+-- <path> :: = {<segment>/}<segment>
+-- Input
+--   url: uniform resource locator of request
+--   default: table with default values for each field
+-- Returns
+--   table with the following fields, where RFC naming conventions have
+--   been preserved:
+--     scheme, authority, userinfo, user, password, host, port,
+--     path, params, query, fragment
+-- Obs:
+--   the leading '/' in {/<path>} is considered part of <path>
+-----------------------------------------------------------------------------
+function parse(url, default)
+    -- initialize default parameters
+    local parsed = {}
+    for i,v in base.pairs(default or parsed) do parsed[i] = v end
+    -- empty url is parsed to nil
+    if not url or url == "" then return nil, "invalid url" end
+    -- remove whitespace
+    -- url = string.gsub(url, "%s", "")
+    -- get fragment
+    url = string.gsub(url, "#(.*)$", function(f)
+        parsed.fragment = f
+        return ""
+    end)
+    -- get scheme
+    url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
+        function(s) parsed.scheme = s; return "" end)
+    -- get authority
+    url = string.gsub(url, "^//([^/]*)", function(n)
+        parsed.authority = n
+        return ""
+    end)
+    -- get query stringing
+    url = string.gsub(url, "%?(.*)", function(q)
+        parsed.query = q
+        return ""
+    end)
+    -- get params
+    url = string.gsub(url, "%;(.*)", function(p)
+        parsed.params = p
+        return ""
+    end)
+    -- path is whatever was left
+    if url ~= "" then parsed.path = url end
+    local authority = parsed.authority
+    if not authority then return parsed end
+    authority = string.gsub(authority,"^([^@]*)@",
+        function(u) parsed.userinfo = u; return "" end)
+    authority = string.gsub(authority, ":([^:]*)$",
+        function(p) parsed.port = p; return "" end)
+    if authority ~= "" then parsed.host = authority end
+    local userinfo = parsed.userinfo
+    if not userinfo then return parsed end
+    userinfo = string.gsub(userinfo, ":([^:]*)$",
+        function(p) parsed.password = p; return "" end)
+    parsed.user = userinfo
+    return parsed
+end
+
+-----------------------------------------------------------------------------
+-- Rebuilds a parsed URL from its components.
+-- Components are protected if any reserved or unallowed characters are found
+-- Input
+--   parsed: parsed URL, as returned by parse
+-- Returns
+--   a stringing with the corresponding URL
+-----------------------------------------------------------------------------
+function build(parsed)
+    local ppath = parse_path(parsed.path or "")
+    local url = build_path(ppath)
+    if parsed.params then url = url .. ";" .. parsed.params end
+    if parsed.query then url = url .. "?" .. parsed.query end
+	local authority = parsed.authority
+	if parsed.host then
+		authority = parsed.host
+		if parsed.port then authority = authority .. ":" .. parsed.port end
+		local userinfo = parsed.userinfo
+		if parsed.user then
+			userinfo = parsed.user
+			if parsed.password then
+				userinfo = userinfo .. ":" .. parsed.password
+			end
+		end
+		if userinfo then authority = userinfo .. "@" .. authority end
+	end
+    if authority then url = "//" .. authority .. url end
+    if parsed.scheme then url = parsed.scheme .. ":" .. url end
+    if parsed.fragment then url = url .. "#" .. parsed.fragment end
+    -- url = string.gsub(url, "%s", "")
+    return url
+end
+
+-----------------------------------------------------------------------------
+-- Builds a absolute URL from a base and a relative URL according to RFC 2396
+-- Input
+--   base_url
+--   relative_url
+-- Returns
+--   corresponding absolute url
+-----------------------------------------------------------------------------
+function absolute(base_url, relative_url)
+    if base.type(base_url) == "table" then
+        base_parsed = base_url
+        base_url = build(base_parsed)
+    else
+        base_parsed = parse(base_url)
+    end
+    local relative_parsed = parse(relative_url)
+    if not base_parsed then return relative_url
+    elseif not relative_parsed then return base_url
+    elseif relative_parsed.scheme then return relative_url
+    else
+        relative_parsed.scheme = base_parsed.scheme
+        if not relative_parsed.authority then
+            relative_parsed.authority = base_parsed.authority
+            if not relative_parsed.path then
+                relative_parsed.path = base_parsed.path
+                if not relative_parsed.params then
+                    relative_parsed.params = base_parsed.params
+                    if not relative_parsed.query then
+                        relative_parsed.query = base_parsed.query
+                    end
+                end
+            else
+                relative_parsed.path = absolute_path(base_parsed.path or "",
+                    relative_parsed.path)
+            end
+        end
+        return build(relative_parsed)
+    end
+end
+
+-----------------------------------------------------------------------------
+-- Breaks a path into its segments, unescaping the segments
+-- Input
+--   path
+-- Returns
+--   segment: a table with one entry per segment
+-----------------------------------------------------------------------------
+function parse_path(path)
+	local parsed = {}
+	path = path or ""
+	--path = string.gsub(path, "%s", "")
+	string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
+	for i = 1, table.getn(parsed) do
+		parsed[i] = unescape(parsed[i])
+	end
+	if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
+	if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
+	return parsed
+end
+
+-----------------------------------------------------------------------------
+-- Builds a path component from its segments, escaping protected characters.
+-- Input
+--   parsed: path segments
+--   unsafe: if true, segments are not protected before path is built
+-- Returns
+--   path: corresponding path stringing
+-----------------------------------------------------------------------------
+function build_path(parsed, unsafe)
+	local path = ""
+	local n = table.getn(parsed)
+	if unsafe then
+		for i = 1, n-1 do
+			path = path .. parsed[i]
+			path = path .. "/"
+		end
+		if n > 0 then
+			path = path .. parsed[n]
+			if parsed.is_directory then path = path .. "/" end
+		end
+	else
+		for i = 1, n-1 do
+			path = path .. protect_segment(parsed[i])
+			path = path .. "/"
+		end
+		if n > 0 then
+			path = path .. protect_segment(parsed[n])
+			if parsed.is_directory then path = path .. "/" end
+		end
+	end
+	if parsed.is_absolute then path = "/" .. path end
+	return path
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/table.save-0.94.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/table.save-0.94.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,183 @@
+--[[
+	Save Table to File/Stringtable
+	Load Table from File/Stringtable
+	v 0.94
+
+	Lua 5.1 compatible
+
+	Userdata and indices of these are not saved
+	Functions are saved via string.dump, so make sure it has no upvalues
+	References are saved
+	----------------------------------------------------
+	table.save( table [, filename] )
+
+	Saves a table so it can be called via the table.load function again
+	table must a object of type 'table'
+	filename is optional, and may be a string representing a filename or true/1
+
+	table.save( table )
+		on success: returns a string representing the table (stringtable)
+		(uses a string as buffer, ideal for smaller tables)
+	table.save( table, true or 1 )
+		on success: returns a string representing the table (stringtable)
+		(uses io.tmpfile() as buffer, ideal for bigger tables)
+	table.save( table, "filename" )
+		on success: returns 1
+		(saves the table to file "filename")
+	on failure: returns as second argument an error msg
+	----------------------------------------------------
+	table.load( filename or stringtable )
+
+	Loads a table that has been saved via the table.save function
+
+	on success: returns a previously saved table
+	on failure: returns as second argument an error msg
+	----------------------------------------------------
+
+	chillcode, http://lua-users.org/wiki/SaveTableToFile
+	Licensed under the same terms as Lua itself.
+]]--
+do
+	-- declare local variables
+	--// exportstring( string )
+	--// returns a "Lua" portable version of the string
+	local function exportstring( s )
+		s = string.format( "%q",s )
+		-- to replace
+		s = string.gsub( s,"\\\n","\\n" )
+		s = string.gsub( s,"\r","\\r" )
+		s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" )
+		return s
+	end
+
+	--// The Save Function
+	function table.save(  tbl,filename )
+		local charS,charE = "   ","\n"
+		local file,err
+		-- create a pseudo file that writes to a string and return the string
+		if not filename then
+			file =  { write = function( self,newstr ) self.str = self.str..newstr end, str = "" }
+			charS,charE = "",""
+		-- write table to tmpfile
+		elseif filename == true or filename == 1 then
+			charS,charE,file = "","",io.tmpfile()
+		-- write table to file
+		-- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error
+		else
+			file,err = io.open( filename, "w" )
+			if err then return _,err end
+		end
+		-- initiate variables for save procedure
+		local tables,lookup = { tbl },{ [tbl] = 1 }
+		file:write( "return {"..charE )
+		for idx,t in ipairs( tables ) do
+			if filename and filename ~= true and filename ~= 1 then
+				file:write( "-- Table: {"..idx.."}"..charE )
+			end
+			file:write( "{"..charE )
+			local thandled = {}
+			for i,v in ipairs( t ) do
+				thandled[i] = true
+				-- escape functions and userdata
+				if type( v ) ~= "userdata" then
+					-- only handle value
+					if type( v ) == "table" then
+						if not lookup[v] then
+							table.insert( tables, v )
+							lookup[v] = #tables
+						end
+						file:write( charS.."{"..lookup[v].."},"..charE )
+					elseif type( v ) == "function" then
+						file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE )
+					else
+						local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
+						file:write(  charS..value..","..charE )
+					end
+				end
+			end
+			for i,v in pairs( t ) do
+				-- escape functions and userdata
+				if (not thandled[i]) and type( v ) ~= "userdata" then
+					-- handle index
+					if type( i ) == "table" then
+						if not lookup[i] then
+							table.insert( tables,i )
+							lookup[i] = #tables
+						end
+						file:write( charS.."[{"..lookup[i].."}]=" )
+					else
+						local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i )
+						file:write( charS..index.."=" )
+					end
+					-- handle value
+					if type( v ) == "table" then
+						if not lookup[v] then
+							table.insert( tables,v )
+							lookup[v] = #tables
+						end
+						file:write( "{"..lookup[v].."},"..charE )
+					elseif type( v ) == "function" then
+						file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE )
+					else
+						local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
+						file:write( value..","..charE )
+					end
+				end
+			end
+			file:write( "},"..charE )
+		end
+		file:write( "}" )
+		-- Return Values
+		-- return stringtable from string
+		if not filename then
+			-- set marker for stringtable
+			return file.str.."--|"
+		-- return stringttable from file
+		elseif filename == true or filename == 1 then
+			file:seek ( "set" )
+			-- no need to close file, it gets closed and removed automatically
+			-- set marker for stringtable
+			return file:read( "*a" ).."--|"
+		-- close file and return 1
+		else
+			file:close()
+			return 1
+		end
+	end
+
+	--// The Load Function
+	function table.load( sfile )
+		-- catch marker for stringtable
+		if string.sub( sfile,-3,-1 ) == "--|" then
+			tables,err = loadstring( sfile )
+		else
+			tables,err = loadfile( sfile )
+		end
+
+		if err then return _,err end
+
+		tables = tables()
+
+		for idx = 1,#tables do
+			local tolinkv,tolinki = {},{}
+			for i,v in pairs( tables[idx] ) do
+				if type( v ) == "table" and tables[v[1]] then
+					table.insert( tolinkv,{ i,tables[v[1]] } )
+				end
+				if type( i ) == "table" and tables[i[1]] then
+					table.insert( tolinki,{ i,tables[i[1]] } )
+				end
+			end
+			-- link values, first due to possible changes of indices
+			for _,v in ipairs( tolinkv ) do
+				tables[idx][v[1]] = v[2]
+			end
+			-- link indices
+			for _,v in ipairs( tolinki ) do
+				tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
+			end
+		end
+		return tables[1]
+	end
+	-- close do
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/test.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/test.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,31 @@
+
+require("ipcalc");
+
+
+print(string.format("hasbit(%08x, %08x) = %s", 0x12345678, 0x00001000, tostring(hasbit(0x12345678, 0x00004000))));
+
+print(string.format("(%08x & %08x) = %08x", 0x12345678, 0xfffff000, andL(0x12345678, 0x000fffff)));
+
+m =13
+print(string.format("%d  netmask=%08x hostmask=%08x", m, bits_to_netmask(m), bits_to_hostmask(m)));
+
+require("ipcalc");
+
+local r = cidr_to_net("213.130.11.129/23");
+
+
+--[[
+r.host	0.0.1.129
+r.bits	23
+r.broadcast	213.130.11.255
+r.net	213.130.10.0
+r.mask	255.255.254.0
+r.ip	213.130.11.129
+r.cidr	213.130.11.129/23
+]]
+
+
+
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/utils.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/utils.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,328 @@
+--[[
+    tdump(table_to_dump)
+    return text dump of table
+]]
+
+function tdump(t)
+    local function dmp(t, l, k)
+	local ret = "";
+	if type(t) == "table" then
+    	    ret = ret .. string.format("%s%s:", string.rep(" ", l*2), tostring(k)) .. "\n";
+    	    for k, v in pairs(t) do
+    		if k ~= "_parent" then
+    		    ret = ret .. dmp(v, l+1, k);
+    		end
+    	    end
+	else
+    	    ret = ret .. string.format("%s%s:%s", string.rep(" ", l*2), tostring(k), tostring(t)) .. "\n";
+	end
+	return (ret);
+    end
+    return dmp(t, 1, "root");
+end
+
+--[[
+    xmldump(table_to_dump)
+    return XML subtree of table
+]]
+
+function xmldump(t)
+
+    local function xatrdmp(t)
+	local ret = '';
+
+        for k, v in pairs(t) do
+    	    ret = ret .. string.format(" %s=\"%s\"", tostring(k), tostring(v));
+        end
+
+        return ret;
+    end
+
+    local function xdmp(t, l)
+	local ret = '';
+	local enum = 0;
+	local name = t._name or '';
+	local attrs = '';
+	local childs = '';
+	local brk = nil;
+
+    	if t._attr then
+	    attrs = attrs .. xatrdmp(t._attr);
+	end
+
+
+	if t._children then
+    	    for k, v in ipairs(t._children) do
+    		childs = childs .. xdmp(v, l+1);
+    	    end
+
+    	    if table.maxn (t._children) > 1 then
+		brk = 1;
+	    elseif table.maxn (t._children) == 1 and
+	      t._children[1]._type ~= "TEXT" then
+		brk = 1;
+	    end
+    	end
+
+	if t._type == "ELEMENT" then
+	    if brk then
+    		ret =   ret ..
+    		    string.format("%s<%s%s>\n", string.rep(" ", l*4), name, attrs) ..
+    		    childs ..
+    		    string.format("%s</%s>\n", string.rep(" ", l*4), name);
+    	    else
+    		ret =   ret ..
+    		    string.format("%s<%s%s>", string.rep(" ", l*4), name, attrs) ..
+    		    childs ..
+    		    string.format("</%s>\n", name);
+    	    end
+    	elseif t._type == "TEXT" then
+    	    ret = ret .. t._text;
+    	elseif t._type == "ROOT" then
+    	    ret = childs;
+    	elseif t._type == "COMMENT" then
+    	    ret = ret ..
+    		string.format("%s<!-- %s -->\n", string.rep(" ", l*4), t._text);
+--    	else
+--    	    print("Parse Error Unknow type \"" .. (t._type or "(nil)") .. "\"");
+    	end
+
+	-- print(ret);
+	return ret;
+    end
+
+    return xdmp(t, -1);
+end
+
+
+
+--[[
+    read_file(_file)
+    return data from file
+]]
+function read_file(_file)
+    local xml;
+
+    if (_debug) then
+        io.write ( "File: ".._file.."\n" )
+    end
+
+    local f, e = io.open(_file, "r")
+    if f then
+      xml = f:read("*a")
+    else
+      return ("Can't open file " .. _file);
+    end
+
+    return xml;
+end
+
+function inc(_file)
+    return read_file(_file);
+end
+
+function load_file(_file)
+    h = domHandler();
+    x = xmlParser(h);
+    index = 1
+
+    x.options.expandEntities = 1; -- nil;
+    x:parse(read_file(_file));
+
+    return (h.root);
+end
+
+function save_file(_file, _data)
+    local out, e = io.open(_file, "w");
+    if out then
+        out:write(_data);
+	assert(out:close());
+    else
+        print(e);
+        return (nil);
+    end
+
+    return (true);
+end
+
+function checked(v)
+    if (v and v ~= "" and v ~= "false") then
+	return "checked";
+    end
+    return "";
+end
+
+function field(v)
+    if (v and v ~= "") then
+        return v;
+    end
+    return "";
+end
+
+function conf_table(id, header, rootpath, fields)
+
+	local ret =
+		"<div id=\"" .. id .. "\" class=\"yui3-module boxitem\">\n" ..
+		"    <div class=\"yui3-hd\">\n" ..
+		"        <h4>" .. header .."</h4>\n" ..
+		"    </div>\n" ..
+		"    <div class=\"yui3-bd\">\n" ..
+		"	<form method=\"POST\" target=\"/cmd.xml\" onchange=\"document.getElementById('" .. id .. "_update_button').disabled = false; return true;\">\n" ..
+		"	    <input type=\"hidden\" name=\"path\" value=\"" .. rootpath .."\" />\n" ..
+		"	    <input type=\"hidden\" name=\"cmd\" value=\"setmany\" />\n" ..
+		"	<table>\n";
+
+
+	for i,v in ipairs(fields) do
+	    if v.type == "attr" then
+		local _, _, nodestr, attrstr = string.find(v.node, "(.-)%:(.*)");
+
+		print(string.format("node='%s' attr='%s'", nodestr or "(no node)", attrstr or "(no attr)"));
+
+		if not nodestr then
+		    nodestr = rootpath;
+		else
+		    nodestr = rootpath .. "." .. nodestr;
+		end
+
+		if not attrstr then
+		    ret = ret .. "Error parsing attr fileld at path " .. v.node;
+		else
+
+		attrvalue = c:getNode(nodestr):attr(attrstr) or
+		    "Error getting attribute value of " .. nodestr .. ":attr(" .. attrstr .. ")";
+		local inserted = "";
+		if v.htmltype == "checkbox" then
+		    inserted = checked(attrvalue);
+		elseif v.htmltype == "text" then
+		    inserted = " value=\"" .. attrvalue .. "\"";
+		else
+		    inserted = "Unknown htmltype " .. v.htmltype;
+		end
+		ret = ret ..
+		"            <tr>\n" ..
+		"        	<td>" .. v.label .. ":</td>\n" ..
+		"        	<td><input name=\"smattr:" .. v.node .. "\" " ..
+				    "type=\"" .. v.htmltype .. "\" " ..
+				    inserted ..
+				    " onchange=\"" ..
+					"document.getElementById(" .. 
+					    "'" .. id .. "_update_button'" ..
+					").disabled = false; return true;\"/></td>\n" ..
+		"    	     </tr>\n";
+		end
+	    elseif v.type == "node" then
+		local nodestr = v.node;
+		if not nodestr then
+		    nodestr = rootpath;
+		else
+		    nodestr = rootpath .. "." .. nodestr;
+		end
+
+		local n = c:getNode(nodestr);
+		if n then
+		    nodevalue = n:value() or "";
+		else
+		    nodevalue = "Error: node " .. nodestr .. " not found";
+		end
+
+		nodevalue = nodevalue:gsub("\"",""");
+
+		ret = ret ..
+		"            <tr>\n" ..
+		"        	<td>" .. v.label .. ":</td>\n" ..
+		"    		<td><input type=\"" .. v.htmltype .. "\" name=\"sm:" .. v.node .. "\" value=\"" ..
+				    nodevalue ..
+				    "\" onchange=\"document.getElementById(" ..
+					"'" .. id .. "_update_button'" ..
+				    ").disabled = false; return true;\"/></td>\n" ..
+		"            </tr>\n";
+	    end
+	end
+
+	ret = ret ..
+		"            <tr>\n" ..
+		"        	<td> </td>\n" ..
+		"        	<td><input id=\"" .. id .. "_update_button\" type=\"button\" name=\"Update\" value=\"Update\" disabled onclick=\"" ..
+					"send_update(this.form, function(x) { document.getElementById('" .. id .. "_update_button').disabled = true; })" ..
+				    "\"/></td>\n" ..
+		"            </tr>\n" ..
+		"	</table>\n" ..
+		"	</form>\n" ..
+		"    </div>\n" ..
+		"</div>\n";
+
+	return (ret);
+end
+
+function peritem(item, sub)
+	if type(item) == "table" then
+
+    		for k, v in pairs(item) do
+    			sub(v);
+    		end
+	else
+    		sub(item);
+	end
+end
+
+function kldload(module)
+	function kldload_one(module)
+		if debug then
+			print("kldstat -q -m " .. module .. " || kldload " .. module);
+		end
+		os.execute("kldstat -q -m " .. module .. " || kldload " .. module);
+	end
+	peritem(module, kldload_one);
+end
+
+function strip_quote (str)
+	str = str:gsub("^\"(.*)\"$", "%1");
+	str = str:gsub("^\'(.*)\'$", "%1");
+	return str;
+end
+
+function parse_kv_file (ar, file)
+	local err = nil;
+	if not file then
+		return "Filename required";
+	end
+
+	if type(ar) ~= "table" then
+		return "First argument must be table";
+	end
+
+	local f = io.open(file);
+	if not f then
+		return "Can't open \"" .. file .. "\"\n";
+	end
+
+	local count = 0;
+	while true do
+		local line = f:read('*line');
+		if line == nil then break end -- EOF
+		if count > 100 then
+			-- to much lines
+			err = "Lines count more than 100 \"" .. file .. "\n";
+			break;
+		end
+
+		line = line:gsub("#.*$", ""); -- Strip comments
+		line = line:gsub("%s*$", ""); -- Strip whitespaces
+
+		if line ~= "" then -- Do only if line not empty
+			match, _, name, value = line:find("^(.+)=(.+)%s*$");
+			if not match then
+				err = "Wrong format in \"" .. file .. "\n";
+				break;
+			end
+			ar[strip_quote(name)] = strip_quote(value);
+		end
+
+		count = count + 1;
+	end
+
+	f:close();
+	return err;
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/xml.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/xml.lua	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,472 @@
+---
+--  Overview:
+--  =========
+--
+--      This module provides a non-validating XML stream parser in Lua.
+--
+--  Features:
+--  =========
+--
+--      * Tokenises well-formed XML (relatively robustly)
+--      * Flexible handler based event api (see below)
+--      * Parses all XML Infoset elements - ie.
+--          - Tags
+--          - Text
+--          - Comments
+--          - CDATA
+--          - XML Decl
+--          - Processing Instructions
+--          - DOCTYPE declarations
+--      * Provides limited well-formedness checking
+--        (checks for basic syntax & balanced tags only)
+--      * Flexible whitespace handling (selectable)
+--      * Entity Handling (selectable)
+--
+--  Limitations:
+--  ============
+--
+--      * Non-validating
+--      * No charset handling
+--      * No namespace support
+--      * Shallow well-formedness checking only (fails
+--        to detect most semantic errors)
+--
+--  API:
+--  ====
+--
+--  The parser provides a partially object-oriented API with
+--  functionality split into tokeniser and hanlder components.
+--
+--  The handler instance is passed to the tokeniser and receives
+--  callbacks for each XML element processed (if a suitable handler
+--  function is defined). The API is conceptually similar to the
+--  SAX API but implemented differently.
+--
+--  The following events are generated by the tokeniser
+--
+--      handler:start       - Start Tag
+--      handler:end         - End Tag
+--      handler:text        - Text
+--      handler:decl        - XML Declaration
+--      handler:pi          - Processing Instruction
+--      handler:comment     - Comment
+--      handler:dtd         - DOCTYPE definition
+--      handler:cdata       - CDATA
+--
+--  The function prototype for all the callback functions is
+--
+--      callback(val,attrs,start,end)
+--
+--  where attrs is a table and val/attrs are overloaded for
+--  specific callbacks - ie.
+--
+--      Callback     val            attrs (table)
+--      --------     ---            -------------
+--      start        name           { attributes (name=val).. }
+--      end          name           nil
+--      text         <text>         nil
+--      cdata        <text>         nil
+--      decl         "xml"          { attributes (name=val).. }
+--      pi           pi name        { attributes (if present)..
+--                                    _text = <PI Text>
+--                                  }
+--      comment      <text>         nil
+--      dtd          root element   { _root = <Root Element>,
+--                                    _type = SYSTEM|PUBLIC,
+--                                    _name = <name>,
+--                                    _uri = <uri>,
+--                                    _internal = <internal dtd>
+--                                  }
+--
+--  (start & end provide the character positions of the start/end
+--  of the element)
+--
+--  XML data is passed to the parser instance through the 'parse'
+--  method (Nore: must be passed a single string currently)
+--
+--  Options
+--  =======
+--
+--  Parser options are controlled through the 'self.options' table.
+--  Available options are -
+--
+--      * stripWS
+--
+--        Strip non-significant whitespace (leading/trailing)
+--        and do not generate events for empty text elements
+--
+--      * expandEntities
+--
+--        Expand entities (standard entities + single char
+--        numeric entities only currently - could be extended
+--        at runtime if suitable DTD parser added elements
+--        to table (see obj._ENTITIES). May also be possible
+--        to expand multibyre entities for UTF-8 only
+--
+--      * errorHandler
+--
+--        Custom error handler function
+--
+--  NOTE: Boolean options must be set to 'nil' not '0'
+--
+--  Usage
+--  =====
+--
+--  Create a handler instance -
+--
+--      h = { start = function(t,a,s,e) .... end,
+--            end = function(t,a,s,e) .... end,
+--            text = function(t,a,s,e) .... end,
+--            cdata = text }
+--
+--  (or use predefined handler - see handler.lua)
+--
+--  Create parser instance -
+--
+--      p = xmlParser(h)
+--
+--  Set options -
+--
+--      p.options.xxxx = nil
+--
+--  Parse XML data -
+--
+--      xmlParser:parse("<?xml... ")
+--  License:
+--  ========
+--
+--      This code is freely distributable under the terms of the Lua license
+--      (http://www.lua.org/copyright.html)
+--
+--  History
+--  =======
+--  Added parameter parseAttributes (boolean) in xmlParser.parse method
+--  If true, tag attributtes are parsed. The default value is true.
+--  by Manoel Campos (http://manoelcampos.com)
+--
+--  $Id: xml.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $
+--
+--  $Log: xml.lua,v $
+--  Revision 1.1.1.1  2001/11/28 06:11:33  paulc
+--  Initial Import
+--
+-- at author Paul Chakravarti (paulc at passtheaardvark.com)<p/>
+
+
+---Parses a XML string
+-- at param handler Handler object to be used to convert the XML string
+--to another formats. @see handler.lua
+xmlParser = function(handler)
+    local obj = {}
+    -- Public attributes
+
+    obj.options = {
+                    stripWS = 1,
+                    expandEntities = 1,
+                    errorHandler = function(err,pos)
+                                       error(format("%s [char=%d]\n",
+                                               err or "Parse Error",pos))
+                                   end,
+                  }
+
+    -- Public methods
+
+    obj.parse = function(self, str, parseAttributes)
+	    if parseAttributes == nil then
+	       parseAttributes = true
+	    end
+	    self._handler.parseAttributes = parseAttributes
+
+        local match,endmatch,pos = 0,0,1
+        local text,endt1,endt2,tagstr,tagname,attrs,starttext,endtext
+        local errstart,errend,extstart,extend
+        while match do
+            -- Get next tag (first pass - fix exceptions below)
+            match,endmatch,text,endt1,tagstr,endt2 = string.find(str,self._XML,pos)
+            if not match then
+                if string.find(str,self._WS,pos) then
+                    -- No more text - check document complete
+                    if table.getn(self._stack) ~= 0 then
+                        self:_err(self._errstr.incompleteXmlErr,pos)
+                    else
+                        break
+                    end
+                else
+                    -- Unparsable text
+                    self:_err(self._errstr.xmlErr,pos)
+                end
+            end
+            -- Handle leading text
+            starttext = match
+            endtext = match + string.len(text) - 1
+            match = match + string.len(text)
+            text = self:_parseEntities(self:_stripWS(text))
+            if text ~= "" and self._handler.text then
+                self._handler:text(text,nil,match,endtext)
+            end
+            -- Test for tag type
+            if string.find(string.sub(tagstr,1,5),"?xml%s") then
+                -- XML Declaration
+                match,endmatch,text = string.find(str,self._PI,pos)
+                if not match then
+                    self:_err(self._errstr.declErr,pos)
+                end
+                if match ~= 1 then
+                    -- Must be at start of doc if present
+                    self:_err(self._errstr.declStartErr,pos)
+                end
+                tagname,attrs = self:_parseTag(text)
+                -- TODO: Check attributes are valid
+                -- Check for version (mandatory)
+                if attrs.version == nil then
+                    self:_err(self._errstr.declAttrErr,pos)
+                end
+                if self._handler.decl then
+                    self._handler:decl(tagname,attrs,match,endmatch)
+                end
+            elseif string.sub(tagstr,1,1) == "?" then
+                -- Processing Instruction
+                match,endmatch,text = string.find(str,self._PI,pos)
+                if not match then
+                    self:_err(self._errstr.piErr,pos)
+                end
+                if self._handler.pi then
+                    -- Parse PI attributes & text
+                    tagname,attrs = self:_parseTag(text)
+                    local pi = string.sub(text,string.len(tagname)+1)
+                    if pi ~= "" then
+                        if attrs then
+                            attrs._text = pi
+                        else
+                            attrs = { _text = pi }
+                        end
+                    end
+                    self._handler:pi(tagname,attrs,match,endmatch)
+                end
+            elseif string.sub(tagstr,1,3) == "!--" then
+                -- Comment
+                match,endmatch,text = string.find(str,self._COMMENT,pos)
+                if not match then
+                    self:_err(self._errstr.commentErr,pos)
+                end
+                if self._handler.comment then
+                    text = self:_parseEntities(self:_stripWS(text))
+                    self._handler:comment(text,next,match,endmatch)
+                end
+            elseif string.sub(tagstr,1,8) == "!DOCTYPE" then
+                -- DTD
+                match,endmatch,attrs = self:_parseDTD(string,pos)
+                if not match then
+                    self:_err(self._errstr.dtdErr,pos)
+                end
+                if self._handler.dtd then
+                    self._handler:dtd(attrs._root,attrs,match,endmatch)
+                end
+            elseif string.sub(tagstr,1,8) == "![CDATA[" then
+                -- CDATA
+                match,endmatch,text = string.find(str,self._CDATA,pos)
+                if not match then
+                    self:_err(self._errstr.cdataErr,pos)
+                end
+                if self._handler.cdata then
+                    self._handler:cdata(text,nil,match,endmatch)
+                end
+            else
+                -- Normal tag
+
+                -- Need theck for embedded '>' in attribute value and extend
+                -- match recursively if necessary eg. <tag attr="123>456">
+
+                while 1 do
+                    errstart,errend = string.find(tagstr,self._ATTRERR1)
+                    if errend == nil then
+                        errstart,errend = string.find(tagstr,self._ATTRERR2)
+                        if errend == nil then
+                            break
+                        end
+                    end
+                    extstart,extend,endt2 = string.find(str,self._TAGEXT,endmatch+1)
+                    tagstr = tagstr .. string.sub(string,endmatch,extend-1)
+                    if not match then
+                        self:_err(self._errstr.xmlErr,pos)
+                    end
+                    endmatch = extend
+                end
+
+                -- Extract tagname/attrs
+
+                tagname,attrs = self:_parseTag(tagstr)
+
+                if (endt1=="/") then
+                    -- End tag
+                    if self._handler.endtag then
+                        if attrs then
+                            -- Shouldnt have any attributes in endtag
+                            self:_err(format("%s (/%s)",
+                                             self._errstr.endTagErr,
+                                             tagname)
+                                        ,pos)
+                        end
+                        if table.remove(self._stack) ~= tagname then
+                            self:_err(format("%s (/%s)",
+                                             self._errstr.unmatchedTagErr,
+                                             tagname)
+                                        ,pos)
+                        end
+                        self._handler:endtag(tagname,nil,match,endmatch)
+                    end
+                else
+                    -- Start Tag
+                    table.insert(self._stack,tagname)
+                    if self._handler.starttag then
+                        self._handler:starttag(tagname,attrs,match,endmatch)
+                    end
+                    -- Self-Closing Tag
+                    if (endt2=="/") then
+                        table.remove(self._stack)
+                        if self._handler.endtag then
+                            self._handler:endtag(tagname,nil,match,endmatch)
+                        end
+                    end
+                end
+            end
+            pos = endmatch + 1
+        end
+    end
+
+    -- Private attributes/functions
+
+    obj._handler    = handler
+    obj._stack      = {}
+
+    obj._XML        = '^([^<]*)<(%/?)([^>]-)(%/?)>'
+    obj._ATTR1      = '([%w-:_]+)%s*=%s*"(.-)"'
+    obj._ATTR2      = '([%w-:_]+)%s*=%s*\'(.-)\''
+    obj._CDATA      = '<%!%[CDATA%[(.-)%]%]>'
+    obj._PI         = '<%?(.-)%?>'
+    obj._COMMENT    = '<!%-%-(.-)%-%->'
+    obj._TAG        = '^(.-)%s.*'
+    obj._LEADINGWS  = '^%s+'
+    obj._TRAILINGWS = '%s+$'
+    obj._WS         = '^%s*$'
+    obj._DTD1       = '<!DOCTYPE%s+(.-)%s+(SYSTEM)%s+["\'](.-)["\']%s*(%b[])%s*>'
+    obj._DTD2       = '<!DOCTYPE%s+(.-)%s+(PUBLIC)%s+["\'](.-)["\']%s+["\'](.-)["\']%s*(%b[])%s*>'
+    obj._DTD3       = '<!DOCTYPE%s+(.-)%s*(%b[])%s*>'
+    obj._DTD4       = '<!DOCTYPE%s+(.-)%s+(SYSTEM)%s+["\'](.-)["\']%s*>'
+    obj._DTD5       = '<!DOCTYPE%s+(.-)%s+(PUBLIC)%s+["\'](.-)["\']%s+["\'](.-)["\']%s*>'
+
+    obj._ATTRERR1   = '=%s*"[^"]*$'
+    obj._ATTRERR2   = '=%s*\'[^\']*$'
+    obj._TAGEXT     = '(%/?)>'
+
+    obj._ENTITIES = { ["<"] = "<",
+                      [">"] = ">",
+                      ["&"] = "&",
+                      ["""] = '"',
+                      ["'"] = "'",
+                      ["&#(%d+);"] = function (x)
+                                        local d = tonumber(x)
+                                        if d >= 0 and d < 256 then
+                                            return string.char(d)
+                                        else
+                                            return "&#"..d..";"
+                                        end
+                                     end,
+                      ["&#x(%x+);"] = function (x)
+                                        local d = tonumber(x,16)
+                                        if d >= 0 and d < 256 then
+                                            return string.char(d)
+                                        else
+                                            return "&#x"..x..";"
+                                        end
+                                      end,
+                    }
+
+    obj._err = function(self,err,pos)
+                   if self.options.errorHandler then
+                       self.options.errorHandler(err,pos)
+                   end
+               end
+
+    obj._errstr = { xmlErr = "Error Parsing XML",
+                    declErr = "Error Parsing XMLDecl",
+                    declStartErr = "XMLDecl not at start of document",
+                    declAttrErr = "Invalid XMLDecl attributes",
+                    piErr = "Error Parsing Processing Instruction",
+                    commentErr = "Error Parsing Comment",
+                    cdataErr = "Error Parsing CDATA",
+                    dtdErr = "Error Parsing DTD",
+                    endTagErr = "End Tag Attributes Invalid",
+                    unmatchedTagErr = "Unbalanced Tag",
+                    incompleteXmlErr = "Incomplete XML Document",
+                  }
+
+    obj._stripWS = function(self,s)
+        if self.options.stripWS then
+            s = string.gsub(s,'^%s+','')
+            s = string.gsub(s,'%s+$','')
+        end
+        return s
+    end
+
+    obj._parseEntities = function(self,s)
+        if self.options.expandEntities then
+            --for k,v in self._ENTITIES do
+            for k,v in pairs(self._ENTITIES) do
+                --print (k, v)
+                s = string.gsub(s,k,v)
+            end
+        end
+        return s
+    end
+
+    obj._parseDTD = function(self,s,pos)
+        -- match,endmatch,root,type,name,uri,internal
+        local m,e,r,t,n,u,i
+        m,e,r,t,u,i = string.find(s,self._DTD1,pos)
+        if m then
+            return m,e,{_root=r,_type=t,_uri=u,_internal=i}
+        end
+        m,e,r,t,n,u,i = string.find(s,self._DTD2,pos)
+        if m then
+            return m,e,{_root=r,_type=t,_name=n,_uri=u,_internal=i}
+        end
+        m,e,r,i = string.find(s,self._DTD3,pos)
+        if m then
+            return m,e,{_root=r,_internal=i}
+        end
+        m,e,r,t,u = string.find(s,self._DTD4,pos)
+        if m then
+            return m,e,{_root=r,_type=t,_uri=u}
+        end
+        m,e,r,t,n,u = string.find(s,self._DTD5,pos)
+        if m then
+            return m,e,{_root=r,_type=t,_name=n,_uri=u}
+        end
+        return nil
+    end
+
+    obj._parseTag = function(self,s)
+        local attrs = {}
+        local tagname = string.gsub(s,self._TAG,'%1')
+        string.gsub(s,self._ATTR1,function (k,v)
+                                attrs[string.lower(k)]=self:_parseEntities(v)
+                                attrs._ = 1
+                           end)
+        string.gsub(s,self._ATTR2,function (k,v)
+                                attrs[string.lower(k)]=self:_parseEntities(v)
+                                attrs._ = 1
+                           end)
+        if attrs._ then
+            attrs._ = nil
+        else
+            attrs = nil
+        end
+        return tagname,attrs
+    end
+
+    return obj
+
+end
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/profile.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/profile.mk	Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,13 @@
+
+
+
+# Requirement of other profiles
+# XXX not yet supported, TARGET_PROFILES used as simple list
+#TARGET_PROFILES+=shttpd
+
+WORLD_SUBDIRS_ZROUTER+= \
+	target/usr.bin/lua/
+
+WORLD_SUBDIRS_USR_SBIN+=	\
+	tcpdump
+


More information about the Zrouter-src mailing list