diff options
author | Steven Barth <steven@midlink.org> | 2009-11-29 13:46:04 +0000 |
---|---|---|
committer | Steven Barth <steven@midlink.org> | 2009-11-29 13:46:04 +0000 |
commit | e822874a710a00ee8b6de988ece12ba76e193236 (patch) | |
tree | 3d58aa56031e0cebbbe2749485cda9e7241f7f76 /modules | |
parent | 2aa4534db4c01851fa38293766f326cf4089c032 (diff) |
NIU:
Add WDS bridge client mode
Extending / repeating WDS network in AP wizard
Better 802.11s support
Diffstat (limited to 'modules')
-rw-r--r-- | modules/niu/luasrc/controller/niu/wireless.lua | 13 | ||||
-rw-r--r-- | modules/niu/luasrc/model/cbi/niu/network/lan1.lua | 48 | ||||
-rw-r--r-- | modules/niu/luasrc/model/cbi/niu/network/wlanwan.lua | 55 | ||||
-rw-r--r-- | modules/niu/luasrc/model/cbi/niu/wireless/ap.lua | 9 | ||||
-rw-r--r-- | modules/niu/luasrc/model/cbi/niu/wireless/ap1.lua | 30 | ||||
-rw-r--r-- | modules/niu/luasrc/model/cbi/niu/wireless/apdevice.lua | 27 | ||||
-rw-r--r-- | modules/niu/luasrc/model/cbi/niu/wireless/brdevice.lua | 33 | ||||
-rw-r--r-- | modules/niu/luasrc/model/cbi/niu/wireless/bridge.lua | 91 | ||||
-rw-r--r-- | modules/niu/luasrc/niulib.lua | 4 |
9 files changed, 257 insertions, 53 deletions
diff --git a/modules/niu/luasrc/controller/niu/wireless.lua b/modules/niu/luasrc/controller/niu/wireless.lua index 478142629..ee402bc49 100644 --- a/modules/niu/luasrc/controller/niu/wireless.lua +++ b/modules/niu/luasrc/controller/niu/wireless.lua @@ -23,11 +23,20 @@ function index() local toniu = {on_success_to={"niu"}} - local e = entry({"niu", "wireless"}, alias("niu"), "Wireless", 20) + local e = entry({"niu", "wireless"}, alias("niu"), i18n.translate("Wireless"), 20) --e.niu_dbtemplate = "niu/wireless" e.niu_dbtasks = true e.niu_dbicon = "icons32/network-wireless.png" entry({"niu", "wireless", "ap"}, - cbi("niu/wireless/ap", toniu), "Configure Private Access Point", 1) + cbi("niu/wireless/ap", toniu), i18n.translate("Configure Private Access Point"), 1) + + local bridge = false + uci.inst:foreach("wireless", "wifi-device", function(s) + if not bridge and (s.type == "mac80211" or s.type == "atheros") then + entry({"niu", "wireless", "bridge"}, + cbi("niu/wireless/bridge", toniu), i18n.translate("Join a local WDS network"), 2) + bridge = true + end + end) end
\ No newline at end of file diff --git a/modules/niu/luasrc/model/cbi/niu/network/lan1.lua b/modules/niu/luasrc/model/cbi/niu/network/lan1.lua index 423b4dfbe..7d24dcd0f 100644 --- a/modules/niu/luasrc/model/cbi/niu/network/lan1.lua +++ b/modules/niu/luasrc/model/cbi/niu/network/lan1.lua @@ -13,17 +13,30 @@ You may obtain a copy of the License at $Id$ ]]-- +local bridge = (arg[1] == "bridgelan") local niulib = require "luci.niulib" local fs = require "nixio.fs" local has_ipv6 = fs.access("/proc/net/ipv6_route") -m = Map("network", "Configure Local Network", "These settings affect the devices in your local network. ".. -"Usually you do not need to change anything here for your router to work correctly.") +m = Map("network", translate("Configure Local Network"), bridge and +translate([[The wireless network will be connected directly to your local network. +Make sure you to assign any address to this device that is in the same subnet +of the other devices in your network but that is not already occupied. +If you have a DHCP-Server in this network you may also choose DHCP for address configuration.]]) +or translate("These settings affect the devices in your local network. ".. +"Usually you do not need to change anything here for your router to work correctly.")) s = m:section(NamedSection, "lan", "interface", "Network Settings") s.addremove = false s:tab("general", translate("General Settings")) +s:tab("expert", translate("Expert Settings")) + +p = s:taboption("expert", ListValue, "proto", translate("Address Configuration")) +p.default = "static" +p:value("static", translate("Static Configuration")) +p:value("dhcp", "DHCP") + ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address")) ipaddr.default = "192.168.0.1" @@ -37,14 +50,6 @@ nm:value("255.0.0.0") nm:depends("proto", "static") - -s:tab("expert", translate("Expert Settings")) - -p = s:taboption("expert", ListValue, "proto", translate("Connection Protocol")) -p.default = "static" -p:value("static", translate("Static Ethernet")) -p:value("dhcp", "DHCP") - mac = s:taboption("expert", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address")) mtu = s:taboption("expert", Value, "mtu", "MTU") @@ -54,7 +59,7 @@ dns = s:taboption("expert", Value, "dns", translate("<abbr title=\"Domain Name S dns:depends("peerdns", "") -gw = s:taboption("expert", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway")) +gw = s:taboption(bridge and "general" or "expert", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway")) gw:depends("proto", "static") bcast = s:taboption("expert", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast")) @@ -68,8 +73,11 @@ if has_ipv6 then ip6gw:depends("proto", "static") end -emerg = s:taboption("expert", Value, "_emergv4", translate("Emergency Access Address")) +emerg = s:taboption("expert", Value, "_emergv4", translate("Emergency Access Address"), +translate([[In case the DHCP request fails you will still be able to access this device using given IP +by configuring your computer to an address in the same subnet and netmask 255.255.255.0.]])) emerg:depends("proto", "dhcp") +emerg:value("", translate("disable")) emerg.default = "169.254.255.169" @@ -83,7 +91,6 @@ for _, eth in ipairs(niulib.eth_get_available("lan")) do end - m2 = Map("dhcp") s = m2:section(TypedSection, "dhcp", "DHCP") @@ -95,7 +102,10 @@ s:tab("general", translate("General Settings")) s:depends("interface", "lan") -enable = s:taboption("general", ListValue, "ignore", "Automatic address assignment for network devices", "") +enable = s:taboption("general", ListValue, "ignore", translate("Automatic address assignment for network devices"), +bridge and +translate("Note: Be careful that you do not accidently two DHCP servers in the same network with overlapping address ranges.") +or "") enable:value(0, translate("enable"), {["network.lan.proto"] = "static"}) enable:value(1, translate("disable")) @@ -103,17 +113,19 @@ enable:value(1, translate("disable")) s:tab("expert", translate("Expert Settings")) start = s:taboption("expert", Value, "start", translate("First leased address")) start:depends("ignore", "0") +start.default = "100" limit = s:taboption("expert", Value, "limit", translate("Number of leased addresses"), "") limit:depends("ignore", "0") +limit.default = "150" -time = s:taboption("expert", Value, "leasetime", "Lease Time") +time = s:taboption("expert", Value, "leasetime", translate("Lease Time")) time:depends("ignore", "0") +time.default = "12h" -local dd = s:taboption("expert", Flag, "dynamicdhcp", "Also generate addresses for unknown devices") +local dd = s:taboption("expert", Flag, "dynamicdhcp", translate("Also generate addresses for unknown devices")) dd.rmempty = false dd.default = "1" dd:depends("ignore", "0") - -return m, m2 +return m, m2
\ No newline at end of file diff --git a/modules/niu/luasrc/model/cbi/niu/network/wlanwan.lua b/modules/niu/luasrc/model/cbi/niu/network/wlanwan.lua index 16c74f05c..40d2486bc 100644 --- a/modules/niu/luasrc/model/cbi/niu/network/wlanwan.lua +++ b/modules/niu/luasrc/model/cbi/niu/network/wlanwan.lua @@ -18,47 +18,56 @@ local uci = require "luci.model.uci" local nixio = require "nixio" local iwinfo = require "iwinfo" +local bridge +local iface = "client" +local net = "wan" +if arg[1] == "bridge" then + bridge = true + iface = "bridge" + net = "lan" +end + local cursor = uci.inst local state = uci.inst_state cursor:unload("wireless") state:unload("wireless") local has_ipv6 = fs.access("/proc/net/ipv6_route") -local device = cursor:get("wireless", "client", "device") +local device = cursor:get("wireless", iface, "device") local hwtype = cursor:get("wireless", device, "type") -- Bring up interface and scan -- -if not state:get("wireless", "client", "network") then +if not state:get("wireless", iface, "network") then local olduci = uci.cursor(nil, "") - local oldcl = olduci:get_all("wireless", "client") + local oldcl = olduci:get_all("wireless", iface) olduci:unload("wireless") local newuci = uci.cursor() - local newcl = newuci:get_all("wireless", "client") - newcl.network = "wan" + local newcl = newuci:get_all("wireless", iface) + newcl.network = net local proc = nixio.fork() if proc == 0 then - newuci:delete("wireless", "client", "ssid") + newuci:delete("wireless", iface, "ssid") newuci:commit("wireless") nixio.exec("/sbin/wifi", "up", device) os.exit(1) end nixio.wait(proc) - newuci:delete("wireless", "client") - newuci:section("wireless", "wifi-iface", "client", oldcl) + newuci:delete("wireless", iface) + newuci:section("wireless", "wifi-iface", iface, oldcl) newuci:commit("wireless") - newuci:tset("wireless", "client", newcl) + newuci:tset("wireless", iface, newcl) newuci:save("wireless") newuci:unload("wireless") state:unload("wireless") end -local ifname = state:get("wireless", "client", "ifname") or "wlan0dummy" +local ifname = state:get("wireless", iface, "ifname") or "wlan0dummy" local iwlib = iwinfo.type(ifname) and iwinfo[iwinfo.type(ifname)] local suggest = {} local encrdep = { @@ -78,9 +87,13 @@ end -- Form definition -- -m2 = Map("wireless", "Configure WLAN-Adapter for Internet Connection") +m2 = Map("wireless", translate("Configure WLAN-Adapter for Client Connection"), +bridge and ("<strong>" .. translate([[It is absolutely necessary that the network you are joining +supports and allows bridging (WDS) otherwise your connection will fail.]]) .. "</strong> " .. +translate([[Note: You can use the access point wizard to configure your +private access point to increase the range of the network you are connected to.]])) or "") -s = m2:section(NamedSection, "client", "wifi-iface", "Wireless Settings") +s = m2:section(NamedSection, iface, "wifi-iface", translate("Wireless Settings")) s.addremove = false s:tab("general", translate("General Settings")) @@ -122,9 +135,11 @@ encr = s:taboption("general", ListValue, "encryption", translate("Encryption")) if hwtype == "mac80211" then - mode:value("mesh", translate("Mesh (802.11s)")) - local meshid = s:taboption("expert", Value, "mesh_id", translate("Mesh ID")) - meshid:depends("mode", "mesh") + if not bridge then + mode:value("mesh", translate("Mesh (802.11s)")) + local meshid = s:taboption("expert", Value, "mesh_id", translate("Mesh ID")) + meshid:depends("mode", "mesh") + end local ps = s:taboption("expert", Flag, "powersave", translate("Enable Powersaving")) ps:depends("mode", "sta") @@ -208,11 +223,11 @@ end - +if not bridge then m = Map("network") -s = m:section(NamedSection, "wan", "interface", translate("Address Settings")) +s = m:section(NamedSection, net, "interface", translate("Address Settings")) s.addremove = false s:tab("general", translate("General Settings")) @@ -261,3 +276,9 @@ mtu.isinteger = true mac = s:taboption("expert", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address")) return m2, m + +else + +return m2 + +end
\ No newline at end of file diff --git a/modules/niu/luasrc/model/cbi/niu/wireless/ap.lua b/modules/niu/luasrc/model/cbi/niu/wireless/ap.lua index 08cc565e2..77325d30c 100644 --- a/modules/niu/luasrc/model/cbi/niu/wireless/ap.lua +++ b/modules/niu/luasrc/model/cbi/niu/wireless/ap.lua @@ -9,12 +9,21 @@ end local function deviceroute(self) cursor:unload("wireless") local d = cursor:get("wireless", "ap", "device") + local t = cursor:get("wireless", "ap", "_cfgtpl") if d ~= "none" then cursor:delete_all("wireless", "wifi-iface", function(s) return s.device == d and s._niu ~= "1" end) cursor:set("wireless", d, "disabled", 0) cursor:set("wireless", "ap", "network", "lan") + if t and #t > 0 then + cursor:delete("wireless", "ap", "_cfgtpl") + cursor:set("wireless", "ap", "ssid", cursor:get("wireless", "bridge", "ssid")) + cursor:set("wireless", "ap", "encryption", cursor:get("wireless", "bridge", "encryption")) + cursor:set("wireless", "ap", "key", cursor:get("wireless", "bridge", "key")) + cursor:set("wireless", "ap", "wds", "1") + end + self:set_route("ap1") else cursor:delete("wireless", "ap", "network") diff --git a/modules/niu/luasrc/model/cbi/niu/wireless/ap1.lua b/modules/niu/luasrc/model/cbi/niu/wireless/ap1.lua index 5ce93b400..2b748ad9d 100644 --- a/modules/niu/luasrc/model/cbi/niu/wireless/ap1.lua +++ b/modules/niu/luasrc/model/cbi/niu/wireless/ap1.lua @@ -16,13 +16,13 @@ $Id$ local iface = "ap" local ap = true - local fs = require "nixio.fs" local sys = require "luci.sys" local cursor = require "luci.model.uci".inst local state = require "luci.model.uci".inst_state cursor:unload("wireless") + local device = cursor:get("wireless", iface, "device") local hwtype = cursor:get("wireless", device, "type") @@ -175,7 +175,9 @@ s.addremove = false s:tab("general", translate("General Settings")) s:tab("expert", translate("Expert Settings")) -s:taboption("general", Value, "ssid", translate("Network Name (<abbr title=\"Extended Service Set Identifier\">ESSID</abbr>)")) + + +local ssid = s:taboption("general", Value, "ssid", translate("Network Name (<abbr title=\"Extended Service Set Identifier\">ESSID</abbr>)")) mode = s:taboption("expert", ListValue, "mode", translate("Operating Mode")) mode.override_values = true @@ -185,8 +187,12 @@ encr = s:taboption("expert", ListValue, "encryption", translate("Encryption")) if hwtype == "mac80211" then - s:taboption("expert", Flag, "wds", translate("Enable Bridging and Repeating (WDS)")) - s:taboption("expert", Flag, "powersave", translate("Enable Powersaving")) + mode:value("mesh", translate("Mesh (802.11s)")) + local meshid = s:taboption("expert", Value, "mesh_id", translate("Mesh ID")) + meshid:depends("mode", "mesh") + + s:taboption("expert", Flag, "wds", translate("Enable Bridging and Repeating (WDS)")):depends("mode", "ap") + s:taboption("expert", Flag, "powersave", translate("Enable Powersaving")):depends("mode", "ap") elseif hwtype == "atheros" then -- mode:value("wds", translate("Static WDS")) @@ -246,16 +252,26 @@ encr:value("wep", "WEP", {mode="ap"}) if hwtype == "atheros" or hwtype == "mac80211" or hwtype == "prism2" then local hostapd = fs.access("/usr/sbin/hostapd") or os.getenv("LUCI_SYSROOT") + local supplicant = fs.access("/usr/sbin/wpa_supplicant") or os.getenv("LUCI_SYSROOT") - if hostapd then - --s:taboption("expert", Flag, "_alloweap", "Allow EAP / 802.11i authentication") - + if hostapd and not supplicant then encr:value("psk", "WPA", {mode="ap"}) encr:value("wpa", "WPA-EAP", {mode="ap"}) encr:value("psk-mixed", "WPA + WPA2", {mode="ap"}) encr:value("psk2", "WPA2", {mode="ap"}) encr:value("wpa2", "WPA2-EAP (802.11i)", {mode="ap"}) encr.default = "psk-mixed" + elseif not hostapd and supplicant then + encr:value("psk", "WPA", {mode="mesh"}) + encr:value("psk2", "WPA2", {mode="mesh"}) + encr.default = "psk2" + elseif hostapd and supplicant then + encr:value("psk", "WPA", {mode="ap"}, {mode="mesh"}) + encr:value("wpa", "WPA-EAP", {mode="ap"}) + encr:value("psk-mixed", "WPA + WPA2", {mode="ap"}) + encr:value("psk2", "WPA2", {mode="ap"}, {mode="mesh"}) + encr:value("wpa2", "WPA2-EAP (802.11i)", {mode="ap"}) + encr.default = "psk-mixed" end elseif hwtype == "broadcom" then encr:value("psk", "WPA") diff --git a/modules/niu/luasrc/model/cbi/niu/wireless/apdevice.lua b/modules/niu/luasrc/model/cbi/niu/wireless/apdevice.lua index 98f5fc5d6..66b21ab7a 100644 --- a/modules/niu/luasrc/model/cbi/niu/wireless/apdevice.lua +++ b/modules/niu/luasrc/model/cbi/niu/wireless/apdevice.lua @@ -12,22 +12,35 @@ You may obtain a copy of the License at $Id$ ]]-- local niulib = require "luci.niulib" +local cursor = require "luci.model.uci".inst -m = Map("wireless", "Configure Private Access Point") -s = m:section(NamedSection, "ap", "interface", translate("Wireless Radio Device"), +m = Map("wireless", translate("Configure Private Access Point")) +s = m:section(NamedSection, "ap", "wifi-iface", translate("Wireless Radio Device"), translate( "Select the wireless radio device that should be used to run the interface.".. " Note that wireless radios will not show up here if you already use".. -" them for other wireless services and are not capable of being used as".. -" an access point in parallel.")) +" them for other wireless services and are not capable of being used by".. +" more than one service simultaneously or run this specific service at all.")) s.anonymous = true s.addremove = false -l = s:option(ListValue, "device", "Device providing Access Point") +local l = s:option(ListValue, "device", translate("Wireless Device")) for _, wifi in ipairs(niulib.wifi_get_available("ap")) do - l:value(wifi, "WLAN-Adapter (%s)" % wifi) + l:value(wifi, translate("WLAN-Adapter (%s)") % wifi) +end +l:value("none", translate("Disable Private Access Point")) + + +local extend = cursor:get("wireless", "bridge", "network") + and cursor:get("wireless", "bridge", "ssid") + +if extend ~= cursor:get("wireless", "ap", "ssid") then + local templ = s:option(ListValue, "_cfgtpl", translate("Configuration Template")) + templ:depends({["!default"] = 1}) + templ:depends({["!reverse"] = 1, device = "none"}) + templ:value("", translate("Access Point (Current Settings)")) + templ:value("bridge", translate("Extend network %s") % extend) end -l:value("none", "Disable Private Access Point") return m diff --git a/modules/niu/luasrc/model/cbi/niu/wireless/brdevice.lua b/modules/niu/luasrc/model/cbi/niu/wireless/brdevice.lua new file mode 100644 index 000000000..be5c475cc --- /dev/null +++ b/modules/niu/luasrc/model/cbi/niu/wireless/brdevice.lua @@ -0,0 +1,33 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2009 Steven Barth <steven@midlink.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- +local niulib = require "luci.niulib" + +m = Map("wireless", translate("Join a local WDS network")) +s = m:section(NamedSection, "bridge", "wifi-iface", translate("Wireless Radio Device"), +translate( +"Select the wireless radio device that should be used to run the interface.".. +" Note that wireless radios will not show up here if you already use".. +" them for other wireless services and are not capable of being used by".. +" more than one service simultaneously or run this specific service at all.")) +s.anonymous = true +s.addremove = false + +l = s:option(ListValue, "device", translate("Wireless Device")) + +for _, wifi in ipairs(niulib.wifi_get_available("bridge", {atheros = true, mac80211 = true})) do + l:value(wifi, translate("WLAN-Adapter (%s)") % wifi) +end +l:value("none", translate("Disable Bridge")) + +return m diff --git a/modules/niu/luasrc/model/cbi/niu/wireless/bridge.lua b/modules/niu/luasrc/model/cbi/niu/wireless/bridge.lua new file mode 100644 index 000000000..7ac2fff99 --- /dev/null +++ b/modules/niu/luasrc/model/cbi/niu/wireless/bridge.lua @@ -0,0 +1,91 @@ +local uci = require "luci.model.uci" +local cursor = uci.cursor() + +if not cursor:get("wireless", "bridge") then + cursor:section("wireless", "wifi-iface", "bridge", + {device = "_", doth = "1", _niu = "1", mode = "sta", wds = "1"}) + cursor:save("wireless") +end + +local function deviceroute(self) + cursor:unload("wireless") + local d = cursor:get("wireless", "bridge", "device") + if d ~= "none" then + local nc = uci.cursor(nil, "") + cursor:delete_all("wireless", "wifi-iface", function(s) + return s.device == d and s._niu ~= "1" + end) + if nc:get("wireless", "bridge", "network") + ~= cursor:get("wireless", "bridge", "network") then + cursor:delete("wireless", "bridge", "network") + end + cursor:set("wireless", d, "disabled", 0) + cursor:foreach("dhcp", "dhcp", function(s) + if s.interface == "lan" and s.ignore ~= "1" then + cursor:set("dhcp", s[".name"], "ignore", "1") + end + end) + self:set_route("scan", "bridge", "bridgelan") + else + if cursor:get("wireless", "bridge", "network") then + cursor:delete("wireless", "bridge", "network") + cursor:foreach("dhcp", "dhcp", function(s) + if s.interface == "lan" and s.ignore == "1" then + cursor:set("dhcp", s[".name"], "ignore", "0") + end + end) + self:set_route("lan") + end + end + cursor:save("dhcp") + cursor:save("wireless") +end + + +local d = Delegator() +d.allow_finish = true +d.allow_back = true +d.allow_cancel = true + +d:add("device", "niu/wireless/brdevice") +d:add("deviceroute", deviceroute) +d:set("scan", "niu/network/wlanwanscan") +d:set("bridge", "niu/network/wlanwan") +d:set("bridgelan", "niu/network/lan1") +d:set("lan", "niu/network/lan1") + +function d.on_cancel() + cursor:revert("network") + cursor:revert("wireless") + cursor:revert("dhcp") +end + +function d.on_done() + if uci.inst_state:get("network", "lan", "ipaddr") ~= cursor:get("network", "lan", "ipaddr") then + local cs = uci.cursor_state() + cs:set("network", "lan", "_ipchanged", "1") + cs:save("network") + end + + if cursor:get("network", "lan", "proto") == "dhcp" then + local emergv4 = cursor:get("network", "lan", "_emergv4") + if emergv4 then + if cursor:get("network", "lan_ea") then + cursor:set("network", "lan_ea", "ipaddr", emergv4) + else + cursor:section("network", "alias", "lan_ea", { + ipaddr = emergv4, + netmask = "255.255.255.0", + network = "lan" + }) + end + else + cursor:delete("network", "lan_ea") + end + end + cursor:commit("network") + cursor:commit("wireless") + cursor:commit("dhcp") +end + +return d
\ No newline at end of file diff --git a/modules/niu/luasrc/niulib.lua b/modules/niu/luasrc/niulib.lua index 73918a8ac..7690294bc 100644 --- a/modules/niu/luasrc/niulib.lua +++ b/modules/niu/luasrc/niulib.lua @@ -52,7 +52,7 @@ function eth_get_bridged(except) return cnt > 1 and ifs or {} end -function wifi_get_available(except) +function wifi_get_available(except, types) cursor:unload("wireless") local iwinfo = require "iwinfo" @@ -72,7 +72,7 @@ function wifi_get_available(except) local wifis = {} cursor:foreach("wireless", "wifi-device", function(s) - if not used[s[".name"]] then + if not used[s[".name"]] and (not types or types[s.type]) then wifis[#wifis+1] = s[".name"] end end) |