tazpanel view index.cgi @ rev 475

network.cgi: add ether-wake support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Fri May 01 23:56:00 2015 +0200 (2015-05-01)
parents 836e45b5567b
children 3117717c007d
line source
1 #!/bin/sh
2 #
3 # Main CGI interface for TazPanel. In on word: KISS. Use the main CSS form
4 # command so we are faster and do not load unneeded functions. If necessary
5 # you can use the lib/ dir to handle external resources.
6 #
7 # Copyright (C) 2011-2015 SliTaz GNU/Linux - BSD License
8 #
11 # Common functions from libtazpanel
13 . lib/libtazpanel
14 get_config
16 TITLE="TazPanel"
20 # Check whether a configuration file has been modified after installation
22 file_is_modified() {
23 grep -l " $1$" $INSTALLED/*/md5sum | while read file; do
25 # Found, but can we do diff?
26 [ "$(grep -h " $1$" $file)" != "$(md5sum $1)" ] || break
27 orig=$(dirname $file)/volatile.cpio.gz
28 zcat $orig 2>/dev/null | cpio -t 2>/dev/null | grep -q "^${1#/}$" || break
30 case "$2" in
31 diff)
32 tmp=$(mktemp -d)
33 ( cd $tmp; zcat $orig | cpio -id ${1#/} )
34 diff -abu $tmp$1 $1 | sed "s|$tmp||"
35 rm -rf $tmp;;
36 button)
37 echo -n '<button name="action" value="diff" data-icon="diff">'$(_ 'Differences')'</button>';;
38 esac
39 break
40 done
41 }
45 # OK status in table
47 ok_status_t() {
48 echo '<td><span class="diff-add" data-img="ok"></span></td></tr>'
49 }
53 # Terminal prompt
55 term_prompt() {
56 if [ "$user" == 'root' ]; then
57 local color1='color31' sign='#'
58 else
59 local color1='color32' sign='$'
60 fi
61 echo -n "<span class='$color1'>$user@$(hostname)</span>:<span class='color33'>"
62 pwd | sed "s|^$HOME|~|" | tr -d '\n'; echo -n "</span>$sign "
63 }
67 #
68 # Commands
69 #
71 case " $(GET) " in
74 *\ exec\ *)
75 # Execute command and display its result in a terminal-like window
77 header; TITLE=$(_ 'TazPanel - exec'); xhtml_header
79 exec="$(GET exec)"
80 font="${TERM_FONT:-monospace}"
81 palette=$(echo $TERM_PALETTE | tr A-Z a-z)
83 cat <<EOT
84 <section>
85 <header>
86 $exec
87 $(back_button "$(GET back)" "$(GET back_caption)" "$(GET back_icon)")
88 </header>
89 <div class="term_">
90 <pre class="term $palette" style="font-family: '$font'">$($exec 2>&1 | htmlize | filter_taztools_msgs)</pre>
91 </div>
92 </section>
93 EOT
94 ;;
97 *\ file\ *)
98 #
99 # Handle files
100 #
101 header
102 file="$(GET file)"
103 action="$(POST action)"; [ -z "$action" ] && action="$(GET action)" # receive 'action' both on POST or GET
104 title="$(POST title)"; [ -z "$title" ] && title="$(GET title)" # (optional)
106 case $file in
107 *.html)
108 cat $file; exit 0 ;;
109 *)
110 TITLE=$(_ 'TazPanel - File'); xhtml_header ;;
111 esac
113 case "$action" in
114 edit)
115 cat <<EOT
116 <section>
117 <header>
118 <span data-icon="edit">${title:-$file}</span>
119 <form id="editform" method="post" action="?file=$file">
120 <button data-icon="save">$(_ 'Save')</button>
121 <button name="action" value="diff" data-icon="diff">$(_ 'Differences')</button>
122 </form>
123 </header>
124 <textarea form="editform" name="content" class="wide" rows="30" autofocus>$(cat $file | htmlize)</textarea>
125 </section>
126 EOT
127 #The space before textarea gets muddled when the form is submitted.
128 #It prevents anything else from getting messed up
129 ;;
131 setvar)
132 data="$(. $(GET file) ;eval echo \$$(GET var))"
133 cat <<EOT
134 <section>
135 <header>$(GET var)</header>
136 <form method="post" action="?file=$file" class="nogap">
137 <input type="hidden" name="var" value="$(GET var)">
138 <input type="text" name="content" value="${data:-$(GET default)}">
139 <button type="submit" data-icon="save">$(_ 'Save')</button>
140 </form>
141 </section>
142 EOT
143 ;;
145 diff)
146 cat <<EOT
147 <section>
148 <pre id="diff">$(file_is_modified $file diff | syntax_highlighter diff)</pre>
149 </section>
150 EOT
151 ;;
153 *)
154 R=$(echo -en '\r')
155 if [ -n "$(POST content)" ]; then
156 if [ -n "$(POST var)" ]; then
157 sed -i "s|^\\($(POST var)=\\).*|\1\"$(POST content)\"|" $file
158 else
159 sed "s/$R /\n/g;s/$R%0//g" > $file <<EOT
160 $(POST content)
161 EOT
162 fi
163 fi
165 cat <<EOT
166 <section class="bigNoScrollable">
167 <header>
168 <span data-icon="text">${title:-$file}</span>
169 EOT
170 if [ -w "$file" ]; then
171 cat <<EOT
172 <form>
173 <input type="hidden" name="file" value="$file"/>
174 <button onclick='editFile(); return false' id="edit_button"
175 data-icon="edit">$(_ 'Edit')</button><!--
176 --><button onclick='saveFile("$file", "$title"); return false' id="save_button"
177 data-icon="save" style="display:none">$(_ 'Save')</button><!--
178 -->$(file_is_modified $file button)
179 </form>
180 EOT
181 elif [ -r "$file" ]; then
182 cat <<EOT
183 <form>
184 <input type="hidden" name="file" value="$file"/>
185 $(file_is_modified $file button)
186 </form>
187 EOT
188 fi
189 cat <<EOT
190 </header>
192 <div>
193 <pre id="fileContent" class="bigScrollable">
194 EOT
195 end_code=''
196 # Handle file type by extension as a Web Server does it.
197 case "$file" in
198 *.sh|*.cgi|*/receipt|*.conf)
199 echo '<code class="language-bash">'; end_code='</code>'
200 cat | htmlize ;;
201 *.ini)
202 echo '<code class="language-ini">'; end_code='</code>'
203 cat | htmlize ;;
204 *.conf|*.lst)
205 syntax_highlighter conf ;;
206 *Xorg.0.log)
207 syntax_highlighter xlog ;;
208 *dmesg.log)
209 syntax_highlighter kernel ;;
210 *)
211 cat | htmlize ;;
212 esac < $file
213 cat <<EOT
214 $end_code</pre>
215 </div>
216 </section>
217 EOT
218 esac
219 ;;
223 *\ terminal\ *|*\ cmd\ *)
224 # Cmdline terminal
226 header; TITLE=$(_ 'TazPanel - Terminal'); xhtml_header
228 user="$REMOTE_USER"
229 HOME="$(awk -F: -vu=$user '$1==u{print $6}' /etc/passwd)"
230 historyfile="$HOME/.ash_history"
232 cmd=$(GET cmd)
233 path="$(GET path)"; path="${path:-/tmp}"; cd "$path"
235 font="${TERM_FONT:-monospace}"
236 palette=$(echo $TERM_PALETTE | tr A-Z a-z)
238 [ -n "$cmd" -a "$cmd" != "$(tail -n1 $historyfile)" ] && echo "$cmd" >> $historyfile
241 # Terminal history
243 if [ "$cmd" == 'history' ]; then
244 cat <<EOT
245 <section>
246 <header>
247 $(_ 'History')
248 <form><button name="terminal" data-icon="terminal">$(_ 'Back')</button></form>
249 </header>
250 <form>
251 <input type="hidden" name="path" value="$path"/>
252 <pre class="term $palette" style="font-family: '$font'">
253 EOT
254 htmlize < $historyfile | awk -vrun="$(_ 'run')" -vpath="$path" '
255 BEGIN { num=1 }
256 {
257 printf("%3d ", num);
258 cmd = $0
259 gsub("%", "%25", cmd); gsub("+", "%2B", cmd); gsub(" ", "+", cmd);
260 gsub("\"", "%22", cmd); gsub("!", "%21", cmd); gsub("'\''", "%27", cmd);
261 printf("<a data-icon=\"run\" href=\"?cmd=%s&path=%s\">%s</a> ", cmd, path, run);
262 printf("<input type=\"checkbox\" name=\"rm\" value=\"%d\" id=\"hist%d\">", num, num);
263 printf("<label for=\"hist%d\">%s</label>\n", num, $0);
264 num++
265 }'
266 cat <<EOT
267 </pre>
268 <footer>
269 <button name="rmhistory" data-icon="remove">$(_ 'Clear')</button>
270 </footer>
271 </form>
272 </section>
273 EOT
274 xhtml_footer
275 exit 0
276 fi
279 # Terminal window
281 cat <<EOT
282 <span id="num_hist"></span>
283 <section>
284 <pre class="term $palette" style="font-family: '$font'" onclick="document.getElementById('typeField').focus()">
285 EOT
286 if [ -n "$cmd" ]; then
287 term_prompt
288 echo "$cmd" | htmlize
289 fi
291 case "$cmd" in
292 usage|help)
293 _ 'Small non-interactive terminal emulator.'; echo
294 _ 'Run any command at your own risk, avoid interactive commands (%s)' 'nano, mc, ...'; echo
295 ;;
296 wget*)
297 dl=/var/cache/downloads
298 [ ! -d "$dl" ] && mkdir -p $dl
299 _ 'Downloading to: %s' $dl; echo
300 cd $dl; $cmd 2>&1 ;;
301 cd|cd\ *)
302 path="${cmd#cd}"; path="${path:-$HOME}";
303 path="$(realpath $path)"; cd "$path" ;;
304 ls|ls\ *)
305 $cmd -w80 --color=always 2>&1 | filter_taztools_msgs ;;
306 cat)
307 # Cmd must be used with an arg.
308 _ '%s needs an argument' "$cmd" ;;
309 mc|nano|su)
310 # List of restricted (interactive) commands
311 _ "Please, don't run interactive command \"%s\"" "$cmd"; echo; echo ;;
312 *)
313 unset HTTP_REFERER # for fooling /lib/libtaz.sh formatting utils (<hr> in the terminal is so-so)
314 export DISPLAY=:0.0 # for run X applications
315 /bin/sh -c "$cmd" 2>&1 | htmlize | filter_taztools_msgs
316 ;;
317 esac
319 cat <<EOT
320 <form id="term">
321 <div class="cmdline" id="cmdline"><span id="prompt">$(term_prompt)</span><span id="typeField"> </span></div>
322 <input type="hidden" name="path" value="$(pwd)"/>
323 <input type="hidden" name="cmd" id="cmd"/>
324 </form>
325 </pre>
326 </section>
328 <form>
329 <button name="termsettings" data-icon="settings">$(_ 'Settings')</button>
330 <button name="cmd" value="history" data-icon="history">$(_ 'History')</button>
331 </form>
333 <script type="text/javascript">
334 with (document.getElementById('typeField')) {
335 contentEditable=true;
336 focus();
337 }
338 document.onkeydown=keydownHandler;
339 EOT
341 # Export history as array.
342 # Escape "all \"quotes\" in quotes", and all '\'
343 # (because \u, \x, \c has special meaning and can produce syntax error and stop js)
344 sed 's|\\|\\\\|g; s|"|\\"|g' $historyfile | awk '
345 BEGIN{ i=1; printf("ash_history=[") }
346 { printf("\"%s\",", $0); i++ }
347 END{
348 printf("\"\"];")
349 i--; printf("cur_hist=\"%d\";max_hist=\"%d\";", i, i)
350 }'
351 cat <<EOT
352 </script>
353 EOT
354 ;;
357 *\ rmhistory\ *)
358 # Manage shell commandline history
359 user="$REMOTE_USER"
360 [ -z "$HOME" ] && HOME="$(awk -F: -vu=$user '$1==u{print $6}' /etc/passwd)"
361 historyfile="$HOME/.ash_history"
363 # Return sed command for removing history lines ('8d12d' to remove 8 and 12 lines)
364 rms=$(echo $QUERY_STRING | awk 'BEGIN{RS="&";FS="="}{if($1=="rm")printf "%dd", $2}')
366 if [ -n "$rms" ]; then
367 # Actually remove lines
368 sed -i $rms $historyfile
369 # Redirects back to the history table
370 header "HTTP/1.1 301 Moved Permanently" "Location: ?terminal&cmd=history&path=$(GET path)"
371 exit 0
372 fi
373 ;;
376 *\ termsettings\ *)
377 # Terminal settings
378 TITLE=$(_ 'TazPanel - Terminal'); header; xhtml_header;
379 user="$REMOTE_USER"
380 font="$(GET font)"; font="${font:-$TERM_FONT}"
381 palette="$(GET palette)"; palette="${palette:-$TERM_PALETTE}"
382 pal=$(echo $palette | tr A-Z a-z)
384 # Add or change settings in TazPanel config
385 if [ -z "$TERM_FONT" ]; then
386 echo -e "\n# Terminal font family\nTERM_FONT=\"$font\"" >> $CONFIG
387 else
388 sed -i "s|TERM_FONT=.*|TERM_FONT=\"$font\"|" $CONFIG
389 fi
390 if [ -z "$TERM_PALETTE" ]; then
391 echo -e "\n# Terminal color palette\nTERM_PALETTE=\"$palette\"" >> $CONFIG
392 else
393 sed -i "s|TERM_PALETTE=.*|TERM_PALETTE=\"$palette\"|" $CONFIG
394 fi
396 cat <<EOT
397 <section style="position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: 0.5rem;">
398 <header>
399 $(_ 'Terminal settings')
400 <form>
401 <button name="terminal" data-icon="terminal">$(_ 'Terminal')</button>
402 </form>
403 </header>
404 <pre class="term $pal" style="height: auto; font-family: '$font'">
405 <span class='color31'>$user@$(hostname)</span>:<span class='color33'>~</span># palette
407 $(
408 for i in $(seq 30 37); do
409 for b in 0 1; do
410 for j in $(seq 40 47); do
411 echo -n "<span class=\"color$b color$i color$j\">$i:$j</span>"
412 done
413 done
414 echo
415 done
416 )
417 </pre>
418 <footer>
419 <form class="wide">
420 $(_ 'Font:')
421 <select name="font">
422 <option value="">$(_ 'Default')</option>
423 $(fc-list :spacing=mono:lang=en family | sed '/\.pcf/d;/,/d;s|\\-|-|g' | sort -u | \
424 awk -vfont="$font" '{
425 printf("<option value=\"%s\"%s>%s</option>\n", $0, ($0 == font)?" selected":"", $0)
426 }')
427 </select>
428 $(_ 'Palette:')
429 <select name="palette">
430 $(echo -e 'Tango\nLinux\nXterm\nRxvt\nEcho' | awk -vpal="$palette" '{
431 printf("<option value=\"%s\"%s>%s</option>\n", $0, ($0 == pal)?" selected":"", $0)
432 }')
433 </select>
434 <button name="termsettings" data-icon="ok">$(_ 'Apply')</button>
435 </form>
436 </footer>
437 </section>
438 EOT
440 ;;
443 *\ top\ *)
444 header; TITLE=$(_ 'TazPanel - Process activity'); xhtml_header
446 r=$(GET refresh)
447 cat <<EOT
448 <form>
449 <p>$(_ 'Refresh:')
450 <input type="hidden" name="top"/>
451 <input type="radio" name="refresh" value="1" id="r1" $([ "$r" == 1 ] && echo checked) onchange="this.form.submit()"/>
452 <label for="r1">$(_ '1s' )</label>
453 <input type="radio" name="refresh" value="5" id="r2" $([ "$r" == 5 ] && echo checked) onchange="this.form.submit()"/>
454 <label for="r2">$(_ '5s' )</label>
455 <input type="radio" name="refresh" value="10" id="r3" $([ "$r" == 10 ] && echo checked) onchange="this.form.submit()"/>
456 <label for="r3">$(_ '10s' )</label>
457 <input type="radio" name="refresh" value="" id="r4" $([ -z "$r" ] && echo checked) onchange="this.form.submit()"/>
458 <label for="r4">$(_ 'none')</label>
459 </p>
460 </form>
461 EOT
462 [ -n "$r" ] && echo "<meta http-equiv=\"refresh\" content=\"$r\">"
464 echo '<section><div><pre class="term log">'
465 top -n1 -b | htmlize | sed \
466 -e 's|^[A-Z].*:|<span class="color1 color31">\0</span>|g' \
467 -e 's|^\ *PID|<span class="color1 color32">\0</span>|g'
468 echo '</pre></div></section>' ;;
471 *\ debug\ *)
472 header; TITLE=$(_ 'TazPanel - Debug'); xhtml_header
474 cat <<EOT
475 <h2>$(_ 'HTTP Environment')</h2>
477 <section>
478 <div>
479 <pre>$(httpinfo | syntax_highlighter conf)</pre>
480 </div>
481 </section>
482 EOT
483 ;;
486 *\ report\ *)
487 header; TITLE=$(_ 'TazPanel - System report'); xhtml_header
489 [ -d /var/cache/slitaz ] || mkdir -p /var/cache/slitaz
490 output=/var/cache/slitaz/sys-report.html
492 cat <<EOT
494 <section>
495 <header>$(_ 'Reporting to: %s' "$output")</header>
496 <table class="wide zebra">
497 <tbody>
498 <tr><td>$(_ 'Creating report header...')</td>
499 EOT
500 cat > $output <<EOT
501 <!DOCTYPE html>
502 <html xmlns="http://www.w3.org/1999/xhtml">
503 <head>
504 <meta charset="utf-8"/>
505 <title>$(_ 'SliTaz system report')</title>
506 <style type="text/css">
507 body { padding: 20px 60px; font-size: 13px; }
508 h1, h2 { color: #444; }
509 pre { background: #f1f1f1; border: 1px solid #ddd;
510 padding: 10px; border-radius: 4px; }
511 span.diff-rm { color: red; }
512 span.diff-add { color: green; }
513 </style>
514 </head>
515 <body>
516 EOT
517 cat <<EOT
518 $(ok_status_t)
519 <tr><td>$(_ 'Creating system summary...')</td>
520 EOT
521 cat >> $output <<EOT
522 <h1>$(_ 'SliTaz system report')</h1>
523 $(_ 'Date:') $(date)
524 <pre>
525 uptime : $(uptime)
526 cmdline : $(cat /proc/cmdline)
527 version : $(cat /etc/slitaz-release)
528 packages : $(ls /var/lib/tazpkg/installed | wc -l) installed
529 kernel : $(uname -r)
530 </pre>
531 EOT
532 cat <<EOT
533 $(ok_status_t)
534 <tr><td>$(_ 'Getting hardware info...')</td>
535 EOT
536 cat >> $output <<EOT
537 <h2>free</h2>
538 <pre>$(free)</pre>
540 <h2>lspci -k</h2>
541 <pre>$(lspci -k)</pre>
543 <h2>lsusb</h2>
544 <pre>$(lsusb)</pre>
546 <h2>lsmod</h2>
547 <pre>$(lsmod)</pre>
549 EOT
550 cat <<EOT
551 $(ok_status_t)
552 <tr><td>$(_ 'Getting networking info...')</td>
553 EOT
554 cat >> $output <<EOT
555 <h2>ifconfig -a</h2>
556 <pre>$(ifconfig -a)</pre>
558 <h2>route -n</h2>
559 <pre>$(route -n)</pre>
561 <h2>/etc/resolv.conf</h2>
562 <pre>$(cat /etc/resolv.conf)</pre>
563 EOT
564 cat <<EOT
565 $(ok_status_t)
566 <tr><td>$(_ 'Getting filesystems info...')</td>
567 EOT
568 cat >> $output <<EOT
569 <h2>blkid</h2>
570 <pre>$(blkid)</pre>
572 <h2>fdisk -l</h2>
573 <pre>$(fdisk -l)</pre>
575 <h2>mount</h2>
576 <pre>$(mount)</pre>
578 <h2>df -h</h2>
579 <pre>$(df -h)</pre>
581 <h2>df -i</h2>
582 <pre>$(df -i)</pre>
583 EOT
584 cat <<EOT
585 $(ok_status_t)
586 <tr><td>$(_ 'Getting boot logs...')</td>
587 EOT
588 cat >> $output <<EOT
589 <h2>$(_ 'Kernel messages')</h2>
590 <pre>$(cat /var/log/dmesg.log)</pre>
592 <h2>$(_ 'Boot scripts')</h2>
593 <pre>$(cat /var/log/boot.log | filter_taztools_msgs)</pre>
594 EOT
595 cat <<EOT
596 $(ok_status_t)
597 <tr><td>$(_ 'Creating report footer...')</td>
598 EOT
599 cat cat >> $output <<EOT
600 </body>
601 </html>
602 EOT
603 cat <<EOT
604 $(ok_status_t)
605 </tbody>
606 </table>
607 <footer>
608 <form><button name="file" value="$output" data-icon="view">$(_ 'View')</button></form>
609 </footer>
610 </section>
613 $(msg tip "$(_ 'This report can be attached with a bug report on:')
614 <a href="http://bugs.slitaz.org/" target="_blank">bugs.slitaz.org</a></p>")
615 EOT
616 ;;
619 *)
620 #
621 # Default xHTML content
622 #
623 header; xhtml_header
624 [ -n "$(GET gen_locale)" ] && new_locale=$(GET gen_locale)
625 [ -n "$(GET rdate)" ] && echo ""
626 hostname=$(hostname)
628 cat <<EOT
629 <h2>$(_ 'Host: %s' $hostname)</h2>
630 <p>$(_ 'SliTaz administration and configuration Panel')<p>
632 <form class="nogap"><!--
633 --><button name="terminal" data-icon="terminal">$(_ 'Terminal')</button><!--
634 --><button name="top" data-icon="proc" >$(_ 'Process activity')</button><!--
635 --><button name="report" data-icon="report" data-root>$(_ 'Create a report')</button><!--
636 --></form>
638 <section>
639 <header>$(_ 'Summary')</header>
640 <table>
641 <tr><td>$(_ 'Uptime:')</td>
642 <td id="uptime">$(uptime | sed 's|\([0-9.:][0-9.:]*\)|<b>\1</b>|g')</td>
643 </tr>
644 <tr><td>$(_ 'Memory in Mb:')</td>
645 <td>$(free -m | grep Mem: | \
646 awk -vline="$(gettext 'Total: %d, Used: %d, Free: %d')" \
647 '{ printf(line, $2, $3, $4) }' | \
648 sed 's|\([0-9][0-9]*\)|<b>\1</b>|g')</td>
649 </tr>
650 <tr><td>$(_ 'Linux kernel:')</td>
651 <td>$(uname -r)</td>
652 </tr>
653 </table>
654 </section>
657 <section>
658 <header>
659 $(_ 'Network status')
660 <form action="network.cgi">
661 <button data-icon="wifi">$(_ 'Network')</button>
662 </form>
663 </header>
664 $(list_network_interfaces)
665 </section>
668 <section>
669 <header>
670 $(_ 'Filesystem usage statistics')
671 <form action="hardware.cgi">
672 <button data-icon="hdd">$(_ 'Disks')</button>
673 </form>
674 </header>
675 <table class="wide zebra center">
676 EOT
677 # Disk stats (management is done as hardware.cgi)
678 df_thead
679 echo '<tbody>'
680 df -h | grep ^/dev | while read fs size used av pct mp; do
681 cat <<EOT
682 <tr>
683 <td><span data-icon="hdd">${fs#/dev/}</span></td>
684 <td>$(blkid $fs | sed '/LABEL=/!d;s/.*LABEL="\([^"]*\).*/\1/')</td>
685 <td>$(blkid $fs | sed '/TYPE=/!d;s/.*TYPE="\([^"]*\).*/\1/')</td>
686 <td>$size</td>
687 <td>$av</td>
688 <td class="meter"><meter min="0" max="100" value="$(echo $pct | cut -d% -f1)"
689 low="$DU_WARN" high="$DU_CRIT" optimum="10"></meter>
690 <span>$used - $pct</span>
691 </td>
692 <td>$mp</td>
693 <td>$(blkid $fs | sed '/UUID=/!d;s/.*UUID="\([^"]*\).*/\1/')</td>
694 </tr>
695 EOT
696 done
697 cat <<EOT
698 </tbody>
699 </table>
700 </section>
702 <section>
703 <header>
704 $(_ 'Panel Activity')
705 <form>
706 <button name="file" value="$LOG_FILE" data-icon="view">$(_ 'View')</button>
707 </form>
708 </header>
709 <div>
710 <pre id="panel-activity">
711 $(cat $LOG_FILE | tail -n 8 | sort -r | syntax_highlighter activity)</pre>
712 </div>
713 </section>
714 EOT
715 ;;
716 esac
718 xhtml_footer
719 exit 0