3cf97d537c83815993f7c2e8855cf421a080fcd2
[oweals/luci.git] / docs / jsapi / luci.js.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4     <meta charset="utf-8">
5     <title>Source: luci.js</title>
6     
7     
8     <script src="scripts/prettify/prettify.js"></script>
9     <script src="scripts/prettify/lang-css.js"></script>
10     <script src="scripts/jquery.min.js"></script>
11     <!--[if lt IE 9]>
12       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13     <![endif]-->
14     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
15     <link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
16     <link type="text/css" rel="stylesheet" href="styles/jaguar.css">
17     
18     
19     <script>
20     var config = {"monospaceLinks":true,"cleverLinks":true,"default":{"outputSourceFiles":true}};
21     </script>
22     
23
24     
25 </head>
26 <body>
27 <div id="wrap" class="clearfix">
28     
29 <div class="navigation">
30     <h3 class="applicationName"><a href="index.html"></a></h3>
31
32     <div class="search">
33         <input id="search" type="text" class="form-control input-sm" placeholder="Search Documentations">
34     </div>
35     <ul class="list">
36     
37         <li class="item" data-name="LuCI">
38             <span class="title">
39                 <a href="LuCI.html">LuCI</a>
40                 
41             </span>
42             <ul class="members itemMembers">
43             
44             <span class="subtitle">Members</span>
45             
46                 <li data-name="LuCI#Class"><a href="LuCI.html#Class">Class</a></li>
47             
48                 <li data-name="LuCI#dom"><a href="LuCI.html#dom">dom</a></li>
49             
50                 <li data-name="LuCI#env"><a href="LuCI.html#env">env</a></li>
51             
52                 <li data-name="LuCI#Poll"><a href="LuCI.html#Poll">Poll</a></li>
53             
54                 <li data-name="LuCI#Request"><a href="LuCI.html#Request">Request</a></li>
55             
56                 <li data-name="LuCI#view"><a href="LuCI.html#view">view</a></li>
57             
58             </ul>
59             <ul class="typedefs itemMembers">
60             
61             <span class="subtitle">Typedefs</span>
62             
63                 <li data-name="LuCI.requestCallbackFn"><a href="LuCI.html#.requestCallbackFn">requestCallbackFn</a></li>
64             
65             </ul>
66             <ul class="typedefs itemMembers">
67             
68             </ul>
69             <ul class="methods itemMembers">
70             
71             <span class="subtitle">Methods</span>
72             
73                 <li data-name="LuCI#bind"><a href="LuCI.html#bind">bind</a></li>
74             
75                 <li data-name="LuCI#error"><a href="LuCI.html#error">error</a></li>
76             
77                 <li data-name="LuCI#get"><a href="LuCI.html#get">get</a></li>
78             
79                 <li data-name="LuCI#halt"><a href="LuCI.html#halt">halt</a></li>
80             
81                 <li data-name="LuCI#hasSystemFeature"><a href="LuCI.html#hasSystemFeature">hasSystemFeature</a></li>
82             
83                 <li data-name="LuCI#isObject"><a href="LuCI.html#isObject">isObject</a></li>
84             
85                 <li data-name="LuCI#location"><a href="LuCI.html#location">location</a></li>
86             
87                 <li data-name="LuCI#media"><a href="LuCI.html#media">media</a></li>
88             
89                 <li data-name="LuCI#path"><a href="LuCI.html#path">path</a></li>
90             
91                 <li data-name="LuCI#poll"><a href="LuCI.html#poll">poll</a></li>
92             
93                 <li data-name="LuCI#post"><a href="LuCI.html#post">post</a></li>
94             
95                 <li data-name="LuCI#raise"><a href="LuCI.html#raise">raise</a></li>
96             
97                 <li data-name="LuCI#require"><a href="LuCI.html#require">require</a></li>
98             
99                 <li data-name="LuCI#resolveDefault"><a href="LuCI.html#resolveDefault">resolveDefault</a></li>
100             
101                 <li data-name="LuCI#resource"><a href="LuCI.html#resource">resource</a></li>
102             
103                 <li data-name="LuCI#run"><a href="LuCI.html#run">run</a></li>
104             
105                 <li data-name="LuCI#sortedKeys"><a href="LuCI.html#sortedKeys">sortedKeys</a></li>
106             
107                 <li data-name="LuCI#stop"><a href="LuCI.html#stop">stop</a></li>
108             
109                 <li data-name="LuCI#toArray"><a href="LuCI.html#toArray">toArray</a></li>
110             
111                 <li data-name="LuCI#url"><a href="LuCI.html#url">url</a></li>
112             
113             </ul>
114             <ul class="events itemMembers">
115             
116             </ul>
117         </li>
118     
119         <li class="item" data-name="LuCI.baseclass">
120             <span class="title">
121                 <a href="LuCI.baseclass.html">LuCI.baseclass</a>
122                 
123             </span>
124             <ul class="members itemMembers">
125             
126             </ul>
127             <ul class="typedefs itemMembers">
128             
129             </ul>
130             <ul class="typedefs itemMembers">
131             
132             </ul>
133             <ul class="methods itemMembers">
134             
135             <span class="subtitle">Methods</span>
136             
137                 <li data-name="LuCI.baseclass.extend"><a href="LuCI.baseclass.html#.extend">extend</a></li>
138             
139                 <li data-name="LuCI.baseclass.instantiate"><a href="LuCI.baseclass.html#.instantiate">instantiate</a></li>
140             
141                 <li data-name="LuCI.baseclass.isSubclass"><a href="LuCI.baseclass.html#.isSubclass">isSubclass</a></li>
142             
143                 <li data-name="LuCI.baseclass.singleton"><a href="LuCI.baseclass.html#.singleton">singleton</a></li>
144             
145                 <li data-name="LuCI.baseclass#super"><a href="LuCI.baseclass.html#super">super</a></li>
146             
147                 <li data-name="LuCI.baseclass#varargs"><a href="LuCI.baseclass.html#varargs">varargs</a></li>
148             
149             </ul>
150             <ul class="events itemMembers">
151             
152             </ul>
153         </li>
154     
155         <li class="item" data-name="LuCI.dom">
156             <span class="title">
157                 <a href="LuCI.dom.html">LuCI.dom</a>
158                 
159             </span>
160             <ul class="members itemMembers">
161             
162             </ul>
163             <ul class="typedefs itemMembers">
164             
165             <span class="subtitle">Typedefs</span>
166             
167                 <li data-name="LuCI.dom~ignoreCallbackFn"><a href="LuCI.dom.html#~ignoreCallbackFn">ignoreCallbackFn</a></li>
168             
169             </ul>
170             <ul class="typedefs itemMembers">
171             
172             </ul>
173             <ul class="methods itemMembers">
174             
175             <span class="subtitle">Methods</span>
176             
177                 <li data-name="LuCI.dom#append"><a href="LuCI.dom.html#append">append</a></li>
178             
179                 <li data-name="LuCI.dom#attr"><a href="LuCI.dom.html#attr">attr</a></li>
180             
181                 <li data-name="LuCI.dom#bindClassInstance"><a href="LuCI.dom.html#bindClassInstance">bindClassInstance</a></li>
182             
183                 <li data-name="LuCI.dom#callClassMethod"><a href="LuCI.dom.html#callClassMethod">callClassMethod</a></li>
184             
185                 <li data-name="LuCI.dom#content"><a href="LuCI.dom.html#content">content</a></li>
186             
187                 <li data-name="LuCI.dom#create"><a href="LuCI.dom.html#create">create</a></li>
188             
189                 <li data-name="LuCI.dom#data"><a href="LuCI.dom.html#data">data</a></li>
190             
191                 <li data-name="LuCI.dom#elem"><a href="LuCI.dom.html#elem">elem</a></li>
192             
193                 <li data-name="LuCI.dom#findClassInstance"><a href="LuCI.dom.html#findClassInstance">findClassInstance</a></li>
194             
195                 <li data-name="LuCI.dom#isEmpty"><a href="LuCI.dom.html#isEmpty">isEmpty</a></li>
196             
197                 <li data-name="LuCI.dom#matches"><a href="LuCI.dom.html#matches">matches</a></li>
198             
199                 <li data-name="LuCI.dom#parent"><a href="LuCI.dom.html#parent">parent</a></li>
200             
201                 <li data-name="LuCI.dom#parse"><a href="LuCI.dom.html#parse">parse</a></li>
202             
203             </ul>
204             <ul class="events itemMembers">
205             
206             </ul>
207         </li>
208     
209         <li class="item" data-name="LuCI.fs">
210             <span class="title">
211                 <a href="LuCI.fs.html">LuCI.fs</a>
212                 
213             </span>
214             <ul class="members itemMembers">
215             
216             </ul>
217             <ul class="typedefs itemMembers">
218             
219             <span class="subtitle">Typedefs</span>
220             
221                 <li data-name="LuCI.fs.FileExecResult"><a href="LuCI.fs.html#.FileExecResult">FileExecResult</a></li>
222             
223                 <li data-name="LuCI.fs.FileStatEntry"><a href="LuCI.fs.html#.FileStatEntry">FileStatEntry</a></li>
224             
225             </ul>
226             <ul class="typedefs itemMembers">
227             
228             </ul>
229             <ul class="methods itemMembers">
230             
231             <span class="subtitle">Methods</span>
232             
233                 <li data-name="LuCI.fs#exec"><a href="LuCI.fs.html#exec">exec</a></li>
234             
235                 <li data-name="LuCI.fs#exec_direct"><a href="LuCI.fs.html#exec_direct">exec_direct</a></li>
236             
237                 <li data-name="LuCI.fs#lines"><a href="LuCI.fs.html#lines">lines</a></li>
238             
239                 <li data-name="LuCI.fs#list"><a href="LuCI.fs.html#list">list</a></li>
240             
241                 <li data-name="LuCI.fs#read"><a href="LuCI.fs.html#read">read</a></li>
242             
243                 <li data-name="LuCI.fs#read_direct"><a href="LuCI.fs.html#read_direct">read_direct</a></li>
244             
245                 <li data-name="LuCI.fs#remove"><a href="LuCI.fs.html#remove">remove</a></li>
246             
247                 <li data-name="LuCI.fs#stat"><a href="LuCI.fs.html#stat">stat</a></li>
248             
249                 <li data-name="LuCI.fs#trimmed"><a href="LuCI.fs.html#trimmed">trimmed</a></li>
250             
251                 <li data-name="LuCI.fs#write"><a href="LuCI.fs.html#write">write</a></li>
252             
253             </ul>
254             <ul class="events itemMembers">
255             
256             </ul>
257         </li>
258     
259         <li class="item" data-name="LuCI.headers">
260             <span class="title">
261                 <a href="LuCI.headers.html">LuCI.headers</a>
262                 
263             </span>
264             <ul class="members itemMembers">
265             
266             </ul>
267             <ul class="typedefs itemMembers">
268             
269             </ul>
270             <ul class="typedefs itemMembers">
271             
272             </ul>
273             <ul class="methods itemMembers">
274             
275             <span class="subtitle">Methods</span>
276             
277                 <li data-name="LuCI.headers#get"><a href="LuCI.headers.html#get">get</a></li>
278             
279                 <li data-name="LuCI.headers#has"><a href="LuCI.headers.html#has">has</a></li>
280             
281             </ul>
282             <ul class="events itemMembers">
283             
284             </ul>
285         </li>
286     
287         <li class="item" data-name="LuCI.network">
288             <span class="title">
289                 <a href="LuCI.network.html">LuCI.network</a>
290                 
291             </span>
292             <ul class="members itemMembers">
293             
294             </ul>
295             <ul class="typedefs itemMembers">
296             
297             <span class="subtitle">Typedefs</span>
298             
299                 <li data-name="LuCI.network.SwitchTopology"><a href="LuCI.network.html#.SwitchTopology">SwitchTopology</a></li>
300             
301                 <li data-name="LuCI.network.WifiEncryption"><a href="LuCI.network.html#.WifiEncryption">WifiEncryption</a></li>
302             
303                 <li data-name="LuCI.network.WifiPeerEntry"><a href="LuCI.network.html#.WifiPeerEntry">WifiPeerEntry</a></li>
304             
305                 <li data-name="LuCI.network.WifiRateEntry"><a href="LuCI.network.html#.WifiRateEntry">WifiRateEntry</a></li>
306             
307                 <li data-name="LuCI.network.WifiScanResult"><a href="LuCI.network.html#.WifiScanResult">WifiScanResult</a></li>
308             
309             </ul>
310             <ul class="typedefs itemMembers">
311             
312             </ul>
313             <ul class="methods itemMembers">
314             
315             <span class="subtitle">Methods</span>
316             
317                 <li data-name="LuCI.network#addNetwork"><a href="LuCI.network.html#addNetwork">addNetwork</a></li>
318             
319                 <li data-name="LuCI.network#addWifiNetwork"><a href="LuCI.network.html#addWifiNetwork">addWifiNetwork</a></li>
320             
321                 <li data-name="LuCI.network#deleteNetwork"><a href="LuCI.network.html#deleteNetwork">deleteNetwork</a></li>
322             
323                 <li data-name="LuCI.network#deleteWifiNetwork"><a href="LuCI.network.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
324             
325                 <li data-name="LuCI.network#flushCache"><a href="LuCI.network.html#flushCache">flushCache</a></li>
326             
327                 <li data-name="LuCI.network#formatWifiEncryption"><a href="LuCI.network.html#formatWifiEncryption">formatWifiEncryption</a></li>
328             
329                 <li data-name="LuCI.network#getDevice"><a href="LuCI.network.html#getDevice">getDevice</a></li>
330             
331                 <li data-name="LuCI.network#getDevices"><a href="LuCI.network.html#getDevices">getDevices</a></li>
332             
333                 <li data-name="LuCI.network#getDSLModemType"><a href="LuCI.network.html#getDSLModemType">getDSLModemType</a></li>
334             
335                 <li data-name="LuCI.network#getHostHints"><a href="LuCI.network.html#getHostHints">getHostHints</a></li>
336             
337                 <li data-name="LuCI.network#getIfnameOf"><a href="LuCI.network.html#getIfnameOf">getIfnameOf</a></li>
338             
339                 <li data-name="LuCI.network#getNetwork"><a href="LuCI.network.html#getNetwork">getNetwork</a></li>
340             
341                 <li data-name="LuCI.network#getNetworks"><a href="LuCI.network.html#getNetworks">getNetworks</a></li>
342             
343                 <li data-name="LuCI.network#getProtocol"><a href="LuCI.network.html#getProtocol">getProtocol</a></li>
344             
345                 <li data-name="LuCI.network#getProtocols"><a href="LuCI.network.html#getProtocols">getProtocols</a></li>
346             
347                 <li data-name="LuCI.network#getSwitchTopologies"><a href="LuCI.network.html#getSwitchTopologies">getSwitchTopologies</a></li>
348             
349                 <li data-name="LuCI.network#getWAN6Networks"><a href="LuCI.network.html#getWAN6Networks">getWAN6Networks</a></li>
350             
351                 <li data-name="LuCI.network#getWANNetworks"><a href="LuCI.network.html#getWANNetworks">getWANNetworks</a></li>
352             
353                 <li data-name="LuCI.network#getWifiDevice"><a href="LuCI.network.html#getWifiDevice">getWifiDevice</a></li>
354             
355                 <li data-name="LuCI.network#getWifiDevices"><a href="LuCI.network.html#getWifiDevices">getWifiDevices</a></li>
356             
357                 <li data-name="LuCI.network#getWifiNetwork"><a href="LuCI.network.html#getWifiNetwork">getWifiNetwork</a></li>
358             
359                 <li data-name="LuCI.network#getWifiNetworks"><a href="LuCI.network.html#getWifiNetworks">getWifiNetworks</a></li>
360             
361                 <li data-name="LuCI.network#isIgnoredDevice"><a href="LuCI.network.html#isIgnoredDevice">isIgnoredDevice</a></li>
362             
363                 <li data-name="LuCI.network#maskToPrefix"><a href="LuCI.network.html#maskToPrefix">maskToPrefix</a></li>
364             
365                 <li data-name="LuCI.network#prefixToMask"><a href="LuCI.network.html#prefixToMask">prefixToMask</a></li>
366             
367                 <li data-name="LuCI.network#registerErrorCode"><a href="LuCI.network.html#registerErrorCode">registerErrorCode</a></li>
368             
369                 <li data-name="LuCI.network#registerPatternVirtual"><a href="LuCI.network.html#registerPatternVirtual">registerPatternVirtual</a></li>
370             
371                 <li data-name="LuCI.network#registerProtocol"><a href="LuCI.network.html#registerProtocol">registerProtocol</a></li>
372             
373                 <li data-name="LuCI.network#renameNetwork"><a href="LuCI.network.html#renameNetwork">renameNetwork</a></li>
374             
375             </ul>
376             <ul class="events itemMembers">
377             
378             </ul>
379         </li>
380     
381         <li class="item" data-name="LuCI.network.Device">
382             <span class="title">
383                 <a href="LuCI.network.Device.html">LuCI.network.Device</a>
384                 
385             </span>
386             <ul class="members itemMembers">
387             
388             </ul>
389             <ul class="typedefs itemMembers">
390             
391             </ul>
392             <ul class="typedefs itemMembers">
393             
394             </ul>
395             <ul class="methods itemMembers">
396             
397             <span class="subtitle">Methods</span>
398             
399                 <li data-name="LuCI.network.Device#getBridgeID"><a href="LuCI.network.Device.html#getBridgeID">getBridgeID</a></li>
400             
401                 <li data-name="LuCI.network.Device#getBridgeSTP"><a href="LuCI.network.Device.html#getBridgeSTP">getBridgeSTP</a></li>
402             
403                 <li data-name="LuCI.network.Device#getI18n"><a href="LuCI.network.Device.html#getI18n">getI18n</a></li>
404             
405                 <li data-name="LuCI.network.Device#getIP6Addrs"><a href="LuCI.network.Device.html#getIP6Addrs">getIP6Addrs</a></li>
406             
407                 <li data-name="LuCI.network.Device#getIPAddrs"><a href="LuCI.network.Device.html#getIPAddrs">getIPAddrs</a></li>
408             
409                 <li data-name="LuCI.network.Device#getMAC"><a href="LuCI.network.Device.html#getMAC">getMAC</a></li>
410             
411                 <li data-name="LuCI.network.Device#getMTU"><a href="LuCI.network.Device.html#getMTU">getMTU</a></li>
412             
413                 <li data-name="LuCI.network.Device#getName"><a href="LuCI.network.Device.html#getName">getName</a></li>
414             
415                 <li data-name="LuCI.network.Device#getNetwork"><a href="LuCI.network.Device.html#getNetwork">getNetwork</a></li>
416             
417                 <li data-name="LuCI.network.Device#getNetworks"><a href="LuCI.network.Device.html#getNetworks">getNetworks</a></li>
418             
419                 <li data-name="LuCI.network.Device#getPorts"><a href="LuCI.network.Device.html#getPorts">getPorts</a></li>
420             
421                 <li data-name="LuCI.network.Device#getRXBytes"><a href="LuCI.network.Device.html#getRXBytes">getRXBytes</a></li>
422             
423                 <li data-name="LuCI.network.Device#getRXPackets"><a href="LuCI.network.Device.html#getRXPackets">getRXPackets</a></li>
424             
425                 <li data-name="LuCI.network.Device#getShortName"><a href="LuCI.network.Device.html#getShortName">getShortName</a></li>
426             
427                 <li data-name="LuCI.network.Device#getTXBytes"><a href="LuCI.network.Device.html#getTXBytes">getTXBytes</a></li>
428             
429                 <li data-name="LuCI.network.Device#getTXPackets"><a href="LuCI.network.Device.html#getTXPackets">getTXPackets</a></li>
430             
431                 <li data-name="LuCI.network.Device#getType"><a href="LuCI.network.Device.html#getType">getType</a></li>
432             
433                 <li data-name="LuCI.network.Device#getTypeI18n"><a href="LuCI.network.Device.html#getTypeI18n">getTypeI18n</a></li>
434             
435                 <li data-name="LuCI.network.Device#getWifiNetwork"><a href="LuCI.network.Device.html#getWifiNetwork">getWifiNetwork</a></li>
436             
437                 <li data-name="LuCI.network.Device#isBridge"><a href="LuCI.network.Device.html#isBridge">isBridge</a></li>
438             
439                 <li data-name="LuCI.network.Device#isBridgePort"><a href="LuCI.network.Device.html#isBridgePort">isBridgePort</a></li>
440             
441                 <li data-name="LuCI.network.Device#isUp"><a href="LuCI.network.Device.html#isUp">isUp</a></li>
442             
443             </ul>
444             <ul class="events itemMembers">
445             
446             </ul>
447         </li>
448     
449         <li class="item" data-name="LuCI.network.Hosts">
450             <span class="title">
451                 <a href="LuCI.network.Hosts.html">LuCI.network.Hosts</a>
452                 
453             </span>
454             <ul class="members itemMembers">
455             
456             </ul>
457             <ul class="typedefs itemMembers">
458             
459             </ul>
460             <ul class="typedefs itemMembers">
461             
462             </ul>
463             <ul class="methods itemMembers">
464             
465             <span class="subtitle">Methods</span>
466             
467                 <li data-name="LuCI.network.Hosts#getHostnameByIP6Addr"><a href="LuCI.network.Hosts.html#getHostnameByIP6Addr">getHostnameByIP6Addr</a></li>
468             
469                 <li data-name="LuCI.network.Hosts#getHostnameByIPAddr"><a href="LuCI.network.Hosts.html#getHostnameByIPAddr">getHostnameByIPAddr</a></li>
470             
471                 <li data-name="LuCI.network.Hosts#getHostnameByMACAddr"><a href="LuCI.network.Hosts.html#getHostnameByMACAddr">getHostnameByMACAddr</a></li>
472             
473                 <li data-name="LuCI.network.Hosts#getIP6AddrByMACAddr"><a href="LuCI.network.Hosts.html#getIP6AddrByMACAddr">getIP6AddrByMACAddr</a></li>
474             
475                 <li data-name="LuCI.network.Hosts#getIPAddrByMACAddr"><a href="LuCI.network.Hosts.html#getIPAddrByMACAddr">getIPAddrByMACAddr</a></li>
476             
477                 <li data-name="LuCI.network.Hosts#getMACAddrByIP6Addr"><a href="LuCI.network.Hosts.html#getMACAddrByIP6Addr">getMACAddrByIP6Addr</a></li>
478             
479                 <li data-name="LuCI.network.Hosts#getMACAddrByIPAddr"><a href="LuCI.network.Hosts.html#getMACAddrByIPAddr">getMACAddrByIPAddr</a></li>
480             
481                 <li data-name="LuCI.network.Hosts#getMACHints"><a href="LuCI.network.Hosts.html#getMACHints">getMACHints</a></li>
482             
483             </ul>
484             <ul class="events itemMembers">
485             
486             </ul>
487         </li>
488     
489         <li class="item" data-name="LuCI.network.Protocol">
490             <span class="title">
491                 <a href="LuCI.network.Protocol.html">LuCI.network.Protocol</a>
492                 
493             </span>
494             <ul class="members itemMembers">
495             
496             </ul>
497             <ul class="typedefs itemMembers">
498             
499             </ul>
500             <ul class="typedefs itemMembers">
501             
502             </ul>
503             <ul class="methods itemMembers">
504             
505             <span class="subtitle">Methods</span>
506             
507                 <li data-name="LuCI.network.Protocol#addDevice"><a href="LuCI.network.Protocol.html#addDevice">addDevice</a></li>
508             
509                 <li data-name="LuCI.network.Protocol#containsDevice"><a href="LuCI.network.Protocol.html#containsDevice">containsDevice</a></li>
510             
511                 <li data-name="LuCI.network.Protocol#deleteConfiguration"><a href="LuCI.network.Protocol.html#deleteConfiguration">deleteConfiguration</a></li>
512             
513                 <li data-name="LuCI.network.Protocol#deleteDevice"><a href="LuCI.network.Protocol.html#deleteDevice">deleteDevice</a></li>
514             
515                 <li data-name="LuCI.network.Protocol#get"><a href="LuCI.network.Protocol.html#get">get</a></li>
516             
517                 <li data-name="LuCI.network.Protocol#getDevice"><a href="LuCI.network.Protocol.html#getDevice">getDevice</a></li>
518             
519                 <li data-name="LuCI.network.Protocol#getDevices"><a href="LuCI.network.Protocol.html#getDevices">getDevices</a></li>
520             
521                 <li data-name="LuCI.network.Protocol#getDNS6Addrs"><a href="LuCI.network.Protocol.html#getDNS6Addrs">getDNS6Addrs</a></li>
522             
523                 <li data-name="LuCI.network.Protocol#getDNSAddrs"><a href="LuCI.network.Protocol.html#getDNSAddrs">getDNSAddrs</a></li>
524             
525                 <li data-name="LuCI.network.Protocol#getErrors"><a href="LuCI.network.Protocol.html#getErrors">getErrors</a></li>
526             
527                 <li data-name="LuCI.network.Protocol#getExpiry"><a href="LuCI.network.Protocol.html#getExpiry">getExpiry</a></li>
528             
529                 <li data-name="LuCI.network.Protocol#getGateway6Addr"><a href="LuCI.network.Protocol.html#getGateway6Addr">getGateway6Addr</a></li>
530             
531                 <li data-name="LuCI.network.Protocol#getGatewayAddr"><a href="LuCI.network.Protocol.html#getGatewayAddr">getGatewayAddr</a></li>
532             
533                 <li data-name="LuCI.network.Protocol#getI18n"><a href="LuCI.network.Protocol.html#getI18n">getI18n</a></li>
534             
535                 <li data-name="LuCI.network.Protocol#getIfname"><a href="LuCI.network.Protocol.html#getIfname">getIfname</a></li>
536             
537                 <li data-name="LuCI.network.Protocol#getIP6Addr"><a href="LuCI.network.Protocol.html#getIP6Addr">getIP6Addr</a></li>
538             
539                 <li data-name="LuCI.network.Protocol#getIP6Addrs"><a href="LuCI.network.Protocol.html#getIP6Addrs">getIP6Addrs</a></li>
540             
541                 <li data-name="LuCI.network.Protocol#getIP6Prefix"><a href="LuCI.network.Protocol.html#getIP6Prefix">getIP6Prefix</a></li>
542             
543                 <li data-name="LuCI.network.Protocol#getIPAddr"><a href="LuCI.network.Protocol.html#getIPAddr">getIPAddr</a></li>
544             
545                 <li data-name="LuCI.network.Protocol#getIPAddrs"><a href="LuCI.network.Protocol.html#getIPAddrs">getIPAddrs</a></li>
546             
547                 <li data-name="LuCI.network.Protocol#getL2Device"><a href="LuCI.network.Protocol.html#getL2Device">getL2Device</a></li>
548             
549                 <li data-name="LuCI.network.Protocol#getL3Device"><a href="LuCI.network.Protocol.html#getL3Device">getL3Device</a></li>
550             
551                 <li data-name="LuCI.network.Protocol#getMetric"><a href="LuCI.network.Protocol.html#getMetric">getMetric</a></li>
552             
553                 <li data-name="LuCI.network.Protocol#getName"><a href="LuCI.network.Protocol.html#getName">getName</a></li>
554             
555                 <li data-name="LuCI.network.Protocol#getNetmask"><a href="LuCI.network.Protocol.html#getNetmask">getNetmask</a></li>
556             
557                 <li data-name="LuCI.network.Protocol#getOpkgPackage"><a href="LuCI.network.Protocol.html#getOpkgPackage">getOpkgPackage</a></li>
558             
559                 <li data-name="LuCI.network.Protocol#getProtocol"><a href="LuCI.network.Protocol.html#getProtocol">getProtocol</a></li>
560             
561                 <li data-name="LuCI.network.Protocol#getType"><a href="LuCI.network.Protocol.html#getType">getType</a></li>
562             
563                 <li data-name="LuCI.network.Protocol#getUptime"><a href="LuCI.network.Protocol.html#getUptime">getUptime</a></li>
564             
565                 <li data-name="LuCI.network.Protocol#getZoneName"><a href="LuCI.network.Protocol.html#getZoneName">getZoneName</a></li>
566             
567                 <li data-name="LuCI.network.Protocol#isAlias"><a href="LuCI.network.Protocol.html#isAlias">isAlias</a></li>
568             
569                 <li data-name="LuCI.network.Protocol#isBridge"><a href="LuCI.network.Protocol.html#isBridge">isBridge</a></li>
570             
571                 <li data-name="LuCI.network.Protocol#isDynamic"><a href="LuCI.network.Protocol.html#isDynamic">isDynamic</a></li>
572             
573                 <li data-name="LuCI.network.Protocol#isEmpty"><a href="LuCI.network.Protocol.html#isEmpty">isEmpty</a></li>
574             
575                 <li data-name="LuCI.network.Protocol#isFloating"><a href="LuCI.network.Protocol.html#isFloating">isFloating</a></li>
576             
577                 <li data-name="LuCI.network.Protocol#isInstalled"><a href="LuCI.network.Protocol.html#isInstalled">isInstalled</a></li>
578             
579                 <li data-name="LuCI.network.Protocol#isUp"><a href="LuCI.network.Protocol.html#isUp">isUp</a></li>
580             
581                 <li data-name="LuCI.network.Protocol#isVirtual"><a href="LuCI.network.Protocol.html#isVirtual">isVirtual</a></li>
582             
583                 <li data-name="LuCI.network.Protocol#set"><a href="LuCI.network.Protocol.html#set">set</a></li>
584             
585             </ul>
586             <ul class="events itemMembers">
587             
588             </ul>
589         </li>
590     
591         <li class="item" data-name="LuCI.network.WifiDevice">
592             <span class="title">
593                 <a href="LuCI.network.WifiDevice.html">LuCI.network.WifiDevice</a>
594                 
595             </span>
596             <ul class="members itemMembers">
597             
598             </ul>
599             <ul class="typedefs itemMembers">
600             
601             </ul>
602             <ul class="typedefs itemMembers">
603             
604             </ul>
605             <ul class="methods itemMembers">
606             
607             <span class="subtitle">Methods</span>
608             
609                 <li data-name="LuCI.network.WifiDevice#addWifiNetwork"><a href="LuCI.network.WifiDevice.html#addWifiNetwork">addWifiNetwork</a></li>
610             
611                 <li data-name="LuCI.network.WifiDevice#deleteWifiNetwork"><a href="LuCI.network.WifiDevice.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
612             
613                 <li data-name="LuCI.network.WifiDevice#get"><a href="LuCI.network.WifiDevice.html#get">get</a></li>
614             
615                 <li data-name="LuCI.network.WifiDevice#getHTModes"><a href="LuCI.network.WifiDevice.html#getHTModes">getHTModes</a></li>
616             
617                 <li data-name="LuCI.network.WifiDevice#getHWModes"><a href="LuCI.network.WifiDevice.html#getHWModes">getHWModes</a></li>
618             
619                 <li data-name="LuCI.network.WifiDevice#getI18n"><a href="LuCI.network.WifiDevice.html#getI18n">getI18n</a></li>
620             
621                 <li data-name="LuCI.network.WifiDevice#getName"><a href="LuCI.network.WifiDevice.html#getName">getName</a></li>
622             
623                 <li data-name="LuCI.network.WifiDevice#getScanList"><a href="LuCI.network.WifiDevice.html#getScanList">getScanList</a></li>
624             
625                 <li data-name="LuCI.network.WifiDevice#getWifiNetwork"><a href="LuCI.network.WifiDevice.html#getWifiNetwork">getWifiNetwork</a></li>
626             
627                 <li data-name="LuCI.network.WifiDevice#getWifiNetworks"><a href="LuCI.network.WifiDevice.html#getWifiNetworks">getWifiNetworks</a></li>
628             
629                 <li data-name="LuCI.network.WifiDevice#isDisabled"><a href="LuCI.network.WifiDevice.html#isDisabled">isDisabled</a></li>
630             
631                 <li data-name="LuCI.network.WifiDevice#isUp"><a href="LuCI.network.WifiDevice.html#isUp">isUp</a></li>
632             
633                 <li data-name="LuCI.network.WifiDevice#set"><a href="LuCI.network.WifiDevice.html#set">set</a></li>
634             
635             </ul>
636             <ul class="events itemMembers">
637             
638             </ul>
639         </li>
640     
641         <li class="item" data-name="LuCI.network.WifiNetwork">
642             <span class="title">
643                 <a href="LuCI.network.WifiNetwork.html">LuCI.network.WifiNetwork</a>
644                 
645             </span>
646             <ul class="members itemMembers">
647             
648             </ul>
649             <ul class="typedefs itemMembers">
650             
651             </ul>
652             <ul class="typedefs itemMembers">
653             
654             </ul>
655             <ul class="methods itemMembers">
656             
657             <span class="subtitle">Methods</span>
658             
659                 <li data-name="LuCI.network.WifiNetwork#disconnectClient"><a href="LuCI.network.WifiNetwork.html#disconnectClient">disconnectClient</a></li>
660             
661                 <li data-name="LuCI.network.WifiNetwork#get"><a href="LuCI.network.WifiNetwork.html#get">get</a></li>
662             
663                 <li data-name="LuCI.network.WifiNetwork#getActiveBSSID"><a href="LuCI.network.WifiNetwork.html#getActiveBSSID">getActiveBSSID</a></li>
664             
665                 <li data-name="LuCI.network.WifiNetwork#getActiveEncryption"><a href="LuCI.network.WifiNetwork.html#getActiveEncryption">getActiveEncryption</a></li>
666             
667                 <li data-name="LuCI.network.WifiNetwork#getActiveMode"><a href="LuCI.network.WifiNetwork.html#getActiveMode">getActiveMode</a></li>
668             
669                 <li data-name="LuCI.network.WifiNetwork#getActiveModeI18n"><a href="LuCI.network.WifiNetwork.html#getActiveModeI18n">getActiveModeI18n</a></li>
670             
671                 <li data-name="LuCI.network.WifiNetwork#getActiveSSID"><a href="LuCI.network.WifiNetwork.html#getActiveSSID">getActiveSSID</a></li>
672             
673                 <li data-name="LuCI.network.WifiNetwork#getAssocList"><a href="LuCI.network.WifiNetwork.html#getAssocList">getAssocList</a></li>
674             
675                 <li data-name="LuCI.network.WifiNetwork#getBitRate"><a href="LuCI.network.WifiNetwork.html#getBitRate">getBitRate</a></li>
676             
677                 <li data-name="LuCI.network.WifiNetwork#getBSSID"><a href="LuCI.network.WifiNetwork.html#getBSSID">getBSSID</a></li>
678             
679                 <li data-name="LuCI.network.WifiNetwork#getChannel"><a href="LuCI.network.WifiNetwork.html#getChannel">getChannel</a></li>
680             
681                 <li data-name="LuCI.network.WifiNetwork#getCountryCode"><a href="LuCI.network.WifiNetwork.html#getCountryCode">getCountryCode</a></li>
682             
683                 <li data-name="LuCI.network.WifiNetwork#getDevice"><a href="LuCI.network.WifiNetwork.html#getDevice">getDevice</a></li>
684             
685                 <li data-name="LuCI.network.WifiNetwork#getFrequency"><a href="LuCI.network.WifiNetwork.html#getFrequency">getFrequency</a></li>
686             
687                 <li data-name="LuCI.network.WifiNetwork#getI18n"><a href="LuCI.network.WifiNetwork.html#getI18n">getI18n</a></li>
688             
689                 <li data-name="LuCI.network.WifiNetwork#getID"><a href="LuCI.network.WifiNetwork.html#getID">getID</a></li>
690             
691                 <li data-name="LuCI.network.WifiNetwork#getIfname"><a href="LuCI.network.WifiNetwork.html#getIfname">getIfname</a></li>
692             
693                 <li data-name="LuCI.network.WifiNetwork#getMeshID"><a href="LuCI.network.WifiNetwork.html#getMeshID">getMeshID</a></li>
694             
695                 <li data-name="LuCI.network.WifiNetwork#getMode"><a href="LuCI.network.WifiNetwork.html#getMode">getMode</a></li>
696             
697                 <li data-name="LuCI.network.WifiNetwork#getName"><a href="LuCI.network.WifiNetwork.html#getName">getName</a></li>
698             
699                 <li data-name="LuCI.network.WifiNetwork#getNetwork"><a href="LuCI.network.WifiNetwork.html#getNetwork">getNetwork</a></li>
700             
701                 <li data-name="LuCI.network.WifiNetwork#getNetworkNames"><a href="LuCI.network.WifiNetwork.html#getNetworkNames">getNetworkNames</a></li>
702             
703                 <li data-name="LuCI.network.WifiNetwork#getNetworks"><a href="LuCI.network.WifiNetwork.html#getNetworks">getNetworks</a></li>
704             
705                 <li data-name="LuCI.network.WifiNetwork#getNoise"><a href="LuCI.network.WifiNetwork.html#getNoise">getNoise</a></li>
706             
707                 <li data-name="LuCI.network.WifiNetwork#getShortName"><a href="LuCI.network.WifiNetwork.html#getShortName">getShortName</a></li>
708             
709                 <li data-name="LuCI.network.WifiNetwork#getSignal"><a href="LuCI.network.WifiNetwork.html#getSignal">getSignal</a></li>
710             
711                 <li data-name="LuCI.network.WifiNetwork#getSignalLevel"><a href="LuCI.network.WifiNetwork.html#getSignalLevel">getSignalLevel</a></li>
712             
713                 <li data-name="LuCI.network.WifiNetwork#getSignalPercent"><a href="LuCI.network.WifiNetwork.html#getSignalPercent">getSignalPercent</a></li>
714             
715                 <li data-name="LuCI.network.WifiNetwork#getSSID"><a href="LuCI.network.WifiNetwork.html#getSSID">getSSID</a></li>
716             
717                 <li data-name="LuCI.network.WifiNetwork#getTXPower"><a href="LuCI.network.WifiNetwork.html#getTXPower">getTXPower</a></li>
718             
719                 <li data-name="LuCI.network.WifiNetwork#getTXPowerOffset"><a href="LuCI.network.WifiNetwork.html#getTXPowerOffset">getTXPowerOffset</a></li>
720             
721                 <li data-name="LuCI.network.WifiNetwork#getWifiDevice"><a href="LuCI.network.WifiNetwork.html#getWifiDevice">getWifiDevice</a></li>
722             
723                 <li data-name="LuCI.network.WifiNetwork#getWifiDeviceName"><a href="LuCI.network.WifiNetwork.html#getWifiDeviceName">getWifiDeviceName</a></li>
724             
725                 <li data-name="LuCI.network.WifiNetwork#isClientDisconnectSupported"><a href="LuCI.network.WifiNetwork.html#isClientDisconnectSupported">isClientDisconnectSupported</a></li>
726             
727                 <li data-name="LuCI.network.WifiNetwork#isDisabled"><a href="LuCI.network.WifiNetwork.html#isDisabled">isDisabled</a></li>
728             
729                 <li data-name="LuCI.network.WifiNetwork#isUp"><a href="LuCI.network.WifiNetwork.html#isUp">isUp</a></li>
730             
731                 <li data-name="LuCI.network.WifiNetwork#set"><a href="LuCI.network.WifiNetwork.html#set">set</a></li>
732             
733             </ul>
734             <ul class="events itemMembers">
735             
736             </ul>
737         </li>
738     
739         <li class="item" data-name="LuCI.poll">
740             <span class="title">
741                 <a href="LuCI.poll.html">LuCI.poll</a>
742                 
743             </span>
744             <ul class="members itemMembers">
745             
746             </ul>
747             <ul class="typedefs itemMembers">
748             
749             </ul>
750             <ul class="typedefs itemMembers">
751             
752             </ul>
753             <ul class="methods itemMembers">
754             
755             <span class="subtitle">Methods</span>
756             
757                 <li data-name="LuCI.poll#active"><a href="LuCI.poll.html#active">active</a></li>
758             
759                 <li data-name="LuCI.poll#add"><a href="LuCI.poll.html#add">add</a></li>
760             
761                 <li data-name="LuCI.poll#remove"><a href="LuCI.poll.html#remove">remove</a></li>
762             
763                 <li data-name="LuCI.poll#start"><a href="LuCI.poll.html#start">start</a></li>
764             
765                 <li data-name="LuCI.poll#stop"><a href="LuCI.poll.html#stop">stop</a></li>
766             
767             </ul>
768             <ul class="events itemMembers">
769             
770             </ul>
771         </li>
772     
773         <li class="item" data-name="LuCI.request">
774             <span class="title">
775                 <a href="LuCI.request.html">LuCI.request</a>
776                 
777             </span>
778             <ul class="members itemMembers">
779             
780             </ul>
781             <ul class="typedefs itemMembers">
782             
783             <span class="subtitle">Typedefs</span>
784             
785                 <li data-name="LuCI.request.interceptorFn"><a href="LuCI.request.html#.interceptorFn">interceptorFn</a></li>
786             
787                 <li data-name="LuCI.request.RequestOptions"><a href="LuCI.request.html#.RequestOptions">RequestOptions</a></li>
788             
789             </ul>
790             <ul class="typedefs itemMembers">
791             
792             </ul>
793             <ul class="methods itemMembers">
794             
795             <span class="subtitle">Methods</span>
796             
797                 <li data-name="LuCI.request#addInterceptor"><a href="LuCI.request.html#addInterceptor">addInterceptor</a></li>
798             
799                 <li data-name="LuCI.request#expandURL"><a href="LuCI.request.html#expandURL">expandURL</a></li>
800             
801                 <li data-name="LuCI.request#get"><a href="LuCI.request.html#get">get</a></li>
802             
803                 <li data-name="LuCI.request#post"><a href="LuCI.request.html#post">post</a></li>
804             
805                 <li data-name="LuCI.request#removeInterceptor"><a href="LuCI.request.html#removeInterceptor">removeInterceptor</a></li>
806             
807                 <li data-name="LuCI.request#request"><a href="LuCI.request.html#request">request</a></li>
808             
809             </ul>
810             <ul class="events itemMembers">
811             
812             </ul>
813         </li>
814     
815         <li class="item" data-name="LuCI.request.poll">
816             <span class="title">
817                 <a href="LuCI.request.poll.html">LuCI.request.poll</a>
818                 
819             </span>
820             <ul class="members itemMembers">
821             
822             </ul>
823             <ul class="typedefs itemMembers">
824             
825             <span class="subtitle">Typedefs</span>
826             
827                 <li data-name="LuCI.request.poll~callbackFn"><a href="LuCI.request.poll.html#~callbackFn">callbackFn</a></li>
828             
829             </ul>
830             <ul class="typedefs itemMembers">
831             
832             </ul>
833             <ul class="methods itemMembers">
834             
835             <span class="subtitle">Methods</span>
836             
837                 <li data-name="LuCI.request.poll#active"><a href="LuCI.request.poll.html#active">active</a></li>
838             
839                 <li data-name="LuCI.request.poll#add"><a href="LuCI.request.poll.html#add">add</a></li>
840             
841                 <li data-name="LuCI.request.poll#remove"><a href="LuCI.request.poll.html#remove">remove</a></li>
842             
843                 <li data-name="LuCI.request.poll#start"><a href="LuCI.request.poll.html#start">start</a></li>
844             
845                 <li data-name="LuCI.request.poll#stop"><a href="LuCI.request.poll.html#stop">stop</a></li>
846             
847             </ul>
848             <ul class="events itemMembers">
849             
850             </ul>
851         </li>
852     
853         <li class="item" data-name="LuCI.response">
854             <span class="title">
855                 <a href="LuCI.response.html">LuCI.response</a>
856                 
857             </span>
858             <ul class="members itemMembers">
859             
860             <span class="subtitle">Members</span>
861             
862                 <li data-name="LuCI.response#duration"><a href="LuCI.response.html#duration">duration</a></li>
863             
864                 <li data-name="LuCI.response#headers"><a href="LuCI.response.html#headers">headers</a></li>
865             
866                 <li data-name="LuCI.response#ok"><a href="LuCI.response.html#ok">ok</a></li>
867             
868                 <li data-name="LuCI.response#status"><a href="LuCI.response.html#status">status</a></li>
869             
870                 <li data-name="LuCI.response#statusText"><a href="LuCI.response.html#statusText">statusText</a></li>
871             
872                 <li data-name="LuCI.response#url"><a href="LuCI.response.html#url">url</a></li>
873             
874             </ul>
875             <ul class="typedefs itemMembers">
876             
877             </ul>
878             <ul class="typedefs itemMembers">
879             
880             </ul>
881             <ul class="methods itemMembers">
882             
883             <span class="subtitle">Methods</span>
884             
885                 <li data-name="LuCI.response#blob"><a href="LuCI.response.html#blob">blob</a></li>
886             
887                 <li data-name="LuCI.response#clone"><a href="LuCI.response.html#clone">clone</a></li>
888             
889                 <li data-name="LuCI.response#json"><a href="LuCI.response.html#json">json</a></li>
890             
891                 <li data-name="LuCI.response#text"><a href="LuCI.response.html#text">text</a></li>
892             
893             </ul>
894             <ul class="events itemMembers">
895             
896             </ul>
897         </li>
898     
899         <li class="item" data-name="LuCI.rpc">
900             <span class="title">
901                 <a href="LuCI.rpc.html">LuCI.rpc</a>
902                 
903             </span>
904             <ul class="members itemMembers">
905             
906             </ul>
907             <ul class="typedefs itemMembers">
908             
909             <span class="subtitle">Typedefs</span>
910             
911                 <li data-name="LuCI.rpc.DeclareOptions"><a href="LuCI.rpc.html#.DeclareOptions">DeclareOptions</a></li>
912             
913                 <li data-name="LuCI.rpc~filterFn"><a href="LuCI.rpc.html#~filterFn">filterFn</a></li>
914             
915                 <li data-name="LuCI.rpc~interceptorFn"><a href="LuCI.rpc.html#~interceptorFn">interceptorFn</a></li>
916             
917                 <li data-name="LuCI.rpc~invokeFn"><a href="LuCI.rpc.html#~invokeFn">invokeFn</a></li>
918             
919             </ul>
920             <ul class="typedefs itemMembers">
921             
922             </ul>
923             <ul class="methods itemMembers">
924             
925             <span class="subtitle">Methods</span>
926             
927                 <li data-name="LuCI.rpc#addInterceptor"><a href="LuCI.rpc.html#addInterceptor">addInterceptor</a></li>
928             
929                 <li data-name="LuCI.rpc#declare"><a href="LuCI.rpc.html#declare">declare</a></li>
930             
931                 <li data-name="LuCI.rpc#getBaseURL"><a href="LuCI.rpc.html#getBaseURL">getBaseURL</a></li>
932             
933                 <li data-name="LuCI.rpc#getSessionID"><a href="LuCI.rpc.html#getSessionID">getSessionID</a></li>
934             
935                 <li data-name="LuCI.rpc#getStatusText"><a href="LuCI.rpc.html#getStatusText">getStatusText</a></li>
936             
937                 <li data-name="LuCI.rpc#list"><a href="LuCI.rpc.html#list">list</a></li>
938             
939                 <li data-name="LuCI.rpc#removeInterceptor"><a href="LuCI.rpc.html#removeInterceptor">removeInterceptor</a></li>
940             
941                 <li data-name="LuCI.rpc#setBaseURL"><a href="LuCI.rpc.html#setBaseURL">setBaseURL</a></li>
942             
943                 <li data-name="LuCI.rpc#setSessionID"><a href="LuCI.rpc.html#setSessionID">setSessionID</a></li>
944             
945             </ul>
946             <ul class="events itemMembers">
947             
948             </ul>
949         </li>
950     
951         <li class="item" data-name="LuCI.uci">
952             <span class="title">
953                 <a href="LuCI.uci.html">LuCI.uci</a>
954                 
955             </span>
956             <ul class="members itemMembers">
957             
958             </ul>
959             <ul class="typedefs itemMembers">
960             
961             <span class="subtitle">Typedefs</span>
962             
963                 <li data-name="LuCI.uci.ChangeRecord"><a href="LuCI.uci.html#.ChangeRecord">ChangeRecord</a></li>
964             
965                 <li data-name="LuCI.uci.SectionObject"><a href="LuCI.uci.html#.SectionObject">SectionObject</a></li>
966             
967                 <li data-name="LuCI.uci~sectionsFn"><a href="LuCI.uci.html#~sectionsFn">sectionsFn</a></li>
968             
969             </ul>
970             <ul class="typedefs itemMembers">
971             
972             </ul>
973             <ul class="methods itemMembers">
974             
975             <span class="subtitle">Methods</span>
976             
977                 <li data-name="LuCI.uci#add"><a href="LuCI.uci.html#add">add</a></li>
978             
979                 <li data-name="LuCI.uci#apply"><a href="LuCI.uci.html#apply">apply</a></li>
980             
981                 <li data-name="LuCI.uci#changes"><a href="LuCI.uci.html#changes">changes</a></li>
982             
983                 <li data-name="LuCI.uci#createSID"><a href="LuCI.uci.html#createSID">createSID</a></li>
984             
985                 <li data-name="LuCI.uci#get"><a href="LuCI.uci.html#get">get</a></li>
986             
987                 <li data-name="LuCI.uci#get_first"><a href="LuCI.uci.html#get_first">get_first</a></li>
988             
989                 <li data-name="LuCI.uci#load"><a href="LuCI.uci.html#load">load</a></li>
990             
991                 <li data-name="LuCI.uci#move"><a href="LuCI.uci.html#move">move</a></li>
992             
993                 <li data-name="LuCI.uci#remove"><a href="LuCI.uci.html#remove">remove</a></li>
994             
995                 <li data-name="LuCI.uci#resolveSID"><a href="LuCI.uci.html#resolveSID">resolveSID</a></li>
996             
997                 <li data-name="LuCI.uci#save"><a href="LuCI.uci.html#save">save</a></li>
998             
999                 <li data-name="LuCI.uci#sections"><a href="LuCI.uci.html#sections">sections</a></li>
1000             
1001                 <li data-name="LuCI.uci#set"><a href="LuCI.uci.html#set">set</a></li>
1002             
1003                 <li data-name="LuCI.uci#set_first"><a href="LuCI.uci.html#set_first">set_first</a></li>
1004             
1005                 <li data-name="LuCI.uci#unload"><a href="LuCI.uci.html#unload">unload</a></li>
1006             
1007                 <li data-name="LuCI.uci#unset"><a href="LuCI.uci.html#unset">unset</a></li>
1008             
1009                 <li data-name="LuCI.uci#unset_first"><a href="LuCI.uci.html#unset_first">unset_first</a></li>
1010             
1011             </ul>
1012             <ul class="events itemMembers">
1013             
1014             </ul>
1015         </li>
1016     
1017         <li class="item" data-name="LuCI.ui">
1018             <span class="title">
1019                 <a href="LuCI.ui.html">LuCI.ui</a>
1020                 
1021             </span>
1022             <ul class="members itemMembers">
1023             
1024             </ul>
1025             <ul class="typedefs itemMembers">
1026             
1027             <span class="subtitle">Typedefs</span>
1028             
1029                 <li data-name="LuCI.ui.FileUploadReply"><a href="LuCI.ui.html#.FileUploadReply">FileUploadReply</a></li>
1030             
1031             </ul>
1032             <ul class="typedefs itemMembers">
1033             
1034             </ul>
1035             <ul class="methods itemMembers">
1036             
1037             <span class="subtitle">Methods</span>
1038             
1039                 <li data-name="LuCI.ui#addNotification"><a href="LuCI.ui.html#addNotification">addNotification</a></li>
1040             
1041                 <li data-name="LuCI.ui#addValidator"><a href="LuCI.ui.html#addValidator">addValidator</a></li>
1042             
1043                 <li data-name="LuCI.ui#awaitReconnect"><a href="LuCI.ui.html#awaitReconnect">awaitReconnect</a></li>
1044             
1045                 <li data-name="LuCI.ui#createHandlerFn"><a href="LuCI.ui.html#createHandlerFn">createHandlerFn</a></li>
1046             
1047                 <li data-name="LuCI.ui#hideIndicator"><a href="LuCI.ui.html#hideIndicator">hideIndicator</a></li>
1048             
1049                 <li data-name="LuCI.ui#hideModal"><a href="LuCI.ui.html#hideModal">hideModal</a></li>
1050             
1051                 <li data-name="LuCI.ui#instantiateView"><a href="LuCI.ui.html#instantiateView">instantiateView</a></li>
1052             
1053                 <li data-name="LuCI.ui#itemlist"><a href="LuCI.ui.html#itemlist">itemlist</a></li>
1054             
1055                 <li data-name="LuCI.ui#pingDevice"><a href="LuCI.ui.html#pingDevice">pingDevice</a></li>
1056             
1057                 <li data-name="LuCI.ui#showIndicator"><a href="LuCI.ui.html#showIndicator">showIndicator</a></li>
1058             
1059                 <li data-name="LuCI.ui#showModal"><a href="LuCI.ui.html#showModal">showModal</a></li>
1060             
1061                 <li data-name="LuCI.ui#uploadFile"><a href="LuCI.ui.html#uploadFile">uploadFile</a></li>
1062             
1063             </ul>
1064             <ul class="events itemMembers">
1065             
1066             </ul>
1067         </li>
1068     
1069         <li class="item" data-name="LuCI.ui.AbstractElement">
1070             <span class="title">
1071                 <a href="LuCI.ui.AbstractElement.html">LuCI.ui.AbstractElement</a>
1072                 
1073             </span>
1074             <ul class="members itemMembers">
1075             
1076             </ul>
1077             <ul class="typedefs itemMembers">
1078             
1079             <span class="subtitle">Typedefs</span>
1080             
1081                 <li data-name="LuCI.ui.AbstractElement.InitOptions"><a href="LuCI.ui.AbstractElement.html#.InitOptions">InitOptions</a></li>
1082             
1083             </ul>
1084             <ul class="typedefs itemMembers">
1085             
1086             </ul>
1087             <ul class="methods itemMembers">
1088             
1089             <span class="subtitle">Methods</span>
1090             
1091                 <li data-name="LuCI.ui.AbstractElement#getValue"><a href="LuCI.ui.AbstractElement.html#getValue">getValue</a></li>
1092             
1093                 <li data-name="LuCI.ui.AbstractElement#isValid"><a href="LuCI.ui.AbstractElement.html#isValid">isValid</a></li>
1094             
1095                 <li data-name="LuCI.ui.AbstractElement#registerEvents"><a href="LuCI.ui.AbstractElement.html#registerEvents">registerEvents</a></li>
1096             
1097                 <li data-name="LuCI.ui.AbstractElement#render"><a href="LuCI.ui.AbstractElement.html#render">render</a></li>
1098             
1099                 <li data-name="LuCI.ui.AbstractElement#setChangeEvents"><a href="LuCI.ui.AbstractElement.html#setChangeEvents">setChangeEvents</a></li>
1100             
1101                 <li data-name="LuCI.ui.AbstractElement#setUpdateEvents"><a href="LuCI.ui.AbstractElement.html#setUpdateEvents">setUpdateEvents</a></li>
1102             
1103                 <li data-name="LuCI.ui.AbstractElement#setValue"><a href="LuCI.ui.AbstractElement.html#setValue">setValue</a></li>
1104             
1105                 <li data-name="LuCI.ui.AbstractElement#triggerValidation"><a href="LuCI.ui.AbstractElement.html#triggerValidation">triggerValidation</a></li>
1106             
1107             </ul>
1108             <ul class="events itemMembers">
1109             
1110             </ul>
1111         </li>
1112     
1113         <li class="item" data-name="LuCI.ui.changes">
1114             <span class="title">
1115                 <a href="LuCI.ui.changes.html">LuCI.ui.changes</a>
1116                 
1117             </span>
1118             <ul class="members itemMembers">
1119             
1120             </ul>
1121             <ul class="typedefs itemMembers">
1122             
1123             </ul>
1124             <ul class="typedefs itemMembers">
1125             
1126             </ul>
1127             <ul class="methods itemMembers">
1128             
1129             <span class="subtitle">Methods</span>
1130             
1131                 <li data-name="LuCI.ui.changes#apply"><a href="LuCI.ui.changes.html#apply">apply</a></li>
1132             
1133                 <li data-name="LuCI.ui.changes#displayChanges"><a href="LuCI.ui.changes.html#displayChanges">displayChanges</a></li>
1134             
1135                 <li data-name="LuCI.ui.changes#renderChangeIndicator"><a href="LuCI.ui.changes.html#renderChangeIndicator">renderChangeIndicator</a></li>
1136             
1137                 <li data-name="LuCI.ui.changes#revert"><a href="LuCI.ui.changes.html#revert">revert</a></li>
1138             
1139                 <li data-name="LuCI.ui.changes#setIndicator"><a href="LuCI.ui.changes.html#setIndicator">setIndicator</a></li>
1140             
1141             </ul>
1142             <ul class="events itemMembers">
1143             
1144             </ul>
1145         </li>
1146     
1147         <li class="item" data-name="LuCI.ui.Checkbox">
1148             <span class="title">
1149                 <a href="LuCI.ui.Checkbox.html">LuCI.ui.Checkbox</a>
1150                 
1151             </span>
1152             <ul class="members itemMembers">
1153             
1154             </ul>
1155             <ul class="typedefs itemMembers">
1156             
1157             <span class="subtitle">Typedefs</span>
1158             
1159                 <li data-name="LuCI.ui.Checkbox.InitOptions"><a href="LuCI.ui.Checkbox.html#.InitOptions">InitOptions</a></li>
1160             
1161             </ul>
1162             <ul class="typedefs itemMembers">
1163             
1164             </ul>
1165             <ul class="methods itemMembers">
1166             
1167             <span class="subtitle">Methods</span>
1168             
1169                 <li data-name="LuCI.ui.Checkbox#getValue"><a href="LuCI.ui.Checkbox.html#getValue">getValue</a></li>
1170             
1171                 <li data-name="LuCI.ui.Checkbox#isChecked"><a href="LuCI.ui.Checkbox.html#isChecked">isChecked</a></li>
1172             
1173                 <li data-name="LuCI.ui.Checkbox#isValid"><a href="LuCI.ui.Checkbox.html#isValid">isValid</a></li>
1174             
1175                 <li data-name="LuCI.ui.Checkbox#registerEvents"><a href="LuCI.ui.Checkbox.html#registerEvents">registerEvents</a></li>
1176             
1177                 <li data-name="LuCI.ui.Checkbox#render"><a href="LuCI.ui.Checkbox.html#render">render</a></li>
1178             
1179                 <li data-name="LuCI.ui.Checkbox#setChangeEvents"><a href="LuCI.ui.Checkbox.html#setChangeEvents">setChangeEvents</a></li>
1180             
1181                 <li data-name="LuCI.ui.Checkbox#setUpdateEvents"><a href="LuCI.ui.Checkbox.html#setUpdateEvents">setUpdateEvents</a></li>
1182             
1183                 <li data-name="LuCI.ui.Checkbox#setValue"><a href="LuCI.ui.Checkbox.html#setValue">setValue</a></li>
1184             
1185                 <li data-name="LuCI.ui.Checkbox#triggerValidation"><a href="LuCI.ui.Checkbox.html#triggerValidation">triggerValidation</a></li>
1186             
1187             </ul>
1188             <ul class="events itemMembers">
1189             
1190             </ul>
1191         </li>
1192     
1193         <li class="item" data-name="LuCI.ui.Combobox">
1194             <span class="title">
1195                 <a href="LuCI.ui.Combobox.html">LuCI.ui.Combobox</a>
1196                 
1197             </span>
1198             <ul class="members itemMembers">
1199             
1200             </ul>
1201             <ul class="typedefs itemMembers">
1202             
1203             <span class="subtitle">Typedefs</span>
1204             
1205                 <li data-name="LuCI.ui.Combobox.InitOptions"><a href="LuCI.ui.Combobox.html#.InitOptions">InitOptions</a></li>
1206             
1207             </ul>
1208             <ul class="typedefs itemMembers">
1209             
1210             </ul>
1211             <ul class="methods itemMembers">
1212             
1213             <span class="subtitle">Methods</span>
1214             
1215                 <li data-name="LuCI.ui.Combobox#addChoices"><a href="LuCI.ui.Combobox.html#addChoices">addChoices</a></li>
1216             
1217                 <li data-name="LuCI.ui.Combobox#clearChoices"><a href="LuCI.ui.Combobox.html#clearChoices">clearChoices</a></li>
1218             
1219                 <li data-name="LuCI.ui.Combobox#closeAllDropdowns"><a href="LuCI.ui.Combobox.html#closeAllDropdowns">closeAllDropdowns</a></li>
1220             
1221                 <li data-name="LuCI.ui.Combobox#isValid"><a href="LuCI.ui.Combobox.html#isValid">isValid</a></li>
1222             
1223                 <li data-name="LuCI.ui.Combobox#registerEvents"><a href="LuCI.ui.Combobox.html#registerEvents">registerEvents</a></li>
1224             
1225                 <li data-name="LuCI.ui.Combobox#setChangeEvents"><a href="LuCI.ui.Combobox.html#setChangeEvents">setChangeEvents</a></li>
1226             
1227                 <li data-name="LuCI.ui.Combobox#setUpdateEvents"><a href="LuCI.ui.Combobox.html#setUpdateEvents">setUpdateEvents</a></li>
1228             
1229                 <li data-name="LuCI.ui.Combobox#triggerValidation"><a href="LuCI.ui.Combobox.html#triggerValidation">triggerValidation</a></li>
1230             
1231             </ul>
1232             <ul class="events itemMembers">
1233             
1234             </ul>
1235         </li>
1236     
1237         <li class="item" data-name="LuCI.ui.ComboButton">
1238             <span class="title">
1239                 <a href="LuCI.ui.ComboButton.html">LuCI.ui.ComboButton</a>
1240                 
1241             </span>
1242             <ul class="members itemMembers">
1243             
1244             </ul>
1245             <ul class="typedefs itemMembers">
1246             
1247             <span class="subtitle">Typedefs</span>
1248             
1249                 <li data-name="LuCI.ui.ComboButton.InitOptions"><a href="LuCI.ui.ComboButton.html#.InitOptions">InitOptions</a></li>
1250             
1251             </ul>
1252             <ul class="typedefs itemMembers">
1253             
1254             </ul>
1255             <ul class="methods itemMembers">
1256             
1257             <span class="subtitle">Methods</span>
1258             
1259                 <li data-name="LuCI.ui.ComboButton#addChoices"><a href="LuCI.ui.ComboButton.html#addChoices">addChoices</a></li>
1260             
1261                 <li data-name="LuCI.ui.ComboButton#clearChoices"><a href="LuCI.ui.ComboButton.html#clearChoices">clearChoices</a></li>
1262             
1263                 <li data-name="LuCI.ui.ComboButton#closeAllDropdowns"><a href="LuCI.ui.ComboButton.html#closeAllDropdowns">closeAllDropdowns</a></li>
1264             
1265                 <li data-name="LuCI.ui.ComboButton#isValid"><a href="LuCI.ui.ComboButton.html#isValid">isValid</a></li>
1266             
1267                 <li data-name="LuCI.ui.ComboButton#registerEvents"><a href="LuCI.ui.ComboButton.html#registerEvents">registerEvents</a></li>
1268             
1269                 <li data-name="LuCI.ui.ComboButton#setChangeEvents"><a href="LuCI.ui.ComboButton.html#setChangeEvents">setChangeEvents</a></li>
1270             
1271                 <li data-name="LuCI.ui.ComboButton#setUpdateEvents"><a href="LuCI.ui.ComboButton.html#setUpdateEvents">setUpdateEvents</a></li>
1272             
1273                 <li data-name="LuCI.ui.ComboButton#triggerValidation"><a href="LuCI.ui.ComboButton.html#triggerValidation">triggerValidation</a></li>
1274             
1275             </ul>
1276             <ul class="events itemMembers">
1277             
1278             </ul>
1279         </li>
1280     
1281         <li class="item" data-name="LuCI.ui.Dropdown">
1282             <span class="title">
1283                 <a href="LuCI.ui.Dropdown.html">LuCI.ui.Dropdown</a>
1284                 
1285             </span>
1286             <ul class="members itemMembers">
1287             
1288             </ul>
1289             <ul class="typedefs itemMembers">
1290             
1291             <span class="subtitle">Typedefs</span>
1292             
1293                 <li data-name="LuCI.ui.Dropdown.InitOptions"><a href="LuCI.ui.Dropdown.html#.InitOptions">InitOptions</a></li>
1294             
1295             </ul>
1296             <ul class="typedefs itemMembers">
1297             
1298             </ul>
1299             <ul class="methods itemMembers">
1300             
1301             <span class="subtitle">Methods</span>
1302             
1303                 <li data-name="LuCI.ui.Dropdown#addChoices"><a href="LuCI.ui.Dropdown.html#addChoices">addChoices</a></li>
1304             
1305                 <li data-name="LuCI.ui.Dropdown#clearChoices"><a href="LuCI.ui.Dropdown.html#clearChoices">clearChoices</a></li>
1306             
1307                 <li data-name="LuCI.ui.Dropdown#closeAllDropdowns"><a href="LuCI.ui.Dropdown.html#closeAllDropdowns">closeAllDropdowns</a></li>
1308             
1309                 <li data-name="LuCI.ui.Dropdown#getValue"><a href="LuCI.ui.Dropdown.html#getValue">getValue</a></li>
1310             
1311                 <li data-name="LuCI.ui.Dropdown#isValid"><a href="LuCI.ui.Dropdown.html#isValid">isValid</a></li>
1312             
1313                 <li data-name="LuCI.ui.Dropdown#registerEvents"><a href="LuCI.ui.Dropdown.html#registerEvents">registerEvents</a></li>
1314             
1315                 <li data-name="LuCI.ui.Dropdown#render"><a href="LuCI.ui.Dropdown.html#render">render</a></li>
1316             
1317                 <li data-name="LuCI.ui.Dropdown#setChangeEvents"><a href="LuCI.ui.Dropdown.html#setChangeEvents">setChangeEvents</a></li>
1318             
1319                 <li data-name="LuCI.ui.Dropdown#setUpdateEvents"><a href="LuCI.ui.Dropdown.html#setUpdateEvents">setUpdateEvents</a></li>
1320             
1321                 <li data-name="LuCI.ui.Dropdown#setValue"><a href="LuCI.ui.Dropdown.html#setValue">setValue</a></li>
1322             
1323                 <li data-name="LuCI.ui.Dropdown#triggerValidation"><a href="LuCI.ui.Dropdown.html#triggerValidation">triggerValidation</a></li>
1324             
1325             </ul>
1326             <ul class="events itemMembers">
1327             
1328             </ul>
1329         </li>
1330     
1331         <li class="item" data-name="LuCI.ui.DynamicList">
1332             <span class="title">
1333                 <a href="LuCI.ui.DynamicList.html">LuCI.ui.DynamicList</a>
1334                 
1335             </span>
1336             <ul class="members itemMembers">
1337             
1338             </ul>
1339             <ul class="typedefs itemMembers">
1340             
1341             <span class="subtitle">Typedefs</span>
1342             
1343                 <li data-name="LuCI.ui.DynamicList.InitOptions"><a href="LuCI.ui.DynamicList.html#.InitOptions">InitOptions</a></li>
1344             
1345             </ul>
1346             <ul class="typedefs itemMembers">
1347             
1348             </ul>
1349             <ul class="methods itemMembers">
1350             
1351             <span class="subtitle">Methods</span>
1352             
1353                 <li data-name="LuCI.ui.DynamicList#addChoices"><a href="LuCI.ui.DynamicList.html#addChoices">addChoices</a></li>
1354             
1355                 <li data-name="LuCI.ui.DynamicList#clearChoices"><a href="LuCI.ui.DynamicList.html#clearChoices">clearChoices</a></li>
1356             
1357                 <li data-name="LuCI.ui.DynamicList#getValue"><a href="LuCI.ui.DynamicList.html#getValue">getValue</a></li>
1358             
1359                 <li data-name="LuCI.ui.DynamicList#isValid"><a href="LuCI.ui.DynamicList.html#isValid">isValid</a></li>
1360             
1361                 <li data-name="LuCI.ui.DynamicList#registerEvents"><a href="LuCI.ui.DynamicList.html#registerEvents">registerEvents</a></li>
1362             
1363                 <li data-name="LuCI.ui.DynamicList#render"><a href="LuCI.ui.DynamicList.html#render">render</a></li>
1364             
1365                 <li data-name="LuCI.ui.DynamicList#setChangeEvents"><a href="LuCI.ui.DynamicList.html#setChangeEvents">setChangeEvents</a></li>
1366             
1367                 <li data-name="LuCI.ui.DynamicList#setUpdateEvents"><a href="LuCI.ui.DynamicList.html#setUpdateEvents">setUpdateEvents</a></li>
1368             
1369                 <li data-name="LuCI.ui.DynamicList#setValue"><a href="LuCI.ui.DynamicList.html#setValue">setValue</a></li>
1370             
1371                 <li data-name="LuCI.ui.DynamicList#triggerValidation"><a href="LuCI.ui.DynamicList.html#triggerValidation">triggerValidation</a></li>
1372             
1373             </ul>
1374             <ul class="events itemMembers">
1375             
1376             </ul>
1377         </li>
1378     
1379         <li class="item" data-name="LuCI.ui.FileUpload">
1380             <span class="title">
1381                 <a href="LuCI.ui.FileUpload.html">LuCI.ui.FileUpload</a>
1382                 
1383             </span>
1384             <ul class="members itemMembers">
1385             
1386             </ul>
1387             <ul class="typedefs itemMembers">
1388             
1389             <span class="subtitle">Typedefs</span>
1390             
1391                 <li data-name="LuCI.ui.FileUpload.InitOptions"><a href="LuCI.ui.FileUpload.html#.InitOptions">InitOptions</a></li>
1392             
1393             </ul>
1394             <ul class="typedefs itemMembers">
1395             
1396             </ul>
1397             <ul class="methods itemMembers">
1398             
1399             <span class="subtitle">Methods</span>
1400             
1401                 <li data-name="LuCI.ui.FileUpload#getValue"><a href="LuCI.ui.FileUpload.html#getValue">getValue</a></li>
1402             
1403                 <li data-name="LuCI.ui.FileUpload#isValid"><a href="LuCI.ui.FileUpload.html#isValid">isValid</a></li>
1404             
1405                 <li data-name="LuCI.ui.FileUpload#registerEvents"><a href="LuCI.ui.FileUpload.html#registerEvents">registerEvents</a></li>
1406             
1407                 <li data-name="LuCI.ui.FileUpload#render"><a href="LuCI.ui.FileUpload.html#render">render</a></li>
1408             
1409                 <li data-name="LuCI.ui.FileUpload#setChangeEvents"><a href="LuCI.ui.FileUpload.html#setChangeEvents">setChangeEvents</a></li>
1410             
1411                 <li data-name="LuCI.ui.FileUpload#setUpdateEvents"><a href="LuCI.ui.FileUpload.html#setUpdateEvents">setUpdateEvents</a></li>
1412             
1413                 <li data-name="LuCI.ui.FileUpload#setValue"><a href="LuCI.ui.FileUpload.html#setValue">setValue</a></li>
1414             
1415                 <li data-name="LuCI.ui.FileUpload#triggerValidation"><a href="LuCI.ui.FileUpload.html#triggerValidation">triggerValidation</a></li>
1416             
1417             </ul>
1418             <ul class="events itemMembers">
1419             
1420             </ul>
1421         </li>
1422     
1423         <li class="item" data-name="LuCI.ui.Hiddenfield">
1424             <span class="title">
1425                 <a href="LuCI.ui.Hiddenfield.html">LuCI.ui.Hiddenfield</a>
1426                 
1427             </span>
1428             <ul class="members itemMembers">
1429             
1430             </ul>
1431             <ul class="typedefs itemMembers">
1432             
1433             </ul>
1434             <ul class="typedefs itemMembers">
1435             
1436             </ul>
1437             <ul class="methods itemMembers">
1438             
1439             <span class="subtitle">Methods</span>
1440             
1441                 <li data-name="LuCI.ui.Hiddenfield#getValue"><a href="LuCI.ui.Hiddenfield.html#getValue">getValue</a></li>
1442             
1443                 <li data-name="LuCI.ui.Hiddenfield#isValid"><a href="LuCI.ui.Hiddenfield.html#isValid">isValid</a></li>
1444             
1445                 <li data-name="LuCI.ui.Hiddenfield#registerEvents"><a href="LuCI.ui.Hiddenfield.html#registerEvents">registerEvents</a></li>
1446             
1447                 <li data-name="LuCI.ui.Hiddenfield#render"><a href="LuCI.ui.Hiddenfield.html#render">render</a></li>
1448             
1449                 <li data-name="LuCI.ui.Hiddenfield#setChangeEvents"><a href="LuCI.ui.Hiddenfield.html#setChangeEvents">setChangeEvents</a></li>
1450             
1451                 <li data-name="LuCI.ui.Hiddenfield#setUpdateEvents"><a href="LuCI.ui.Hiddenfield.html#setUpdateEvents">setUpdateEvents</a></li>
1452             
1453                 <li data-name="LuCI.ui.Hiddenfield#setValue"><a href="LuCI.ui.Hiddenfield.html#setValue">setValue</a></li>
1454             
1455                 <li data-name="LuCI.ui.Hiddenfield#triggerValidation"><a href="LuCI.ui.Hiddenfield.html#triggerValidation">triggerValidation</a></li>
1456             
1457             </ul>
1458             <ul class="events itemMembers">
1459             
1460             </ul>
1461         </li>
1462     
1463         <li class="item" data-name="LuCI.ui.Select">
1464             <span class="title">
1465                 <a href="LuCI.ui.Select.html">LuCI.ui.Select</a>
1466                 
1467             </span>
1468             <ul class="members itemMembers">
1469             
1470             </ul>
1471             <ul class="typedefs itemMembers">
1472             
1473             <span class="subtitle">Typedefs</span>
1474             
1475                 <li data-name="LuCI.ui.Select.InitOptions"><a href="LuCI.ui.Select.html#.InitOptions">InitOptions</a></li>
1476             
1477             </ul>
1478             <ul class="typedefs itemMembers">
1479             
1480             </ul>
1481             <ul class="methods itemMembers">
1482             
1483             <span class="subtitle">Methods</span>
1484             
1485                 <li data-name="LuCI.ui.Select#getValue"><a href="LuCI.ui.Select.html#getValue">getValue</a></li>
1486             
1487                 <li data-name="LuCI.ui.Select#isValid"><a href="LuCI.ui.Select.html#isValid">isValid</a></li>
1488             
1489                 <li data-name="LuCI.ui.Select#registerEvents"><a href="LuCI.ui.Select.html#registerEvents">registerEvents</a></li>
1490             
1491                 <li data-name="LuCI.ui.Select#render"><a href="LuCI.ui.Select.html#render">render</a></li>
1492             
1493                 <li data-name="LuCI.ui.Select#setChangeEvents"><a href="LuCI.ui.Select.html#setChangeEvents">setChangeEvents</a></li>
1494             
1495                 <li data-name="LuCI.ui.Select#setUpdateEvents"><a href="LuCI.ui.Select.html#setUpdateEvents">setUpdateEvents</a></li>
1496             
1497                 <li data-name="LuCI.ui.Select#setValue"><a href="LuCI.ui.Select.html#setValue">setValue</a></li>
1498             
1499                 <li data-name="LuCI.ui.Select#triggerValidation"><a href="LuCI.ui.Select.html#triggerValidation">triggerValidation</a></li>
1500             
1501             </ul>
1502             <ul class="events itemMembers">
1503             
1504             </ul>
1505         </li>
1506     
1507         <li class="item" data-name="LuCI.ui.tabs">
1508             <span class="title">
1509                 <a href="LuCI.ui.tabs.html">LuCI.ui.tabs</a>
1510                 
1511             </span>
1512             <ul class="members itemMembers">
1513             
1514             </ul>
1515             <ul class="typedefs itemMembers">
1516             
1517             </ul>
1518             <ul class="typedefs itemMembers">
1519             
1520             </ul>
1521             <ul class="methods itemMembers">
1522             
1523             <span class="subtitle">Methods</span>
1524             
1525                 <li data-name="LuCI.ui.tabs#initTabGroup"><a href="LuCI.ui.tabs.html#initTabGroup">initTabGroup</a></li>
1526             
1527                 <li data-name="LuCI.ui.tabs#isEmptyPane"><a href="LuCI.ui.tabs.html#isEmptyPane">isEmptyPane</a></li>
1528             
1529             </ul>
1530             <ul class="events itemMembers">
1531             
1532             </ul>
1533         </li>
1534     
1535         <li class="item" data-name="LuCI.ui.Textarea">
1536             <span class="title">
1537                 <a href="LuCI.ui.Textarea.html">LuCI.ui.Textarea</a>
1538                 
1539             </span>
1540             <ul class="members itemMembers">
1541             
1542             </ul>
1543             <ul class="typedefs itemMembers">
1544             
1545             <span class="subtitle">Typedefs</span>
1546             
1547                 <li data-name="LuCI.ui.Textarea.InitOptions"><a href="LuCI.ui.Textarea.html#.InitOptions">InitOptions</a></li>
1548             
1549             </ul>
1550             <ul class="typedefs itemMembers">
1551             
1552             </ul>
1553             <ul class="methods itemMembers">
1554             
1555             <span class="subtitle">Methods</span>
1556             
1557                 <li data-name="LuCI.ui.Textarea#getValue"><a href="LuCI.ui.Textarea.html#getValue">getValue</a></li>
1558             
1559                 <li data-name="LuCI.ui.Textarea#isValid"><a href="LuCI.ui.Textarea.html#isValid">isValid</a></li>
1560             
1561                 <li data-name="LuCI.ui.Textarea#registerEvents"><a href="LuCI.ui.Textarea.html#registerEvents">registerEvents</a></li>
1562             
1563                 <li data-name="LuCI.ui.Textarea#render"><a href="LuCI.ui.Textarea.html#render">render</a></li>
1564             
1565                 <li data-name="LuCI.ui.Textarea#setChangeEvents"><a href="LuCI.ui.Textarea.html#setChangeEvents">setChangeEvents</a></li>
1566             
1567                 <li data-name="LuCI.ui.Textarea#setUpdateEvents"><a href="LuCI.ui.Textarea.html#setUpdateEvents">setUpdateEvents</a></li>
1568             
1569                 <li data-name="LuCI.ui.Textarea#setValue"><a href="LuCI.ui.Textarea.html#setValue">setValue</a></li>
1570             
1571                 <li data-name="LuCI.ui.Textarea#triggerValidation"><a href="LuCI.ui.Textarea.html#triggerValidation">triggerValidation</a></li>
1572             
1573             </ul>
1574             <ul class="events itemMembers">
1575             
1576             </ul>
1577         </li>
1578     
1579         <li class="item" data-name="LuCI.ui.Textfield">
1580             <span class="title">
1581                 <a href="LuCI.ui.Textfield.html">LuCI.ui.Textfield</a>
1582                 
1583             </span>
1584             <ul class="members itemMembers">
1585             
1586             </ul>
1587             <ul class="typedefs itemMembers">
1588             
1589             <span class="subtitle">Typedefs</span>
1590             
1591                 <li data-name="LuCI.ui.Textfield.InitOptions"><a href="LuCI.ui.Textfield.html#.InitOptions">InitOptions</a></li>
1592             
1593             </ul>
1594             <ul class="typedefs itemMembers">
1595             
1596             </ul>
1597             <ul class="methods itemMembers">
1598             
1599             <span class="subtitle">Methods</span>
1600             
1601                 <li data-name="LuCI.ui.Textfield#getValue"><a href="LuCI.ui.Textfield.html#getValue">getValue</a></li>
1602             
1603                 <li data-name="LuCI.ui.Textfield#isValid"><a href="LuCI.ui.Textfield.html#isValid">isValid</a></li>
1604             
1605                 <li data-name="LuCI.ui.Textfield#registerEvents"><a href="LuCI.ui.Textfield.html#registerEvents">registerEvents</a></li>
1606             
1607                 <li data-name="LuCI.ui.Textfield#render"><a href="LuCI.ui.Textfield.html#render">render</a></li>
1608             
1609                 <li data-name="LuCI.ui.Textfield#setChangeEvents"><a href="LuCI.ui.Textfield.html#setChangeEvents">setChangeEvents</a></li>
1610             
1611                 <li data-name="LuCI.ui.Textfield#setUpdateEvents"><a href="LuCI.ui.Textfield.html#setUpdateEvents">setUpdateEvents</a></li>
1612             
1613                 <li data-name="LuCI.ui.Textfield#setValue"><a href="LuCI.ui.Textfield.html#setValue">setValue</a></li>
1614             
1615                 <li data-name="LuCI.ui.Textfield#triggerValidation"><a href="LuCI.ui.Textfield.html#triggerValidation">triggerValidation</a></li>
1616             
1617             </ul>
1618             <ul class="events itemMembers">
1619             
1620             </ul>
1621         </li>
1622     
1623         <li class="item" data-name="LuCI.view">
1624             <span class="title">
1625                 <a href="LuCI.view.html">LuCI.view</a>
1626                 
1627             </span>
1628             <ul class="members itemMembers">
1629             
1630             </ul>
1631             <ul class="typedefs itemMembers">
1632             
1633             </ul>
1634             <ul class="typedefs itemMembers">
1635             
1636             </ul>
1637             <ul class="methods itemMembers">
1638             
1639             <span class="subtitle">Methods</span>
1640             
1641                 <li data-name="LuCI.view#addFooter"><a href="LuCI.view.html#addFooter">addFooter</a></li>
1642             
1643                 <li data-name="LuCI.view#handleReset"><a href="LuCI.view.html#handleReset">handleReset</a></li>
1644             
1645                 <li data-name="LuCI.view#handleSave"><a href="LuCI.view.html#handleSave">handleSave</a></li>
1646             
1647                 <li data-name="LuCI.view#handleSaveApply"><a href="LuCI.view.html#handleSaveApply">handleSaveApply</a></li>
1648             
1649                 <li data-name="LuCI.view#load"><a href="LuCI.view.html#load">load</a></li>
1650             
1651                 <li data-name="LuCI.view#render"><a href="LuCI.view.html#render">render</a></li>
1652             
1653             </ul>
1654             <ul class="events itemMembers">
1655             
1656             </ul>
1657         </li>
1658     
1659         <li class="item" data-name="LuCI.xhr">
1660             <span class="title">
1661                 <a href="LuCI.xhr.html">LuCI.xhr</a>
1662                 
1663             </span>
1664             <ul class="members itemMembers">
1665             
1666             </ul>
1667             <ul class="typedefs itemMembers">
1668             
1669             </ul>
1670             <ul class="typedefs itemMembers">
1671             
1672             </ul>
1673             <ul class="methods itemMembers">
1674             
1675             <span class="subtitle">Methods</span>
1676             
1677                 <li data-name="LuCI.xhr#abort"><a href="LuCI.xhr.html#abort">abort</a></li>
1678             
1679                 <li data-name="LuCI.xhr#busy"><a href="LuCI.xhr.html#busy">busy</a></li>
1680             
1681                 <li data-name="LuCI.xhr#cancel"><a href="LuCI.xhr.html#cancel">cancel</a></li>
1682             
1683                 <li data-name="LuCI.xhr#get"><a href="LuCI.xhr.html#get">get</a></li>
1684             
1685                 <li data-name="LuCI.xhr#post"><a href="LuCI.xhr.html#post">post</a></li>
1686             
1687                 <li data-name="LuCI.xhr#send_form"><a href="LuCI.xhr.html#send_form">send_form</a></li>
1688             
1689             </ul>
1690             <ul class="events itemMembers">
1691             
1692             </ul>
1693         </li>
1694     
1695     </ul>
1696 </div>
1697     <div class="main">
1698         <h1 class="page-title" data-filename="luci.js.html">Source: luci.js</h1>
1699         
1700
1701
1702     
1703     <section>
1704         <article>
1705             <pre id="source-code" class="prettyprint source "><code>/**
1706  * @class LuCI
1707  * @classdesc
1708  *
1709  * This is the LuCI base class. It is automatically instantiated and
1710  * accessible using the global `L` variable.
1711  *
1712  * @param {Object} env
1713  * The environment settings to use for the LuCI runtime.
1714  */
1715
1716 (function(window, document, undefined) {
1717         'use strict';
1718
1719         /* Object.assign polyfill for IE */
1720         if (typeof Object.assign !== 'function') {
1721                 Object.defineProperty(Object, 'assign', {
1722                         value: function assign(target, varArgs) {
1723                                 if (target == null)
1724                                         throw new TypeError('Cannot convert undefined or null to object');
1725
1726                                 var to = Object(target);
1727
1728                                 for (var index = 1; index &lt; arguments.length; index++)
1729                                         if (arguments[index] != null)
1730                                                 for (var nextKey in arguments[index])
1731                                                         if (Object.prototype.hasOwnProperty.call(arguments[index], nextKey))
1732                                                                 to[nextKey] = arguments[index][nextKey];
1733
1734                                 return to;
1735                         },
1736                         writable: true,
1737                         configurable: true
1738                 });
1739         }
1740
1741         /* Promise.finally polyfill */
1742         if (typeof Promise.prototype.finally !== 'function') {
1743                 Promise.prototype.finally = function(fn) {
1744                         var onFinally = function(cb) {
1745                                 return Promise.resolve(fn.call(this)).then(cb);
1746                         };
1747
1748                         return this.then(
1749                                 function(result) { return onFinally.call(this, function() { return result }) },
1750                                 function(reason) { return onFinally.call(this, function() { return Promise.reject(reason) }) }
1751                         );
1752                 };
1753         }
1754
1755         /*
1756          * Class declaration and inheritance helper
1757          */
1758
1759         var toCamelCase = function(s) {
1760                 return s.replace(/(?:^|[\. -])(.)/g, function(m0, m1) { return m1.toUpperCase() });
1761         };
1762
1763         /**
1764          * @class baseclass
1765          * @hideconstructor
1766          * @memberof LuCI
1767          * @classdesc
1768          *
1769          * `LuCI.baseclass` is the abstract base class all LuCI classes inherit from.
1770          *
1771          * It provides simple means to create subclasses of given classes and
1772          * implements prototypal inheritance.
1773          */
1774         var superContext = {}, classIndex = 0, Class = Object.assign(function() {}, {
1775                 /**
1776                  * Extends this base class with the properties described in
1777                  * `properties` and returns a new subclassed Class instance
1778                  *
1779                  * @memberof LuCI.baseclass
1780                  *
1781                  * @param {Object&lt;string, *>} properties
1782                  * An object describing the properties to add to the new
1783                  * subclass.
1784                  *
1785                  * @returns {LuCI.baseclass}
1786                  * Returns a new LuCI.baseclass sublassed from this class, extended
1787                  * by the given properties and with its prototype set to this base
1788                  * class to enable inheritance. The resulting value represents a
1789                  * class constructor and can be instantiated with `new`.
1790                  */
1791                 extend: function(properties) {
1792                         var props = {
1793                                 __id__: { value: classIndex },
1794                                 __base__: { value: this.prototype },
1795                                 __name__: { value: properties.__name__ || 'anonymous' + classIndex++ }
1796                         };
1797
1798                         var ClassConstructor = function() {
1799                                 if (!(this instanceof ClassConstructor))
1800                                         throw new TypeError('Constructor must not be called without "new"');
1801
1802                                 if (Object.getPrototypeOf(this).hasOwnProperty('__init__')) {
1803                                         if (typeof(this.__init__) != 'function')
1804                                                 throw new TypeError('Class __init__ member is not a function');
1805
1806                                         this.__init__.apply(this, arguments)
1807                                 }
1808                                 else {
1809                                         this.super('__init__', arguments);
1810                                 }
1811                         };
1812
1813                         for (var key in properties)
1814                                 if (!props[key] &amp;&amp; properties.hasOwnProperty(key))
1815                                         props[key] = { value: properties[key], writable: true };
1816
1817                         ClassConstructor.prototype = Object.create(this.prototype, props);
1818                         ClassConstructor.prototype.constructor = ClassConstructor;
1819                         Object.assign(ClassConstructor, this);
1820                         ClassConstructor.displayName = toCamelCase(props.__name__.value + 'Class');
1821
1822                         return ClassConstructor;
1823                 },
1824
1825                 /**
1826                  * Extends this base class with the properties described in
1827                  * `properties`, instantiates the resulting subclass using
1828                  * the additional optional arguments passed to this function
1829                  * and returns the resulting subclassed Class instance.
1830                  *
1831                  * This function serves as a convenience shortcut for
1832                  * {@link LuCI.baseclass.extend Class.extend()} and subsequent
1833                  * `new`.
1834                  *
1835                  * @memberof LuCI.baseclass
1836                  *
1837                  * @param {Object&lt;string, *>} properties
1838                  * An object describing the properties to add to the new
1839                  * subclass.
1840                  *
1841                  * @param {...*} [new_args]
1842                  * Specifies arguments to be passed to the subclass constructor
1843                  * as-is in order to instantiate the new subclass.
1844                  *
1845                  * @returns {LuCI.baseclass}
1846                  * Returns a new LuCI.baseclass instance extended by the given
1847                  * properties with its prototype set to this base class to
1848                  * enable inheritance.
1849                  */
1850                 singleton: function(properties /*, ... */) {
1851                         return Class.extend(properties)
1852                                 .instantiate(Class.prototype.varargs(arguments, 1));
1853                 },
1854
1855                 /**
1856                  * Calls the class constructor using `new` with the given argument
1857                  * array being passed as variadic parameters to the constructor.
1858                  *
1859                  * @memberof LuCI.baseclass
1860                  *
1861                  * @param {Array&lt;*>} params
1862                  * An array of arbitrary values which will be passed as arguments
1863                  * to the constructor function.
1864                  *
1865                  * @param {...*} [new_args]
1866                  * Specifies arguments to be passed to the subclass constructor
1867                  * as-is in order to instantiate the new subclass.
1868                  *
1869                  * @returns {LuCI.baseclass}
1870                  * Returns a new LuCI.baseclass instance extended by the given
1871                  * properties with its prototype set to this base class to
1872                  * enable inheritance.
1873                  */
1874                 instantiate: function(args) {
1875                         return new (Function.prototype.bind.apply(this,
1876                                 Class.prototype.varargs(args, 0, null)))();
1877                 },
1878
1879                 /* unused */
1880                 call: function(self, method) {
1881                         if (typeof(this.prototype[method]) != 'function')
1882                                 throw new ReferenceError(method + ' is not defined in class');
1883
1884                         return this.prototype[method].apply(self, self.varargs(arguments, 1));
1885                 },
1886
1887                 /**
1888                  * Checks whether the given class value is a subclass of this class.
1889                  *
1890                  * @memberof LuCI.baseclass
1891                  *
1892                  * @param {LuCI.baseclass} classValue
1893                  * The class object to test.
1894                  *
1895                  * @returns {boolean}
1896                  * Returns `true` when the given `classValue` is a subclass of this
1897                  * class or `false` if the given value is not a valid class or not
1898                  * a subclass of this class'.
1899                  */
1900                 isSubclass: function(classValue) {
1901                         return (classValue != null &amp;&amp;
1902                                 typeof(classValue) == 'function' &amp;&amp;
1903                                 classValue.prototype instanceof this);
1904                 },
1905
1906                 prototype: {
1907                         /**
1908                          * Extract all values from the given argument array beginning from
1909                          * `offset` and prepend any further given optional parameters to
1910                          * the beginning of the resulting array copy.
1911                          *
1912                          * @memberof LuCI.baseclass
1913                          * @instance
1914                          *
1915                          * @param {Array&lt;*>} args
1916                          * The array to extract the values from.
1917                          *
1918                          * @param {number} offset
1919                          * The offset from which to extract the values. An offset of `0`
1920                          * would copy all values till the end.
1921                          *
1922                          * @param {...*} [extra_args]
1923                          * Extra arguments to add to prepend to the resultung array.
1924                          *
1925                          * @returns {Array&lt;*>}
1926                          * Returns a new array consisting of the optional extra arguments
1927                          * and the values extracted from the `args` array beginning with
1928                          * `offset`.
1929                          */
1930                         varargs: function(args, offset /*, ... */) {
1931                                 return Array.prototype.slice.call(arguments, 2)
1932                                         .concat(Array.prototype.slice.call(args, offset));
1933                         },
1934
1935                         /**
1936                          * Walks up the parent class chain and looks for a class member
1937                          * called `key` in any of the parent classes this class inherits
1938                          * from. Returns the member value of the superclass or calls the
1939                          * member as function and returns its return value when the
1940                          * optional `callArgs` array is given.
1941                          *
1942                          * This function has two signatures and is sensitive to the
1943                          * amount of arguments passed to it:
1944                          *  - `super('key')` -
1945                          *    Returns the value of `key` when found within one of the
1946                          *    parent classes.
1947                          *  - `super('key', ['arg1', 'arg2'])` -
1948                          *    Calls the `key()` method with parameters `arg1` and `arg2`
1949                          *    when found within one of the parent classes.
1950                          *
1951                          * @memberof LuCI.baseclass
1952                          * @instance
1953                          *
1954                          * @param {string} key
1955                          * The name of the superclass member to retrieve.
1956                          *
1957                          * @param {Array&lt;*>} [callArgs]
1958                          * An optional array of function call parameters to use. When
1959                          * this parameter is specified, the found member value is called
1960                          * as function using the values of this array as arguments.
1961                          *
1962                          * @throws {ReferenceError}
1963                          * Throws a `ReferenceError` when `callArgs` are specified and
1964                          * the found member named by `key` is not a function value.
1965                          *
1966                          * @returns {*|null}
1967                          * Returns the value of the found member or the return value of
1968                          * the call to the found method. Returns `null` when no member
1969                          * was found in the parent class chain or when the call to the
1970                          * superclass method returned `null`.
1971                          */
1972                         super: function(key, callArgs) {
1973                                 if (key == null)
1974                                         return null;
1975
1976                                 var slotIdx = this.__id__ + '.' + key,
1977                                     symStack = superContext[slotIdx],
1978                                     protoCtx = null;
1979
1980                                 for (protoCtx = Object.getPrototypeOf(symStack ? symStack[0] : Object.getPrototypeOf(this));
1981                                      protoCtx != null &amp;&amp; !protoCtx.hasOwnProperty(key);
1982                                      protoCtx = Object.getPrototypeOf(protoCtx)) {}
1983
1984                                 if (protoCtx == null)
1985                                         return null;
1986
1987                                 var res = protoCtx[key];
1988
1989                                 if (arguments.length > 1) {
1990                                         if (typeof(res) != 'function')
1991                                                 throw new ReferenceError(key + ' is not a function in base class');
1992
1993                                         if (typeof(callArgs) != 'object')
1994                                                 callArgs = this.varargs(arguments, 1);
1995
1996                                         if (symStack)
1997                                                 symStack.unshift(protoCtx);
1998                                         else
1999                                                 superContext[slotIdx] = [ protoCtx ];
2000
2001                                         res = res.apply(this, callArgs);
2002
2003                                         if (symStack &amp;&amp; symStack.length > 1)
2004                                                 symStack.shift(protoCtx);
2005                                         else
2006                                                 delete superContext[slotIdx];
2007                                 }
2008
2009                                 return res;
2010                         },
2011
2012                         /**
2013                          * Returns a string representation of this class.
2014                          *
2015                          * @returns {string}
2016                          * Returns a string representation of this class containing the
2017                          * constructor functions `displayName` and describing the class
2018                          * members and their respective types.
2019                          */
2020                         toString: function() {
2021                                 var s = '[' + this.constructor.displayName + ']', f = true;
2022                                 for (var k in this) {
2023                                         if (this.hasOwnProperty(k)) {
2024                                                 s += (f ? ' {\n' : '') + '  ' + k + ': ' + typeof(this[k]) + '\n';
2025                                                 f = false;
2026                                         }
2027                                 }
2028                                 return s + (f ? '' : '}');
2029                         }
2030                 }
2031         });
2032
2033
2034         /**
2035          * @class headers
2036          * @memberof LuCI
2037          * @hideconstructor
2038          * @classdesc
2039          *
2040          * The `Headers` class is an internal utility class exposed in HTTP
2041          * response objects using the `response.headers` property.
2042          */
2043         var Headers = Class.extend(/** @lends LuCI.headers.prototype */ {
2044                 __name__: 'LuCI.headers',
2045                 __init__: function(xhr) {
2046                         var hdrs = this.headers = {};
2047                         xhr.getAllResponseHeaders().split(/\r\n/).forEach(function(line) {
2048                                 var m = /^([^:]+):(.*)$/.exec(line);
2049                                 if (m != null)
2050                                         hdrs[m[1].trim().toLowerCase()] = m[2].trim();
2051                         });
2052                 },
2053
2054                 /**
2055                  * Checks whether the given header name is present.
2056                  * Note: Header-Names are case-insensitive.
2057                  *
2058                  * @instance
2059                  * @memberof LuCI.headers
2060                  * @param {string} name
2061                  * The header name to check
2062                  *
2063                  * @returns {boolean}
2064                  * Returns `true` if the header name is present, `false` otherwise
2065                  */
2066                 has: function(name) {
2067                         return this.headers.hasOwnProperty(String(name).toLowerCase());
2068                 },
2069
2070                 /**
2071                  * Returns the value of the given header name.
2072                  * Note: Header-Names are case-insensitive.
2073                  *
2074                  * @instance
2075                  * @memberof LuCI.headers
2076                  * @param {string} name
2077                  * The header name to read
2078                  *
2079                  * @returns {string|null}
2080                  * The value of the given header name or `null` if the header isn't present.
2081                  */
2082                 get: function(name) {
2083                         var key = String(name).toLowerCase();
2084                         return this.headers.hasOwnProperty(key) ? this.headers[key] : null;
2085                 }
2086         });
2087
2088         /**
2089          * @class response
2090          * @memberof LuCI
2091          * @hideconstructor
2092          * @classdesc
2093          *
2094          * The `Response` class is an internal utility class representing HTTP responses.
2095          */
2096         var Response = Class.extend({
2097                 __name__: 'LuCI.response',
2098                 __init__: function(xhr, url, duration, headers, content) {
2099                         /**
2100                          * Describes whether the response is successful (status codes `200..299`) or not
2101                          * @instance
2102                          * @memberof LuCI.response
2103                          * @name ok
2104                          * @type {boolean}
2105                          */
2106                         this.ok = (xhr.status >= 200 &amp;&amp; xhr.status &lt;= 299);
2107
2108                         /**
2109                          * The numeric HTTP status code of the response
2110                          * @instance
2111                          * @memberof LuCI.response
2112                          * @name status
2113                          * @type {number}
2114                          */
2115                         this.status = xhr.status;
2116
2117                         /**
2118                          * The HTTP status description message of the response
2119                          * @instance
2120                          * @memberof LuCI.response
2121                          * @name statusText
2122                          * @type {string}
2123                          */
2124                         this.statusText = xhr.statusText;
2125
2126                         /**
2127                          * The HTTP headers of the response
2128                          * @instance
2129                          * @memberof LuCI.response
2130                          * @name headers
2131                          * @type {LuCI.headers}
2132                          */
2133                         this.headers = (headers != null) ? headers : new Headers(xhr);
2134
2135                         /**
2136                          * The total duration of the HTTP request in milliseconds
2137                          * @instance
2138                          * @memberof LuCI.response
2139                          * @name duration
2140                          * @type {number}
2141                          */
2142                         this.duration = duration;
2143
2144                         /**
2145                          * The final URL of the request, i.e. after following redirects.
2146                          * @instance
2147                          * @memberof LuCI.response
2148                          * @name url
2149                          * @type {string}
2150                          */
2151                         this.url = url;
2152
2153                         /* privates */
2154                         this.xhr = xhr;
2155
2156                         if (content instanceof Blob) {
2157                                 this.responseBlob = content;
2158                                 this.responseJSON = null;
2159                                 this.responseText = null;
2160                         }
2161                         else if (content != null &amp;&amp; typeof(content) == 'object') {
2162                                 this.responseBlob = null;
2163                                 this.responseJSON = content;
2164                                 this.responseText = null;
2165                         }
2166                         else if (content != null) {
2167                                 this.responseBlob = null;
2168                                 this.responseJSON = null;
2169                                 this.responseText = String(content);
2170                         }
2171                         else {
2172                                 this.responseJSON = null;
2173
2174                                 if (xhr.responseType == 'blob') {
2175                                         this.responseBlob = xhr.response;
2176                                         this.responseText = null;
2177                                 }
2178                                 else {
2179                                         this.responseBlob = null;
2180                                         this.responseText = xhr.responseText;
2181                                 }
2182                         }
2183                 },
2184
2185                 /**
2186                  * Clones the given response object, optionally overriding the content
2187                  * of the cloned instance.
2188                  *
2189                  * @instance
2190                  * @memberof LuCI.response
2191                  * @param {*} [content]
2192                  * Override the content of the cloned response. Object values will be
2193                  * treated as JSON response data, all other types will be converted
2194                  * using `String()` and treated as response text.
2195                  *
2196                  * @returns {LuCI.response}
2197                  * The cloned `Response` instance.
2198                  */
2199                 clone: function(content) {
2200                         var copy = new Response(this.xhr, this.url, this.duration, this.headers, content);
2201
2202                         copy.ok = this.ok;
2203                         copy.status = this.status;
2204                         copy.statusText = this.statusText;
2205
2206                         return copy;
2207                 },
2208
2209                 /**
2210                  * Access the response content as JSON data.
2211                  *
2212                  * @instance
2213                  * @memberof LuCI.response
2214                  * @throws {SyntaxError}
2215                  * Throws `SyntaxError` if the content isn't valid JSON.
2216                  *
2217                  * @returns {*}
2218                  * The parsed JSON data.
2219                  */
2220                 json: function() {
2221                         if (this.responseJSON == null)
2222                                 this.responseJSON = JSON.parse(this.responseText);
2223
2224                         return this.responseJSON;
2225                 },
2226
2227                 /**
2228                  * Access the response content as string.
2229                  *
2230                  * @instance
2231                  * @memberof LuCI.response
2232                  * @returns {string}
2233                  * The response content.
2234                  */
2235                 text: function() {
2236                         if (this.responseText == null &amp;&amp; this.responseJSON != null)
2237                                 this.responseText = JSON.stringify(this.responseJSON);
2238
2239                         return this.responseText;
2240                 },
2241
2242                 /**
2243                  * Access the response content as blob.
2244                  *
2245                  * @instance
2246                  * @memberof LuCI.response
2247                  * @returns {Blob}
2248                  * The response content as blob.
2249                  */
2250                 blob: function() {
2251                         return this.responseBlob;
2252                 }
2253         });
2254
2255
2256         var requestQueue = [];
2257
2258         function isQueueableRequest(opt) {
2259                 if (!classes.rpc)
2260                         return false;
2261
2262                 if (opt.method != 'POST' || typeof(opt.content) != 'object')
2263                         return false;
2264
2265                 if (opt.nobatch === true)
2266                         return false;
2267
2268                 var rpcBaseURL = Request.expandURL(classes.rpc.getBaseURL());
2269
2270                 return (rpcBaseURL != null &amp;&amp; opt.url.indexOf(rpcBaseURL) == 0);
2271         }
2272
2273         function flushRequestQueue() {
2274                 if (!requestQueue.length)
2275                         return;
2276
2277                 var reqopt = Object.assign({}, requestQueue[0][0], { content: [], nobatch: true }),
2278                     batch = [];
2279
2280                 for (var i = 0; i &lt; requestQueue.length; i++) {
2281                         batch[i] = requestQueue[i];
2282                         reqopt.content[i] = batch[i][0].content;
2283                 }
2284
2285                 requestQueue.length = 0;
2286
2287                 Request.request(rpcBaseURL, reqopt).then(function(reply) {
2288                         var json = null, req = null;
2289
2290                         try { json = reply.json() }
2291                         catch(e) { }
2292
2293                         while ((req = batch.shift()) != null)
2294                                 if (Array.isArray(json) &amp;&amp; json.length)
2295                                         req[2].call(reqopt, reply.clone(json.shift()));
2296                                 else
2297                                         req[1].call(reqopt, new Error('No related RPC reply'));
2298                 }).catch(function(error) {
2299                         var req = null;
2300
2301                         while ((req = batch.shift()) != null)
2302                                 req[1].call(reqopt, error);
2303                 });
2304         }
2305
2306         /**
2307          * @class request
2308          * @memberof LuCI
2309          * @hideconstructor
2310          * @classdesc
2311          *
2312          * The `Request` class allows initiating HTTP requests and provides utilities
2313          * for dealing with responses.
2314          */
2315         var Request = Class.singleton(/** @lends LuCI.request.prototype */ {
2316                 __name__: 'LuCI.request',
2317
2318                 interceptors: [],
2319
2320                 /**
2321                  * Turn the given relative URL into an absolute URL if necessary.
2322                  *
2323                  * @instance
2324                  * @memberof LuCI.request
2325                  * @param {string} url
2326                  * The URL to convert.
2327                  *
2328                  * @returns {string}
2329                  * The absolute URL derived from the given one, or the original URL
2330                  * if it already was absolute.
2331                  */
2332                 expandURL: function(url) {
2333                         if (!/^(?:[^/]+:)?\/\//.test(url))
2334                                 url = location.protocol + '//' + location.host + url;
2335
2336                         return url;
2337                 },
2338
2339                 /**
2340                  * @typedef {Object} RequestOptions
2341                  * @memberof LuCI.request
2342                  *
2343                  * @property {string} [method=GET]
2344                  * The HTTP method to use, e.g. `GET` or `POST`.
2345                  *
2346                  * @property {Object&lt;string, Object|string>} [query]
2347                  * Query string data to append to the URL. Non-string values of the
2348                  * given object will be converted to JSON.
2349                  *
2350                  * @property {boolean} [cache=false]
2351                  * Specifies whether the HTTP response may be retrieved from cache.
2352                  *
2353                  * @property {string} [username]
2354                  * Provides a username for HTTP basic authentication.
2355                  *
2356                  * @property {string} [password]
2357                  * Provides a password for HTTP basic authentication.
2358                  *
2359                  * @property {number} [timeout]
2360                  * Specifies the request timeout in seconds.
2361                  *
2362                  * @property {boolean} [credentials=false]
2363                  * Whether to include credentials such as cookies in the request.
2364                  *
2365                  * @property {string} [responseType=text]
2366                  * Overrides the request response type. Valid values or `text` to
2367                  * interpret the response as UTF-8 string or `blob` to handle the
2368                  * response as binary `Blob` data.
2369                  *
2370                  * @property {*} [content]
2371                  * Specifies the HTTP message body to send along with the request.
2372                  * If the value is a function, it is invoked and the return value
2373                  * used as content, if it is a FormData instance, it is used as-is,
2374                  * if it is an object, it will be converted to JSON, in all other
2375                  * cases it is converted to a string.
2376                  *
2377              * @property {Object&lt;string, string>} [header]
2378              * Specifies HTTP headers to set for the request.
2379              *
2380              * @property {function} [progress]
2381              * An optional request callback function which receives ProgressEvent
2382              * instances as sole argument during the HTTP request transfer.
2383                  */
2384
2385                 /**
2386                  * Initiate an HTTP request to the given target.
2387                  *
2388                  * @instance
2389                  * @memberof LuCI.request
2390                  * @param {string} target
2391                  * The URL to request.
2392                  *
2393                  * @param {LuCI.request.RequestOptions} [options]
2394                  * Additional options to configure the request.
2395                  *
2396                  * @returns {Promise&lt;LuCI.response>}
2397                  * The resulting HTTP response.
2398                  */
2399                 request: function(target, options) {
2400                         var state = { xhr: new XMLHttpRequest(), url: this.expandURL(target), start: Date.now() },
2401                             opt = Object.assign({}, options, state),
2402                             content = null,
2403                             contenttype = null,
2404                             callback = this.handleReadyStateChange;
2405
2406                         return new Promise(function(resolveFn, rejectFn) {
2407                                 opt.xhr.onreadystatechange = callback.bind(opt, resolveFn, rejectFn);
2408                                 opt.method = String(opt.method || 'GET').toUpperCase();
2409
2410                                 if ('query' in opt) {
2411                                         var q = (opt.query != null) ? Object.keys(opt.query).map(function(k) {
2412                                                 if (opt.query[k] != null) {
2413                                                         var v = (typeof(opt.query[k]) == 'object')
2414                                                                 ? JSON.stringify(opt.query[k])
2415                                                                 : String(opt.query[k]);
2416
2417                                                         return '%s=%s'.format(encodeURIComponent(k), encodeURIComponent(v));
2418                                                 }
2419                                                 else {
2420                                                         return encodeURIComponent(k);
2421                                                 }
2422                                         }).join('&amp;') : '';
2423
2424                                         if (q !== '') {
2425                                                 switch (opt.method) {
2426                                                 case 'GET':
2427                                                 case 'HEAD':
2428                                                 case 'OPTIONS':
2429                                                         opt.url += ((/\?/).test(opt.url) ? '&amp;' : '?') + q;
2430                                                         break;
2431
2432                                                 default:
2433                                                         if (content == null) {
2434                                                                 content = q;
2435                                                                 contenttype = 'application/x-www-form-urlencoded';
2436                                                         }
2437                                                 }
2438                                         }
2439                                 }
2440
2441                                 if (!opt.cache)
2442                                         opt.url += ((/\?/).test(opt.url) ? '&amp;' : '?') + (new Date()).getTime();
2443
2444                                 if (isQueueableRequest(opt)) {
2445                                         requestQueue.push([opt, rejectFn, resolveFn]);
2446                                         requestAnimationFrame(flushRequestQueue);
2447                                         return;
2448                                 }
2449
2450                                 if ('username' in opt &amp;&amp; 'password' in opt)
2451                                         opt.xhr.open(opt.method, opt.url, true, opt.username, opt.password);
2452                                 else
2453                                         opt.xhr.open(opt.method, opt.url, true);
2454
2455                                 opt.xhr.responseType = opt.responseType || 'text';
2456
2457                                 if ('overrideMimeType' in opt.xhr)
2458                                         opt.xhr.overrideMimeType('application/octet-stream');
2459
2460                                 if ('timeout' in opt)
2461                                         opt.xhr.timeout = +opt.timeout;
2462
2463                                 if ('credentials' in opt)
2464                                         opt.xhr.withCredentials = !!opt.credentials;
2465
2466                                 if (opt.content != null) {
2467                                         switch (typeof(opt.content)) {
2468                                         case 'function':
2469                                                 content = opt.content(xhr);
2470                                                 break;
2471
2472                                         case 'object':
2473                                                 if (!(opt.content instanceof FormData)) {
2474                                                         content = JSON.stringify(opt.content);
2475                                                         contenttype = 'application/json';
2476                                                 }
2477                                                 else {
2478                                                         content = opt.content;
2479                                                 }
2480                                                 break;
2481
2482                                         default:
2483                                                 content = String(opt.content);
2484                                         }
2485                                 }
2486
2487                                 if ('headers' in opt)
2488                                         for (var header in opt.headers)
2489                                                 if (opt.headers.hasOwnProperty(header)) {
2490                                                         if (header.toLowerCase() != 'content-type')
2491                                                                 opt.xhr.setRequestHeader(header, opt.headers[header]);
2492                                                         else
2493                                                                 contenttype = opt.headers[header];
2494                                                 }
2495
2496                                 if ('progress' in opt &amp;&amp; 'upload' in opt.xhr)
2497                                         opt.xhr.upload.addEventListener('progress', opt.progress);
2498
2499                                 if (contenttype != null)
2500                                         opt.xhr.setRequestHeader('Content-Type', contenttype);
2501
2502                                 try {
2503                                         opt.xhr.send(content);
2504                                 }
2505                                 catch (e) {
2506                                         rejectFn.call(opt, e);
2507                                 }
2508                         });
2509                 },
2510
2511                 handleReadyStateChange: function(resolveFn, rejectFn, ev) {
2512                         var xhr = this.xhr,
2513                             duration = Date.now() - this.start;
2514
2515                         if (xhr.readyState !== 4)
2516                                 return;
2517
2518                         if (xhr.status === 0 &amp;&amp; xhr.statusText === '') {
2519                                 if (duration >= this.timeout)
2520                                         rejectFn.call(this, new Error('XHR request timed out'));
2521                                 else
2522                                         rejectFn.call(this, new Error('XHR request aborted by browser'));
2523                         }
2524                         else {
2525                                 var response = new Response(
2526                                         xhr, xhr.responseURL || this.url, duration);
2527
2528                                 Promise.all(Request.interceptors.map(function(fn) { return fn(response) }))
2529                                         .then(resolveFn.bind(this, response))
2530                                         .catch(rejectFn.bind(this));
2531                         }
2532                 },
2533
2534                 /**
2535                  * Initiate an HTTP GET request to the given target.
2536                  *
2537                  * @instance
2538                  * @memberof LuCI.request
2539                  * @param {string} target
2540                  * The URL to request.
2541                  *
2542                  * @param {LuCI.request.RequestOptions} [options]
2543                  * Additional options to configure the request.
2544                  *
2545                  * @returns {Promise&lt;LuCI.response>}
2546                  * The resulting HTTP response.
2547                  */
2548                 get: function(url, options) {
2549                         return this.request(url, Object.assign({ method: 'GET' }, options));
2550                 },
2551
2552                 /**
2553                  * Initiate an HTTP POST request to the given target.
2554                  *
2555                  * @instance
2556                  * @memberof LuCI.request
2557                  * @param {string} target
2558                  * The URL to request.
2559                  *
2560                  * @param {*} [data]
2561                  * The request data to send, see {@link LuCI.request.RequestOptions} for details.
2562                  *
2563                  * @param {LuCI.request.RequestOptions} [options]
2564                  * Additional options to configure the request.
2565                  *
2566                  * @returns {Promise&lt;LuCI.response>}
2567                  * The resulting HTTP response.
2568                  */
2569                 post: function(url, data, options) {
2570                         return this.request(url, Object.assign({ method: 'POST', content: data }, options));
2571                 },
2572
2573                 /**
2574                  * Interceptor functions are invoked whenever an HTTP reply is received, in the order
2575                  * these functions have been registered.
2576                  * @callback LuCI.request.interceptorFn
2577                  * @param {LuCI.response} res
2578                  * The HTTP response object
2579                  */
2580
2581                 /**
2582                  * Register an HTTP response interceptor function. Interceptor
2583                  * functions are useful to perform default actions on incoming HTTP
2584                  * responses, such as checking for expired authentication or for
2585                  * implementing request retries before returning a failure.
2586                  *
2587                  * @instance
2588                  * @memberof LuCI.request
2589                  * @param {LuCI.request.interceptorFn} interceptorFn
2590                  * The interceptor function to register.
2591                  *
2592                  * @returns {LuCI.request.interceptorFn}
2593                  * The registered function.
2594                  */
2595                 addInterceptor: function(interceptorFn) {
2596                         if (typeof(interceptorFn) == 'function')
2597                                 this.interceptors.push(interceptorFn);
2598                         return interceptorFn;
2599                 },
2600
2601                 /**
2602                  * Remove an HTTP response interceptor function. The passed function
2603                  * value must be the very same value that was used to register the
2604                  * function.
2605                  *
2606                  * @instance
2607                  * @memberof LuCI.request
2608                  * @param {LuCI.request.interceptorFn} interceptorFn
2609                  * The interceptor function to remove.
2610                  *
2611                  * @returns {boolean}
2612                  * Returns `true` if any function has been removed, else `false`.
2613                  */
2614                 removeInterceptor: function(interceptorFn) {
2615                         var oldlen = this.interceptors.length, i = oldlen;
2616                         while (i--)
2617                                 if (this.interceptors[i] === interceptorFn)
2618                                         this.interceptors.splice(i, 1);
2619                         return (this.interceptors.length &lt; oldlen);
2620                 },
2621
2622                 /**
2623                  * @class
2624                  * @memberof LuCI.request
2625                  * @hideconstructor
2626                  * @classdesc
2627                  *
2628                  * The `Request.poll` class provides some convience wrappers around
2629                  * {@link LuCI.poll} mainly to simplify registering repeating HTTP
2630                  * request calls as polling functions.
2631                  */
2632                 poll: {
2633                         /**
2634                          * The callback function is invoked whenever an HTTP reply to a
2635                          * polled request is received or when the polled request timed
2636                          * out.
2637                          *
2638                          * @callback LuCI.request.poll~callbackFn
2639                          * @param {LuCI.response} res
2640                          * The HTTP response object.
2641                          *
2642                          * @param {*} data
2643                          * The response JSON if the response could be parsed as such,
2644                          * else `null`.
2645                          *
2646                          * @param {number} duration
2647                          * The total duration of the request in milliseconds.
2648                          */
2649
2650                         /**
2651                          * Register a repeating HTTP request with an optional callback
2652                          * to invoke whenever a response for the request is received.
2653                          *
2654                          * @instance
2655                          * @memberof LuCI.request.poll
2656                          * @param {number} interval
2657                          * The poll interval in seconds.
2658                          *
2659                          * @param {string} url
2660                          * The URL to request on each poll.
2661                          *
2662                          * @param {LuCI.request.RequestOptions} [options]
2663                          * Additional options to configure the request.
2664                          *
2665                          * @param {LuCI.request.poll~callbackFn} [callback]
2666                          * {@link LuCI.request.poll~callbackFn Callback} function to
2667                          * invoke for each HTTP reply.
2668                          *
2669                          * @throws {TypeError}
2670                          * Throws `TypeError` when an invalid interval was passed.
2671                          *
2672                          * @returns {function}
2673                          * Returns the internally created poll function.
2674                          */
2675                         add: function(interval, url, options, callback) {
2676                                 if (isNaN(interval) || interval &lt;= 0)
2677                                         throw new TypeError('Invalid poll interval');
2678
2679                                 var ival = interval >>> 0,
2680                                     opts = Object.assign({}, options, { timeout: ival * 1000 - 5 });
2681
2682                                 var fn = function() {
2683                                         return Request.request(url, options).then(function(res) {
2684                                                 if (!Poll.active())
2685                                                         return;
2686
2687                                                 try {
2688                                                         callback(res, res.json(), res.duration);
2689                                                 }
2690                                                 catch (err) {
2691                                                         callback(res, null, res.duration);
2692                                                 }
2693                                         });
2694                                 };
2695
2696                                 return (Poll.add(fn, ival) ? fn : null);
2697                         },
2698
2699                         /**
2700                          * Remove a polling request that has been previously added using `add()`.
2701                          * This function is essentially a wrapper around
2702                          * {@link LuCI.poll.remove LuCI.poll.remove()}.
2703                          *
2704                          * @instance
2705                          * @memberof LuCI.request.poll
2706                          * @param {function} entry
2707                          * The poll function returned by {@link LuCI.request.poll#add add()}.
2708                          *
2709                          * @returns {boolean}
2710                          * Returns `true` if any function has been removed, else `false`.
2711                          */
2712                         remove: function(entry) { return Poll.remove(entry) },
2713
2714                         /**
2715                           * Alias for {@link LuCI.poll.start LuCI.poll.start()}.
2716                           *
2717                           * @instance
2718                           * @memberof LuCI.request.poll
2719                           */
2720                         start: function() { return Poll.start() },
2721
2722                         /**
2723                           * Alias for {@link LuCI.poll.stop LuCI.poll.stop()}.
2724                           *
2725                           * @instance
2726                           * @memberof LuCI.request.poll
2727                           */
2728                         stop: function() { return Poll.stop() },
2729
2730                         /**
2731                           * Alias for {@link LuCI.poll.active LuCI.poll.active()}.
2732                           *
2733                           * @instance
2734                           * @memberof LuCI.request.poll
2735                           */
2736                         active: function() { return Poll.active() }
2737                 }
2738         });
2739
2740         /**
2741          * @class poll
2742          * @memberof LuCI
2743          * @hideconstructor
2744          * @classdesc
2745          *
2746          * The `Poll` class allows registering and unregistering poll actions,
2747          * as well as starting, stopping and querying the state of the polling
2748          * loop.
2749          */
2750         var Poll = Class.singleton(/** @lends LuCI.poll.prototype */ {
2751                 __name__: 'LuCI.poll',
2752
2753                 queue: [],
2754
2755                 /**
2756                  * Add a new operation to the polling loop. If the polling loop is not
2757                  * already started at this point, it will be implicitely started.
2758                  *
2759                  * @instance
2760                  * @memberof LuCI.poll
2761                  * @param {function} fn
2762                  * The function to invoke on each poll interval.
2763                  *
2764                  * @param {number} interval
2765                  * The poll interval in seconds.
2766                  *
2767                  * @throws {TypeError}
2768                  * Throws `TypeError` when an invalid interval was passed.
2769                  *
2770                  * @returns {boolean}
2771                  * Returns `true` if the function has been added or `false` if it
2772                  * already is registered.
2773                  */
2774                 add: function(fn, interval) {
2775                         if (interval == null || interval &lt;= 0)
2776                                 interval = window.L ? window.L.env.pollinterval : null;
2777
2778                         if (isNaN(interval) || typeof(fn) != 'function')
2779                                 throw new TypeError('Invalid argument to LuCI.poll.add()');
2780
2781                         for (var i = 0; i &lt; this.queue.length; i++)
2782                                 if (this.queue[i].fn === fn)
2783                                         return false;
2784
2785                         var e = {
2786                                 r: true,
2787                                 i: interval >>> 0,
2788                                 fn: fn
2789                         };
2790
2791                         this.queue.push(e);
2792
2793                         if (this.tick != null &amp;&amp; !this.active())
2794                                 this.start();
2795
2796                         return true;
2797                 },
2798
2799                 /**
2800                  * Remove an operation from the polling loop. If no further operatons
2801                  * are registered, the polling loop is implicitely stopped.
2802                  *
2803                  * @instance
2804                  * @memberof LuCI.poll
2805                  * @param {function} fn
2806                  * The function to remove.
2807                  *
2808                  * @throws {TypeError}
2809                  * Throws `TypeError` when the given argument isn't a function.
2810                  *
2811                  * @returns {boolean}
2812                  * Returns `true` if the function has been removed or `false` if it
2813                  * wasn't found.
2814                  */
2815                 remove: function(fn) {
2816                         if (typeof(fn) != 'function')
2817                                 throw new TypeError('Invalid argument to LuCI.poll.remove()');
2818
2819                         var len = this.queue.length;
2820
2821                         for (var i = len; i > 0; i--)
2822                                 if (this.queue[i-1].fn === fn)
2823                                         this.queue.splice(i-1, 1);
2824
2825                         if (!this.queue.length &amp;&amp; this.stop())
2826                                 this.tick = 0;
2827
2828                         return (this.queue.length != len);
2829                 },
2830
2831                 /**
2832                  * (Re)start the polling loop. Dispatches a custom `poll-start` event
2833                  * to the `document` object upon successful start.
2834                  *
2835                  * @instance
2836                  * @memberof LuCI.poll
2837                  * @returns {boolean}
2838                  * Returns `true` if polling has been started (or if no functions
2839                  * where registered) or `false` when the polling loop already runs.
2840                  */
2841                 start: function() {
2842                         if (this.active())
2843                                 return false;
2844
2845                         this.tick = 0;
2846
2847                         if (this.queue.length) {
2848                                 this.timer = window.setInterval(this.step, 1000);
2849                                 this.step();
2850                                 document.dispatchEvent(new CustomEvent('poll-start'));
2851                         }
2852
2853                         return true;
2854                 },
2855
2856                 /**
2857                  * Stop the polling loop. Dispatches a custom `poll-stop` event
2858                  * to the `document` object upon successful stop.
2859                  *
2860                  * @instance
2861                  * @memberof LuCI.poll
2862                  * @returns {boolean}
2863                  * Returns `true` if polling has been stopped or `false` if it din't
2864                  * run to begin with.
2865                  */
2866                 stop: function() {
2867                         if (!this.active())
2868                                 return false;
2869
2870                         document.dispatchEvent(new CustomEvent('poll-stop'));
2871                         window.clearInterval(this.timer);
2872                         delete this.timer;
2873                         delete this.tick;
2874                         return true;
2875                 },
2876
2877                 /* private */
2878                 step: function() {
2879                         for (var i = 0, e = null; (e = Poll.queue[i]) != null; i++) {
2880                                 if ((Poll.tick % e.i) != 0)
2881                                         continue;
2882
2883                                 if (!e.r)
2884                                         continue;
2885
2886                                 e.r = false;
2887
2888                                 Promise.resolve(e.fn()).finally((function() { this.r = true }).bind(e));
2889                         }
2890
2891                         Poll.tick = (Poll.tick + 1) % Math.pow(2, 32);
2892                 },
2893
2894                 /**
2895                  * Test whether the polling loop is running.
2896                  *
2897                  * @instance
2898                  * @memberof LuCI.poll
2899                  * @returns {boolean} - Returns `true` if polling is active, else `false`.
2900                  */
2901                 active: function() {
2902                         return (this.timer != null);
2903                 }
2904         });
2905
2906         /**
2907          * @class dom
2908          * @memberof LuCI
2909          * @hideconstructor
2910          * @classdesc
2911          *
2912          * The `dom` class provides convenience method for creating and
2913          * manipulating DOM elements.
2914          *
2915          * To import the class in views, use `'require dom'`, to import it in
2916          * external JavaScript, use `L.require("dom").then(...)`.
2917          */
2918         var DOM = Class.singleton(/* @lends LuCI.dom.prototype */ {
2919                 __name__: 'LuCI.dom',
2920
2921                 /**
2922                  * Tests whether the given argument is a valid DOM `Node`.
2923                  *
2924                  * @instance
2925                  * @memberof LuCI.dom
2926                  * @param {*} e
2927                  * The value to test.
2928                  *
2929                  * @returns {boolean}
2930                  * Returns `true` if the value is a DOM `Node`, else `false`.
2931                  */
2932                 elem: function(e) {
2933                         return (e != null &amp;&amp; typeof(e) == 'object' &amp;&amp; 'nodeType' in e);
2934                 },
2935
2936                 /**
2937                  * Parses a given string as HTML and returns the first child node.
2938                  *
2939                  * @instance
2940                  * @memberof LuCI.dom
2941                  * @param {string} s
2942                  * A string containing an HTML fragment to parse. Note that only
2943                  * the first result of the resulting structure is returned, so an
2944                  * input value of `&lt;div>foo&lt;/div> &lt;div>bar&lt;/div>` will only return
2945                  * the first `div` element node.
2946                  *
2947                  * @returns {Node}
2948                  * Returns the first DOM `Node` extracted from the HTML fragment or
2949                  * `null` on parsing failures or if no element could be found.
2950                  */
2951                 parse: function(s) {
2952                         var elem;
2953
2954                         try {
2955                                 domParser = domParser || new DOMParser();
2956                                 elem = domParser.parseFromString(s, 'text/html').body.firstChild;
2957                         }
2958                         catch(e) {}
2959
2960                         if (!elem) {
2961                                 try {
2962                                         dummyElem = dummyElem || document.createElement('div');
2963                                         dummyElem.innerHTML = s;
2964                                         elem = dummyElem.firstChild;
2965                                 }
2966                                 catch (e) {}
2967                         }
2968
2969                         return elem || null;
2970                 },
2971
2972                 /**
2973                  * Tests whether a given `Node` matches the given query selector.
2974                  *
2975                  * This function is a convenience wrapper around the standard
2976                  * `Node.matches("selector")` function with the added benefit that
2977                  * the `node` argument may be a non-`Node` value, in which case
2978                  * this function simply returns `false`.
2979                  *
2980                  * @instance
2981                  * @memberof LuCI.dom
2982                  * @param {*} node
2983                  * The `Node` argument to test the selector against.
2984                  *
2985                  * @param {string} [selector]
2986                  * The query selector expression to test against the given node.
2987                  *
2988                  * @returns {boolean}
2989                  * Returns `true` if the given node matches the specified selector
2990                  * or `false` when the node argument is no valid DOM `Node` or the
2991                  * selector didn't match.
2992                  */
2993                 matches: function(node, selector) {
2994                         var m = this.elem(node) ? node.matches || node.msMatchesSelector : null;
2995                         return m ? m.call(node, selector) : false;
2996                 },
2997
2998                 /**
2999                  * Returns the closest parent node that matches the given query
3000                  * selector expression.
3001                  *
3002                  * This function is a convenience wrapper around the standard
3003                  * `Node.closest("selector")` function with the added benefit that
3004                  * the `node` argument may be a non-`Node` value, in which case
3005                  * this function simply returns `null`.
3006                  *
3007                  * @instance
3008                  * @memberof LuCI.dom
3009                  * @param {*} node
3010                  * The `Node` argument to find the closest parent for.
3011                  *
3012                  * @param {string} [selector]
3013                  * The query selector expression to test against each parent.
3014                  *
3015                  * @returns {Node|null}
3016                  * Returns the closest parent node matching the selector or
3017                  * `null` when the node argument is no valid DOM `Node` or the
3018                  * selector didn't match any parent.
3019                  */
3020                 parent: function(node, selector) {
3021                         if (this.elem(node) &amp;&amp; node.closest)
3022                                 return node.closest(selector);
3023
3024                         while (this.elem(node))
3025                                 if (this.matches(node, selector))
3026                                         return node;
3027                                 else
3028                                         node = node.parentNode;
3029
3030                         return null;
3031                 },
3032
3033                 /**
3034                  * Appends the given children data to the given node.
3035                  *
3036                  * @instance
3037                  * @memberof LuCI.dom
3038                  * @param {*} node
3039                  * The `Node` argument to append the children to.
3040                  *
3041                  * @param {*} [children]
3042                  * The childrens to append to the given node.
3043                  *
3044                  * When `children` is an array, then each item of the array
3045                  * will be either appended as child element or text node,
3046                  * depending on whether the item is a DOM `Node` instance or
3047                  * some other non-`null` value. Non-`Node`, non-`null` values
3048                  * will be converted to strings first before being passed as
3049                  * argument to `createTextNode()`.
3050                  *
3051                  * When `children` is a function, it will be invoked with
3052                  * the passed `node` argument as sole parameter and the `append`
3053                  * function will be invoked again, with the given `node` argument
3054                  * as first and the return value of the `children` function as
3055                  * second parameter.
3056                  *
3057                  * When `children` is is a DOM `Node` instance, it will be
3058                  * appended to the given `node`.
3059                  *
3060                  * When `children` is any other non-`null` value, it will be
3061                  * converted to a string and appened to the `innerHTML` property
3062                  * of the given `node`.
3063                  *
3064                  * @returns {Node|null}
3065                  * Returns the last children `Node` appended to the node or `null`
3066                  * if either the `node` argument was no valid DOM `node` or if the
3067                  * `children` was `null` or didn't result in further DOM nodes.
3068                  */
3069                 append: function(node, children) {
3070                         if (!this.elem(node))
3071                                 return null;
3072
3073                         if (Array.isArray(children)) {
3074                                 for (var i = 0; i &lt; children.length; i++)
3075                                         if (this.elem(children[i]))
3076                                                 node.appendChild(children[i]);
3077                                         else if (children !== null &amp;&amp; children !== undefined)
3078                                                 node.appendChild(document.createTextNode('' + children[i]));
3079
3080                                 return node.lastChild;
3081                         }
3082                         else if (typeof(children) === 'function') {
3083                                 return this.append(node, children(node));
3084                         }
3085                         else if (this.elem(children)) {
3086                                 return node.appendChild(children);
3087                         }
3088                         else if (children !== null &amp;&amp; children !== undefined) {
3089                                 node.innerHTML = '' + children;
3090                                 return node.lastChild;
3091                         }
3092
3093                         return null;
3094                 },
3095
3096                 /**
3097                  * Replaces the content of the given node with the given children.
3098                  *
3099                  * This function first removes any children of the given DOM
3100                  * `Node` and then adds the given given children following the
3101                  * rules outlined below.
3102                  *
3103                  * @instance
3104                  * @memberof LuCI.dom
3105                  * @param {*} node
3106                  * The `Node` argument to replace the children of.
3107                  *
3108                  * @param {*} [children]
3109                  * The childrens to replace into the given node.
3110                  *
3111                  * When `children` is an array, then each item of the array
3112                  * will be either appended as child element or text node,
3113                  * depending on whether the item is a DOM `Node` instance or
3114                  * some other non-`null` value. Non-`Node`, non-`null` values
3115                  * will be converted to strings first before being passed as
3116                  * argument to `createTextNode()`.
3117                  *
3118                  * When `children` is a function, it will be invoked with
3119                  * the passed `node` argument as sole parameter and the `append`
3120                  * function will be invoked again, with the given `node` argument
3121                  * as first and the return value of the `children` function as
3122                  * second parameter.
3123                  *
3124                  * When `children` is is a DOM `Node` instance, it will be
3125                  * appended to the given `node`.
3126                  *
3127                  * When `children` is any other non-`null` value, it will be
3128                  * converted to a string and appened to the `innerHTML` property
3129                  * of the given `node`.
3130                  *
3131                  * @returns {Node|null}
3132                  * Returns the last children `Node` appended to the node or `null`
3133                  * if either the `node` argument was no valid DOM `node` or if the
3134                  * `children` was `null` or didn't result in further DOM nodes.
3135                  */
3136                 content: function(node, children) {
3137                         if (!this.elem(node))
3138                                 return null;
3139
3140                         var dataNodes = node.querySelectorAll('[data-idref]');
3141
3142                         for (var i = 0; i &lt; dataNodes.length; i++)
3143                                 delete this.registry[dataNodes[i].getAttribute('data-idref')];
3144
3145                         while (node.firstChild)
3146                                 node.removeChild(node.firstChild);
3147
3148                         return this.append(node, children);
3149                 },
3150
3151                 /**
3152                  * Sets attributes or registers event listeners on element nodes.
3153                  *
3154                  * @instance
3155                  * @memberof LuCI.dom
3156                  * @param {*} node
3157                  * The `Node` argument to set the attributes or add the event
3158                  * listeners for. When the given `node` value is not a valid
3159                  * DOM `Node`, the function returns and does nothing.
3160                  *
3161                  * @param {string|Object&lt;string, *>} key
3162                  * Specifies either the attribute or event handler name to use,
3163                  * or an object containing multiple key, value pairs which are
3164                  * each added to the node as either attribute or event handler,
3165                  * depending on the respective value.
3166                  *
3167                  * @param {*} [val]
3168                  * Specifies the attribute value or event handler function to add.
3169                  * If the `key` parameter is an `Object`, this parameter will be
3170                  * ignored.
3171                  *
3172                  * When `val` is of type function, it will be registered as event
3173                  * handler on the given `node` with the `key` parameter being the
3174                  * event name.
3175                  *
3176                  * When `val` is of type object, it will be serialized as JSON and
3177                  * added as attribute to the given `node`, using the given `key`
3178                  * as attribute name.
3179                  *
3180                  * When `val` is of any other type, it will be added as attribute
3181                  * to the given `node` as-is, with the underlying `setAttribute()`
3182                  * call implicitely turning it into a string.
3183                  */
3184                 attr: function(node, key, val) {
3185                         if (!this.elem(node))
3186                                 return null;
3187
3188                         var attr = null;
3189
3190                         if (typeof(key) === 'object' &amp;&amp; key !== null)
3191                                 attr = key;
3192                         else if (typeof(key) === 'string')
3193                                 attr = {}, attr[key] = val;
3194
3195                         for (key in attr) {
3196                                 if (!attr.hasOwnProperty(key) || attr[key] == null)
3197                                         continue;
3198
3199                                 switch (typeof(attr[key])) {
3200                                 case 'function':
3201                                         node.addEventListener(key, attr[key]);
3202                                         break;
3203
3204                                 case 'object':
3205                                         node.setAttribute(key, JSON.stringify(attr[key]));
3206                                         break;
3207
3208                                 default:
3209                                         node.setAttribute(key, attr[key]);
3210                                 }
3211                         }
3212                 },
3213
3214                 /**
3215                  * Creates a new DOM `Node` from the given `html`, `attr` and
3216                  * `data` parameters.
3217                  *
3218                  * This function has multiple signatures, it can be either invoked
3219                  * in the form `create(html[, attr[, data]])` or in the form
3220                  * `create(html[, data])`. The used variant is determined from the
3221                  * type of the second argument.
3222                  *
3223                  * @instance
3224                  * @memberof LuCI.dom
3225                  * @param {*} html
3226                  * Describes the node to create.
3227                  *
3228                  * When the value of `html` is of type array, a `DocumentFragment`
3229                  * node is created and each item of the array is first converted
3230                  * to a DOM `Node` by passing it through `create()` and then added
3231                  * as child to the fragment.
3232                  *
3233                  * When the value of `html` is a DOM `Node` instance, no new
3234                  * element will be created but the node will be used as-is.
3235                  *
3236                  * When the value of `html` is a string starting with `&lt;`, it will
3237                  * be passed to `dom.parse()` and the resulting value is used.
3238                  *
3239                  * When the value of `html` is any other string, it will be passed
3240                  * to `document.createElement()` for creating a new DOM `Node` of
3241                  * the given name.
3242                  *
3243                  * @param {Object&lt;string, *>} [attr]
3244                  * Specifies an Object of key, value pairs to set as attributes
3245                  * or event handlers on the created node. Refer to
3246                  * {@link LuCI.dom#attr dom.attr()} for details.
3247                  *
3248                  * @param {*} [data]
3249                  * Specifies children to append to the newly created element.
3250                  * Refer to {@link LuCI.dom#append dom.append()} for details.
3251                  *
3252                  * @throws {InvalidCharacterError}
3253                  * Throws an `InvalidCharacterError` when the given `html`
3254                  * argument contained malformed markup (such as not escaped
3255                  * `&amp;` characters in XHTML mode) or when the given node name
3256                  * in `html` contains characters which are not legal in DOM
3257                  * element names, such as spaces.
3258                  *
3259                  * @returns {Node}
3260                  * Returns the newly created `Node`.
3261                  */
3262                 create: function() {
3263                         var html = arguments[0],
3264                             attr = arguments[1],
3265                             data = arguments[2],
3266                             elem;
3267
3268                         if (!(attr instanceof Object) || Array.isArray(attr))
3269                                 data = attr, attr = null;
3270
3271                         if (Array.isArray(html)) {
3272                                 elem = document.createDocumentFragment();
3273                                 for (var i = 0; i &lt; html.length; i++)
3274                                         elem.appendChild(this.create(html[i]));
3275                         }
3276                         else if (this.elem(html)) {
3277                                 elem = html;
3278                         }
3279                         else if (html.charCodeAt(0) === 60) {
3280                                 elem = this.parse(html);
3281                         }
3282                         else {
3283                                 elem = document.createElement(html);
3284                         }
3285
3286                         if (!elem)
3287                                 return null;
3288
3289                         this.attr(elem, attr);
3290                         this.append(elem, data);
3291
3292                         return elem;
3293                 },
3294
3295                 registry: {},
3296
3297                 /**
3298                  * Attaches or detaches arbitrary data to and from a DOM `Node`.
3299                  *
3300                  * This function is useful to attach non-string values or runtime
3301                  * data that is not serializable to DOM nodes. To decouple data
3302                  * from the DOM, values are not added directly to nodes, but
3303                  * inserted into a registry instead which is then referenced by a
3304                  * string key stored as `data-idref` attribute in the node.
3305                  *
3306                  * This function has multiple signatures and is sensitive to the
3307                  * number of arguments passed to it.
3308                  *
3309                  *  - `dom.data(node)` -
3310                  *     Fetches all data associated with the given node.
3311                  *  - `dom.data(node, key)` -
3312                  *     Fetches a specific key associated with the given node.
3313                  *  - `dom.data(node, key, val)` -
3314                  *     Sets a specific key to the given value associated with the
3315                  *     given node.
3316                  *  - `dom.data(node, null)` -
3317                  *     Clears any data associated with the node.
3318                  *  - `dom.data(node, key, null)` -
3319                  *     Clears the given key associated with the node.
3320                  *
3321                  * @instance
3322                  * @memberof LuCI.dom
3323                  * @param {Node} node
3324                  * The DOM `Node` instance to set or retrieve the data for.
3325                  *
3326                  * @param {string|null} [key]
3327                  * This is either a string specifying the key to retrieve, or
3328                  * `null` to unset the entire node data.
3329                  *
3330                  * @param {*|null} [val]
3331                  * This is either a non-`null` value to set for a given key or
3332                  * `null` to remove the given `key` from the specified node.
3333                  *
3334                  * @returns {*}
3335                  * Returns the get or set value, or `null` when no value could
3336                  * be found.
3337                  */
3338                 data: function(node, key, val) {
3339                         if (!node || !node.getAttribute)
3340                                 return null;
3341
3342                         var id = node.getAttribute('data-idref');
3343
3344                         /* clear all data */
3345                         if (arguments.length > 1 &amp;&amp; key == null) {
3346                                 if (id != null) {
3347                                         node.removeAttribute('data-idref');
3348                                         val = this.registry[id]
3349                                         delete this.registry[id];
3350                                         return val;
3351                                 }
3352
3353                                 return null;
3354                         }
3355
3356                         /* clear a key */
3357                         else if (arguments.length > 2 &amp;&amp; key != null &amp;&amp; val == null) {
3358                                 if (id != null) {
3359                                         val = this.registry[id][key];
3360                                         delete this.registry[id][key];
3361                                         return val;
3362                                 }
3363
3364                                 return null;
3365                         }
3366
3367                         /* set a key */
3368                         else if (arguments.length > 2 &amp;&amp; key != null &amp;&amp; val != null) {
3369                                 if (id == null) {
3370                                         do { id = Math.floor(Math.random() * 0xffffffff).toString(16) }
3371                                         while (this.registry.hasOwnProperty(id));
3372
3373                                         node.setAttribute('data-idref', id);
3374                                         this.registry[id] = {};
3375                                 }
3376
3377                                 return (this.registry[id][key] = val);
3378                         }
3379
3380                         /* get all data */
3381                         else if (arguments.length == 1) {
3382                                 if (id != null)
3383                                         return this.registry[id];
3384
3385                                 return null;
3386                         }
3387
3388                         /* get a key */
3389                         else if (arguments.length == 2) {
3390                                 if (id != null)
3391                                         return this.registry[id][key];
3392                         }
3393
3394                         return null;
3395                 },
3396
3397                 /**
3398                  * Binds the given class instance ot the specified DOM `Node`.
3399                  *
3400                  * This function uses the `dom.data()` facility to attach the
3401                  * passed instance of a Class to a node. This is needed for
3402                  * complex widget elements or similar where the corresponding
3403                  * class instance responsible for the element must be retrieved
3404                  * from DOM nodes obtained by `querySelector()` or similar means.
3405                  *
3406                  * @instance
3407                  * @memberof LuCI.dom
3408                  * @param {Node} node
3409                  * The DOM `Node` instance to bind the class to.
3410                  *
3411                  * @param {Class} inst
3412                  * The Class instance to bind to the node.
3413                  *
3414                  * @throws {TypeError}
3415                  * Throws a `TypeError` when the given instance argument isn't
3416                  * a valid Class instance.
3417                  *
3418                  * @returns {Class}
3419                  * Returns the bound class instance.
3420                  */
3421                 bindClassInstance: function(node, inst) {
3422                         if (!(inst instanceof Class))
3423                                 L.error('TypeError', 'Argument must be a class instance');
3424
3425                         return this.data(node, '_class', inst);
3426                 },
3427
3428                 /**
3429                  * Finds a bound class instance on the given node itself or the
3430                  * first bound instance on its closest parent node.
3431                  *
3432                  * @instance
3433                  * @memberof LuCI.dom
3434                  * @param {Node} node
3435                  * The DOM `Node` instance to start from.
3436                  *
3437                  * @returns {Class|null}
3438                  * Returns the founds class instance if any or `null` if no bound
3439                  * class could be found on the node itself or any of its parents.
3440                  */
3441                 findClassInstance: function(node) {
3442                         var inst = null;
3443
3444                         do {
3445                                 inst = this.data(node, '_class');
3446                                 node = node.parentNode;
3447                         }
3448                         while (!(inst instanceof Class) &amp;&amp; node != null);
3449
3450                         return inst;
3451                 },
3452
3453                 /**
3454                  * Finds a bound class instance on the given node itself or the
3455                  * first bound instance on its closest parent node and invokes
3456                  * the specified method name on the found class instance.
3457                  *
3458                  * @instance
3459                  * @memberof LuCI.dom
3460                  * @param {Node} node
3461                  * The DOM `Node` instance to start from.
3462                  *
3463                  * @param {string} method
3464                  * The name of the method to invoke on the found class instance.
3465                  *
3466                  * @param {...*} params
3467                  * Additional arguments to pass to the invoked method as-is.
3468                  *
3469                  * @returns {*|null}
3470                  * Returns the return value of the invoked method if a class
3471                  * instance and method has been found. Returns `null` if either
3472                  * no bound class instance could be found, or if the found
3473                  * instance didn't have the requested `method`.
3474                  */
3475                 callClassMethod: function(node, method /*, ... */) {
3476                         var inst = this.findClassInstance(node);
3477
3478                         if (inst == null || typeof(inst[method]) != 'function')
3479                                 return null;
3480
3481                         return inst[method].apply(inst, inst.varargs(arguments, 2));
3482                 },
3483
3484                 /**
3485                  * The ignore callback function is invoked by `isEmpty()` for each
3486                  * child node to decide whether to ignore a child node or not.
3487                  *
3488                  * When this function returns `false`, the node passed to it is
3489                  * ignored, else not.
3490                  *
3491                  * @callback LuCI.dom~ignoreCallbackFn
3492                  * @param {Node} node
3493                  * The child node to test.
3494                  *
3495                  * @returns {boolean}
3496                  * Boolean indicating whether to ignore the node or not.
3497                  */
3498
3499                 /**
3500                  * Tests whether a given DOM `Node` instance is empty or appears
3501                  * empty.
3502                  *
3503                  * Any element child nodes which have the CSS class `hidden` set
3504                  * or for which the optionally passed `ignoreFn` callback function
3505                  * returns `false` are ignored.
3506                  *
3507                  * @instance
3508                  * @memberof LuCI.dom
3509                  * @param {Node} node
3510                  * The DOM `Node` instance to test.
3511                  *
3512                  * @param {LuCI.dom~ignoreCallbackFn} [ignoreFn]
3513                  * Specifies an optional function which is invoked for each child
3514                  * node to decide whether the child node should be ignored or not.
3515                  *
3516                  * @returns {boolean}
3517                  * Returns `true` if the node does not have any children or if
3518                  * any children node either has a `hidden` CSS class or a `false`
3519                  * result when testing it using the given `ignoreFn`.
3520                  */
3521                 isEmpty: function(node, ignoreFn) {
3522                         for (var child = node.firstElementChild; child != null; child = child.nextElementSibling)
3523                                 if (!child.classList.contains('hidden') &amp;&amp; (!ignoreFn || !ignoreFn(child)))
3524                                         return false;
3525
3526                         return true;
3527                 }
3528         });
3529
3530         /**
3531          * @class view
3532          * @memberof LuCI
3533          * @hideconstructor
3534          * @classdesc
3535          *
3536          * The `view` class forms the basis of views and provides a standard
3537          * set of methods to inherit from.
3538          */
3539         var View = Class.extend(/* @lends LuCI.view.prototype */ {
3540                 __name__: 'LuCI.view',
3541
3542                 __init__: function() {
3543                         var vp = document.getElementById('view');
3544
3545                         DOM.content(vp, E('div', { 'class': 'spinning' }, _('Loading view…')));
3546
3547                         return Promise.resolve(this.load())
3548                                 .then(L.bind(this.render, this))
3549                                 .then(L.bind(function(nodes) {
3550                                         var vp = document.getElementById('view');
3551
3552                                         DOM.content(vp, nodes);
3553                                         DOM.append(vp, this.addFooter());
3554                                 }, this)).catch(L.error);
3555                 },
3556
3557                 /**
3558                  * The load function is invoked before the view is rendered.
3559                  *
3560                  * The invocation of this function is wrapped by
3561                  * `Promise.resolve()` so it may return Promises if needed.
3562                  *
3563                  * The return value of the function (or the resolved values
3564                  * of the promise returned by it) will be passed as first
3565                  * argument to `render()`.
3566                  *
3567                  * This function is supposed to be overwritten by subclasses,
3568                  * the default implementation does nothing.
3569                  *
3570                  * @instance
3571                  * @abstract
3572                  * @memberof LuCI.view
3573                  *
3574                  * @returns {*|Promise&lt;*>}
3575                  * May return any value or a Promise resolving to any value.
3576                  */
3577                 load: function() {},
3578
3579                 /**
3580                  * The render function is invoked after the
3581                  * {@link LuCI.view#load load()} function and responsible
3582                  * for setting up the view contents. It must return a DOM
3583                  * `Node` or `DocumentFragment` holding the contents to
3584                  * insert into the view area.
3585                  *
3586                  * The invocation of this function is wrapped by
3587                  * `Promise.resolve()` so it may return Promises if needed.
3588                  *
3589                  * The return value of the function (or the resolved values
3590                  * of the promise returned by it) will be inserted into the
3591                  * main content area using
3592                  * {@link LuCI.dom#append dom.append()}.
3593                  *
3594                  * This function is supposed to be overwritten by subclasses,
3595                  * the default implementation does nothing.
3596                  *
3597                  * @instance
3598                  * @abstract
3599                  * @memberof LuCI.view
3600                  * @param {*|null} load_results
3601                  * This function will receive the return value of the
3602                  * {@link LuCI.view#load view.load()} function as first
3603                  * argument.
3604                  *
3605                  * @returns {Node|Promise&lt;Node>}
3606                  * Should return a DOM `Node` value or a `Promise` resolving
3607                  * to a `Node` value.
3608                  */
3609                 render: function() {},
3610
3611                 /**
3612                  * The handleSave function is invoked when the user clicks
3613                  * the `Save` button in the page action footer.
3614                  *
3615                  * The default implementation should be sufficient for most
3616                  * views using {@link form#Map form.Map()} based forms - it
3617                  * will iterate all forms present in the view and invoke
3618                  * the {@link form#Map#save Map.save()} method on each form.
3619                  *
3620                  * Views not using `Map` instances or requiring other special
3621                  * logic should overwrite `handleSave()` with a custom
3622                  * implementation.
3623                  *
3624                  * To disable the `Save` page footer button, views extending
3625                  * this base class should overwrite the `handleSave` function
3626                  * with `null`.
3627                  *
3628                  * The invocation of this function is wrapped by
3629                  * `Promise.resolve()` so it may return Promises if needed.
3630                  *
3631                  * @instance
3632                  * @memberof LuCI.view
3633                  * @param {Event} ev
3634                  * The DOM event that triggered the function.
3635                  *
3636                  * @returns {*|Promise&lt;*>}
3637                  * Any return values of this function are discarded, but
3638                  * passed through `Promise.resolve()` to ensure that any
3639                  * returned promise runs to completion before the button
3640                  * is reenabled.
3641                  */
3642                 handleSave: function(ev) {
3643                         var tasks = [];
3644
3645                         document.getElementById('maincontent')
3646                                 .querySelectorAll('.cbi-map').forEach(function(map) {
3647                                         tasks.push(DOM.callClassMethod(map, 'save'));
3648                                 });
3649
3650                         return Promise.all(tasks);
3651                 },
3652
3653                 /**
3654                  * The handleSaveApply function is invoked when the user clicks
3655                  * the `Save &amp; Apply` button in the page action footer.
3656                  *
3657                  * The default implementation should be sufficient for most
3658                  * views using {@link form#Map form.Map()} based forms - it
3659                  * will first invoke
3660                  * {@link LuCI.view.handleSave view.handleSave()} and then
3661                  * call {@link ui#changes#apply ui.changes.apply()} to start the
3662                  * modal config apply and page reload flow.
3663                  *
3664                  * Views not using `Map` instances or requiring other special
3665                  * logic should overwrite `handleSaveApply()` with a custom
3666                  * implementation.
3667                  *
3668                  * To disable the `Save &amp; Apply` page footer button, views
3669                  * extending this base class should overwrite the
3670                  * `handleSaveApply` function with `null`.
3671                  *
3672                  * The invocation of this function is wrapped by
3673                  * `Promise.resolve()` so it may return Promises if needed.
3674                  *
3675                  * @instance
3676                  * @memberof LuCI.view
3677                  * @param {Event} ev
3678                  * The DOM event that triggered the function.
3679                  *
3680                  * @returns {*|Promise&lt;*>}
3681                  * Any return values of this function are discarded, but
3682                  * passed through `Promise.resolve()` to ensure that any
3683                  * returned promise runs to completion before the button
3684                  * is reenabled.
3685                  */
3686                 handleSaveApply: function(ev, mode) {
3687                         return this.handleSave(ev).then(function() {
3688                                 L.ui.changes.apply(mode == '0');
3689                         });
3690                 },
3691
3692                 /**
3693                  * The handleReset function is invoked when the user clicks
3694                  * the `Reset` button in the page action footer.
3695                  *
3696                  * The default implementation should be sufficient for most
3697                  * views using {@link form#Map form.Map()} based forms - it
3698                  * will iterate all forms present in the view and invoke
3699                  * the {@link form#Map#save Map.reset()} method on each form.
3700                  *
3701                  * Views not using `Map` instances or requiring other special
3702                  * logic should overwrite `handleReset()` with a custom
3703                  * implementation.
3704                  *
3705                  * To disable the `Reset` page footer button, views extending
3706                  * this base class should overwrite the `handleReset` function
3707                  * with `null`.
3708                  *
3709                  * The invocation of this function is wrapped by
3710                  * `Promise.resolve()` so it may return Promises if needed.
3711                  *
3712                  * @instance
3713                  * @memberof LuCI.view
3714                  * @param {Event} ev
3715                  * The DOM event that triggered the function.
3716                  *
3717                  * @returns {*|Promise&lt;*>}
3718                  * Any return values of this function are discarded, but
3719                  * passed through `Promise.resolve()` to ensure that any
3720                  * returned promise runs to completion before the button
3721                  * is reenabled.
3722                  */
3723                 handleReset: function(ev) {
3724                         var tasks = [];
3725
3726                         document.getElementById('maincontent')
3727                                 .querySelectorAll('.cbi-map').forEach(function(map) {
3728                                         tasks.push(DOM.callClassMethod(map, 'reset'));
3729                                 });
3730
3731                         return Promise.all(tasks);
3732                 },
3733
3734                 /**
3735                  * Renders a standard page action footer if any of the
3736                  * `handleSave()`, `handleSaveApply()` or `handleReset()`
3737                  * functions are defined.
3738                  *
3739                  * The default implementation should be sufficient for most
3740                  * views - it will render a standard page footer with action
3741                  * buttons labeled `Save`, `Save &amp; Apply` and `Reset`
3742                  * triggering the `handleSave()`, `handleSaveApply()` and
3743                  * `handleReset()` functions respectively.
3744                  *
3745                  * When any of these `handle*()` functions is overwritten
3746                  * with `null` by a view extending this class, the
3747                  * corresponding button will not be rendered.
3748                  *
3749                  * @instance
3750                  * @memberof LuCI.view
3751                  * @returns {DocumentFragment}
3752                  * Returns a `DocumentFragment` containing the footer bar
3753                  * with buttons for each corresponding `handle*()` action
3754                  * or an empty `DocumentFragment` if all three `handle*()`
3755                  * methods are overwritten with `null`.
3756                  */
3757                 addFooter: function() {
3758                         var footer = E([]);
3759
3760                         var saveApplyBtn = this.handleSaveApply ? new L.ui.ComboButton('0', {
3761                                 0: [ _('Save &amp; Apply') ],
3762                                 1: [ _('Apply unchecked') ]
3763                         }, {
3764                                 classes: {
3765                                         0: 'btn cbi-button cbi-button-apply important',
3766                                         1: 'btn cbi-button cbi-button-negative important'
3767                                 },
3768                                 click: L.ui.createHandlerFn(this, 'handleSaveApply')
3769                         }).render() : E([]);
3770
3771                         if (this.handleSaveApply || this.handleSave || this.handleReset) {
3772                                 footer.appendChild(E('div', { 'class': 'cbi-page-actions control-group' }, [
3773                                         saveApplyBtn, ' ',
3774                                         this.handleSave ? E('button', {
3775                                                 'class': 'cbi-button cbi-button-save',
3776                                                 'click': L.ui.createHandlerFn(this, 'handleSave')
3777                                         }, [ _('Save') ]) : '', ' ',
3778                                         this.handleReset ? E('button', {
3779                                                 'class': 'cbi-button cbi-button-reset',
3780                                                 'click': L.ui.createHandlerFn(this, 'handleReset')
3781                                         }, [ _('Reset') ]) : ''
3782                                 ]));
3783                         }
3784
3785                         return footer;
3786                 }
3787         });
3788
3789
3790         var dummyElem = null,
3791             domParser = null,
3792             originalCBIInit = null,
3793             rpcBaseURL = null,
3794             sysFeatures = null;
3795
3796         /* "preload" builtin classes to make the available via require */
3797         var classes = {
3798                 baseclass: Class,
3799                 dom: DOM,
3800                 poll: Poll,
3801                 request: Request,
3802                 view: View
3803         };
3804
3805         var LuCI = Class.extend(/** @lends LuCI.prototype */ {
3806                 __name__: 'LuCI',
3807                 __init__: function(env) {
3808
3809                         document.querySelectorAll('script[src*="/luci.js"]').forEach(function(s) {
3810                                 if (env.base_url == null || env.base_url == '') {
3811                                         var m = (s.getAttribute('src') || '').match(/^(.*)\/luci\.js(?:\?v=([^?]+))?$/);
3812                                         if (m) {
3813                                                 env.base_url = m[1];
3814                                                 env.resource_version = m[2];
3815                                         }
3816                                 }
3817                         });
3818
3819                         if (env.base_url == null)
3820                                 this.error('InternalError', 'Cannot find url of luci.js');
3821
3822                         env.cgi_base = env.scriptname.replace(/\/[^\/]+$/, '');
3823
3824                         Object.assign(this.env, env);
3825
3826                         document.addEventListener('poll-start', function(ev) {
3827                                 document.querySelectorAll('[id^="xhr_poll_status"]').forEach(function(e) {
3828                                         e.style.display = (e.id == 'xhr_poll_status_off') ? 'none' : '';
3829                                 });
3830                         });
3831
3832                         document.addEventListener('poll-stop', function(ev) {
3833                                 document.querySelectorAll('[id^="xhr_poll_status"]').forEach(function(e) {
3834                                         e.style.display = (e.id == 'xhr_poll_status_on') ? 'none' : '';
3835                                 });
3836                         });
3837
3838                         var domReady = new Promise(function(resolveFn, rejectFn) {
3839                                 document.addEventListener('DOMContentLoaded', resolveFn);
3840                         });
3841
3842                         Promise.all([
3843                                 domReady,
3844                                 this.require('ui'),
3845                                 this.require('rpc'),
3846                                 this.require('form'),
3847                                 this.probeRPCBaseURL()
3848                         ]).then(this.setupDOM.bind(this)).catch(this.error);
3849
3850                         originalCBIInit = window.cbi_init;
3851                         window.cbi_init = function() {};
3852                 },
3853
3854                 /**
3855                  * Captures the current stack trace and throws an error of the
3856                  * specified type as a new exception. Also logs the exception as
3857                  * error to the debug console if it is available.
3858                  *
3859                  * @instance
3860                  * @memberof LuCI
3861                  *
3862                  * @param {Error|string} [type=Error]
3863                  * Either a string specifying the type of the error to throw or an
3864                  * existing `Error` instance to copy.
3865                  *
3866                  * @param {string} [fmt=Unspecified error]
3867                  * A format string which is used to form the error message, together
3868                  * with all subsequent optional arguments.
3869                  *
3870                  * @param {...*} [args]
3871                  * Zero or more variable arguments to the supplied format string.
3872                  *
3873                  * @throws {Error}
3874                  * Throws the created error object with the captured stack trace
3875                  * appended to the message and the type set to the given type
3876                  * argument or copied from the given error instance.
3877                  */
3878                 raise: function(type, fmt /*, ...*/) {
3879                         var e = null,
3880                             msg = fmt ? String.prototype.format.apply(fmt, this.varargs(arguments, 2)) : null,
3881                             stack = null;
3882
3883                         if (type instanceof Error) {
3884                                 e = type;
3885
3886                                 if (msg)
3887                                         e.message = msg + ': ' + e.message;
3888                         }
3889                         else {
3890                                 try { throw new Error('stacktrace') }
3891                                 catch (e2) { stack = (e2.stack || '').split(/\n/) }
3892
3893                                 e = new (window[type || 'Error'] || Error)(msg || 'Unspecified error');
3894                                 e.name = type || 'Error';
3895                         }
3896
3897                         stack = (stack || []).map(function(frame) {
3898                                 frame = frame.replace(/(.*?)@(.+):(\d+):(\d+)/g, 'at $1 ($2:$3:$4)').trim();
3899                                 return frame ? '  ' + frame : '';
3900                         });
3901
3902                         if (!/^  at /.test(stack[0]))
3903                                 stack.shift();
3904
3905                         if (/\braise /.test(stack[0]))
3906                                 stack.shift();
3907
3908                         if (/\berror /.test(stack[0]))
3909                                 stack.shift();
3910
3911                         if (stack.length)
3912                                 e.message += '\n' + stack.join('\n');
3913
3914                         if (window.console &amp;&amp; console.debug)
3915                                 console.debug(e);
3916
3917                         throw e;
3918                 },
3919
3920                 /**
3921                  * A wrapper around {@link LuCI#raise raise()} which also renders
3922                  * the error either as modal overlay when `ui.js` is already loaed
3923                  * or directly into the view body.
3924                  *
3925                  * @instance
3926                  * @memberof LuCI
3927                  *
3928                  * @param {Error|string} [type=Error]
3929                  * Either a string specifying the type of the error to throw or an
3930                  * existing `Error` instance to copy.
3931                  *
3932                  * @param {string} [fmt=Unspecified error]
3933                  * A format string which is used to form the error message, together
3934                  * with all subsequent optional arguments.
3935                  *
3936                  * @param {...*} [args]
3937                  * Zero or more variable arguments to the supplied format string.
3938                  *
3939                  * @throws {Error}
3940                  * Throws the created error object with the captured stack trace
3941                  * appended to the message and the type set to the given type
3942                  * argument or copied from the given error instance.
3943                  */
3944                 error: function(type, fmt /*, ...*/) {
3945                         try {
3946                                 L.raise.apply(L, Array.prototype.slice.call(arguments));
3947                         }
3948                         catch (e) {
3949                                 if (!e.reported) {
3950                                         if (L.ui)
3951                                                 L.ui.addNotification(e.name || _('Runtime error'),
3952                                                         E('pre', {}, e.message), 'danger');
3953                                         else
3954                                                 DOM.content(document.querySelector('#maincontent'),
3955                                                         E('pre', { 'class': 'alert-message error' }, e.message));
3956
3957                                         e.reported = true;
3958                                 }
3959
3960                                 throw e;
3961                         }
3962                 },
3963
3964                 /**
3965                  * Return a bound function using the given `self` as `this` context
3966                  * and any further arguments as parameters to the bound function.
3967                  *
3968                  * @instance
3969                  * @memberof LuCI
3970                  *
3971                  * @param {function} fn
3972                  * The function to bind.
3973                  *
3974                  * @param {*} self
3975                  * The value to bind as `this` context to the specified function.
3976                  *
3977                  * @param {...*} [args]
3978                  * Zero or more variable arguments which are bound to the function
3979                  * as parameters.
3980                  *
3981                  * @returns {function}
3982                  * Returns the bound function.
3983                  */
3984                 bind: function(fn, self /*, ... */) {
3985                         return Function.prototype.bind.apply(fn, this.varargs(arguments, 2, self));
3986                 },
3987
3988                 /**
3989                  * Load an additional LuCI JavaScript class and its dependencies,
3990                  * instantiate it and return the resulting class instance. Each
3991                  * class is only loaded once. Subsequent attempts to load the same
3992                  * class will return the already instantiated class.
3993                  *
3994                  * @instance
3995                  * @memberof LuCI
3996                  *
3997                  * @param {string} name
3998                  * The name of the class to load in dotted notation. Dots will
3999                  * be replaced by spaces and joined with the runtime-determined
4000                  * base URL of LuCI.js to form an absolute URL to load the class
4001                  * file from.
4002                  *
4003                  * @throws {DependencyError}
4004                  * Throws a `DependencyError` when the class to load includes
4005                  * circular dependencies.
4006                  *
4007                  * @throws {NetworkError}
4008                  * Throws `NetworkError` when the underlying {@link LuCI.request}
4009                  * call failed.
4010                  *
4011                  * @throws {SyntaxError}
4012                  * Throws `SyntaxError` when the loaded class file code cannot
4013                  * be interpreted by `eval`.
4014                  *
4015                  * @throws {TypeError}
4016                  * Throws `TypeError` when the class file could be loaded and
4017                  * interpreted, but when invoking its code did not yield a valid
4018                  * class instance.
4019                  *
4020                  * @returns {Promise&lt;LuCI.baseclass>}
4021                  * Returns the instantiated class.
4022                  */
4023                 require: function(name, from) {
4024                         var L = this, url = null, from = from || [];
4025
4026                         /* Class already loaded */
4027                         if (classes[name] != null) {
4028                                 /* Circular dependency */
4029                                 if (from.indexOf(name) != -1)
4030                                         L.raise('DependencyError',
4031                                                 'Circular dependency: class "%s" depends on "%s"',
4032                                                 name, from.join('" which depends on "'));
4033
4034                                 return Promise.resolve(classes[name]);
4035                         }
4036
4037                         url = '%s/%s.js%s'.format(L.env.base_url, name.replace(/\./g, '/'), (L.env.resource_version ? '?v=' + L.env.resource_version : ''));
4038                         from = [ name ].concat(from);
4039
4040                         var compileClass = function(res) {
4041                                 if (!res.ok)
4042                                         L.raise('NetworkError',
4043                                                 'HTTP error %d while loading class file "%s"', res.status, url);
4044
4045                                 var source = res.text(),
4046                                     requirematch = /^require[ \t]+(\S+)(?:[ \t]+as[ \t]+([a-zA-Z_]\S*))?$/,
4047                                     strictmatch = /^use[ \t]+strict$/,
4048                                     depends = [],
4049                                     args = '';
4050
4051                                 /* find require statements in source */
4052                                 for (var i = 0, off = -1, quote = -1, esc = false; i &lt; source.length; i++) {
4053                                         var chr = source.charCodeAt(i);
4054
4055                                         if (esc) {
4056                                                 esc = false;
4057                                         }
4058                                         else if (chr == 92) {
4059                                                 esc = true;
4060                                         }
4061                                         else if (chr == quote) {
4062                                                 var s = source.substring(off, i),
4063                                                     m = requirematch.exec(s);
4064
4065                                                 if (m) {
4066                                                         var dep = m[1], as = m[2] || dep.replace(/[^a-zA-Z0-9_]/g, '_');
4067                                                         depends.push(L.require(dep, from));
4068                                                         args += ', ' + as;
4069                                                 }
4070                                                 else if (!strictmatch.exec(s)) {
4071                                                         break;
4072                                                 }
4073
4074                                                 off = -1;
4075                                                 quote = -1;
4076                                         }
4077                                         else if (quote == -1 &amp;&amp; (chr == 34 || chr == 39)) {
4078                                                 off = i + 1;
4079                                                 quote = chr;
4080                                         }
4081                                 }
4082
4083                                 /* load dependencies and instantiate class */
4084                                 return Promise.all(depends).then(function(instances) {
4085                                         var _factory, _class;
4086
4087                                         try {
4088                                                 _factory = eval(
4089                                                         '(function(window, document, L%s) { %s })\n\n//# sourceURL=%s\n'
4090                                                                 .format(args, source, res.url));
4091                                         }
4092                                         catch (error) {
4093                                                 L.raise('SyntaxError', '%s\n  in %s:%s',
4094                                                         error.message, res.url, error.lineNumber || '?');
4095                                         }
4096
4097                                         _factory.displayName = toCamelCase(name + 'ClassFactory');
4098                                         _class = _factory.apply(_factory, [window, document, L].concat(instances));
4099
4100                                         if (!Class.isSubclass(_class))
4101                                             L.error('TypeError', '"%s" factory yields invalid constructor', name);
4102
4103                                         if (_class.displayName == 'AnonymousClass')
4104                                                 _class.displayName = toCamelCase(name + 'Class');
4105
4106                                         var ptr = Object.getPrototypeOf(L),
4107                                             parts = name.split(/\./),
4108                                             instance = new _class();
4109
4110                                         for (var i = 0; ptr &amp;&amp; i &lt; parts.length - 1; i++)
4111                                                 ptr = ptr[parts[i]];
4112
4113                                         if (ptr)
4114                                                 ptr[parts[i]] = instance;
4115
4116                                         classes[name] = instance;
4117
4118                                         return instance;
4119                                 });
4120                         };
4121
4122                         /* Request class file */
4123                         classes[name] = Request.get(url, { cache: true }).then(compileClass);
4124
4125                         return classes[name];
4126                 },
4127
4128                 /* DOM setup */
4129                 probeRPCBaseURL: function() {
4130                         if (rpcBaseURL == null) {
4131                                 try {
4132                                         rpcBaseURL = window.sessionStorage.getItem('rpcBaseURL');
4133                                 }
4134                                 catch (e) { }
4135                         }
4136
4137                         if (rpcBaseURL == null) {
4138                                 var rpcFallbackURL = this.url('admin/ubus');
4139
4140                                 rpcBaseURL = Request.get(this.env.ubuspath).then(function(res) {
4141                                         return (rpcBaseURL = (res.status == 400) ? L.env.ubuspath : rpcFallbackURL);
4142                                 }, function() {
4143                                         return (rpcBaseURL = rpcFallbackURL);
4144                                 }).then(function(url) {
4145                                         try {
4146                                                 window.sessionStorage.setItem('rpcBaseURL', url);
4147                                         }
4148                                         catch (e) { }
4149
4150                                         return url;
4151                                 });
4152                         }
4153
4154                         return Promise.resolve(rpcBaseURL);
4155                 },
4156
4157                 probeSystemFeatures: function() {
4158                         var sessionid = classes.rpc.getSessionID();
4159
4160                         if (sysFeatures == null) {
4161                                 try {
4162                                         var data = JSON.parse(window.sessionStorage.getItem('sysFeatures'));
4163
4164                                         if (this.isObject(data) &amp;&amp; this.isObject(data[sessionid]))
4165                                                 sysFeatures = data[sessionid];
4166                                 }
4167                                 catch (e) {}
4168                         }
4169
4170                         if (!this.isObject(sysFeatures)) {
4171                                 sysFeatures = classes.rpc.declare({
4172                                         object: 'luci',
4173                                         method: 'getFeatures',
4174                                         expect: { '': {} }
4175                                 })().then(function(features) {
4176                                         try {
4177                                                 var data = {};
4178                                                     data[sessionid] = features;
4179
4180                                                 window.sessionStorage.setItem('sysFeatures', JSON.stringify(data));
4181                                         }
4182                                         catch (e) {}
4183
4184                                         sysFeatures = features;
4185
4186                                         return features;
4187                                 });
4188                         }
4189
4190                         return Promise.resolve(sysFeatures);
4191                 },
4192
4193                 /**
4194                  * Test whether a particular system feature is available, such as
4195                  * hostapd SAE support or an installed firewall. The features are
4196                  * queried once at the beginning of the LuCI session and cached in
4197                  * `SessionStorage` throughout the lifetime of the associated tab or
4198                  * browser window.
4199                  *
4200                  * @instance
4201                  * @memberof LuCI
4202                  *
4203                  * @param {string} feature
4204                  * The feature to test. For detailed list of known feature flags,
4205                  * see `/modules/luci-base/root/usr/libexec/rpcd/luci`.
4206                  *
4207                  * @param {string} [subfeature]
4208                  * Some feature classes like `hostapd` provide sub-feature flags,
4209                  * such as `sae` or `11w` support. The `subfeature` argument can
4210                  * be used to query these.
4211                  *
4212                  * @return {boolean|null}
4213                  * Return `true` if the queried feature (and sub-feature) is available
4214                  * or `false` if the requested feature isn't present or known.
4215                  * Return `null` when a sub-feature was queried for a feature which
4216                  * has no sub-features.
4217                  */
4218                 hasSystemFeature: function() {
4219                         var ft = sysFeatures[arguments[0]];
4220
4221                         if (arguments.length == 2)
4222                                 return this.isObject(ft) ? ft[arguments[1]] : null;
4223
4224                         return (ft != null &amp;&amp; ft != false);
4225                 },
4226
4227                 /* private */
4228                 notifySessionExpiry: function() {
4229                         Poll.stop();
4230
4231                         L.ui.showModal(_('Session expired'), [
4232                                 E('div', { class: 'alert-message warning' },
4233                                         _('A new login is required since the authentication session expired.')),
4234                                 E('div', { class: 'right' },
4235                                         E('div', {
4236                                                 class: 'btn primary',
4237                                                 click: function() {
4238                                                         var loc = window.location;
4239                                                         window.location = loc.protocol + '//' + loc.host + loc.pathname + loc.search;
4240                                                 }
4241                                         }, _('To login…')))
4242                         ]);
4243
4244                         L.raise('SessionError', 'Login session is expired');
4245                 },
4246
4247                 /* private */
4248                 setupDOM: function(res) {
4249                         var domEv = res[0],
4250                             uiClass = res[1],
4251                             rpcClass = res[2],
4252                             formClass = res[3],
4253                             rpcBaseURL = res[4];
4254
4255                         rpcClass.setBaseURL(rpcBaseURL);
4256
4257                         rpcClass.addInterceptor(function(msg, req) {
4258                                 if (!L.isObject(msg) || !L.isObject(msg.error) || msg.error.code != -32002)
4259                                         return;
4260
4261                                 if (!L.isObject(req) || (req.object == 'session' &amp;&amp; req.method == 'access'))
4262                                         return;
4263
4264                                 return rpcClass.declare({
4265                                         'object': 'session',
4266                                         'method': 'access',
4267                                         'params': [ 'scope', 'object', 'function' ],
4268                                         'expect': { access: true }
4269                                 })('uci', 'luci', 'read').catch(L.notifySessionExpiry);
4270                         });
4271
4272                         Request.addInterceptor(function(res) {
4273                                 var isDenied = false;
4274
4275                                 if (res.status == 403 &amp;&amp; res.headers.get('X-LuCI-Login-Required') == 'yes')
4276                                         isDenied = true;
4277
4278                                 if (!isDenied)
4279                                         return;
4280
4281                                 L.notifySessionExpiry();
4282                         });
4283
4284                         return this.probeSystemFeatures().finally(this.initDOM);
4285                 },
4286
4287                 /* private */
4288                 initDOM: function() {
4289                         originalCBIInit();
4290                         Poll.start();
4291                         document.dispatchEvent(new CustomEvent('luci-loaded'));
4292                 },
4293
4294                 /**
4295                  * The `env` object holds environment settings used by LuCI, such
4296                  * as request timeouts, base URLs etc.
4297                  *
4298                  * @instance
4299                  * @memberof LuCI
4300                  */
4301                 env: {},
4302
4303                 /**
4304                  * Construct a relative URL path from the given prefix and parts.
4305                  * The resulting URL is guaranteed to only contain the characters
4306                  * `a-z`, `A-Z`, `0-9`, `_`, `.`, `%`, `,`, `;`, and `-` as well
4307                  * as `/` for the path separator.
4308                  *
4309                  * @instance
4310                  * @memberof LuCI
4311                  *
4312                  * @param {string} [prefix]
4313                  * The prefix to join the given parts with. If the `prefix` is
4314                  * omitted, it defaults to an empty string.
4315                  *
4316                  * @param {string[]} [parts]
4317                  * An array of parts to join into an URL path. Parts may contain
4318                  * slashes and any of the other characters mentioned above.
4319                  *
4320                  * @return {string}
4321                  * Return the joined URL path.
4322                  */
4323                 path: function(prefix, parts) {
4324                         var url = [ prefix || '' ];
4325
4326                         for (var i = 0; i &lt; parts.length; i++)
4327                                 if (/^(?:[a-zA-Z0-9_.%,;-]+\/)*[a-zA-Z0-9_.%,;-]+$/.test(parts[i]))
4328                                         url.push('/', parts[i]);
4329
4330                         if (url.length === 1)
4331                                 url.push('/');
4332
4333                         return url.join('');
4334                 },
4335
4336                 /**
4337                  * Construct an URL  pathrelative to the script path of the server
4338                  * side LuCI application (usually `/cgi-bin/luci`).
4339                  *
4340                  * The resulting URL is guaranteed to only contain the characters
4341                  * `a-z`, `A-Z`, `0-9`, `_`, `.`, `%`, `,`, `;`, and `-` as well
4342                  * as `/` for the path separator.
4343                  *
4344                  * @instance
4345                  * @memberof LuCI
4346                  *
4347                  * @param {string[]} [parts]
4348                  * An array of parts to join into an URL path. Parts may contain
4349                  * slashes and any of the other characters mentioned above.
4350                  *
4351                  * @return {string}
4352                  * Returns the resulting URL path.
4353                  */
4354                 url: function() {
4355                         return this.path(this.env.scriptname, arguments);
4356                 },
4357
4358                 /**
4359                  * Construct an URL path relative to the global static resource path
4360                  * of the LuCI ui (usually `/luci-static/resources`).
4361                  *
4362                  * The resulting URL is guaranteed to only contain the characters
4363                  * `a-z`, `A-Z`, `0-9`, `_`, `.`, `%`, `,`, `;`, and `-` as well
4364                  * as `/` for the path separator.
4365                  *
4366                  * @instance
4367                  * @memberof LuCI
4368                  *
4369                  * @param {string[]} [parts]
4370                  * An array of parts to join into an URL path. Parts may contain
4371                  * slashes and any of the other characters mentioned above.
4372                  *
4373                  * @return {string}
4374                  * Returns the resulting URL path.
4375                  */
4376                 resource: function() {
4377                         return this.path(this.env.resource, arguments);
4378                 },
4379
4380                 /**
4381                  * Construct an URL path relative to the media resource path of the
4382                  * LuCI ui (usually `/luci-static/$theme_name`).
4383                  *
4384                  * The resulting URL is guaranteed to only contain the characters
4385                  * `a-z`, `A-Z`, `0-9`, `_`, `.`, `%`, `,`, `;`, and `-` as well
4386                  * as `/` for the path separator.
4387                  *
4388                  * @instance
4389                  * @memberof LuCI
4390                  *
4391                  * @param {string[]} [parts]
4392                  * An array of parts to join into an URL path. Parts may contain
4393                  * slashes and any of the other characters mentioned above.
4394                  *
4395                  * @return {string}
4396                  * Returns the resulting URL path.
4397                  */
4398                 media: function() {
4399                         return this.path(this.env.media, arguments);
4400                 },
4401
4402                 /**
4403                  * Return the complete URL path to the current view.
4404                  *
4405                  * @instance
4406                  * @memberof LuCI
4407                  *
4408                  * @return {string}
4409                  * Returns the URL path to the current view.
4410                  */
4411                 location: function() {
4412                         return this.path(this.env.scriptname, this.env.requestpath);
4413                 },
4414
4415
4416                 /**
4417                  * Tests whether the passed argument is a JavaScript object.
4418                  * This function is meant to be an object counterpart to the
4419                  * standard `Array.isArray()` function.
4420                  *
4421                  * @instance
4422                  * @memberof LuCI
4423                  *
4424                  * @param {*} [val]
4425                  * The value to test
4426                  *
4427                  * @return {boolean}
4428                  * Returns `true` if the given value is of type object and
4429                  * not `null`, else returns `false`.
4430                  */
4431                 isObject: function(val) {
4432                         return (val != null &amp;&amp; typeof(val) == 'object');
4433                 },
4434
4435                 /**
4436                  * Return an array of sorted object keys, optionally sorted by
4437                  * a different key or a different sorting mode.
4438                  *
4439                  * @instance
4440                  * @memberof LuCI
4441                  *
4442                  * @param {object} obj
4443                  * The object to extract the keys from. If the given value is
4444                  * not an object, the function will return an empty array.
4445                  *
4446                  * @param {string} [key]
4447                  * Specifies the key to order by. This is mainly useful for
4448                  * nested objects of objects or objects of arrays when sorting
4449                  * shall not be performed by the primary object keys but by
4450                  * some other key pointing to a value within the nested values.
4451                  *
4452                  * @param {string} [sortmode]
4453                  * May be either `addr` or `num` to override the natural
4454                  * lexicographic sorting with a sorting suitable for IP/MAC style
4455                  * addresses or numeric values respectively.
4456                  *
4457                  * @return {string[]}
4458                  * Returns an array containing the sorted keys of the given object.
4459                  */
4460                 sortedKeys: function(obj, key, sortmode) {
4461                         if (obj == null || typeof(obj) != 'object')
4462                                 return [];
4463
4464                         return Object.keys(obj).map(function(e) {
4465                                 var v = (key != null) ? obj[e][key] : e;
4466
4467                                 switch (sortmode) {
4468                                 case 'addr':
4469                                         v = (v != null) ? v.replace(/(?:^|[.:])([0-9a-fA-F]{1,4})/g,
4470                                                 function(m0, m1) { return ('000' + m1.toLowerCase()).substr(-4) }) : null;
4471                                         break;
4472
4473                                 case 'num':
4474                                         v = (v != null) ? +v : null;
4475                                         break;
4476                                 }
4477
4478                                 return [ e, v ];
4479                         }).filter(function(e) {
4480                                 return (e[1] != null);
4481                         }).sort(function(a, b) {
4482                                 return (a[1] > b[1]);
4483                         }).map(function(e) {
4484                                 return e[0];
4485                         });
4486                 },
4487
4488                 /**
4489                  * Converts the given value to an array. If the given value is of
4490                  * type array, it is returned as-is, values of type object are
4491                  * returned as one-element array containing the object, empty
4492                  * strings and `null` values are returned as empty array, all other
4493                  * values are converted using `String()`, trimmed, split on white
4494                  * space and returned as array.
4495                  *
4496                  * @instance
4497                  * @memberof LuCI
4498                  *
4499                  * @param {*} val
4500                  * The value to convert into an array.
4501                  *
4502                  * @return {Array&lt;*>}
4503                  * Returns the resulting array.
4504                  */
4505                 toArray: function(val) {
4506                         if (val == null)
4507                                 return [];
4508                         else if (Array.isArray(val))
4509                                 return val;
4510                         else if (typeof(val) == 'object')
4511                                 return [ val ];
4512
4513                         var s = String(val).trim();
4514
4515                         if (s == '')
4516                                 return [];
4517
4518                         return s.split(/\s+/);
4519                 },
4520
4521                 /**
4522                  * Returns a promise resolving with either the given value or or with
4523                  * the given default in case the input value is a rejecting promise.
4524                  *
4525                  * @instance
4526                  * @memberof LuCI
4527                  *
4528                  * @param {*} value
4529                  * The value to resolve the promise with.
4530                  *
4531                  * @param {*} defvalue
4532                  * The default value to resolve the promise with in case the given
4533                  * input value is a rejecting promise.
4534                  *
4535                  * @returns {Promise&lt;*>}
4536                  * Returns a new promise resolving either to the given input value or
4537                  * to the given default value on error.
4538                  */
4539                 resolveDefault: function(value, defvalue) {
4540                         return Promise.resolve(value).catch(function() { return defvalue });
4541                 },
4542
4543                 /**
4544                  * The request callback function is invoked whenever an HTTP
4545                  * reply to a request made using the `L.get()`, `L.post()` or
4546                  * `L.poll()` function is timed out or received successfully.
4547                  *
4548                  * @instance
4549                  * @memberof LuCI
4550                  *
4551                  * @callback LuCI.requestCallbackFn
4552                  * @param {XMLHTTPRequest} xhr
4553                  * The XMLHTTPRequest instance used to make the request.
4554                  *
4555                  * @param {*} data
4556                  * The response JSON if the response could be parsed as such,
4557                  * else `null`.
4558                  *
4559                  * @param {number} duration
4560                  * The total duration of the request in milliseconds.
4561                  */
4562
4563                 /**
4564                  * Issues a GET request to the given url and invokes the specified
4565                  * callback function. The function is a wrapper around
4566                  * {@link LuCI.request#request Request.request()}.
4567                  *
4568                  * @deprecated
4569                  * @instance
4570                  * @memberof LuCI
4571                  *
4572                  * @param {string} url
4573                  * The URL to request.
4574                  *
4575                  * @param {Object&lt;string, string>} [args]
4576                  * Additional query string arguments to append to the URL.
4577                  *
4578                  * @param {LuCI.requestCallbackFn} cb
4579                  * The callback function to invoke when the request finishes.
4580                  *
4581                  * @return {Promise&lt;null>}
4582                  * Returns a promise resolving to `null` when concluded.
4583                  */
4584                 get: function(url, args, cb) {
4585                         return this.poll(null, url, args, cb, false);
4586                 },
4587
4588                 /**
4589                  * Issues a POST request to the given url and invokes the specified
4590                  * callback function. The function is a wrapper around
4591                  * {@link LuCI.request#request Request.request()}. The request is
4592                  * sent using `application/x-www-form-urlencoded` encoding and will
4593                  * contain a field `token` with the current value of `LuCI.env.token`
4594                  * by default.
4595                  *
4596                  * @deprecated
4597                  * @instance
4598                  * @memberof LuCI
4599                  *
4600                  * @param {string} url
4601                  * The URL to request.
4602                  *
4603                  * @param {Object&lt;string, string>} [args]
4604                  * Additional post arguments to append to the request body.
4605                  *
4606                  * @param {LuCI.requestCallbackFn} cb
4607                  * The callback function to invoke when the request finishes.
4608                  *
4609                  * @return {Promise&lt;null>}
4610                  * Returns a promise resolving to `null` when concluded.
4611                  */
4612                 post: function(url, args, cb) {
4613                         return this.poll(null, url, args, cb, true);
4614                 },
4615
4616                 /**
4617                  * Register a polling HTTP request that invokes the specified
4618                  * callback function. The function is a wrapper around
4619                  * {@link LuCI.request.poll#add Request.poll.add()}.
4620                  *
4621                  * @deprecated
4622                  * @instance
4623                  * @memberof LuCI
4624                  *
4625                  * @param {number} interval
4626                  * The poll interval to use. If set to a value less than or equal
4627                  * to `0`, it will default to the global poll interval configured
4628                  * in `LuCI.env.pollinterval`.
4629                  *
4630                  * @param {string} url
4631                  * The URL to request.
4632                  *
4633                  * @param {Object&lt;string, string>} [args]
4634                  * Specifies additional arguments for the request. For GET requests,
4635                  * the arguments are appended to the URL as query string, for POST
4636                  * requests, they'll be added to the request body.
4637                  *
4638                  * @param {LuCI.requestCallbackFn} cb
4639                  * The callback function to invoke whenever a request finishes.
4640                  *
4641                  * @param {boolean} [post=false]
4642                  * When set to `false` or not specified, poll requests will be made
4643                  * using the GET method. When set to `true`, POST requests will be
4644                  * issued. In case of POST requests, the request body will contain
4645                  * an argument `token` with the current value of `LuCI.env.token` by
4646                  * default, regardless of the parameters specified with `args`.
4647                  *
4648                  * @return {function}
4649                  * Returns the internally created function that has been passed to
4650                  * {@link LuCI.request.poll#add Request.poll.add()}. This value can
4651                  * be passed to {@link LuCI.poll.remove Poll.remove()} to remove the
4652                  * polling request.
4653                  */
4654                 poll: function(interval, url, args, cb, post) {
4655                         if (interval !== null &amp;&amp; interval &lt;= 0)
4656                                 interval = this.env.pollinterval;
4657
4658                         var data = post ? { token: this.env.token } : null,
4659                             method = post ? 'POST' : 'GET';
4660
4661                         if (!/^(?:\/|\S+:\/\/)/.test(url))
4662                                 url = this.url(url);
4663
4664                         if (args != null)
4665                                 data = Object.assign(data || {}, args);
4666
4667                         if (interval !== null)
4668                                 return Request.poll.add(interval, url, { method: method, query: data }, cb);
4669                         else
4670                                 return Request.request(url, { method: method, query: data })
4671                                         .then(function(res) {
4672                                                 var json = null;
4673                                                 if (/^application\/json\b/.test(res.headers.get('Content-Type')))
4674                                                         try { json = res.json() } catch(e) {}
4675                                                 cb(res.xhr, json, res.duration);
4676                                         });
4677                 },
4678
4679                 /**
4680                  * Deprecated wrapper around {@link LuCI.poll.remove Poll.remove()}.
4681                  *
4682                  * @deprecated
4683                  * @instance
4684                  * @memberof LuCI
4685                  *
4686                  * @param {function} entry
4687                  * The polling function to remove.
4688                  *
4689                  * @return {boolean}
4690                  * Returns `true` when the function has been removed or `false` if
4691                  * it could not be found.
4692                  */
4693                 stop: function(entry) { return Poll.remove(entry) },
4694
4695                 /**
4696                  * Deprecated wrapper around {@link LuCI.poll.stop Poll.stop()}.
4697                  *
4698                  * @deprecated
4699                  * @instance
4700                  * @memberof LuCI
4701                  *
4702                  * @return {boolean}
4703                  * Returns `true` when the polling loop has been stopped or `false`
4704                  * when it didn't run to begin with.
4705                  */
4706                 halt: function() { return Poll.stop() },
4707
4708                 /**
4709                  * Deprecated wrapper around {@link LuCI.poll.start Poll.start()}.
4710                  *
4711                  * @deprecated
4712                  * @instance
4713                  * @memberof LuCI
4714                  *
4715                  * @return {boolean}
4716                  * Returns `true` when the polling loop has been started or `false`
4717                  * when it was already running.
4718                  */
4719                 run: function() { return Poll.start() },
4720
4721                 /**
4722                  * Legacy `L.dom` class alias. New view code should use `'require dom';`
4723                  * to request the `LuCI.dom` class.
4724                  *
4725                  * @instance
4726                  * @memberof LuCI
4727                  * @deprecated
4728                  */
4729                 dom: DOM,
4730
4731                 /**
4732                  * Legacy `L.view` class alias. New view code should use `'require view';`
4733                  * to request the `LuCI.view` class.
4734                  *
4735                  * @instance
4736                  * @memberof LuCI
4737                  * @deprecated
4738                  */
4739                 view: View,
4740
4741                 /**
4742                  * Legacy `L.Poll` class alias. New view code should use `'require poll';`
4743                  * to request the `LuCI.poll` class.
4744                  *
4745                  * @instance
4746                  * @memberof LuCI
4747                  * @deprecated
4748                  */
4749                 Poll: Poll,
4750
4751                 /**
4752                  * Legacy `L.Request` class alias. New view code should use `'require request';`
4753                  * to request the `LuCI.request` class.
4754                  *
4755                  * @instance
4756                  * @memberof LuCI
4757                  * @deprecated
4758                  */
4759                 Request: Request,
4760
4761                 /**
4762                  * Legacy `L.Class` class alias. New view code should use `'require baseclass';`
4763                  * to request the `LuCI.baseclass` class.
4764                  *
4765                  * @instance
4766                  * @memberof LuCI
4767                  * @deprecated
4768                  */
4769                 Class: Class
4770         });
4771
4772         /**
4773          * @class xhr
4774          * @memberof LuCI
4775          * @deprecated
4776          * @classdesc
4777          *
4778          * The `LuCI.xhr` class is a legacy compatibility shim for the
4779          * functionality formerly provided by `xhr.js`. It is registered as global
4780          * `window.XHR` symbol for compatibility with legacy code.
4781          *
4782          * New code should use {@link LuCI.request} instead to implement HTTP
4783          * request handling.
4784          */
4785         var XHR = Class.extend(/** @lends LuCI.xhr.prototype */ {
4786                 __name__: 'LuCI.xhr',
4787                 __init__: function() {
4788                         if (window.console &amp;&amp; console.debug)
4789                                 console.debug('Direct use XHR() is deprecated, please use L.Request instead');
4790                 },
4791
4792                 _response: function(cb, res, json, duration) {
4793                         if (this.active)
4794                                 cb(res, json, duration);
4795                         delete this.active;
4796                 },
4797
4798                 /**
4799                  * This function is a legacy wrapper around
4800                  * {@link LuCI#get LuCI.get()}.
4801                  *
4802                  * @instance
4803                  * @deprecated
4804                  * @memberof LuCI.xhr
4805                  *
4806                  * @param {string} url
4807                  * The URL to request
4808                  *
4809                  * @param {Object} [data]
4810                  * Additional query string data
4811                  *
4812                  * @param {LuCI.requestCallbackFn} [callback]
4813                  * Callback function to invoke on completion
4814                  *
4815                  * @param {number} [timeout]
4816                  * Request timeout to use
4817                  *
4818                  * @return {Promise&lt;null>}
4819                  */
4820                 get: function(url, data, callback, timeout) {
4821                         this.active = true;
4822                         L.get(url, data, this._response.bind(this, callback), timeout);
4823                 },
4824
4825                 /**
4826                  * This function is a legacy wrapper around
4827                  * {@link LuCI#post LuCI.post()}.
4828                  *
4829                  * @instance
4830                  * @deprecated
4831                  * @memberof LuCI.xhr
4832                  *
4833                  * @param {string} url
4834                  * The URL to request
4835                  *
4836                  * @param {Object} [data]
4837                  * Additional data to append to the request body.
4838                  *
4839                  * @param {LuCI.requestCallbackFn} [callback]
4840                  * Callback function to invoke on completion
4841                  *
4842                  * @param {number} [timeout]
4843                  * Request timeout to use
4844                  *
4845                  * @return {Promise&lt;null>}
4846                  */
4847                 post: function(url, data, callback, timeout) {
4848                         this.active = true;
4849                         L.post(url, data, this._response.bind(this, callback), timeout);
4850                 },
4851
4852                 /**
4853                  * Cancels a running request.
4854                  *
4855                  * This function does not actually cancel the underlying
4856                  * `XMLHTTPRequest` request but it sets a flag which prevents the
4857                  * invocation of the callback function when the request eventually
4858                  * finishes or timed out.
4859                  *
4860                  * @instance
4861                  * @deprecated
4862                  * @memberof LuCI.xhr
4863                  */
4864                 cancel: function() { delete this.active },
4865
4866                 /**
4867                  * Checks the running state of the request.
4868                  *
4869                  * @instance
4870                  * @deprecated
4871                  * @memberof LuCI.xhr
4872                  *
4873                  * @returns {boolean}
4874                  * Returns `true` if the request is still running or `false` if it
4875                  * already completed.
4876                  */
4877                 busy: function() { return (this.active === true) },
4878
4879                 /**
4880                  * Ignored for backwards compatibility.
4881                  *
4882                  * This function does nothing.
4883                  *
4884                  * @instance
4885                  * @deprecated
4886                  * @memberof LuCI.xhr
4887                  */
4888                 abort: function() {},
4889
4890                 /**
4891                  * Existing for backwards compatibility.
4892                  *
4893                  * This function simply throws an `InternalError` when invoked.
4894                  *
4895                  * @instance
4896                  * @deprecated
4897                  * @memberof LuCI.xhr
4898                  *
4899                  * @throws {InternalError}
4900                  * Throws an `InternalError` with the message `Not implemented`
4901                  * when invoked.
4902                  */
4903                 send_form: function() { L.error('InternalError', 'Not implemented') },
4904         });
4905
4906         XHR.get = function() { return window.L.get.apply(window.L, arguments) };
4907         XHR.post = function() { return window.L.post.apply(window.L, arguments) };
4908         XHR.poll = function() { return window.L.poll.apply(window.L, arguments) };
4909         XHR.stop = Request.poll.remove.bind(Request.poll);
4910         XHR.halt = Request.poll.stop.bind(Request.poll);
4911         XHR.run = Request.poll.start.bind(Request.poll);
4912         XHR.running = Request.poll.active.bind(Request.poll);
4913
4914         window.XHR = XHR;
4915         window.LuCI = LuCI;
4916 })(window, document);
4917 </code></pre>
4918         </article>
4919     </section>
4920
4921
4922
4923
4924
4925
4926         
4927
4928         <footer>
4929             Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Fri Apr 03 2020 13:28:08 GMT+0200 (Central European Summer Time)
4930         </footer>
4931     </div>
4932 </div>
4933 <script>prettyPrint();</script>
4934 <script src="scripts/jaguar.js"></script>
4935 </body>
4936 </html>