Browse Source

Adjustments for the Gluon project

Matthias Schiffer 11 years ago
commit
d9902c0664
17 changed files with 536 additions and 0 deletions
  1. 38 0
      package/gluon-config-mode/Makefile
  2. 3 0
      package/gluon-config-mode/files/etc/config/config_mode
  3. 29 0
      package/gluon-config-mode/files/etc/hotplug.d/button/50-config-mode
  4. 53 0
      package/gluon-config-mode/files/etc/init.d/config_mode
  5. 13 0
      package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/index.lua
  6. 30 0
      package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/wizard.lua
  7. 38 0
      package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/hostname.lua
  8. 67 0
      package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/meshvpn.lua
  9. 43 0
      package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/password.lua
  10. 43 0
      package/gluon-config-mode/files/usr/lib/lua/luci/tools/freifunk-wizard/nav.lua
  11. 16 0
      package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/completed.htm
  12. 19 0
      package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/footer.htm
  13. 24 0
      package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/header.htm
  14. 18 0
      package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/meshvpn-key.htm
  15. 15 0
      package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/nav.htm
  16. 19 0
      package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/welcome.htm
  17. 68 0
      package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/wizardform.htm

+ 38 - 0
package/gluon-config-mode/Makefile

@@ -0,0 +1,38 @@
+# Copyright (C) 2012 Nils Schneider <nils at nilsschneider.net>
+# This is free software, licensed under the Apache 2.0 license.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gluon-config-mode
+PKG_RELEASE:=0.0.1
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/gluon-config-mode
+  SECTION:=gluon
+  CATEGORY:=Gluon
+  TITLE:=Luci based config mode for user friendly setup of new meshnodes
+  DEPENDS:=+luci-mod-admin-core
+endef
+
+define Package/gluon-config-mode/description
+	Luci based config mode
+endef
+
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/gluon-config-mode/install
+	$(CP) ./files/* $(1)/
+endef
+
+$(eval $(call BuildPackage,gluon-config-mode))

+ 3 - 0
package/gluon-config-mode/files/etc/config/config_mode

@@ -0,0 +1,3 @@
+config wizard
+	option enabled '1'
+	option configured '0'

+ 29 - 0
package/gluon-config-mode/files/etc/hotplug.d/button/50-config-mode

@@ -0,0 +1,29 @@
+#!/bin/sh
+
+
+wait=3
+
+
+wait_config_mode() {
+	sleep $wait
+	uci set 'config_mode.@wizard[0].enabled=1'
+	uci commit config_mode
+	reboot
+}
+
+
+if [ "$BUTTON" = wps -o "$BUTTON" = reset ]; then
+	case "$ACTION" in
+		pressed)
+			wait_config_mode &
+			PID=$!
+			echo $PID > /tmp/.wait_config_mode
+			;;
+		released)
+			if [ -r /tmp/.wait_config_mode ]; then
+				kill $(cat /tmp/.wait_config_mode)
+				rm /tmp/.wait_config_mode
+			fi
+			;;
+	esac
+fi

+ 53 - 0
package/gluon-config-mode/files/etc/init.d/config_mode

@@ -0,0 +1,53 @@
+#!/bin/sh /etc/rc.common
+
+START=12
+
+
+config_mode_iface=eth0
+config_mode_addr=192.168.1.1
+config_mode_plen=24
+
+config_mode_dnsname=freifunk
+config_mode_dhcp_range=192.168.1.2,192.168.1.254
+
+check_enable() {
+	config_get enabled "$1" enabled
+	config_get configured "$1" configured
+
+	if [ "$enabled" = 1 -o "$configured" != 1 ]; then
+		export enable=1
+	fi
+}
+
+start() {
+	enable=0
+	config_load config_mode
+	config_foreach check_enable wizard
+
+	if [ "$enable" = '1' ]; then
+		lua -luci -e 'require "luci.model.uci"; uci_state=luci.model.uci.cursor_state(); uci_state:section("config_mode", "wizard", nil, { running = "1" }); uci_state:save("config_mode")'
+		uci set 'config_mode.@wizard[0].enabled=0'
+		uci commit config_mode
+
+		ip addr add $config_mode_addr/$config_mode_plen dev $config_mode_iface
+		ip link set up dev $config_mode_iface
+
+		/etc/init.d/telnet start
+		/etc/init.d/dropbear start
+		/etc/init.d/uhttpd start
+		/etc/init.d/led start
+
+		# correctly finish firstboot
+		/etc/init.d/done boot
+
+		echo "$config_mode_addr $config_mode_dnsname" > /tmp/hosts.config_mode
+		dnsmasq -h -H /tmp/hosts.config_mode -R -F interface:$config_mode_iface,$config_mode_dhcp_range -l /tmp/dhcp.leases -O option:router
+
+		. /etc/diag.sh
+		get_status_led
+		status_led_set_timer 1000 300
+
+		# block further boot
+		while true; do sleep 1; done
+	fi
+}

+ 13 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/index.lua

@@ -0,0 +1,13 @@
+module("luci.controller.freifunk.index", package.seeall)
+
+
+function index()
+  local uci_state = luci.model.uci.cursor_state()
+
+  if uci_state:get_first("config_mode", "wizard", "running", "0") == "1" then
+    local root = node()
+    root.target = alias("wizard", "welcome")
+    root.index = true
+  end
+end
+

+ 30 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/wizard.lua

@@ -0,0 +1,30 @@
+module("luci.controller.freifunk.wizard", package.seeall)
+
+function index()
+  local uci_state = luci.model.uci.cursor_state()
+  if uci_state:get_first("config_mode", "wizard", "running", "0") == "1" then
+    entry({"wizard", "welcome"}, template("freifunk-wizard/welcome"), "Willkommen", 10).dependent=false
+    entry({"wizard", "password"}, form("freifunk-wizard/password"), "Passwort", 20).dependent=false
+    entry({"wizard", "hostname"}, form("freifunk-wizard/hostname"), "Hostname", 30).dependent=false
+    entry({"wizard", "meshvpn"}, form("freifunk-wizard/meshvpn"), "Mesh-VPN", 40).dependent=false
+    entry({"wizard", "meshvpn", "pubkey"}, template("freifunk-wizard/meshvpn-key"), "Mesh-VPN Key", 1).dependent=false
+    entry({"wizard", "completed"}, template("freifunk-wizard/completed"), "Fertig", 50).dependent=false
+    entry({"wizard", "completed", "reboot"}, call("reboot"), "reboot", 1).dependent=false
+  end
+end
+
+function reboot()
+  local uci = luci.model.uci.cursor()
+
+  uci:foreach("config_mode", "wizard",
+              function(s)
+                uci:set("config_mode", s[".name"], "configured", "1")
+              end
+             )
+
+  uci:save("config_mode")
+  uci:commit("config_mode")
+
+  luci.sys.reboot()
+end
+

+ 38 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/hostname.lua

@@ -0,0 +1,38 @@
+local uci = luci.model.uci.cursor()
+
+local nav = require "luci.tools.freifunk-wizard.nav"
+
+local f = SimpleForm("hostname", "Name deines Freifunkknotens", "Als nächstes solltest du einem Freifunkknoten einen individuellen Namen geben. Dieser hilft dir und auch uns den Überblick zu behalten.")
+f.template = "freifunk-wizard/wizardform"
+
+hostname = f:field(Value, "hostname", "Hostname")
+hostname.value = uci:get_first("system", "system", "hostname")
+hostname.rmempty = false
+
+function hostname.validate(self, value, section)
+  return value
+end
+
+function f.handle(self, state, data)
+  if state == FORM_VALID then
+    local stat = true
+    uci:foreach("system", "system", function(s)
+        stat = stat and uci:set("system", s[".name"], "hostname", data.hostname)
+      end
+    )
+
+    stat = stat and uci:save("system")
+    stat = stat and uci:commit("system")
+
+    if stat then
+      nav.maybe_redirect_to_successor()
+            f.message = "Hostname geändert!"
+    else
+      f.errmessage = "Fehler!"
+    end
+  end
+
+  return true
+end
+
+return f

+ 67 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/meshvpn.lua

@@ -0,0 +1,67 @@
+local meshvpn_name = "mesh_vpn"
+
+local uci = luci.model.uci.cursor()
+local nav = require "luci.tools.freifunk-wizard.nav"
+
+local f = SimpleForm("meshvpn", "Mesh-VPN", "<p>Um deinen Freifunkknoten auch über das Internet mit dem Freifunk-Netzwerk zu verbinden, kann das Mesh-VPN aktiviert werden.\
+Dies erlaubt es, den Freifunk-Knoten zu betreiben, auch wenn es keine anderen Knoten in deiner Umgebung gibt, mit denen eine WLAN-Verbindung möglich ist.</p>\
+<p>Dabei wird zur Kommunikation ein verschlüsselter Tunnel verwendet, sodass für den Anschluss-Inhaber keinerlei Risiken entstehen.</p>\
+<p>Damit das Mesh-VPN deine Internet-Verbindung nicht unverhältnismäßig auslastet, kann die Bandbreite begrenzt werden. Wenn du zum Beispiel eine DSL-16000-Leitung hast\
+und maximal ein Viertel der Leitung zur Verfügung stellen willst, muss als Downstream-Bandbreite 4000 kbit/s eingetragen werden.</p>\
+<p>Um das Freifunk-Netz nicht zu sehr auszubremsen, bitten wir darum, mindestens 1000 kbit/s im Downstream und 100 kbit/s im Upstream bereitzustellen.</p>")
+f.template = "freifunk-wizard/wizardform"
+
+meshvpn = f:field(Flag, "meshvpn", "Mesh-VPN aktivieren?")
+meshvpn.default = string.format("%d", uci:get("fastd", meshvpn_name, "enabled", "0"))
+meshvpn.rmempty = false
+
+tc = f:field(Flag, "tc", "Bandbreitenbegrenzung aktivieren?")
+tc.default = string.format("%d", uci:get_first("freifunk", "bandwidth", "enabled", "0"))
+tc.rmempty = false
+
+downstream = f:field(Value, "downstream", "Downstream-Bandbreite (kbit/s)")
+downstream.value = uci:get_first("freifunk", "bandwidth", "downstream", "0")
+upstream = f:field(Value, "upstream", "Upstream-Bandbreite (kbit/s)")
+upstream.value = uci:get_first("freifunk", "bandwidth", "upstream", "0")
+
+function f.handle(self, state, data)
+  if state == FORM_VALID then
+    local stat = false
+    uci:set("fastd", meshvpn_name, "enabled", data.meshvpn)
+    uci:save("fastd")
+    uci:commit("fastd")
+
+    uci:foreach("freifunk", "bandwidth", function(s)
+            uci:set("freifunk", s[".name"], "upstream", data.upstream)
+            uci:set("freifunk", s[".name"], "downstream", data.downstream)
+            uci:set("freifunk", s[".name"], "enabled", data.tc)
+            end
+    )
+
+    uci:save("freifunk")
+    uci:commit("freifunk")
+
+    if data.meshvpn == "1" then
+      local secret = uci:get("fastd", meshvpn_name, "secret")
+      if not secret or not secret:match("%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x") then
+        luci.sys.call("/etc/init.d/haveged start")
+        local f = io.popen("fastd --generate-key --machine-readable", "r")
+        local secret = f:read("*a")
+        f:close()
+        luci.sys.call("/etc/init.d/haveged stop")
+
+        uci:set("fastd", meshvpn_name, "secret", secret)
+        uci:save("fastd")
+        uci:commit("fastd")
+
+      end
+      luci.http.redirect(luci.dispatcher.build_url("wizard", "meshvpn", "pubkey"))
+    else
+      nav.maybe_redirect_to_successor()
+    end
+  end
+
+  return true
+end
+
+return f

+ 43 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/password.lua

@@ -0,0 +1,43 @@
+local nav = require "luci.tools.freifunk-wizard.nav"
+
+f = SimpleForm("password", "Administrator-Passwort setzen", "<p>Damit nur du Zugriff auf deinen Freifunkknoten hast, solltest du jetzt ein Passwort vergeben. \
+Da man mit Hilfe von diesem beliebige Einstellungen geändert werden können, sollte es möglichst sicher sein.</p>\
+<p>Bitte beachte dazu folgende Hinweise:</p>\
+<ul>\
+  <li>Es sollte in keinem Wörterbuch vorkommen.</li>\
+  <li>Es sollte mehr als acht Zeichen beinhalten.</li>\
+  <li>Es sollte auch Zahlen &amp; Sonderzeichen enthalten.</li>\
+</ul>")
+f.template = "freifunk-wizard/wizardform"
+
+pw1 = f:field(Value, "pw1", "Passwort")
+pw1.password = true
+pw1.rmempty = false
+
+pw2 = f:field(Value, "pw2", "Wiederholung")
+pw2.password = true
+pw2.rmempty = false
+
+function pw2.validate(self, value, section)
+  return pw1:formvalue(section) == value and value
+end
+
+function f.handle(self, state, data)
+  if state == FORM_VALID then
+    local stat = luci.sys.user.setpasswd("root", data.pw1) == 0
+
+    if stat then
+            nav.maybe_redirect_to_successor()
+            f.message = "Passwort geändert!"
+    else
+      f.errmessage = "Fehler!"
+    end
+
+    data.pw1 = nil
+    data.pw2 = nil
+  end
+
+  return true
+end
+
+return f

+ 43 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/tools/freifunk-wizard/nav.lua

@@ -0,0 +1,43 @@
+module("luci.tools.freifunk-wizard.nav", package.seeall)
+
+function maybe_redirect_to_successor()
+  local pre, suc = get()
+
+  if suc then
+          luci.http.redirect(luci.dispatcher.build_url("wizard", suc.href))
+        end
+end
+
+function get()
+
+        local disp = require "luci.dispatcher"
+
+        local request  = disp.context.path
+        local category = request[1]
+        local cattree  = category and disp.node(category)
+
+  local childs = disp.node_childs(cattree)
+
+  local predecessor = nil
+  local successor = nil
+
+        if #childs > 0 then
+          local found_pre = false
+          for i, r in ipairs(childs) do
+                  local nnode = cattree.nodes[r]
+                  nnode.href = r
+
+                        if r == request[2] then
+                          found_pre = true
+                        elseif found_pre and successor == nil then
+                          successor = nnode
+                        end
+
+                        if not found_pre then
+                          predecessor = nnode
+                        end
+                end
+        end
+
+        return predecessor, successor
+end

+ 16 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/completed.htm

@@ -0,0 +1,16 @@
+<%
+  local disp = require "luci.dispatcher"
+%>
+<%+header%>
+  <h2>Konfiguration abgeschlossen</h2>
+
+  <p>Die Konfiguration deines Freifunkknotens ist nun abgeschlossen. Damit sie aktiv wird, muss der Knoten neugestartet werden.<p>
+
+  <p>Um später wieder in den Konfiguration-Modus zurückzukehren, zum Beispiel um die Konfiguration zu verändern oder ein Firmware-Upgrade durchzuführen,
+  muss der QSS-Button am Gehäuse für einige Sekunden gedrückt gehalten werden, während der Knoten läuft. Der Knoten wird dann neu starten und in
+  den Konfigurationsmodus zurückkehren.</p>
+
+  <p>
+    <a class="btn primary" href="<%=disp.build_url("wizard", "completed", "reboot")%>">Jetzt neustarten!</a>
+  </p>
+<%+footer%>

+ 19 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/footer.htm

@@ -0,0 +1,19 @@
+<% local xtime
+if exectime then
+  xtime = (string.format("%.2fs", os.clock() - exectime))
+end %>
+
+<footer class="footer">
+<p><a href="http://luci.subsignal.org">Powered by <%= luci.__appname__ .. " (" .. luci.__version__ .. ")" %></a>
+<% if xtime then %>
+<br/>
+Script execution time: <%=xtime%>
+<% end %>
+</p>
+</footer>
+
+</div>
+
+</body>
+</html>
+

+ 24 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/header.htm

@@ -0,0 +1,24 @@
+<%
+        local fs   = require "luci.fs"
+        local sys  = require "luci.sys"
+        local http = require "luci.http"
+        local disp = require "luci.dispatcher"
+
+        local hostname = sys.hostname()
+%>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta http-equiv="Content-Script-Type" content="text/javascript" />
+<link rel="stylesheet" type="text/css" media="screen" href="/wizard/bootstrap.css" />
+
+<title><%=striptags( hostname )%> - Wizard</title>
+</head>
+
+<body class="lang_<%=luci.i18n.context.lang%>">
+
+<div class="container">
+
+<div class="page-header">
+  <h1>Freifunk Wizard</h1>
+</div>

+ 18 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/meshvpn-key.htm

@@ -0,0 +1,18 @@
+<%
+  local meshvpn_name = "mesh_vpn"
+  local address = "freifunk.luebeck@asta.uni-luebeck.de"
+
+  local disp = require "luci.dispatcher"
+  local f = io.popen("/etc/init.d/fastd show_key " .. meshvpn_name, "r")
+  local key = f:read("*a")
+  f:close()
+
+%>
+<%+header%>
+  <h2>Schlüsselaustausch</h2>
+  <p>Dies ist der öffentliche Schlüssel deines Freifunkknotens. Bitte schicke ihn an <%=address%>, um ihn auf den Freifunkservern eintragen zu lassen. Sobald der Schlüssel eingetragen wurde, kann dein Knoten das Mesh-VPN nutzen.</p>
+  <div style="text-align: center;font-size: 2em;line-height: 1em; background: #f5f5f5; border: 1px solid #ececec; margin-bottom: 0.5em; padding: 0.5em">
+    <%=key%>
+  </div>
+<%+freifunk-wizard/nav%>
+<%+footer%>

+ 15 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/nav.htm

@@ -0,0 +1,15 @@
+<%
+        local nav = require "luci.tools.freifunk-wizard.nav"
+        local predecessor, successor = nav.get()
+%>
+
+<div class="actions">
+
+<% if successor then %>
+  <a class="btn primary" href="<%=luci.dispatcher.build_url("wizard", successor.href)%>">Weiter</a>
+<% end %>
+
+<% if predecessor then %>
+  <a class="btn" href="<%=luci.dispatcher.build_url("wizard", predecessor.href)%>">Zurück</a>
+<% end %>
+</div>

+ 19 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/welcome.htm

@@ -0,0 +1,19 @@
+<%
+        local disp = require "luci.dispatcher"
+        local nav = require "luci.tools.freifunk-wizard.nav"
+        local predecessor, successor = nav.get()
+%>
+<%+header%>
+        <h2>Willkommen auf deinem Freifunkknoten!</h2>
+        <p>Danke, dass du Freifunk unterstützt.</p>
+        <p>Dieser Wizard hilft dir nun deinen Knoten einzurichten. Dabei führt er dich schrittweise durch die wichtigsten Punkte.</p>
+
+        <div class="actions">
+<% if successor then %>
+                <a class="btn primary" href="<%=luci.dispatcher.build_url("wizard", successor.href)%>">Knoten neu einrichten</a>
+<% end %>
+
+                <a class="btn" href="<%=luci.dispatcher.build_url("admin", "system", "flashops")%>">Firmwareupgrade einspielen</a>
+        </div>
+<%+footer%>
+

+ 68 - 0
package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/wizardform.htm

@@ -0,0 +1,68 @@
+<% if not self.embedded then %>
+<form method="post" enctype="multipart/form-data" action="<%=REQUEST_URI%>">
+  <div>
+    <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+    <input type="hidden" name="cbi.submit" value="1" />
+  </div>
+<% end %>
+  <div class="cbi-map" id="cbi-<%=self.config%>">
+    <% if self.title and #self.title > 0 then %><h2><a id="content" name="content"><%=self.title%></a></h2><% end %>
+    <% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
+    <% self:render_children() %>
+    <br />
+  </div>
+<%- if self.message then %>
+  <div><%=self.message%></div>
+<%- end %>
+<%- if self.errmessage then %>
+  <div class="error"><%=self.errmessage%></div>
+<%- end %>
+<% if not self.embedded then %>
+  <div>
+<%-
+  if type(self.hidden) == "table" then
+    for k, v in pairs(self.hidden) do
+-%>
+  <input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" />
+<%-
+    end
+  end
+%>
+  <div class="actions">
+<% if redirect then %>
+  <div style="float:left">
+    <input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" />
+  </div>
+<% end %>
+<%- if self.flow and self.flow.skip then %>
+  <input class="cbi-button cbi-button-skip" type="submit" name="cbi.skip" value="<%:Skip%>" />
+<% end %>
+<%- if self.submit ~= false then %>
+  <input class="cbi-button cbi-button-save btn primary" type="submit" value="
+    <%- if not self.submit then -%>Weiter<%-else-%><%=self.submit%><%end-%>
+  " />
+<% end %>
+<%- if self.reset ~= false then %>
+  <input class="cbi-button cbi-button-reset" type="reset" value="
+    <%- if not self.reset then -%><%-:Reset-%><%-else-%><%=self.reset%><%end-%>
+  " />
+<% end %>
+<%- if self.cancel ~= false and self.on_cancel then %>
+  <input class="cbi-button cbi-button-reset" type="submit" name="cbi.cancel" value="
+    <%- if not self.cancel then -%><%-:Cancel-%><%-else-%><%=self.cancel%><%end-%>
+  " />
+<% end %>
+<%
+        local nav = require "luci.tools.freifunk-wizard.nav"
+        local predecessor, successor = nav.get()
+%>
+  <% if predecessor then %>
+    <a class="btn" href="<%=luci.dispatcher.build_url("wizard", predecessor.href)%>">
+      Zurück
+    </a>
+  <% end %>
+    <script type="text/javascript">cbi_d_update();</script>
+  </div>
+ </div>
+</form>
+<% end %>