aboutsummaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorJoachim Tingvold <joachim@tingvold.com>2014-04-06 03:11:04 +0200
committerJoachim Tingvold <joachim@tingvold.com>2014-04-06 03:11:04 +0200
commit2a0c0a3dbbdf7fa5040953c0b0d88ad6f62c011e (patch)
tree92c7cbf54272466b46f64e5dc8d1ddb429858836 /web
parentfe0be5960aac1f9bb600dbf853d862a9f4e60de8 (diff)
Initial commit. Source; TG13-goodiebag.
Diffstat (limited to 'web')
-rw-r--r--web/etc/apache2/nms-public.tg13.gathering.org11
-rw-r--r--web/etc/apache2/nms.tg13.gathering.org39
-rw-r--r--web/etc/apache2/stream.tg13.gathering.org25
-rw-r--r--web/etc/apache2/tech.tg13.gathering.org12
-rw-r--r--web/etc/cron/update-public-nms3
-rw-r--r--web/nms-public.gathering.org/dhcp.html10
-rw-r--r--web/nms-public.gathering.org/dhcpkart.html10
-rw-r--r--web/nms-public.gathering.org/index.html15
-rw-r--r--web/nms-public.gathering.org/led.pl128
-rw-r--r--web/nms-public.gathering.org/led.txt256
-rw-r--r--web/nms-public.gathering.org/nettkart-dhcp.pngbin0 -> 203313 bytes
-rw-r--r--web/nms-public.gathering.org/nettkart-trafikk.html10
-rw-r--r--web/nms-public.gathering.org/nettkart-trafikk.pngbin0 -> 291454 bytes
-rw-r--r--web/nms-public.gathering.org/trafikk.html10
-rwxr-xr-xweb/nms.gathering.org/apkart.pl89
-rw-r--r--web/nms.gathering.org/bg07.pngbin0 -> 498409 bytes
-rwxr-xr-xweb/nms.gathering.org/dhcpkart.pl94
-rw-r--r--web/nms.gathering.org/index.html92
-rwxr-xr-xweb/nms.gathering.org/led.pl20
-rwxr-xr-xweb/nms.gathering.org/mbd-status.pl44
-rwxr-xr-xweb/nms.gathering.org/mygraph.pl179
-rw-r--r--web/nms.gathering.org/nettkart-continuous.html31
-rwxr-xr-xweb/nms.gathering.org/nettkart-telnet.pl47
-rwxr-xr-xweb/nms.gathering.org/nettkart-text.pl47
-rwxr-xr-xweb/nms.gathering.org/nettkart-web.pl47
-rwxr-xr-xweb/nms.gathering.org/nettkart.pl142
-rwxr-xr-xweb/nms.gathering.org/portkart.pl82
-rwxr-xr-xweb/nms.gathering.org/showswitch.pl221
-rw-r--r--web/nms.gathering.org/slide.html38
-rwxr-xr-xweb/nms.gathering.org/smanagement.pl239
-rwxr-xr-xweb/nms.gathering.org/ssendfile.pl48
-rwxr-xr-xweb/nms.gathering.org/sshow.pl257
-rwxr-xr-xweb/nms.gathering.org/stromkart.pl69
-rwxr-xr-xweb/nms.gathering.org/uplinkkart-text.pl38
-rwxr-xr-xweb/nms.gathering.org/uplinkkart.pl70
-rwxr-xr-xweb/nms.gathering.org/uplinktrafikkart.pl90
-rwxr-xr-xweb/stream.tg13.gathering.org/fix_count.pl31
-rw-r--r--web/stream.tg13.gathering.org/img/cam-map.pngbin0 -> 113375 bytes
-rw-r--r--web/stream.tg13.gathering.org/img/icon_1.pngbin0 -> 3142 bytes
-rw-r--r--web/stream.tg13.gathering.org/img/icon_2.pngbin0 -> 3336 bytes
-rw-r--r--web/stream.tg13.gathering.org/img/icon_3.pngbin0 -> 3385 bytes
-rw-r--r--web/stream.tg13.gathering.org/img/icon_camera.pngbin0 -> 3786 bytes
-rw-r--r--web/stream.tg13.gathering.org/img/icon_event.pngbin0 -> 3463 bytes
-rw-r--r--web/stream.tg13.gathering.org/img/icon_hd.pngbin0 -> 3412 bytes
-rw-r--r--web/stream.tg13.gathering.org/img/icon_sd.pngbin0 -> 3731 bytes
-rwxr-xr-xweb/stream.tg13.gathering.org/index-bak.pl67
-rw-r--r--web/stream.tg13.gathering.org/index-bak.tmpl31
-rwxr-xr-xweb/stream.tg13.gathering.org/index.pl72
-rw-r--r--web/stream.tg13.gathering.org/index.tmpl35
-rw-r--r--web/stream.tg13.gathering.org/ios/PLACEHOLDER0
-rw-r--r--web/stream.tg13.gathering.org/ios/event.m3u816
-rw-r--r--web/stream.tg13.gathering.org/ios/stream.m3u88
-rw-r--r--web/stream.tg13.gathering.org/singularity.css1960
-rw-r--r--web/stream.tg13.gathering.org/singularity.pngbin0 -> 19719 bytes
-rwxr-xr-xweb/stream.tg13.gathering.org/stream.pl87
-rwxr-xr-xweb/stream.tg13.gathering.org/streamstats-fast.pl15
-rw-r--r--web/stream.tg13.gathering.org/streamstats.cpp217
-rw-r--r--web/stream.tg13.gathering.org/streamstats.html81
-rwxr-xr-xweb/stream.tg13.gathering.org/streamstats.pl116
-rw-r--r--web/stream.tg13.gathering.org/superawesomeness.css24
-rwxr-xr-xweb/stream.tg13.gathering.org/test.pl70
-rw-r--r--web/stream.tg13.gathering.org/test.tmpl31
-rw-r--r--web/streamlib/stream.pm36
-rw-r--r--web/streamlib/stream/config.pm160
-rwxr-xr-xweb/tech.gathering.org/event-720p.mp4.pl11
-rw-r--r--web/tech.gathering.org/index.html20
-rw-r--r--web/tech.gathering.org/logo.pngbin0 -> 19719 bytes
-rw-r--r--web/tech.gathering.org/styles.css24
68 files changed, 5625 insertions, 0 deletions
diff --git a/web/etc/apache2/nms-public.tg13.gathering.org b/web/etc/apache2/nms-public.tg13.gathering.org
new file mode 100644
index 0000000..2c6115a
--- /dev/null
+++ b/web/etc/apache2/nms-public.tg13.gathering.org
@@ -0,0 +1,11 @@
+<VirtualHost *:80>
+ ServerAdmin drift@gathering.org
+ ServerName nms-public.tg13.gathering.org
+
+ DocumentRoot /srv/www/nms-public.tg13.gathering.org
+ AddHandler cgi-script .cgi .sh .pl .py
+
+ LogLevel warn
+ ErrorLog /var/log/apache2/error-nms-public.tg13.gathering.org.log
+ CustomLog /var/log/apache2/access-nms-public.tg13.gathering.org.log combined
+</VirtualHost>
diff --git a/web/etc/apache2/nms.tg13.gathering.org b/web/etc/apache2/nms.tg13.gathering.org
new file mode 100644
index 0000000..cb81598
--- /dev/null
+++ b/web/etc/apache2/nms.tg13.gathering.org
@@ -0,0 +1,39 @@
+<VirtualHost *:80>
+ ServerAdmin drift@gathering.org
+ ServerName nms.tg13.gathering.org
+ ServerAlias flexus.tg13.gathering.org
+
+ DocumentRoot /root/tgmanage/web/nms.gathering.org
+ <Directory "/root/tgmanage/web/nms.gathering.org">
+ AllowOverride None
+ Options Indexes FollowSymLinks ExecCGI MultiViews
+ Order allow,deny
+ Satisfy any
+ Allow from ::1
+ Allow from 127.0.0.1
+ Allow from 151.216.125.0/24
+ Allow from 151.216.124.0/24
+ Allow from 2a02:ed02:124::/64
+ Allow from 2a02:ed02:125::/64
+
+ AddHandler cgi-script .cgi .sh .pl .py
+ AddDefaultCharset UTF-8
+
+ AuthUserFile /root/tgmanage/web/.htpasswd
+ AuthGroupFile /dev/null
+ AuthName "Tech:Server Secret Volcano Lair"
+ AuthType Basic
+
+ require valid-user
+ </Directory>
+
+ ErrorLog /var/log/apache2/error-nms.tg13.gathering.org.log
+
+ # Possible values include: debug, info, notice, warn, error, crit,
+ # alert, emerg.
+ LogLevel warn
+
+ CustomLog /var/log/apache2/access-nms.tg13.gathering.org.log combined
+ ServerSignature On
+
+</VirtualHost>
diff --git a/web/etc/apache2/stream.tg13.gathering.org b/web/etc/apache2/stream.tg13.gathering.org
new file mode 100644
index 0000000..b184b1c
--- /dev/null
+++ b/web/etc/apache2/stream.tg13.gathering.org
@@ -0,0 +1,25 @@
+ <VirtualHost *:80>
+ ServerAdmin drift@gathering.org
+ ServerName stream.tg13.gathering.org
+ ServerAlias krosus.tg13.gathering.org
+
+ DocumentRoot /srv/stream.tg13.gathering.org
+ <Directory "/srv/stream.tg13.gathering.org/">
+ AllowOverride None
+ Options Indexes FollowSymLinks ExecCGI MultiViews
+ Order allow,deny
+ Allow from all
+ AddHandler cgi-script .cgi .sh .pl .py
+ AddDefaultCharset UTF-8
+
+ </Directory>
+
+ ErrorLog /var/log/apache2/error-stream.tg13.gathering.org.log
+
+ # Possible values include: debug, info, notice, warn, error, crit,
+ # alert, emerg.
+ LogLevel info
+
+ CustomLog /var/log/apache2/access-stream.tg13.gathering.org.log combined
+ ServerSignature On
+</VirtualHost>
diff --git a/web/etc/apache2/tech.tg13.gathering.org b/web/etc/apache2/tech.tg13.gathering.org
new file mode 100644
index 0000000..7ab303b
--- /dev/null
+++ b/web/etc/apache2/tech.tg13.gathering.org
@@ -0,0 +1,12 @@
+<VirtualHost *:80>
+ ServerAdmin drift@gathering.org
+ ServerName tech.tg13.gathering.org
+
+ DocumentRoot /srv/www/tech.tg13.gathering.org
+
+ LogLevel warn
+ ErrorLog /var/log/apache2/error-tech.tg13.gathering.org.log
+ CustomLog /var/log/apache2/access-tech.tg13.gathering.org.log combined
+
+ AddHandler cgi-script .pl
+</VirtualHost>
diff --git a/web/etc/cron/update-public-nms b/web/etc/cron/update-public-nms
new file mode 100644
index 0000000..3018042
--- /dev/null
+++ b/web/etc/cron/update-public-nms
@@ -0,0 +1,3 @@
+# Update public nms
+
+* * * * * root /root/tgmanage/clients/update-public-nms.sh
diff --git a/web/nms-public.gathering.org/dhcp.html b/web/nms-public.gathering.org/dhcp.html
new file mode 100644
index 0000000..332ea0a
--- /dev/null
+++ b/web/nms-public.gathering.org/dhcp.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>NMS Public - DHCP KART - The Gathering 2013</title>
+<meta http-equiv="refresh" content="5;URL='/dhcp.html'">
+</head>
+<body>
+<img src="nettkart-dhcp.png" alt="DHCP KART" />
+<p>Sist oppdatert: Sun, 31 Mar 2013 16:03:02 +0200
+</body>
+</html>
diff --git a/web/nms-public.gathering.org/dhcpkart.html b/web/nms-public.gathering.org/dhcpkart.html
new file mode 100644
index 0000000..77f7ad5
--- /dev/null
+++ b/web/nms-public.gathering.org/dhcpkart.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <title>DHCP-kart</title>
+ <meta http-equiv="refresh" content="60">
+ </head>
+ <body>
+
+ <p><img src="nettkart-dhcp.png" /></p>
+ </body>
+</html>
diff --git a/web/nms-public.gathering.org/index.html b/web/nms-public.gathering.org/index.html
new file mode 100644
index 0000000..1917fd3
--- /dev/null
+++ b/web/nms-public.gathering.org/index.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<title>NMS Public - The Gathering 2013</title>
+</head>
+
+<body>
+
+<h1>NMS Public - The Gathering 2013</h1>
+
+<h2><a href="dhcp.html">DHCP-kart</a></h2>
+<h2><a href="trafikk.html">Trafikk-kart</a></h2>
+
+</body>
+</html>
+
diff --git a/web/nms-public.gathering.org/led.pl b/web/nms-public.gathering.org/led.pl
new file mode 100644
index 0000000..12b540b
--- /dev/null
+++ b/web/nms-public.gathering.org/led.pl
@@ -0,0 +1,128 @@
+e1-3 on
+e1-4 on
+e3-3 on
+e3-4 on
+e5-3 on
+e5-4 on
+e7-3 on
+e7-4 on
+e9-3 on
+e9-4 on
+e11-1 on
+e11-2 on
+e11-3 on
+e11-4 on
+e13-1 on
+e13-2 on
+e13-3 on
+e13-4 on
+e15-1 on
+e15-2 on
+e15-3 on
+e15-4 on
+e17-1 on
+e17-2 on
+e17-3 on
+e17-4 on
+e19-1 on
+e19-2 on
+e19-3 on
+e19-4 on
+e21-1 on
+e21-2 on
+e21-3 on
+e21-4 on
+e23-1 on
+e23-2 on
+e23-3 on
+e23-4 on
+e25-1 on
+e25-2 on
+e25-3 on
+e25-4 on
+e27-1 on
+e27-2 on
+e29-1 on
+e29-2 on
+e31-1 on
+e31-2 on
+e33-1 on
+e33-2 on
+e35-1 on
+e35-2 on
+e37-1 on
+e37-2 on
+e39-1 on
+e39-2 on
+e41-1 on
+e41-2 on
+e43-1 on
+e43-2 on
+e43-3 on
+e43-4 on
+e45-1 on
+e45-2 on
+e45-3 on
+e45-4 on
+e47-1 on
+e47-2 on
+e47-3 on
+e47-4 on
+e49-1 on
+e49-2 on
+e49-3 on
+e49-4 on
+e51-1 on
+e51-2 on
+e51-3 on
+e51-4 on
+e53-1 on
+e53-2 on
+e53-3 on
+e53-4 on
+e55-1 on
+e55-2 on
+e55-3 on
+e55-4 on
+e57-1 on
+e57-2 on
+e57-3 on
+e57-4 on
+e59-1 on
+e59-2 on
+e59-3 on
+e59-4 on
+e61-1 on
+e61-2 on
+e61-3 on
+e61-4 on
+e63-1 on
+e63-2 on
+e63-3 on
+e63-4 on
+e65-1 on
+e65-2 on
+e65-3 on
+e65-4 on
+e67-1 on
+e67-2 on
+e67-3 on
+e67-4 on
+e69-1 on
+e69-2 on
+e69-3 on
+e69-4 on
+e71-1 on
+e71-2 on
+e71-3 on
+e71-4 on
+e73-1 on
+e73-2 on
+e73-3 on
+e73-4 on
+e75-1 on
+e75-2 on
+e75-3 on
+e75-4 on
+e77-1 on
+e77-2 on
diff --git a/web/nms-public.gathering.org/led.txt b/web/nms-public.gathering.org/led.txt
new file mode 100644
index 0000000..42a189c
--- /dev/null
+++ b/web/nms-public.gathering.org/led.txt
@@ -0,0 +1,256 @@
+e65-4 off
+ap-e47-2 off
+ap-e15-1 off
+e11-4 off
+e69-1 off
+ap-e13-4 off
+ap-e11-3 off
+e23-2 off
+e41-2 off
+e65-1 off
+ap-e25-1 off
+e21-3 off
+e3-3 off
+e45-1 off
+ap-e59-4 off
+ap-e17-3 off
+ap-e69-3 off
+e45-2 off
+e25-2 off
+ap-e61-3 off
+e55-1 off
+ap-e49-2 off
+e5-3 off
+ap-e59-2 off
+e15-3 off
+ap-e49-1 off
+e67-4 off
+e21-1 off
+ap-e13-3 off
+ap-e59-1 off
+e27-1 off
+ap-e43-4 off
+ap-e37-1 off
+e7-3 off
+ap-e77-1 off
+ap-e43-3 off
+ap-e65-4 off
+ap-e23-2 off
+ap-e5-4 off
+e1-3 off
+e63-4 off
+ap-e19-3 off
+ap-e39-1 off
+e53-2 off
+e13-1 off
+ap-e13-1 off
+ap-e63-1 off
+ap-e55-3 off
+e65-2 off
+ap-e73-2 off
+ap-e71-4 off
+ap-e77-2 off
+ap-e63-4 off
+e25-3 off
+ap-e49-4 off
+ap-e43-1 off
+e63-2 off
+e19-2 off
+e61-4 off
+ap-e53-4 off
+e55-4 off
+ap-e69-4 off
+ap-e41-2 off
+e9-4 off
+e43-4 off
+ap-e47-4 off
+ap-e15-4 off
+ap-e17-1 off
+ap-e19-4 off
+ap-e37-2 off
+ap-e67-1 off
+e19-1 off
+ap-e23-1 off
+ap-e29-2 off
+e49-4 off
+ap-e7-3 off
+ap-e65-3 off
+e13-3 off
+e57-3 off
+ap-e25-3 off
+e23-3 off
+e37-2 off
+ap-e1-3 off
+ap-e75-2 off
+e47-4 off
+e21-4 off
+e33-1 off
+ap-e69-2 off
+ap-e17-2 off
+ap-e73-3 off
+ap-e71-3 off
+ap-e25-4 off
+ap-e45-3 off
+e69-2 off
+e13-2 off
+e51-1 off
+ap-e7-4 off
+ap-e9-3 off
+e19-4 off
+e17-4 off
+e61-2 off
+e57-2 off
+ap-e63-3 off
+ap-e45-2 off
+e67-1 off
+ap-e27-1 off
+e51-2 off
+e49-2 off
+ap-e19-1 off
+ap-e47-1 off
+e59-3 off
+ap-e25-2 off
+ap-e65-2 off
+e21-2 off
+e59-4 off
+e39-2 off
+ap-e3-4 off
+e19-3 off
+ap-e29-1 off
+e13-4 off
+ap-e35-1 off
+ap-e75-3 off
+e35-1 off
+ap-e13-2 off
+ap-e57-3 off
+ap-e73-4 off
+e71-2 off
+ap-e71-1 off
+ap-e75-1 off
+e71-1 off
+ap-e41-1 off
+ap-e57-4 off
+e23-1 off
+e77-1 off
+e69-3 off
+e29-1 off
+ap-e49-3 off
+ap-e45-1 off
+e59-1 off
+e73-3 off
+e53-1 off
+ap-e33-2 off
+ap-e47-3 off
+e17-1 off
+e31-1 off
+e55-3 off
+e17-3 off
+ap-e19-2 off
+ap-e61-1 off
+ap-e63-2 off
+ap-e21-3 off
+e75-1 off
+ap-e61-2 off
+ap-e55-1 off
+ap-e33-1 off
+e53-4 off
+e3-4 off
+ap-e9-4 off
+ap-e31-1 off
+e65-3 off
+e75-4 off
+ap-e15-2 off
+ap-e35-2 off
+e51-4 off
+ap-e55-4 off
+e51-3 off
+ap-e21-1 off
+e39-1 off
+e63-1 off
+ap-e57-1 off
+ap-e11-1 off
+e43-2 off
+e75-3 off
+e47-1 off
+e25-4 off
+e71-4 off
+e47-2 off
+e43-3 off
+ap-e15-3 off
+ap-e3-3 off
+ap-e75-4 off
+ap-e43-2 off
+e15-2 off
+ap-e67-3 off
+ap-e59-3 off
+e27-2 off
+e11-1 off
+ap-e23-3 off
+ap-e11-2 off
+ap-e51-2 off
+e55-2 off
+ap-e27-2 off
+ap-e53-2 off
+ap-e11-4 off
+e69-4 off
+e33-2 off
+ap-e57-2 off
+e11-3 off
+e57-1 off
+e37-1 off
+e11-2 off
+e53-3 off
+e67-2 off
+ap-e53-3 off
+e67-3 off
+ap-e71-2 off
+e57-4 off
+e73-4 off
+e73-1 off
+ap-e67-2 off
+e61-3 off
+e29-2 off
+ap-e67-4 off
+e15-1 off
+ap-e53-1 off
+ap-e55-2 off
+ap-e5-3 off
+ap-e51-1 off
+ap-e61-4 off
+ap-e45-4 off
+e35-2 off
+e61-1 off
+e49-1 off
+e43-1 off
+ap-e69-1 off
+ap-e39-2 off
+e45-3 off
+e23-4 off
+e73-2 off
+ap-e23-4 off
+ap-e31-2 off
+e71-3 off
+e15-4 off
+e17-2 off
+e45-4 off
+e47-3 off
+ap-e73-1 off
+e49-3 off
+e63-3 off
+ap-e21-2 off
+ap-e51-4 off
+e7-4 off
+e41-1 off
+ap-e17-4 off
+e1-4 off
+e5-4 off
+ap-e1-4 off
+e59-2 off
+ap-e51-3 off
+ap-e21-4 off
+e25-1 off
+e75-2 off
+e77-2 off
+e31-2 off
+e9-3 off
+ap-e65-1 off
diff --git a/web/nms-public.gathering.org/nettkart-dhcp.png b/web/nms-public.gathering.org/nettkart-dhcp.png
new file mode 100644
index 0000000..d9232de
--- /dev/null
+++ b/web/nms-public.gathering.org/nettkart-dhcp.png
Binary files differ
diff --git a/web/nms-public.gathering.org/nettkart-trafikk.html b/web/nms-public.gathering.org/nettkart-trafikk.html
new file mode 100644
index 0000000..5675473
--- /dev/null
+++ b/web/nms-public.gathering.org/nettkart-trafikk.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <title>nettkart</title>
+ <meta http-equiv="refresh" content="60">
+ </head>
+ <body>
+
+ <p><img src="nettkart-trafikk.png" /></p>
+ </body>
+</html>
diff --git a/web/nms-public.gathering.org/nettkart-trafikk.png b/web/nms-public.gathering.org/nettkart-trafikk.png
new file mode 100644
index 0000000..79661fc
--- /dev/null
+++ b/web/nms-public.gathering.org/nettkart-trafikk.png
Binary files differ
diff --git a/web/nms-public.gathering.org/trafikk.html b/web/nms-public.gathering.org/trafikk.html
new file mode 100644
index 0000000..ee417a8
--- /dev/null
+++ b/web/nms-public.gathering.org/trafikk.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>NMS Public - TRAFIKK KART - The Gathering 2013</title>
+<meta http-equiv="refresh" content="60;URL='/trafikk.html'">
+</head>
+<body>
+<img src="nettkart-trafikk.png" alt="TRAFIKK KART" />
+<p>Sist oppdatert: Sun, 31 Mar 2013 16:03:02 +0200
+</body>
+</html>
diff --git a/web/nms.gathering.org/apkart.pl b/web/nms.gathering.org/apkart.pl
new file mode 100755
index 0000000..a89cb68
--- /dev/null
+++ b/web/nms.gathering.org/apkart.pl
@@ -0,0 +1,89 @@
+#! /usr/bin/perl
+use CGI qw(fatalsToBrowser);
+use GD;
+use DBI;
+use lib '../../include';
+use nms;
+use strict;
+use warnings;
+my $cgi = CGI->new;
+
+#my $greentimeout = 7200;
+my $greentimeout = 15*60;
+my $maxtimeout = $greentimeout*9;
+
+my $dbh = nms::db_connect();
+
+GD::Image->trueColor(1);
+
+my $img = GD::Image->new('bg07.png');
+
+my $blk = $img->colorResolve(0, 0, 0);
+my $red = $img->colorResolve(255, 0, 0);
+my $grn = $img->colorResolve(0, 255, 0);
+my $blu = $img->colorResolve(0, 0, 255);
+
+# Her ska' det bættre skrivas STORT jah!
+my $title = new GD::Image(75,15);
+$img->alphaBlending(1);
+$title->alphaBlending(1);
+my $titlebg = $title->colorResolve(255, 255, 255);
+$title->fill(0,0,$titlebg);
+$title->transparent($titlebg);
+$title->string(gdGiantFont,7,0,"APEKART",$title->colorResolve(255, 0, 0));
+$img->copyResampled($title, 500, 0, 0, 0, 400, 100, 75, 15);
+$img->copyResampled($title, 500, 550, 0, 0, 400, 100, 75, 15);
+
+$img->string(gdMediumBoldFont,0,0,"Access points",$blk);
+$img->string(gdSmallFont,0,20,"Shows if a Cisco access point is plugged into the port",$blk);
+
+my %palette = ( 'notpolled' => $blu, 'missing' => $red, 'present' => $grn );
+
+my @states = qw(present missing notpolled);
+
+for my $i (0..$#states) {
+ my $y = 60 + 20 * (4 - $i);
+ $img->filledRectangle(20, $y, 30, $y + 10, $palette{$states[$i]});
+ $img->rectangle(20, $y, 30, $y + 10, $blk);
+ $img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, $y + 10, $states[$i]);
+}
+
+my $q = $dbh->prepare("select switch,sysname,model,last_poll < now() - '30 seconds'::interval as notpolled,placement from switches natural join placements natural join ap_poll order by zorder");
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ my $sysname = $ref->{'sysname'};
+ my $model = $ref->{'model'};
+ my $state;
+ if ($ref->{'notpolled'}) {
+ $state = 'notpolled';
+ } elsif ($model =~ /^cisco AIR-/) {
+ $state = 'present';
+ } else {
+ $state = 'missing';
+ $sysname .= " $model";
+ }
+ my $clr = $palette{$state};
+
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+ $img->filledRectangle($3,$4,$1,$2,$clr);
+ $img->rectangle($3,$4,$1,$2,$blk);
+
+ my ($x2, $y2, $x1, $y1) = ($1, $2, $3, $4);
+ my $max_textlen = ($x2-$x1) > ($y2-$y1) ? $x2-$x1 : $y2-$y1;
+ while (length($sysname) * 6 > $max_textlen) {
+ # Try to abbreviate sysname if it is too long for the box
+ $sysname =~ s/^(.*)[a-z]~?([0-9]+)$/$1~$2/ or last;
+ }
+ if (($x2-$x1) > ($y2-$y1)) {
+ $img->string(gdSmallFont,$x1+2,$y1,$sysname,$blk);
+ } else {
+ $img->stringUp(gdSmallFont,$x1,$y2-3,$sysname,$blk);
+ }
+}
+$dbh->disconnect;
+
+if (!defined($ARGV[0])) {
+ print $cgi->header(-type=>'image/png',
+ -refresh=>'10; ' . CGI::url());
+}
+print $img->png;
diff --git a/web/nms.gathering.org/bg07.png b/web/nms.gathering.org/bg07.png
new file mode 100644
index 0000000..ec54ad3
--- /dev/null
+++ b/web/nms.gathering.org/bg07.png
Binary files differ
diff --git a/web/nms.gathering.org/dhcpkart.pl b/web/nms.gathering.org/dhcpkart.pl
new file mode 100755
index 0000000..2af4272
--- /dev/null
+++ b/web/nms.gathering.org/dhcpkart.pl
@@ -0,0 +1,94 @@
+#! /usr/bin/perl
+use CGI qw(fatalsToBrowser);
+use GD;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+#my $greentimeout = 7200;
+my $greentimeout = 15*60;
+my $maxtimeout = $greentimeout*9;
+
+my $dbh = nms::db_connect();
+
+GD::Image->trueColor(1);
+my $map = 'bg07.png';
+die "$map does not exist" unless -e $map;
+$img = GD::Image->new($map);
+
+my $blk = $img->colorResolve(0, 0, 0);
+
+$img->string(gdMediumBoldFont,0,0,"DHCP-lease status",$blk);
+$img->string(gdSmallFont,0,20,"Last received DHCP-request",$blk);
+
+# first 1/5: green (<30 min)
+# middle 3/5: yellow -> red (30 min - 6 hours)
+# last 1/5: blue (>6 hours)
+my $grn = $img->colorResolve(0, 255, 0);
+my $blu = $img->colorResolve(0, 0, 255);
+
+my $l1 = 42 + (236 - 42)/5;
+my $l2 = 236 - (236 - 42)/5;
+
+$img->filledRectangle(32, 42, 53, $l1, $grn);
+$img->string(gdSmallFont,56,$l1-8,($greentimeout/60)." min",$blk);
+
+$img->filledRectangle(32, $l2, 53, 237, $blu);
+$img->string(gdSmallFont,56,$l2-5,($maxtimeout/60)." min",$blk);
+
+for my $y ($l1..$l2) {
+ my $i = 1.0 - ($y - $l1) / ($l2 - $l1);
+ my $clr = get_color($i);
+
+ $img->filledRectangle(32,$y,53,$y+1,$clr);
+}
+
+my $q = $dbh->prepare('select switch,sysname,placement,EXTRACT(EPOCH FROM now() - last_ack) as age from switches natural join placements natural join dhcp order by sysname');
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ my $age = $ref->{'age'};
+ if (!defined($age) || $age > $maxtimeout) {
+ $clr = $img->colorResolve(0, 0, 255);
+ } elsif ($age < $greentimeout) {
+ $clr = $img->colorResolve(0, 255, 0);
+ } else {
+ # 30 minutes = 0.0
+ # 6 hours = 1.0
+
+ my $intensity = log($age / $greentimeout) / log($maxtimeout/$greentimeout);
+ $clr = get_color(1.0 - $intensity);
+ }
+
+ my $sysname = $ref->{'sysname'};
+ if ($sysname !~ m/d0/i) { # don't draw distro-switches
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+ $img->filledRectangle($3,$4,$1,$2,$clr);
+ $img->rectangle($3,$4,$1,$2,$blk);
+
+ my ($x2, $y2, $x1, $y1) = ($1, $2, $3, $4);
+ my $max_textlen = ($x2-$x1) > ($y2-$y1) ? $x2-$x1 : $y2-$y1;
+ while (length($sysname) * 6 > $max_textlen) {
+ # Try to abbreviate sysname if it is too long for the box
+ $sysname =~ s/^(.*)[a-z]~?([0-9]+)$/$1~$2/ or last;
+ }
+ if (($x2-$x1) > ($y2-$y1)) {
+ $img->string(gdSmallFont,$x1+2,$y1,$sysname,$blk);
+ } else {
+ $img->stringUp(gdSmallFont,$x1,$y2-3,$sysname,$blk);
+ }
+ }
+}
+$dbh->disconnect;
+
+if (!defined($ARGV[0])) {
+ print $cgi->header(-type=>'image/png',
+ -refresh=>'10; ' . CGI::url());
+}
+print $img->png;
+
+sub get_color {
+ my $intensity = shift;
+ my $gamma = 1.0/1.90;
+ return $img->colorResolve(255.0, 255.0 * ($intensity ** $gamma), 0);
+}
diff --git a/web/nms.gathering.org/index.html b/web/nms.gathering.org/index.html
new file mode 100644
index 0000000..2857377
--- /dev/null
+++ b/web/nms.gathering.org/index.html
@@ -0,0 +1,92 @@
+<html>
+ <head>
+ <title>snmp</title>
+ </head>
+ <body>
+ <p>tg light &amp; magic. :-)</p>
+
+ <ul>
+ <li><a href="dhcpkart.pl">DHCP-kart</a>
+ <br /><i>Oversikt over DHCP-lease etter switch</i>
+ </li>
+
+ <br />
+
+ <li><a href="nettkart-text.pl">Nettkart</a>
+ <br /><i>Trafikkoversikt</i>
+ </li>
+
+ <br />
+
+ <li><a href="nettkart-telnet.pl">Nettkart</a>
+ <br /><i>Trafikkoversikt /m telnetlink</i>
+ </li>
+
+ <br />
+<!-- Kun moderat nyttig når vi har disablet alle webinterfacene...
+ <li><a href="nettkart-web.pl">Nettkart</a>
+ <br /><i>Trafikkoversikt /m weblink</i>
+ </li>
+
+ <br />
+-->
+ <li><a href="portkart.pl">Nettkart, per port</a>
+ <br /><i>Trafikkoversikt per port</i>
+ </li>
+
+ <br />
+
+ <li><a href="uplinkkart.pl">Uplink-kart</a>
+ <br /><i>Hvilke switcher har ikke to uplinker</i>
+ </li>
+
+ <br />
+
+ <li><a href="uplinktrafikkart.pl">Uplink-trafikkart</a>
+ <br /><i>Hvem burde hatt mer enn to uplinker</i>
+ </li>
+
+ <br />
+
+ <li><a href="stromkart.pl">Strømkart</a>
+ <br /><i>Hvilke switcher har færre enn fem tilkoblede klienter</i>
+ </li>
+
+ <br />
+
+ <li><a href="apkart.pl">Aksesspunkt-kart</a>
+ <br /><i>Hvilke aksesspunkter er plugget i</i>
+ </li>
+
+ <br />
+
+ <!--<li><a href="overlay.pl">Overlay-nettkart</a>
+ <br /><i>Teh magic 3D!</i>
+ </li>
+
+ <br /> -->
+
+ <li><a href="smanagement.pl">Kommander switcher</a>
+ <br /><i>Konfigurer switchene</i>
+ </li>
+
+ <br />
+
+ <li><a href="sshow.pl">Utførte og køede kommandoer</a>
+ <br /><i>Se og håndter kommandoer som er utført og fortsatt i køen</i>
+ </li>
+
+ <br />
+
+ <!--<li><a href="stempmap.pl">Temperaturkart</a>
+ <br /><i>Temperaturkart for switchene</i>
+ </li>
+
+ <br /> -->
+
+ <li><a href="mbd-status.pl">MBD-status</a>
+ <br /><i>Hva spiller folk mest?</i>
+ </li>
+ </ul>
+ </body>
+</html>
diff --git a/web/nms.gathering.org/led.pl b/web/nms.gathering.org/led.pl
new file mode 100755
index 0000000..a05041d
--- /dev/null
+++ b/web/nms.gathering.org/led.pl
@@ -0,0 +1,20 @@
+#! /usr/bin/perl
+use CGI;
+use GD;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+
+print $cgi->header(-type=>'text/plain', -expires=>'now');
+
+my $q = $dbh->prepare('select * from ( SELECT switch,sysname,sum(bytes_in) AS bytes_in,sum(bytes_out) AS bytes_out from switches natural left join get_current_datarate() group by switch,sysname) t1 natural join placements order by zorder;');
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ my $sysname = $ref->{'sysname'};
+ next unless $sysname =~ /e\d+-\d+/;
+ printf "%s %s\n", $sysname, (defined($ref->{'bytes_in'}) ? 'on' : 'off');
+}
+$dbh->disconnect;
diff --git a/web/nms.gathering.org/mbd-status.pl b/web/nms.gathering.org/mbd-status.pl
new file mode 100755
index 0000000..d37781f
--- /dev/null
+++ b/web/nms.gathering.org/mbd-status.pl
@@ -0,0 +1,44 @@
+#! /usr/bin/perl
+use CGI;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+print $cgi->header(-type=>'text/html; charset=utf-8', -refresh=>'10; ' . CGI::url());
+
+print <<"EOF";
+<html>
+ <head>
+ <title>MBD status</title>
+ </head>
+ <body>
+ <h1>MBD status</h1>
+
+ <p>Spill søkt etter siste 15 minutter:</p>
+
+ <table>
+ <tr>
+ <th>Beskrivelse</th>
+ <th>Aktive servere</th>
+ </tr>
+EOF
+
+my $q = $dbh->prepare('select description,sum(active_servers) as active_servers from (select distinct on (game,port) * from mbd_log where ts >= now() - \'10 minutes\'::interval order by game,port,ts desc ) t1 group by description order by sum(active_servers) desc, description;');
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ print <<"EOF";
+ <tr>
+ <td>$ref->{'description'}</td>
+ <td>$ref->{'active_servers'}</td>
+ </tr>
+EOF
+}
+$dbh->disconnect;
+
+print <<"EOF";
+ </table>
+ </body>
+</html>
+EOF
diff --git a/web/nms.gathering.org/mygraph.pl b/web/nms.gathering.org/mygraph.pl
new file mode 100755
index 0000000..64104aa
--- /dev/null
+++ b/web/nms.gathering.org/mygraph.pl
@@ -0,0 +1,179 @@
+#! /usr/bin/perl -T
+use strict;
+use warnings;
+use GD;
+use POSIX;
+use Time::Zone;
+
+sub blendpx {
+ my ($gd, $x, $y, $r, $g, $b, $frac) = @_;
+ my ($ro, $go, $bo) = $gd->rgb($gd->getPixel($x, $y));
+
+ # workaround for icky 256-color graphs
+ # $frac = int($frac * 32) / 32;
+
+ my $rn = $ro * (1.0 - $frac) + $r * $frac;
+ my $gn = $go * (1.0 - $frac) + $g * $frac;
+ my $bn = $bo * (1.0 - $frac) + $b * $frac;
+
+ $gd->setPixel($x, $y, $gd->colorResolve($rn, $gn, $bn));
+}
+
+# Standard implementation of Wu's antialiased line algorithm.
+sub wuline {
+ my ($gd, $x1, $y1, $x2, $y2, $r, $g, $b, $a) = @_;
+ $x1 = POSIX::floor($x1);
+ $x2 = POSIX::floor($x2);
+ $y1 = POSIX::floor($y1);
+ $y2 = POSIX::floor($y2);
+
+ if (abs($x2 - $x1) > abs($y2 - $y1)) {
+ # x-directional
+ if ($y2 < $y1) {
+ ($x2, $y2, $x1, $y1) = ($x1, $y1, $x2, $y2);
+ }
+
+ my $y = POSIX::floor($y1);
+ my $frac = $y1 - $y;
+ my $dx = ($x2 > $x1) ? 1 : -1;
+ my $dy = ($y2 - $y1) / abs($x2 - $x1);
+
+ for (my $x = $x1; $x != $x2 + $dx; $x += $dx) {
+ blendpx($gd, $x, $y, $r, $g, $b, $a * (1.0 - $frac));
+ blendpx($gd, $x, $y + 1, $r, $g, $b, $a * $frac);
+ $frac += $dy;
+ if ($frac > 1) {
+ $frac -= 1;
+ ++$y;
+ }
+ }
+ } else {
+ # y-directional
+ if ($x2 < $x1) {
+ ($x2, $y2, $x1, $y1) = ($x1, $y1, $x2, $y2);
+ }
+ my $x = POSIX::floor($x1);
+ my $frac = $x1 - $x;
+ my $dy = ($y2 > $y1) ? 1 : -1;
+ my $dx = ($x2 - $x1) / abs($y2 - $y1);
+
+ for (my $y = $y1; $y != $y2 + $dy; $y += $dy) {
+ blendpx($gd, $x, $y, $r, $g, $b, $a * (1.0 - $frac));
+ blendpx($gd, $x + 1, $y, $r, $g, $b, $a * $frac);
+ $frac += $dx;
+ if ($frac > 1) {
+ $frac -= 1;
+ ++$x;
+ }
+ }
+ }
+}
+
+sub makegraph {
+ my $xoffset = 70;
+ my ($width, $height, $min_x, $max_x, $min_y, $max_y, $tickgran) = @_;
+
+ # Create our base graph
+ my $graph = new GD::Image($width, $height, 1);
+ my $white = $graph->colorAllocate(255, 255, 255);
+ my $gray = $graph->colorAllocate(230, 230, 255);
+ my $black = $graph->colorAllocate(0, 0, 0);
+
+# $graph->fill(0, 0, $white);
+ $graph->filledRectangle(0, 0, $width, $height, $white); # seems to work better
+
+ $::xs = ($width - ($xoffset+2)) / ($max_x - $min_x);
+ $::ys = ($height - 33) / ($min_y - $max_y);
+
+ # Hour marks
+ for my $i ($xoffset+1..$width-2) {
+ if (((($i-($xoffset+1)) / $::xs + $min_x) / 3600) % 2 == 1) {
+ $graph->line($i, 0, $i, $height - 1, $gray);
+ }
+ }
+
+ # Hour text
+ for my $i (0..23) {
+ my @bounds = GD::Image::stringFT(undef, $black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 0, 0, $i);
+ my $w = $bounds[2] - $bounds[0];
+
+ # Determine where the center of this will be
+ my $starthour = POSIX::fmod(($min_x + Time::Zone::tz_local_offset()) / 3600, 24);
+ my $diff = POSIX::fmod($i - $starthour + 24, 24);
+
+ my $center = ($diff * 3600 + 1800) * $::xs;
+
+ next if ($center - $w / 2 < 1 || $center + $w / 2 > $width - ($xoffset+2));
+ $graph->stringFT($black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, $xoffset + $center - $w / 2, $height - 6, $i);
+ }
+
+ #
+ # Y lines; we want max 11 of them (zero-line, plus five on each side, or
+ # whatever) but we don't want the ticks to be on minimum 50 (or
+ # whatever $tickgran is set to). However, if there would be
+ # really really few lines, go down an order of magnitude and try
+ # again.
+ #
+ my $ytick;
+ do {
+ $ytick = ($max_y - $min_y) / 11;
+ $ytick = POSIX::ceil($ytick / $tickgran) * $tickgran;
+ $tickgran *= 0.1;
+ } while (($max_y - $min_y) / $ytick < 4);
+
+ for my $i (-11..11) {
+ my $y = ($i * $ytick - $max_y) * $::ys + 10;
+ next if ($y < 2 || $y > $height - 18);
+
+ if ($i == 0) {
+ wuline($graph, $xoffset, $y, $width - 1, $y, 0, 0, 0, 1.0);
+ wuline($graph, $xoffset, $y + 1, $width - 1, $y + 1, 0, 0, 0, 1.0);
+ } else {
+ wuline($graph, $xoffset, $y, $width - 1, $y, 0, 0, 0, 0.2);
+ }
+
+ # text
+ my $traf = 8 * ($i * $ytick);
+ my $text;
+ if ($traf >= 500_000_000) {
+ $text = (sprintf "%.1f Gbit", ($traf/1_000_000_000));
+ } elsif ($traf >= 500_000) {
+ $text = (sprintf "%.1f Mbit", ($traf/1_000_000));
+ } else {
+ $text = (sprintf "%.1f kbit", ($traf/1_000));
+ }
+
+ my @bounds = GD::Image::stringFT(undef, $black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 0, 0, $text);
+ my $w = $bounds[2] - $bounds[0];
+ my $h = $bounds[1] - $bounds[5];
+
+ next if ($y - $h/2 < 2 || $y + $h/2 > $height - 12);
+ $graph->stringFT($black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, ($xoffset - 4) - $w, $y + $h/2, $text);
+ }
+
+ # Nice border(TM)
+ $graph->rectangle($xoffset, 0, $width - 1, $height - 1, $black);
+
+ return $graph;
+}
+
+sub plotseries {
+ my ($graph, $xvals, $yvals, $r, $g, $b, $min_x, $max_y) = @_;
+ my $xoffset = 70;
+
+ my @xvals = @{$xvals};
+ my @yvals = @{$yvals};
+
+ my $x = $xvals[0];
+ my $y = $yvals[0];
+ for my $i (1..$#xvals) {
+ next if ($::xs * ($xvals[$i] - $x) < 2 && $::ys * ($yvals[$i] - $y) > -2);
+
+ wuline($graph, ($x-$min_x) * $::xs + $xoffset + 1, ($y-$max_y) * $::ys + 10,
+ ($xvals[$i]-$min_x) * $::xs + $xoffset + 1, ($yvals[$i]-$max_y) * $::ys + 10, $r, $g, $b, 1.0);
+ $x = $xvals[$i];
+ $y = $yvals[$i];
+ }
+}
+
+1;
diff --git a/web/nms.gathering.org/nettkart-continuous.html b/web/nms.gathering.org/nettkart-continuous.html
new file mode 100644
index 0000000..e51eea0
--- /dev/null
+++ b/web/nms.gathering.org/nettkart-continuous.html
@@ -0,0 +1,31 @@
+<html>
+ <body>
+ <div id="d"></div>
+ <script type="text/javascript">
+ <!--
+ var existing_img = null;
+
+ function load_new() {
+ var i = document.createElement('img');
+ i.onload = function() { loaded(i); };
+ i.style.display = 'none';
+ i.src = '/nettkart.pl?random=' + (new Date()).getTime();
+ document.getElementById('d').appendChild(i);
+ }
+
+ function loaded(i) {
+ i.style.display = '';
+
+ if (existing_img) {
+ existing_img.parentElement.removeChild(existing_img);
+ }
+ existing_img = i;
+
+ setTimeout(function() { load_new(); }, 10000);
+ }
+
+ load_new();
+ -->
+ </script>
+ </body>
+</html>
diff --git a/web/nms.gathering.org/nettkart-telnet.pl b/web/nms.gathering.org/nettkart-telnet.pl
new file mode 100755
index 0000000..57cac19
--- /dev/null
+++ b/web/nms.gathering.org/nettkart-telnet.pl
@@ -0,0 +1,47 @@
+#! /usr/bin/perl
+use CGI;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+print $cgi->header(-type=>'text/html; charset=utf-8', -refresh=>'45; ' . CGI::url());
+
+print <<"EOF";
+<html>
+ <head>
+ <title>nettkart - telnet</title>
+ </head>
+ <body>
+ <map name="switches">
+EOF
+
+my $q = $dbh->prepare("select * from switches natural join placements where ip <> inet '127.0.0.1'");
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+
+ my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice)
+ my $ttext;
+ if ($traffic >= 1_000_000_000) {
+ $ttext = sprintf "%.2f Gbit/port/sec", $traffic/1_000_000_000;
+ } elsif ($traffic => 1_000_000) {
+ $ttext = sprintf "%.2f Mbit/port/sec", $traffic/1_000_000;
+ } else {
+ $ttext = sprintf "%.2f kbit/port/sec", $traffic/1_000;
+ }
+
+ printf " <area shape=\"rect\" coords=\"%u,%u,%u,%u\" target=\"blank\" href=\"telnet://$ref->{'ip'}\" alt=\"%s (%s)\" onmouseover=\"window.status='%s (%s)'; return true\" onmouseout=\"window.status=''\" />\n",
+ $3, $4, $1, $2, $ref->{'switch'}, $ref->{'sysname'},
+ $ttext, $ref->{'sysname'}, $ttext;
+}
+$dbh->disconnect;
+
+print <<"EOF";
+ </map>
+
+ <p><img src="nettkart.pl" usemap="#switches" /></p>
+ </body>
+</html>
+EOF
diff --git a/web/nms.gathering.org/nettkart-text.pl b/web/nms.gathering.org/nettkart-text.pl
new file mode 100755
index 0000000..d3f4be7
--- /dev/null
+++ b/web/nms.gathering.org/nettkart-text.pl
@@ -0,0 +1,47 @@
+#! /usr/bin/perl
+use CGI;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+print $cgi->header(-type=>'text/html; charset=utf-8', -refresh=>'10; ' . CGI::url());
+
+print <<"EOF";
+<html>
+ <head>
+ <title>nettkart</title>
+ </head>
+ <body>
+ <map name="switches">
+EOF
+
+my $q = $dbh->prepare("select * from switches natural join placements where ip <> inet '127.0.0.1'");
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+
+ my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice)
+ my $ttext;
+ if ($traffic >= 1_000_000_000) {
+ $ttext = sprintf "%.2f Gbit/port/sec", $traffic/1_000_000_000;
+ } elsif ($traffic => 1_000_000) {
+ $ttext = sprintf "%.2f Mbit/port/sec", $traffic/1_000_000;
+ } else {
+ $ttext = sprintf "%.2f kbit/port/sec", $traffic/1_000;
+ }
+
+ printf " <area shape=\"rect\" coords=\"%u,%u,%u,%u\" href=\"showswitch.pl?id=%u\" alt=\"%s (%s)\" onmouseover=\"window.status='%s (%s)'; return true\" onmouseout=\"window.status=''\" />\n",
+ $3, $4, $1, $2, $ref->{'switch'}, $ref->{'sysname'},
+ $ttext, $ref->{'sysname'}, $ttext;
+}
+$dbh->disconnect;
+
+print <<"EOF";
+ </map>
+
+ <p><img src="nettkart.pl" usemap="#switches" /></p>
+ </body>
+</html>
+EOF
diff --git a/web/nms.gathering.org/nettkart-web.pl b/web/nms.gathering.org/nettkart-web.pl
new file mode 100755
index 0000000..ce76c35
--- /dev/null
+++ b/web/nms.gathering.org/nettkart-web.pl
@@ -0,0 +1,47 @@
+#! /usr/bin/perl
+use CGI;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+print $cgi->header(-type=>'text/html; charset=utf-8', -refresh=>'45; ' . CGI::url());
+
+print <<"EOF";
+<html>
+ <head>
+ <title>nettkart - web</title>
+ </head>
+ <body>
+ <map name="switches">
+EOF
+
+my $q = $dbh->prepare("select * from switches natural join placements where ip <> inet '127.0.0.1'");
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+
+ my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice)
+ my $ttext;
+ if ($traffic >= 1_000_000_000) {
+ $ttext = sprintf "%.2f Gbit/port/sec", $traffic/1_000_000_000;
+ } elsif ($traffic => 1_000_000) {
+ $ttext = sprintf "%.2f Mbit/port/sec", $traffic/1_000_000;
+ } else {
+ $ttext = sprintf "%.2f kbit/port/sec", $traffic/1_000;
+ }
+
+ printf " <area shape=\"rect\" coords=\"%u,%u,%u,%u\" href=\"http://$ref->{'ip'}\" alt=\"%s (%s)\" onmouseover=\"window.status='%s (%s)'; return true\" onmouseout=\"window.status=''\" />\n",
+ $3, $4, $1, $2, $ref->{'switch'}, $ref->{'sysname'},
+ $ttext, $ref->{'sysname'}, $ttext;
+}
+$dbh->disconnect;
+
+print <<"EOF";
+ </map>
+
+ <p><img src="nettkart.pl" usemap="#switches" /></p>
+ </body>
+</html>
+EOF
diff --git a/web/nms.gathering.org/nettkart.pl b/web/nms.gathering.org/nettkart.pl
new file mode 100755
index 0000000..b9517f8
--- /dev/null
+++ b/web/nms.gathering.org/nettkart.pl
@@ -0,0 +1,142 @@
+#! /usr/bin/perl
+use CGI;
+use GD;
+use Image::Magick;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+# Sekrit night-mode
+my $night = defined($cgi->param('night'));
+
+my $dbh = nms::db_connect();
+
+GD::Image->trueColor(1);
+my ($img, $text_img);
+
+my $img = GD::Image->new('bg07.png');
+if ($night) {
+ my ($width, $height) = ($img->width, $img->height);
+
+ $img = GD::Image->new($width, $height, 1);
+ $img->alphaBlending(0);
+ $img->saveAlpha(1);
+ my $blank = $img->colorAllocateAlpha(0, 0, 0, 127);
+ $img->filledRectangle(0, 0, $img->width - 1, $img->height - 1, $blank);
+
+ $text_img = GD::Image->new($width, $height, 1);
+ $text_img->alphaBlending(0);
+ $text_img->saveAlpha(1);
+ my $blank = $text_img->colorAllocateAlpha(0, 0, 0, 127);
+ $text_img->filledRectangle(0, 0, $text_img->width - 1, $text_img->height - 1, $blank);
+} else {
+ $img = GD::Image->new('bg07.png');
+ $text_img = $img;
+}
+
+my $blk = $img->colorResolve(0, 0, 0);
+
+for my $y (42..236) {
+ my $i = 4.0 * ($y - 236.0) / (42.0 - 237.0);
+ my $clr = get_color($i);
+
+ $img->filledRectangle(12, $y, 33, $y+1, $clr);
+ $text_img->filledRectangle(12, $y, 33, $y+1, $clr);
+}
+
+$text_img->rectangle(12,42,33,236,$blk);
+
+my $tclr = $night ? $text_img->colorResolve(255, 255, 255) : $blk;
+$text_img->stringFT($tclr, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*0.0/4.0, "100 Gbit/sec");
+$text_img->stringFT($tclr, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*1.0/4.0, "10 Gbit/sec");
+$text_img->stringFT($tclr, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*2.0/4.0, "1 Gbit/sec");
+$text_img->stringFT($tclr, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*3.0/4.0, "100 Mbit/sec");
+$text_img->stringFT($tclr, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*4.0/4.0, "10 Mbit/sec");
+$text_img->stringFT($tclr, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 1000, 700, "NMS (C) 2005-2012 Tech:Server");
+
+my $q = $dbh->prepare("select * from ( SELECT switch,sysname,sum(bytes_in) AS bytes_in,sum(bytes_out) AS bytes_out from switches natural left join get_current_datarate() where ip <> inet '127.0.0.1' group by switch,sysname) t1 natural join placements order by zorder;");
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+
+ # for now:
+ # 10Mbit/switch = green
+ # 100Mbit/switch = yellow
+ # 1Gbit/switch = red
+ # 10Gbit/switch = white
+
+ my $clr;
+
+ if (defined($ref->{'bytes_in'})) {
+ my $intensity = 0.0;
+ my $traffic = 4.0 * ($ref->{'bytes_in'} + $ref->{'bytes_out'}); # average and convert to bits (should be about the same in practice)
+
+ my $max = 100_000_000_000.0; # 100Gbit
+ my $min = 10_000_000.0; # 10Mbit
+ if ($traffic >= $min) {
+ $intensity = log($traffic / $min) / log(10);
+ $intensity = 4.0 if ($intensity > 4.0);
+ }
+ $clr = get_color($intensity);
+ } else {
+ $clr = $img->colorResolve(0, 0, 255);
+ }
+
+ my $sysname = $ref->{'sysname'};
+ $sysname =~ s/-sekrit//;
+
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+ $img->filledRectangle($3,$4,$1,$2,$clr);
+ $text_img->filledRectangle($3,$4,$1,$2,$clr);
+
+ $img->rectangle($3,$4,$1,$2,$blk);
+ $text_img->rectangle($3,$4,$1,$2,$blk);
+ my ($x2, $y2, $x1, $y1) = ($1, $2, $3, $4);
+ my $max_textlen = ($x2-$x1) > ($y2-$y1) ? $x2-$x1 : $y2-$y1;
+ while (length($sysname) * 6 > $max_textlen) {
+ # Try to abbreviate sysname if it is too long for the box
+ $sysname =~ s/^(.*)[a-z]~?([0-9]+)$/$1~$2/ or last;
+ }
+ if (($x2-$x1) > ($y2-$y1)) {
+ $text_img->string(gdSmallFont,$x1+2,$y1,$sysname,$blk);
+ } else {
+ $text_img->stringUp(gdSmallFont,$x1,$y2-3,$sysname,$blk);
+ }
+}
+$dbh->disconnect;
+
+print $cgi->header(-type=>'image/png', -expires=>'now');
+if ($night) {
+ my $magick = Image::Magick->new;
+ $magick->BlobToImage($img->png);
+ $magick->Blur(sigma=>10.0, channel=>'All');
+ $magick->Gamma(gamma=>1.90);
+
+ my $m2 = Image::Magick->new;
+ $m2->Read('bg07.png');
+ $m2->Negate();
+ $m2->Composite(image=>$magick, compose=>'Atop');
+
+ my $m3 = Image::Magick->new;
+ $m3->BlobToImage($text_img->png);
+ $m2->Composite(image=>$m3, compose=>'Atop');
+
+ $img = $m2->ImageToBlob();
+ print $img;
+} else {
+ print $img->png;
+}
+
+sub get_color {
+ my $intensity = shift;
+ my $gamma = 1.0/1.90;
+ if ($intensity > 3.0) {
+ return $img->colorResolve(255.0 * ((4.0 - $intensity) ** $gamma), 255.0 * ((4.0 - $intensity) ** $gamma), 255.0 * ((4.0 - $intensity) ** $gamma));
+ } elsif ($intensity > 2.0) {
+ return $img->colorResolve(255.0, 255.0 * (($intensity - 2.0) ** $gamma), 255.0 * (($intensity - 2.0) ** $gamma));
+ } elsif ($intensity > 1.0) {
+ return $img->colorResolve(255.0, 255.0 * ((2.0 - $intensity) ** $gamma), 0);
+ } else {
+ return $img->colorResolve(255.0 * ($intensity ** $gamma), 255, 0);
+ }
+}
diff --git a/web/nms.gathering.org/portkart.pl b/web/nms.gathering.org/portkart.pl
new file mode 100755
index 0000000..1269173
--- /dev/null
+++ b/web/nms.gathering.org/portkart.pl
@@ -0,0 +1,82 @@
+#! /usr/bin/perl
+use CGI;
+use GD;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+
+GD::Image->trueColor(1);
+$img = GD::Image->new('bg07.png');
+
+my $blk = $img->colorResolve(0, 0, 0);
+
+for my $y (42..236) {
+ my $i = 3.0 * ($y - 236.0) / (42.0 - 237.0);
+ my $clr = get_color($i);
+
+ $img->filledRectangle(12,$y,33,$y+1,$clr);
+}
+
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*0.0/3.0, "1 Gbit/sec");
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*1.0/3.0, "100 Mbit/sec");
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*2.0/3.0, "10 Mbit/sec");
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*3.0/3.0, "1 Mbit/sec");
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 1000, 620, "NMS (C) 2005-2007 Tech:Server");
+
+my $q = $dbh->prepare('select switch,port,bytes_in,bytes_out,placement,switchtype from switches natural join placements natural join get_datarate() where switchtype like \'%3100%\'');
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+
+ # for now:
+ # 100kbit/port = all green
+ # 1gbit/port = all red
+
+ my $clr;
+
+ if (defined($ref->{'bytes_in'})) {
+ my $intensity = 0.0;
+ my $traffic = 4.0 * ($ref->{'bytes_in'} + $ref->{'bytes_out'}); # average and convert to bits (should be about the same in practice)
+
+ my $max = 100_000_000_000.0; # 1Gbit
+ my $min = 1_000_000.0; # 1Mbit
+ if ($traffic >= $min) {
+ $intensity = log($traffic / $min) / log(10);
+ $intensity = 4.0 if ($intensity > 4.0);
+ }
+ $clr = get_color($intensity);
+ } else {
+ $clr = $img->colorResolve(0, 0, 255);
+ }
+
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+ my $npo = 48;
+ my $f = ($ref->{'port'} - 1) % 2;
+ my $po = ($ref->{'port'} - 1 - $f)/2;
+ my $h = 2*($2-$4)/$npo;
+ my $w = ($1-$3)/2;
+
+ $img->filledRectangle($3+$w*$f,$4+$po*$h,$3+$w+$w*$f,$4+$h*($po+1),$clr);
+# $img->rectangle($3+$w*$f,$4+$po*$h,$3+$w+$w*$f,$4+$h*($po+1),$blk);
+ $img->rectangle($3,$4,$1,$2,$blk);
+}
+$dbh->disconnect;
+
+print $cgi->header(-type=>'image/png');
+print $img->png;
+
+sub get_color {
+ my $intensity = shift;
+ my $gamma = 1.0/1.90;
+ if ($intensity > 3.0) {
+ return $img->colorResolve(255.0 * ((4.0 - $intensity) ** $gamma), 255.0 * ((4.0 - $intensity) ** $gamma), 255.0 * ((4.0 - $intensity) ** $gamma));
+ } elsif ($intensity > 2.0) {
+ return $img->colorResolve(255.0, 255.0 * (($intensity - 2.0) ** $gamma), 255.0 * (($intensity - 2.0) ** $gamma));
+ } elsif ($intensity > 1.0) {
+ return $img->colorResolve(255.0, 255.0 * ((2.0 - $intensity) ** $gamma), 0);
+ } else {
+ return $img->colorResolve(255.0 * ($intensity ** $gamma), 255, 0);
+ }
+}
diff --git a/web/nms.gathering.org/showswitch.pl b/web/nms.gathering.org/showswitch.pl
new file mode 100755
index 0000000..5ed0029
--- /dev/null
+++ b/web/nms.gathering.org/showswitch.pl
@@ -0,0 +1,221 @@
+#! /usr/bin/perl
+use CGI;
+use DBI;
+use Time::HiRes;
+use POSIX ":sys_wait_h";
+use strict;
+use warnings;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+my $switch = $cgi->param('id');
+my $width = $cgi->param('width');
+my $height = $cgi->param('height');
+my @pids = ();
+my $resthtml = "";
+
+$width = 500 unless (defined($width));
+$height = 250 unless (defined($height));
+
+require './mygraph.pl';
+
+my $start = [Time::HiRes::gettimeofday];
+my $dbh = nms::db_connect();
+
+# Fetch the name
+my $ref = $dbh->selectrow_hashref('SELECT sysname FROM switches WHERE switch=?', undef, $switch);
+
+print $cgi->header(-type=>'text/html; charset=utf-8');
+print <<"EOF";
+<html>
+ <head>
+ <title>snmp</title>
+ </head>
+ <body>
+ <h1>Switch $switch ($ref->{'sysname'})</h1>
+EOF
+
+my $q = $dbh->prepare('select port,coalesce(description, \'Port \' || port) as description,extract(epoch from time) as time,bytes_in,bytes_out from switches natural left join portnames natural join polls where time between now() - \'1 day\'::interval and now() and switch=? order by switch,port,time;') or die $dbh->errstr;
+$q->execute($switch) or die $dbh->errstr;
+
+my (@totx, @toty1, @toty2) = ();
+
+my (@x, @y1, @y2) = ();
+my $last_port = -1;
+my $portname = "";
+my $min_x = time;
+my $max_x = time - 86400;
+my ($min_y, $max_y, $prev_time, $prev_in, $prev_out);
+my ($if,$of,$ifv,$ofv);
+my $idx;
+my ($min_ty,$max_ty) = (0, 10_000_000/8);
+
+$prev_time = -1;
+my $last_totx;
+while (my $ref = $q->fetchrow_hashref()) {
+ my $time = $ref->{'time'};
+ my $in = $ref->{'bytes_in'};
+ my $out = $ref->{'bytes_out'};
+ next if ($time == $prev_time);
+
+ if ($ref->{'port'} != $last_port) {
+ if ($last_port != -1) {
+ my $filename = "$switch-$last_port-$width-$height.png";
+
+ # reap children
+ waitpid(-1, WNOHANG);
+
+ my $pid = fork();
+ if ($pid == 0) {
+# write out the graph
+ my $graph = makegraph($width, $height, $min_x, $max_x, $min_y, $max_y, 5);
+ plotseries($graph, \@x, \@y1, 255, 0, 0, $min_x, $max_y);
+ plotseries($graph, \@x, \@y2, 0, 0, 255, $min_x, $max_y);
+
+ open GRAPH, ">img/$filename"
+ or die "img/$filename: $!";
+ print GRAPH $graph->png;
+ close GRAPH;
+ exit;
+ }
+
+ push @pids, $pid;
+
+ $resthtml .= "<div style=\"float: left;\"><h2>$portname</h2>\n";
+ $resthtml .= "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
+ }
+
+ # Reset all the variables
+ @x = ();
+ @y1 = ();
+ @y2 = ();
+ ($min_y,$max_y) = (0, 10_000_000/8);
+ $prev_time = $ref->{'time'};
+ $prev_in = $ref->{'bytes_in'};
+ $prev_out = $ref->{'bytes_out'};
+ $last_port = $ref->{'port'};
+ $portname = $ref->{'description'};
+ ($if,$of,$ifv,$ofv) = (0,0,0,0);
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+ $idx = 0;
+ $last_totx = undef;
+ next;
+ }
+
+ # Assume overflow (unless the switch has been down for >10 minutes)
+ my ($calc_in, $calc_out) = ($in, $out);
+ if ($in < $prev_in || $out < $prev_out) {
+ if ($prev_in < 4294967296 && $prev_out < 4294967296) {
+ # ick, heuristics
+ if ($prev_time - $time > 600 || ($in + 4294967296 - $prev_in) > 2147483648 || ($out + 4294967296 - $prev_out) > 2147483648) {
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+ next;
+ }
+
+ $calc_in += 4294967296 if ($in < $prev_in);
+ $calc_out += 4294967296 if ($out < $prev_out);
+ } else {
+ $prev_in = 0;
+ $prev_out = 0;
+ }
+ }
+
+ # Remove dupes
+ if ($in == $prev_in && $out == $prev_out) {
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+ next;
+ }
+
+ # Find the current flow
+ my $if = ($calc_in - $prev_in) / ($time - $prev_time);
+ my $of = ($calc_out - $prev_out) / ($time - $prev_time);
+
+ # Summarize (we don't care about the summed variance for now)
+ $min_x = $time if (!defined($min_x) || $time < $min_x);
+ $max_x = $time if (!defined($max_x) || $time > $max_x);
+ $min_y = $if if (!defined($min_y) || $if < $min_y);
+ $min_y = $of if ($of < $min_y);
+ $max_y = $if if (!defined($max_y) || $if > $max_y);
+ $max_y = $of if ($of > $max_y);
+
+ my $pt = 0.5 * ($time + $prev_time);
+
+ push @x, $pt;
+ push @y1, $if;
+ push @y2, $of;
+
+ while ($idx < $#totx && $pt > $totx[$idx]) {
+ ++$idx;
+ }
+ if ($idx >= $#totx) {
+ push @totx, $pt;
+ push @toty1, $if;
+ push @toty2, $of;
+ ++$idx;
+
+ $min_ty = $if if (!defined($min_ty) || $if < $min_ty);
+ $min_ty = $of if ($of < $min_ty);
+ $max_ty = $if if (!defined($max_ty) || $if > $max_ty);
+ $max_ty = $of if ($of > $max_ty);
+ } else {
+ if (!defined($last_totx) || $last_totx != $idx) {
+ $toty1[$idx] += $if;
+ $toty2[$idx] += $of;
+ }
+ $last_totx = $idx;
+
+ $min_ty = $toty1[$idx] if (!defined($min_ty) || $toty1[$idx] < $min_ty);
+ $min_ty = $toty2[$idx] if ($toty2[$idx] < $min_ty);
+ $max_ty = $toty1[$idx] if (!defined($max_ty) || $toty1[$idx] > $max_ty);
+ $max_ty = $toty2[$idx] if ($toty2[$idx] > $max_ty);
+ }
+
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+}
+$dbh->disconnect;
+
+# last graph
+my $filename = "$switch-$last_port-$width-$height.png";
+
+my $pid = fork();
+if ($pid == 0) {
+ my $graph = makegraph($width, $height, $min_x, $max_x, $min_y, $max_y, 5);
+ plotseries($graph, \@x, \@y1, 255, 0, 0, $min_x, $max_y);
+ plotseries($graph, \@x, \@y2, 0, 0, 255, $min_x, $max_y);
+
+ open GRAPH, ">img/$filename"
+ or die "img/$filename: $!";
+ print GRAPH $graph->png;
+ close GRAPH;
+ exit;
+}
+
+push @pids, $pid;
+
+$resthtml .= "<div style=\"float: left;\"><h2>$portname</h2>\n";
+$resthtml .= "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
+
+# total graph
+my $graph = makegraph($width, $height, $min_x, $max_x, $min_ty, $max_ty, 5);
+plotseries($graph, \@totx, \@toty1, 255, 0, 0, $min_x, $max_ty);
+plotseries($graph, \@totx, \@toty2, 0, 0, 255, $min_x, $max_ty);
+
+$filename = "$switch-$width-$height.png";
+open GRAPH, ">img/$filename" or die "img/$filename: $!";
+print GRAPH $graph->png;
+close GRAPH;
+
+
+# Wait for all the other graphs to be done
+while (waitpid(-1, 0) != -1) {
+ 1;
+}
+
+print $resthtml;
+
+print "<div style=\"float: left;\"><h2>Total</h2>\n";
+print "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
+
+my $elapsed = Time::HiRes::tv_interval($start);
+printf "<p style=\"clear: both;\">Page and all graphs generated in %.2f seconds.</p>\n", $elapsed;
+print "</body>\n</html>\n";
diff --git a/web/nms.gathering.org/slide.html b/web/nms.gathering.org/slide.html
new file mode 100644
index 0000000..046020d
--- /dev/null
+++ b/web/nms.gathering.org/slide.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <body>
+ <iframe id="tgview" style="border: 0; width: 1536px; height: 864px"></iframe>
+
+ <script>
+ (function() {
+ var urls = [
+ 'http://onlineclock.net/',
+ 'http://nms.tg13.gathering.org/dhcpkart.pl',
+ 'http://nms.tg13.gathering.org/nettkart-text.pl',
+ 'http://nms.tg13.gathering.org/nettkart-text.pl',
+ 'http://nms.tg13.gathering.org/uplinkkart.pl',
+ 'http://nms.tg13.gathering.org/uplinktrafikkart.pl',
+ 'http://nms.tg13.gathering.org/apkart.pl',
+ 'http://stats.tg13.gathering.org/'
+ ];
+
+ var view = document.getElementById('tgview');
+ var fload = function( frame, url ) {
+ frame.src = url;
+ };
+
+ var i = 0;
+ (function rotation() {
+ //if ( i != l-1 ) {
+ if ( i != urls.length-1 ) {
+ i++
+ } else {
+ i = 0;
+ }
+ fload( view, urls[i] );
+ setTimeout( arguments.callee, 10000 );
+ })();
+ })();
+ </script>
+ </body>
+</html>
diff --git a/web/nms.gathering.org/smanagement.pl b/web/nms.gathering.org/smanagement.pl
new file mode 100755
index 0000000..c01c52d
--- /dev/null
+++ b/web/nms.gathering.org/smanagement.pl
@@ -0,0 +1,239 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use CGI;
+use DBI;
+use Data::Dumper;
+use Switch;
+use lib '../../include';
+use nms;
+
+# Grab from .htaccess-authentication
+my $user = $ENV{'REMOTE_USER'};
+
+my $dbh = nms::db_connect();
+$dbh->{AutoCommit} = 0;
+
+# Ugly casting, found no other way
+my $sinsert = $dbh->prepare( "INSERT INTO squeue
+ (gid, added, priority, addr, sysname, cmd, author)
+ VALUES(?::text::int, timeofday()::timestamptz, ?::text::int, ?::text::inet, ?, ?, ?)")
+ or die "Could not prepare sinsert";
+my $sgetip = $dbh->prepare("SELECT ip FROM switches WHERE sysname = ?")
+ or die "Could not prepare sgetip";
+my $sgid = $dbh->prepare("SELECT nextval('squeue_group_sequence') as gid");
+my $all_switches = $dbh->prepare("SELECT sysname FROM switches ORDER BY sysname");
+
+sub parse_range($) {
+ my $switches = $_;
+ my @range;
+
+ my @rangecomma = split(/\s*,\s*/, $switches);
+ foreach (@rangecomma) {
+ my ($first, $last) = $_ =~ /(e\d+\-(?:sw)?[123456])\s*\-\s*(e\d+\-(?:sw)?[123456])?/;
+ if (!defined($first) && $_ =~ /e\d+\-(sw)?[123456]/) {
+ $first = $_;
+ }
+ if (!defined($first)) {
+ print "<font color=\"red\">Parse error in: $_</font><br>\n";
+ next;
+ }
+ my ($rowstart, $placestart) = $first =~ /e(\d+)\-(?:sw)?([123456])/;
+ if (!defined($rowstart) || !defined($placestart)) {
+ print "<font color=\"red\">Parse error in: $_</font><br>\n";
+ next;
+ }
+ my ($rowend, $placeend);
+ if (!defined($last)) {
+ $rowend = $rowstart;
+ $placeend = $placestart;
+ }
+ else {
+ ($rowend, $placeend) = $last =~ /e(\d+)\-(?:sw)?([123456])/;
+ }
+ if (!defined($rowend) || !defined($placeend)) {
+ print "<font color=\"red\">Parse error in: $_</font><br>\n";
+ next;
+ }
+ #print "e $rowstart - $placestart to e $rowend - $placeend <br>\n";
+ for (my $i = $rowstart; $i <= $rowend; $i++) {
+ my $dostart;
+ if ($rowstart != $i) {
+ $dostart = 1;
+ }
+ else {
+ $dostart = $placestart;
+ }
+ for (my $j = $dostart; $j <= 6; $j++) {
+ last if ($i == $rowend && $j > $placeend);
+ push(@range, "e$i-$j");
+ }
+ }
+ }
+# foreach (@range) {
+# print ":: $_<br>\n";
+# }
+ return @range;
+}
+
+sub get_addr_from_switchnum($) {
+ my ($sysname) = @_;
+
+ $sgetip->execute($sysname);
+ if ($sgetip->rows() < 1) {
+ print "Could not get the ip for: ".$sysname;
+ return undef;
+ }
+ my $row = $sgetip->fetchrow_hashref();
+ return $row->{'ip'};
+}
+
+my $cgi = new CGI;
+
+print $cgi->header(-type=>'text/html; charset=utf-8');
+
+print << "EOF";
+<html>
+ <head>
+ <title>Switch managment</title>
+ </head>
+ <body>
+ <p>Du er logget inn som: $user</p>
+ <form method="POST" action="smanagement.pl">
+ <table>
+ <tr>
+ <td>Alle switchene</td>
+ <td><input type="radio" name="rangetype" value="all" /></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>Switch</td>
+ <td><input type="radio" checked name="rangetype" value="switch" /></td>
+ <td><input type="text" name="range" /></td>
+ <td>e1-2, e3-3 - e10-2</td>
+ </tr>
+ <tr>
+ <td>Regexp</td>
+ <td><input type="radio" name="rangetype" value="regexp" /></td>
+ <td><input type="text" name="regexp" /></td>
+ <td>Regulært uttrykk</td>
+ </tr>
+ <tr>
+ <td>Rad</td>
+ <td><input type="radio" name="rangetype" value="row" /></td>
+ <td><input type="text" name="range" /></td>
+ <td>1,3-5 (Disabled)</td>
+ </tr>
+ <tr>
+ <td><hr /></td>
+ <td><hr /></td>
+ <td><hr /></td>
+ <td><hr /></td>
+ </tr>
+ <tr>
+ <td>Prioritet</td>
+ <td></td>
+ <td>
+ <select name="priority">
+ <option value="1">1 (lavest)</option>
+ <option value="2">2</option>
+ <option selected value="3">3</option>
+ <option value="4">4</option>
+ <option value="5">5 (høyest)</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>Kommando(er):</td>
+ <td></td>
+ <td><textarea name="cmd" cols="80" rows="24"></textarea></td>
+ <td>En kommando per linje. Linjer som begynner med ! sørger for at nms ikke venter på normal prompt, men fyrer av gårde neste linje umiddelbart. Kjekt for kommandoer av typen "!save\\nY"</td>
+ </td>
+ <tr>
+ <td><hr /></td>
+ <td><hr /></td>
+ <td><hr /></td>
+ <td><hr /></td>
+ </tr>
+ </table>
+ <input type="submit" value="Execute!" /><br />
+ </form>
+EOF
+
+print "<br />\n";
+
+my @switches = ();
+switch ($cgi->param('rangetype')) {
+ case 'all' {
+ print "Sender `".$cgi->param('cmd')."` til alle switchene<br />";
+ @switches = ();
+ $all_switches->execute();
+ while (my $ref = $all_switches->fetchrow_hashref) {
+ push @switches, $ref->{'sysname'};
+ }
+ }
+ case 'switch' {
+# print "Sender `".$cgi->param('cmd')."` til switchene `"
+# .$cgi->param('range')."`.<br />";
+ $_ = $cgi->param('range');
+ @switches = parse_range($_);
+ }
+ case 'regexp' {
+ @switches = ();
+ $all_switches->execute();
+ while (my $ref = $all_switches->fetchrow_hashref) {
+ push @switches, $ref->{'sysname'} if $ref->{'sysname'} =~ $cgi->param('regexp');
+ }
+ }
+ case 'row' {
+# print "Sender `".$cgi->param('cmd')."` til radene `"
+# .$cgi->param('range')."`.<br />";
+# print "This function does not work yet.";
+# $_ = $cgi->param('range');
+# @switches = &parse_row_range($_);
+# @switches = ();
+ print "<font color=\"red\">Slått av!</font>\n";
+ }
+}
+
+my $gid;
+if (@switches > 0) {
+ $sgid->execute();
+ my $row = $sgid->fetchrow_hashref();
+ $gid = $row->{gid};
+}
+
+my $pri = $cgi->param('priority');
+
+print "<pre>\n";
+foreach my $switch (@switches) {
+ my $addr = get_addr_from_switchnum($switch);
+ if (!defined($addr)) {
+ next;
+ }
+ my $cmd = $cgi->param('cmd');
+ print "$switch got addr $addr <br>\n";
+ print "Queuing commands for $switch:\n";
+ my $result = $sinsert->execute($gid, $pri, $addr, $switch, $cmd, $user);
+ if (!$result) {
+ print "\t<font color=\"red\">"
+ ."Could not execute query."
+ ."</font>\n";
+ print "\t".$dbh->errstr."\n";
+ }
+ else {
+ print "\tQueued: $cmd\n";
+ }
+ print "\n";
+}
+$dbh->commit;
+if (defined($gid)) {
+ print "<a href=\"sshow.pl?action=showgid&gid=".$gid."\">Vis resultat</a>\n";
+}
+print "</pre>\n";
+
+print << "EOF";
+ </body>
+</html>
+EOF
diff --git a/web/nms.gathering.org/ssendfile.pl b/web/nms.gathering.org/ssendfile.pl
new file mode 100755
index 0000000..ec2ebb8
--- /dev/null
+++ b/web/nms.gathering.org/ssendfile.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use lib '../../include';
+use POSIX;
+
+my $delaytime = 30;
+my $poll_frequency = 60;
+
+sub mylog {
+ my $msg = shift;
+ my $time = POSIX::ctime(time);
+ $time =~ s/\n.*$//;
+ printf STDERR "[%s] %s\n", $time, $msg;
+}
+
+if ($#ARGV != 1) {
+ die("Error in arguments passed\n".
+ "./ssendfile.pl addr configfile\n");
+}
+
+my $conn = nms::switch_connect($ARGV[0]);
+if (!defined($conn)) {
+ die("Could not connect to switch.\n");
+}
+
+open(CONFIG, $ARGV[1]);
+while (<CONFIG>) {
+ my $cmd = $_;
+ $cmd =~ s/[\r\n]+//g;
+ print "Executing: `$cmd`\n";
+# if ($cmd =~ /ip ifconfig swif0 (\d{1-3}\.\d{1-3}\.\d{1-3}\.\d{1-3})/) {
+# print "New ip: $1\n";
+# $conn->cmd( String => $cmd,
+# Timeout => 3);
+# $conn = nms::switch_connect($1);
+# if (!defined($conn)) {
+# die "Could not connect to new ip: $1\n";
+# }
+# }
+# else {
+ my @data = nms::switch_exec($cmd, $conn);
+ foreach my $line (@data) {
+ $line =~ s/[\r\n]+//g;
+ print "$line\n";
+ }
+# }
+}
diff --git a/web/nms.gathering.org/sshow.pl b/web/nms.gathering.org/sshow.pl
new file mode 100755
index 0000000..f406b69
--- /dev/null
+++ b/web/nms.gathering.org/sshow.pl
@@ -0,0 +1,257 @@
+#!/usr/bin/perl
+use lib '../../include';
+use nms;
+
+use warnings;
+use strict;
+use Switch;
+use CGI;
+use DBI;
+
+# Grab from .htaccess-authentication
+my $user = $ENV{'REMOTE_USER'};
+
+my $dbh = nms::db_connect();
+$dbh->{AutoCommit} = 0;
+
+my $sgetdone = $dbh->prepare(
+"SELECT *
+FROM squeue
+WHERE processed = 't'
+ORDER BY updated DESC, sysname
+LIMIT ?::text::int")
+ or die "Could not prepare sgetdone";
+
+my $sgetdonegid = $dbh->prepare(
+"SELECT *
+FROM squeue
+WHERE processed = 't' AND gid = ?::text::int
+ORDER BY updated DESC, sysname")
+ or die "Could not prepare sgetdonegid";
+
+my $slistdonegid = $dbh->prepare(
+"SELECT DISTINCT gid, cmd, author, added
+FROM squeue
+WHERE processed = 't'
+ORDER BY gid")
+ or die "Could not prepare slistdonegid";
+
+my $slistprocgid = $dbh->prepare(
+"SELECT DISTINCT gid, cmd, author, added
+FROM squeue
+WHERE processed = 'f'
+ORDER BY gid")
+ or die "Could not prepare slistdonegid";
+
+my $sgetgid = $dbh->prepare(
+"SELECT *
+FROM squeue
+WHERE gid = ?")
+ or die "Could not prepare sgetgid";
+
+my $sgetprocessing = $dbh->prepare(
+"SELECT *
+FROM squeue
+WHERE processed = 'f'
+ORDER BY updated DESC, gid, sysname")
+ or die "Could not prepare sgetdone";
+
+my $sgetnoconnect = $dbh->prepare(
+"SELECT *
+FROM squeue
+WHERE result = 'Could not connect to switch, delaying...'")
+ or die "Could not prepare sgetnoconnect";
+
+my $sdisablegid = $dbh->prepare("
+UPDATE squeue SET disabled = 't'
+WHERE gid = ?::text::int")
+ or die "Could not prepare sdisablegid";
+my $senablegid = $dbh->prepare("
+UPDATE squeue SET disabled = 'f'
+WHERE gid = ?::text::int")
+ or die "Could not prepare sdisablegid";
+
+
+my $cgi = new CGI;
+
+print $cgi->header(-type=>'text/html; charset=utf-8');
+
+print << "EOF";
+<html>
+ <head>
+ <title>Switch managment</title>
+ </head>
+ <body>
+ <p>Du er logget inn som: $user</p>
+ <form method="POST" action="sshow.pl">
+ <p>
+ Vis <input type="text" name="count" size="4" value="10" /> siste<br />
+ Vis: <select name="action" />
+ <option value="listgid">Grupper</option>
+ <option value="done">Ferdige</option>
+ <option value="processing">I kø</option>
+ </select>
+ <input type="submit" value="Vis" /><br />
+ </p>
+ </form>
+ <br />
+EOF
+
+my $limit = $cgi->param('count');
+if (!defined($limit)) {
+ $limit = 10;
+}
+my $action = $cgi->param('action');
+if (!defined($action)) {
+ $action = 'listgid';
+}
+
+if (defined($cgi->param('agid'))) {
+ my $gid = $cgi->param('gid');
+ if (!defined($gid)) {
+ print "<font color=\"red\">Du har ikke valgt en gid å slette.</font>\n";
+ print "<p>gid: ".$cgi->param('gid')." har blitt disablet.\n";
+ }
+ else {
+ $senablegid->execute($gid);
+ print "<p>gid: ".$cgi->param('gid')." har blitt enablet.\n";
+ }
+ $dbh->commit();
+}
+
+if ($action eq 'noconnect') {
+ print "<h3>Kunne ikke koble til disse switchene:</h3>\n";
+ $sgetnoconnect->execute();
+ print "<pre>\n";
+ while ((my $row = $sgetnoconnect->fetchrow_hashref())) {
+ print "$row->{'sysname'} : $row->{'cmd'} : Added: $row->{'added'} : Updated: $row->{'updated'}\n";
+ }
+ print "</pre>\n";
+}
+
+if ($action eq 'listgid') {
+ print "<pre>\n";
+ print "<a href=\"sshow.pl?action=noconnect\" />Kunne ikke koble til</a>\n\n\n";
+ print "<b>Ferdige:</b>\n";
+ $slistdonegid->execute();
+ my ($gid, $author);
+ $gid = -1;
+ while ((my $row = $slistdonegid->fetchrow_hashref())) {
+ $author = $row->{author};
+ if ($gid != $row->{gid}) {
+ $gid = $row->{gid};
+ print "GID: <a href=\"sshow.pl?action=showgid&gid=$gid\">$gid</a>\n";
+ print "Author: $author\n";
+ print "Added: ".$row->{added}."\n";
+ }
+ my $cmd = $row->{cmd};
+ print "\t$cmd\n";
+ }
+ print "\n\n";
+ print "<b>I kø:</b>\n";
+ $slistprocgid->execute();
+ $gid = -1;
+ while ((my $row = $slistprocgid->fetchrow_hashref())) {
+ $author = $row->{author};
+ if ($gid != $row->{gid}) {
+ $gid = $row->{gid};
+ print "GID: <a href=\"sshow.pl?action=showgid&gid=$gid\">$gid</a>\n";
+ print "Author: $author\n";
+ print "Added: ".$row->{added}."\n";
+ }
+ my $cmd = $row->{cmd};
+ print "\t$cmd\n";
+ }
+ $dbh->commit();
+ print "</pre>\n";
+}
+
+if ($action eq 'showgid') {
+ print "<pre>\n";
+ $sgetgid->execute($cgi->param('gid'));
+ my $row = $sgetgid->fetchrow_hashref();
+ print "GID: ".$row->{gid}."\n";
+ print "Author: ".$row->{author}."\n";
+ do {
+ print " <b>Name: ".$row->{sysname}." Addr: ".$row->{addr}."</b>\n";
+ print " `<b>".$row->{cmd}."`</b>\n";
+ print " <i>Added: ".$row->{added}." executed ".$row->{updated}."</i>\n";
+ my $data = $row->{result};
+ if (!defined($data)) {
+ $data = "Not executed yet!";
+ }
+ my @lines = split(/[\n\r]+/, $data);
+ foreach my $line (@lines) {
+ print "\t$line\n";
+ }
+ } while (($row = $sgetgid->fetchrow_hashref()));
+ print "</pre>\n";
+}
+
+if ($action eq 'done') {
+ print "<h3>Done</h3>\n";
+ print "<pre>\n";
+
+ my $squery;
+ if (defined($cgi->param('gid'))) {
+ my $gid = $cgi->param('gid');
+ $sgetdonegid->execute($gid);
+ $squery = $sgetdonegid;
+ }
+ else {
+ $sgetdone->execute($limit);
+ $squery = $sgetdone;
+ }
+ my $sysname = '';
+ while (my $row = $squery->fetchrow_hashref()) {
+ if ($sysname ne $row->{'sysname'}) {
+ $sysname = $row->{'sysname'};
+ print "$sysname (".$row->{addr}."):\n";
+ }
+ print " Author: ".$row->{author}."\n";
+ print " Cmd: ".$row->{cmd}."\n";
+ print " Added: ".$row->{added}." Updated: ".$row->{updated}."\n";
+ print " gID: ".$row->{gid}."\n";
+ my @result = split(/[\n\r]+/, $row->{result});
+ foreach (@result) {
+ print "\t".$_."\n";
+ }
+ print "\n";
+ }
+ $dbh->commit();
+ print "</pre>\n";
+}
+elsif ($action eq 'processing') {
+ print "<h3>Processing</h3>\n";
+ print "<pre>\n";
+ $sgetprocessing->execute();
+ while (my $row = $sgetprocessing->fetchrow_hashref()) {
+ my $sysname = $row->{'sysname'};
+ print "$sysname (".$row->{addr}."):\n";
+ print " Author: ".$row->{author}."\n";
+ print " Cmd: ".$row->{cmd}."\n";
+ my $updated;
+ if (defined($row->{updated})) { $updated = $row->{updated}; }
+ else { $updated = 'never'; }
+ print " Added: ".$row->{added}." Updated: ".$updated."\n";
+ print " Disabled: ".$row->{disabled}."\n";
+ print " Locked: ".$row->{locked}."\n";
+ print " gID: ".$row->{gid};
+ print " <form action=\"sshow.pl\" methos=\"POST\">";
+ print "<input type=\"hidden\" name=\"gid\" value=\"".$row->{gid}."\">";
+ print "<input type=\"hidden\" name=\"action\" value=\"processing\">";
+ if ($row->{disabled} == 0) {
+ print "<input type=\"submit\" name=\"agid\" value=\"Disable\">\n";
+ }
+ else {
+ print "<input type=\"submit\" name=\"agid\" value=\"Enable\">\n";
+ }
+ }
+ $dbh->commit();
+ print "</pre>\n";
+}
+
+print << "EOF";
+ </body>
+</html>
+EOF
diff --git a/web/nms.gathering.org/stromkart.pl b/web/nms.gathering.org/stromkart.pl
new file mode 100755
index 0000000..0aef634
--- /dev/null
+++ b/web/nms.gathering.org/stromkart.pl
@@ -0,0 +1,69 @@
+#! /usr/bin/perl
+use CGI qw(fatalsToBrowser);
+use GD;
+use DBI;
+use lib '../../include';
+use nms;
+use strict;
+use warnings;
+my $cgi = CGI->new;
+
+#my $greentimeout = 7200;
+my $greentimeout = 15*60;
+my $maxtimeout = $greentimeout*9;
+
+my $dbh = nms::db_connect();
+
+GD::Image->trueColor(1);
+my $img = GD::Image->new('bg07.png');
+
+my $blk = $img->colorResolve(0, 0, 0);
+
+$img->string(gdMediumBoldFont,0,0,"Switch uplink status",$blk);
+$img->string(gdSmallFont,0,20,"Number of ports with activity",$blk);
+
+my $red = $img->colorResolve(255, 0, 0);
+my $yel = $img->colorResolve(255, 255, 0);
+my $grn = $img->colorResolve(0, 255, 0);
+my $wht = $img->colorResolve(255, 255, 255);
+my $gry = $img->colorResolve(127, 127, 127);
+
+my $q = $dbh->prepare('select switch,sysname,(select placement from placements where placements.switch=switches.switch) as placement,count((bytes_in > 0 and bytes_out > 0) or null) as active_ports,(max(last_poll_time) >= current_timestamp - interval \'2 minutes\') as fresh from switches natural left join get_current_datarate() natural join placements where switchtype like \'dlink3100%\' group by switch,sysname');
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ my $ports = $ref->{'active_ports'};
+ my $sysname = $ref->{'sysname'};
+ my $clr;
+ if ($ports < 5) {
+ $clr = $red;
+ } else {
+ if (!$ref->{'fresh'}) {
+ $clr = $yel;
+ } else {
+ $clr = $grn;
+ }
+ }
+
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+ $img->filledRectangle($3,$4,$1,$2,$clr);
+ $img->rectangle($3,$4,$1,$2,$blk);
+
+ my ($x2, $y2, $x1, $y1) = ($1, $2, $3, $4);
+ my $max_textlen = ($x2-$x1) > ($y2-$y1) ? $x2-$x1 : $y2-$y1;
+ while (length($sysname) * 6 > $max_textlen) {
+ # Try to abbreviate sysname if it is too long for the box
+ $sysname =~ s/^(.*)[a-z]~?([0-9]+)$/$1~$2/ or last;
+ }
+ if (($x2-$x1) > ($y2-$y1)) {
+ $img->string(gdSmallFont,$x1+2,$y1,$sysname,$blk);
+ } else {
+ $img->stringUp(gdSmallFont,$x1,$y2-3,$sysname,$blk);
+ }
+}
+$dbh->disconnect;
+
+if (!defined($ARGV[0])) {
+ print $cgi->header(-type=>'image/png',
+ -refresh=>'10; ' . CGI::url());
+}
+print $img->png;
diff --git a/web/nms.gathering.org/uplinkkart-text.pl b/web/nms.gathering.org/uplinkkart-text.pl
new file mode 100755
index 0000000..de91e92
--- /dev/null
+++ b/web/nms.gathering.org/uplinkkart-text.pl
@@ -0,0 +1,38 @@
+#! /usr/bin/perl
+use CGI;
+use DBI;
+use lib '../../include';
+use nms;
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+print $cgi->header(-type=>'text/html; charset=utf-8', -refresh=>'10; ' . CGI::url());
+
+print <<"EOF";
+<html>
+ <head>
+ <title>Uplinkkart</title>
+ </head>
+ <body>
+ <map name="switches">
+EOF
+
+my $q = $dbh->prepare("SELECT * FROM switches NATURAL JOIN placements WHERE switchtype = 'dlink3100'");
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+
+ my $ttext = 'FIXME: Put something here';
+ printf " <area shape=\"rect\" coords=\"%u,%u,%u,%u\" href=\"switchdiag.pl?id=%u\" alt=\"%s (%s)\" onmouseover=\"window.status='%s (%s)'; return true\" onmouseout=\"window.status=''\" />\n",
+ $3, $4, $1, $2, $ref->{'switch'}, $ref->{'sysname'},
+ $ttext, $ref->{'sysname'}, $ttext;
+}
+$dbh->disconnect;
+
+print <<"EOF";
+ </map>
+
+ <p><img src="uplinkkart.pl" usemap="#switches" /></p>
+ </body>
+</html>
+EOF
diff --git a/web/nms.gathering.org/uplinkkart.pl b/web/nms.gathering.org/uplinkkart.pl
new file mode 100755
index 0000000..32581a6
--- /dev/null
+++ b/web/nms.gathering.org/uplinkkart.pl
@@ -0,0 +1,70 @@
+#! /usr/bin/perl
+use CGI qw(fatalsToBrowser);
+use GD;
+use DBI;
+use lib '../../include';
+use nms;
+use strict;
+use warnings;
+my $cgi = CGI->new;
+
+#my $greentimeout = 7200;
+my $greentimeout = 15*60;
+my $maxtimeout = $greentimeout*9;
+
+my $dbh = nms::db_connect();
+
+GD::Image->trueColor(1);
+my $img = GD::Image->new('bg07.png');
+
+my $blk = $img->colorResolve(0, 0, 0);
+
+$img->string(gdMediumBoldFont,0,0,"Switch uplink status",$blk);
+$img->string(gdSmallFont,0,20,"Number of ports with activity",$blk);
+
+my $red = $img->colorResolve(255, 0, 0);
+my $yel = $img->colorResolve(255, 255, 0);
+my $grn = $img->colorResolve(0, 255, 0);
+my $blu = $img->colorResolve(0, 0, 255);
+my $wht = $img->colorResolve(255, 255, 255);
+my $gry = $img->colorResolve(127, 127, 127);
+
+my @palette = ( $blu, $red, $yel, $grn, $wht );
+
+for my $ports (0..4) {
+ my $y = 60 + 20 * (4 - $ports);
+ $img->filledRectangle(20, $y, 30, $y + 10, $palette[$ports]);
+ $img->rectangle(20, $y, 30, $y + 10, $blk);
+ $img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, $y + 10, $ports);
+}
+
+my $q = $dbh->prepare('select switch,sysname,(select placement from placements where placements.switch=switches.switch) as placement,count((bytes_in > 0 and bytes_out > 0) or null) as active_ports from switches natural left join get_current_datarate() natural join placements where port between 45 and 48 and switchtype like \'dlink3100%\' group by switch,sysname');
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ my $ports = $ref->{'active_ports'};
+ my $sysname = $ref->{'sysname'};
+ my $clr = $palette[$ports];
+
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+ $img->filledRectangle($3,$4,$1,$2,$clr);
+ $img->rectangle($3,$4,$1,$2,$blk);
+
+ my ($x2, $y2, $x1, $y1) = ($1, $2, $3, $4);
+ my $max_textlen = ($x2-$x1) > ($y2-$y1) ? $x2-$x1 : $y2-$y1;
+ while (length($sysname) * 6 > $max_textlen) {
+ # Try to abbreviate sysname if it is too long for the box
+ $sysname =~ s/^(.*)[a-z]~?([0-9]+)$/$1~$2/ or last;
+ }
+ if (($x2-$x1) > ($y2-$y1)) {
+ $img->string(gdSmallFont,$x1+2,$y1,$sysname,$blk);
+ } else {
+ $img->stringUp(gdSmallFont,$x1,$y2-3,$sysname,$blk);
+ }
+}
+$dbh->disconnect;
+
+if (!defined($ARGV[0])) {
+ print $cgi->header(-type=>'image/png',
+ -refresh=>'10; ' . CGI::url());
+}
+print $img->png;
diff --git a/web/nms.gathering.org/uplinktrafikkart.pl b/web/nms.gathering.org/uplinktrafikkart.pl
new file mode 100755
index 0000000..32869b3
--- /dev/null
+++ b/web/nms.gathering.org/uplinktrafikkart.pl
@@ -0,0 +1,90 @@
+#! /usr/bin/perl
+use CGI qw(fatalsToBrowser);
+use GD;
+use DBI;
+use lib '../../include';
+use nms;
+use strict;
+use warnings;
+my $cgi = CGI->new;
+
+#my $greentimeout = 7200;
+my $greentimeout = 15*60;
+my $maxtimeout = $greentimeout*9;
+
+my $dbh = nms::db_connect();
+
+GD::Image->trueColor(1);
+my $img = GD::Image->new('bg07.png');
+
+my $blk = $img->colorResolve(0, 0, 0);
+
+for my $y (42..236) {
+ my $i = 2.0 * ($y - 236.0) / (42.0 - 237.0);
+ my $clr = get_color($i);
+
+ $img->filledRectangle(12, $y, 33, $y+1, $clr);
+}
+
+$img->string(gdMediumBoldFont,0,0,"Switch uplink traffic",$blk);
+$img->string(gdSmallFont,0,20,"max of bytes in/out",$blk);
+
+my $red = $img->colorResolve(255, 0, 0);
+my $yel = $img->colorResolve(255, 255, 0);
+my $grn = $img->colorResolve(0, 255, 0);
+my $wht = $img->colorResolve(255, 255, 255);
+
+$img->rectangle(12,42,33,236,$blk);
+
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*0.0/2.0, "4 Gbit/sec");
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*1.0/2.0, "2 Gbit/sec");
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 40, 47 + (236-42)*2.0/2.0, "1 Gbit/sec");
+$img->stringFT($blk, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 1000, 700, "NMS (C) 2005-2012 Tech:Server");
+
+my $q = $dbh->prepare('select switch,sysname,(select placement from placements where placements.switch=switches.switch) as placement,greatest(sum(bytes_in),sum(bytes_out)) as traffic from switches natural left join get_current_datarate() natural join placements where port between 45 and 48 and switchtype like \'dlink3100%\' group by switch,sysname');
+$q->execute();
+while (my $ref = $q->fetchrow_hashref()) {
+ my $traffic = $ref->{'traffic'} * 8.0; # convert to bits
+ my $sysname = $ref->{'sysname'};
+
+ my $max = 4_000_000_000.0; # 2Gbit
+ my $min = 1_000_000_000.0; # 1Gbit
+ $traffic = $max if ($traffic > $max);
+ $traffic = $min if ($traffic < $min);
+ my $intensity = log($traffic / $min) / log(2);
+ my $clr = get_color($intensity);
+
+ $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;
+ $img->filledRectangle($3,$4,$1,$2,$clr);
+ $img->rectangle($3,$4,$1,$2,$blk);
+
+ my ($x2, $y2, $x1, $y1) = ($1, $2, $3, $4);
+ my $max_textlen = ($x2-$x1) > ($y2-$y1) ? $x2-$x1 : $y2-$y1;
+ while (length($sysname) * 6 > $max_textlen) {
+ # Try to abbreviate sysname if it is too long for the box
+ $sysname =~ s/^(.*)[a-z]~?([0-9]+)$/$1~$2/ or last;
+ }
+ if (($x2-$x1) > ($y2-$y1)) {
+ $img->string(gdSmallFont,$x1+2,$y1,$sysname,$blk);
+ } else {
+ $img->stringUp(gdSmallFont,$x1,$y2-3,$sysname,$blk);
+ }
+}
+$dbh->disconnect;
+
+if (!defined($ARGV[0])) {
+ print $cgi->header(-type=>'image/png',
+ -refresh=>'10; ' . CGI::url());
+}
+print $img->png;
+
+sub get_color {
+ my $intensity = shift;
+ my $gamma = 1.0/1.90;
+ if ($intensity > 1.0) {
+ $intensity -= 1.0;
+ return $img->colorResolve(255.0, 255.0 * ($intensity ** $gamma), 255.0 * ($intensity ** $gamma));
+ } else {
+ return $img->colorResolve(255.0 * ($intensity ** $gamma), 255.0 * (1.0 - ($intensity ** $gamma)), 0);
+ }
+}
diff --git a/web/stream.tg13.gathering.org/fix_count.pl b/web/stream.tg13.gathering.org/fix_count.pl
new file mode 100755
index 0000000..aaaf42e
--- /dev/null
+++ b/web/stream.tg13.gathering.org/fix_count.pl
@@ -0,0 +1,31 @@
+#! /usr/bin/perl
+
+my $lines = {};
+
+open LOG, "<", "/home/techserver/count_datacube.log"
+ or die "count_datacube.log: $!";
+
+while (<LOG>) {
+ chomp;
+ my ($date, $port, $proto, $audience, $count) = split /\s+/;
+ my $key = $port . ' ' . $proto . ' ' . $audience;
+ $lines->{$date}{$key} = $count;
+}
+
+close LOG;
+
+my $last_date = undef;
+for my $date (sort keys %$lines) {
+ for my $key (keys %{$lines->{$date}}) {
+ if (defined($last_date) && !exists($lines->{$last_date}{$key})) {
+ $lines->{$last_date}{$key} = $lines->{$date}{$key};
+ }
+ }
+ $last_date = $date;
+}
+
+for my $date (sort keys %$lines) {
+ for my $key (sort keys %{$lines->{$date}}) {
+ print "$date $key " . $lines->{$date}{$key} . "\n";
+ }
+}
diff --git a/web/stream.tg13.gathering.org/img/cam-map.png b/web/stream.tg13.gathering.org/img/cam-map.png
new file mode 100644
index 0000000..759641a
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/cam-map.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/img/icon_1.png b/web/stream.tg13.gathering.org/img/icon_1.png
new file mode 100644
index 0000000..6d6e67e
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/icon_1.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/img/icon_2.png b/web/stream.tg13.gathering.org/img/icon_2.png
new file mode 100644
index 0000000..599d5f6
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/icon_2.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/img/icon_3.png b/web/stream.tg13.gathering.org/img/icon_3.png
new file mode 100644
index 0000000..4d1de76
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/icon_3.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/img/icon_camera.png b/web/stream.tg13.gathering.org/img/icon_camera.png
new file mode 100644
index 0000000..e1bf2c3
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/icon_camera.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/img/icon_event.png b/web/stream.tg13.gathering.org/img/icon_event.png
new file mode 100644
index 0000000..9ce6df4
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/icon_event.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/img/icon_hd.png b/web/stream.tg13.gathering.org/img/icon_hd.png
new file mode 100644
index 0000000..d9086bc
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/icon_hd.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/img/icon_sd.png b/web/stream.tg13.gathering.org/img/icon_sd.png
new file mode 100644
index 0000000..3bddbe9
--- /dev/null
+++ b/web/stream.tg13.gathering.org/img/icon_sd.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/index-bak.pl b/web/stream.tg13.gathering.org/index-bak.pl
new file mode 100755
index 0000000..3e31107
--- /dev/null
+++ b/web/stream.tg13.gathering.org/index-bak.pl
@@ -0,0 +1,67 @@
+#!/usr/bin/perl -I /srv/streamlib
+use warnings;
+use strict;
+use CGI;
+use Geo::IP;
+use NetAddr::IP;
+use Net::IP;
+# apt-get install libnet-ip-perl libnetaddr-ip-perl
+use HTML::Template;
+use stream;
+use stream::config;
+
+my $client = CGI->new;
+
+my $v4net = $stream::config::v4net;
+my $v6net = $stream::config::v6net;
+my $tg = $stream::config::tg;
+my $tg_full = $stream::config::tg_full;
+my %streams = %stream::config::streams;
+
+my $force_unicast = $client->param('forceunicast');
+
+my $location = undef;
+
+print $client->header();
+
+my $clip = $client->remote_addr();
+my $template = HTML::Template->new(filename => 'index.tmpl');
+my $is_local = &is_ip_local($clip, $v4net, $v6net);
+
+my @streams = &html_local_test();
+$template->param(TG => $tg);
+$template->param(TG_FULL => $tg_full);
+$template->param(STREAMS => \@streams);
+print $template->output();
+
+
+sub html_local_test() {
+ my @s = ();
+ foreach my $name (sort { $streams{$a}->{priority} <=> $streams{$b}->{priority} } keys %streams) {
+ my $title_link = "http://stream.tg$tg.gathering.org/stream.pl?delivery=%s&stream=${name}&interlaced=%s";
+ my $multicast_link = $streams{$name}->{has_multicast} ? "multicast" : "unicast";
+ $multicast_link = "unicast" if ($force_unicast == 1 || not $is_local);
+
+ if ($streams{$name}->{external}) {
+ $title_link = $streams{$name}->{url};
+ } else {
+ $title_link = sprintf($title_link, $multicast_link, $streams{$name}->{interlaced});
+ }
+ my %hash = (
+ 'title_link' => $title_link,
+ 'title' => $streams{$name}->{title},
+ 'source' => $streams{$name}->{source},
+ 'delivery' => $multicast_link
+ );
+ if ($multicast_link eq "multicast") {
+ $hash{'is_multicast'} .= 1;
+ my $unicast_link = $title_link;
+ $unicast_link=~s/multicast/unicast/g;
+ $hash{'unicast_link'} .= $unicast_link;
+ }
+ $hash{'description'} .= $streams{$name}->{description} if exists($streams{$name}->{description});
+ push(@s, \%hash);
+
+ }
+ return @s;
+}
diff --git a/web/stream.tg13.gathering.org/index-bak.tmpl b/web/stream.tg13.gathering.org/index-bak.tmpl
new file mode 100644
index 0000000..c0aa95d
--- /dev/null
+++ b/web/stream.tg13.gathering.org/index-bak.tmpl
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <title>The Gathering <TMPL_VAR NAME=TG_FULL></title>
+ <link rel="stylesheet" type="text/css" media="screen" href="superawesomeness.css">
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
+</head>
+<body>
+ <div id="spaceship"></div>
+ <div id="innhold">
+ <h1>The Gathering <TMPL_VAR NAME=TG_FULL></h1>
+ <ul>
+ <TMPL_LOOP NAME="STREAMS">
+ <li><a href="<TMPL_VAR NAME=TITLE_LINK>"><TMPL_VAR NAME=TITLE ></a>
+ <p>
+ Source: <TMPL_VAR NAME=SOURCE >
+ <br/>Delivery: <TMPL_VAR NAME=delivery> <TMPL_IF NAME=IS_MULTICAST>(<a href='<TMPL_VAR NAME=UNICAST_LINK>'>problems? try unicast vlc link here</a>)</TMPL_IF>
+ <TMPL_IF NAME="DESCRIPTION"><br /><TMPL_VAR NAME=DESCRIPTION></TMPL_IF></li>
+ </TMPL_LOOP>
+ </ul>
+ </div>
+ <footer>
+ <p>Problems with the non game streams? The easiest way to get hold of us is on IRC (EFNet);
+ one of ViD, Rockj and Sesse should be available if there's too much traffic
+ on #tg to be heard.</p>
+ <p><a href="http://stream.tg<TMPL_VAR NAME="TG">.gathering.org">http://stream.tg<TMPL_VAR NAME="TG">.gathering.org</a></p>
+
+ </footer>
+</body>
+</html>
+
+
diff --git a/web/stream.tg13.gathering.org/index.pl b/web/stream.tg13.gathering.org/index.pl
new file mode 100755
index 0000000..e5f103c
--- /dev/null
+++ b/web/stream.tg13.gathering.org/index.pl
@@ -0,0 +1,72 @@
+#!/usr/bin/perl -I /srv/streamlib
+use warnings;
+use strict;
+use CGI;
+use Geo::IP;
+use NetAddr::IP;
+use Net::IP;
+# apt-get install libnet-ip-perl libnetaddr-ip-perl
+use HTML::Template;
+use stream;
+use stream::config;
+
+my $client = CGI->new;
+
+my $v4net = $stream::config::v4net;
+my $v6net = $stream::config::v6net;
+my $tg = $stream::config::tg;
+my $tg_full = $stream::config::tg_full;
+my %streams = %stream::config::streams;
+
+my $force_unicast = $client->param('forceunicast');
+my $no_header = $client->param('noheader');
+
+my $location = undef;
+
+print $client->header();
+
+my $clip = $client->remote_addr();
+my $template = HTML::Template->new(filename => 'index.tmpl');
+my $is_local = &is_ip_local($clip, $v4net, $v6net);
+
+my @streams = &html_local_test();
+$template->param(TG => $tg);
+$template->param(TG_FULL => $tg_full);
+$template->param(STREAMS => \@streams);
+$template->param(NOHEADER => $no_header);
+print $template->output();
+
+
+sub html_local_test() {
+ my @s = ();
+ foreach my $name (sort { $streams{$a}->{priority} <=> $streams{$b}->{priority} } keys %streams) {
+ my $title_link = "http://stream.tg$tg.gathering.org/stream.pl?delivery=%s&stream=${name}&interlaced=%s";
+ my $multicast_link = $streams{$name}->{has_multicast} ? "multicast" : "unicast";
+ $multicast_link = "unicast" if ($force_unicast == 1 || not $is_local);
+
+ if ($streams{$name}->{external}) {
+ $title_link = $streams{$name}->{url};
+ } else {
+ $title_link = sprintf($title_link, $multicast_link, $streams{$name}->{interlaced});
+ }
+ my %hash = (
+ 'title_link' => $title_link,
+ 'title' => $streams{$name}->{title},
+ 'source' => $streams{$name}->{source},
+ 'quality' => $streams{$name}->{quality},
+ 'location' => $streams{$name}->{location},
+ 'type' => $streams{$name}->{type},
+ 'delivery' => $multicast_link,
+ );
+ if ($multicast_link eq "multicast") {
+ $hash{'is_multicast'} .= 1;
+ my $unicast_link = $title_link;
+ $unicast_link=~s/multicast/unicast/g;
+ $hash{'unicast_link'} .= $unicast_link;
+ }
+ $hash{'description'} .= $streams{$name}->{description} if exists($streams{$name}->{description});
+ push(@s, \%hash);
+
+ }
+ return @s;
+}
diff --git a/web/stream.tg13.gathering.org/index.tmpl b/web/stream.tg13.gathering.org/index.tmpl
new file mode 100644
index 0000000..a565f0e
--- /dev/null
+++ b/web/stream.tg13.gathering.org/index.tmpl
@@ -0,0 +1,35 @@
+<html>
+<head>
+ <title>The Gathering <TMPL_VAR NAME=TG_FULL> Streams</title>
+ <link rel="stylesheet" type="text/css" href="singularity.css" media="all">
+</head>
+<body>
+ <div id="innhold">
+ <TMPL_UNLESS NAME=NOHEADER>
+ <h1>The Gathering <TMPL_VAR NAME=TG_FULL> Streams</h1>
+ </TMPL_UNLESS>
+
+ <TMPL_LOOP NAME="STREAMS">
+ <div class="stream-link">
+ <div class="stream-icon"><img src="img/icon_<TMPL_VAR NAME=QUALITY>.png" /> <img src="img/icon_<TMPL_VAR NAME=TYPE>.png" /> <TMPL_IF NAME=LOCATION><img src="img/icon_<TMPL_VAR NAME=LOCATION>.png"></TMPL_IF></div>
+ <div class="stream-link-content">
+ <a href="<TMPL_VAR NAME=TITLE_LINK>"><TMPL_VAR NAME=TITLE></a><br>
+ Source: <TMPL_VAR NAME=SOURCE><br>
+ Delivery: <TMPL_VAR NAME=delivery> <TMPL_IF NAME=IS_MULTICAST>(<a href='<TMPL_VAR NAME=UNICAST_LINK>'>problems? try unicast vlc link here</a>)</TMPL_IF>
+
+ </div>
+ </div>
+ </TMPL_LOOP>
+ <div id="map">
+ <img src="img/cam-map.png">
+ </div>
+
+ </div>
+
+ <p>Problems with the non game streams? The easiest way to get hold of us is on IRC (EFNet); one of ViD, Rockj and Sesse should be available if there's too much traffic on #tg to be heard.</p>
+ <p><a href="http://stream.tg<TMPL_VAR NAME="TG">.gathering.org">http://stream.tg<TMPL_VAR NAME="TG">.gathering.org</a></p>
+
+</body>
+</html>
+
+
diff --git a/web/stream.tg13.gathering.org/ios/PLACEHOLDER b/web/stream.tg13.gathering.org/ios/PLACEHOLDER
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/stream.tg13.gathering.org/ios/PLACEHOLDER
diff --git a/web/stream.tg13.gathering.org/ios/event.m3u8 b/web/stream.tg13.gathering.org/ios/event.m3u8
new file mode 100644
index 0000000..11152d3
--- /dev/null
+++ b/web/stream.tg13.gathering.org/ios/event.m3u8
@@ -0,0 +1,16 @@
+#EXTM3U
+#EXT-X-TARGETDURATION:5
+#EXT-X-VERSION:3
+#EXT-X-ALLOW-CACHE:NO
+#EXT-X-MEDIA-SEQUENCE:27432
+#EXTINF:4.97,
+http://stream.tg13.gathering.org/ios/event-00027432.ts
+#EXTINF:4.04,
+http://stream.tg13.gathering.org/ios/event-00027433.ts
+#EXTINF:3.99,
+http://stream.tg13.gathering.org/ios/event-00027434.ts
+#EXTINF:3.97,
+http://stream.tg13.gathering.org/ios/event-00027435.ts
+#EXTINF:3.74,
+http://stream.tg13.gathering.org/ios/event-00027436.ts
+#EXT-X-ENDLIST
diff --git a/web/stream.tg13.gathering.org/ios/stream.m3u8 b/web/stream.tg13.gathering.org/ios/stream.m3u8
new file mode 100644
index 0000000..d3d46a6
--- /dev/null
+++ b/web/stream.tg13.gathering.org/ios/stream.m3u8
@@ -0,0 +1,8 @@
+#EXTM3U
+#EXT-X-TARGETDURATION:5
+#EXT-X-VERSION:3
+#EXT-X-ALLOW-CACHE:NO
+#EXT-X-MEDIA-SEQUENCE:1
+#EXTINF:3.84,
+http://stream.tg13.gathering.org/ios/stream-00000001.ts
+#EXT-X-ENDLIST
diff --git a/web/stream.tg13.gathering.org/singularity.css b/web/stream.tg13.gathering.org/singularity.css
new file mode 100644
index 0000000..05e1518
--- /dev/null
+++ b/web/stream.tg13.gathering.org/singularity.css
@@ -0,0 +1,1960 @@
+•/* http://meyerweb.com/eric/tools/css/reset/
+ v2.0 | 20110126
+ License: none (public domain)
+*/
+
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1.5;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+/* @override http://www.gathering.org/tg12/files/content/design/css/typography.css */
+
+/* Generic
+------------------------------------------------------ */
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
+ font-family: Arial, Sans-Serif;
+ font-weight: 400;
+}
+body {
+ font-size: 15px;
+ line-height: 20px;
+ color: #777;
+}
+/* Headings
+------------------------------------------------------ */
+h1, h2, h3, h4, h5, h6 { font-weight: bold; color: #404040; }
+h1 { font-size: 45px; line-height: 50px; margin-bottom: 15px; }
+h2 { font-size: 25px; line-height: 31px; margin-bottom: 12px;}
+h3 { font-size: 20px; line-height: 26px; }
+h4 { font-size: 16px; line-height: 22px; }
+h5 { font-size: 15px; line-height: 20px; }
+h6 { font-size: 12px; line-height: 17px; }
+
+/* Text 'n stuff
+------------------------------------------------------ */
+p { margin: 0 0 20px 0; }
+.page p {
+ margin: 0 0 0.8em 0 !important;
+}
+blockquote {
+ margin: 20px;
+ padding: 0 0 0 40px;
+ color: #555;
+ font-style: italic;
+ color: #888;
+ position: relative;
+}
+blockquote p::before {
+ position: absolute;
+ top: 50px;
+ margin-left: -60px;
+ content: "\201D";
+ font-size: 150px;
+ font-style: normal;
+ color: #00aaad;
+}
+blockquote p {
+ display: block;
+ margin-left: 40px !important;
+}
+blockquote small::before {
+ content: "\2013";
+ margin: 5px;
+}
+blockquote small {
+ font-size: 13px;
+ margin-left: -55px;
+}
+strong { font-weight: bold; }
+
+ul {
+ margin: 0 0 20px 10px;
+ list-style-type: none;
+ position: relative;
+}
+ul.submenu ul {
+ margin-bottom: 0px;
+}
+ul li:before {
+ content: "\2022";
+ position: absolute;
+ left: -17px;
+ width: 15px;
+ text-align: right;
+ color: #00aaad;
+ font-size: 13px;
+ line-height: 21px;
+}
+i, em { font-style: italic; }
+
+ol {
+ margin: 0 0 20px 15px;
+ list-style-type: none;
+ position: relative;
+ counter-reset: section;
+}
+ol > li {
+ counter-increment: section;
+}
+ol > li:before {
+ content: counter(section);
+ position: absolute;
+ left: -30px;
+ width: 23px;
+ text-align: right;
+ color: #00aaad;
+ font-size: 12px;
+ line-height: 22px;
+}
+dl dt { font-weight: bold; }
+dd { margin: 0 0 0 20px; }
+
+a { color: #00aaad; text-decoration: none; }
+a:hover { color: #c3027b; }
+code, pre {
+ padding: 0 3px 2px;
+ font-family: Menlo, Monaco, "Courier New", monospace;
+ font-size: 12px;
+ color: #8F8F8F;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ background-color: #F8F8F8;
+ border: 1px solid #C0C4C5;
+}
+code {
+ padding: 3px 4px;
+ color: #00aaad;
+}
+pre {
+ display: block;
+ padding: 8.5px;
+ margin: 0 0 9px;
+ line-height: 18px;
+ white-space: pre;
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+table {
+ margin-bottom: 20px;
+}
+th, td {
+ padding: 4px 5px;
+}
+td, th {
+ border-left: 1px solid #E2E2E2;
+}
+tr td:first-child, tr th:first-child {
+ border: none;
+}
+tr td {
+ text-align: right;
+}
+th {
+ font-weight: bold;
+ vertical-align: bottom;
+}
+th, td {
+ min-width: 100px;
+}
+th p, td p {
+ margin: 0;
+}
+tbody tr:nth-child(even) td, thead tr th {
+ background-color: #F2F2F2;
+}
+hr {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ border: 0;
+ color: #D5D5D5;
+ background-color: #D5D5D5;
+ height: 1px;
+}
+.visible-phone {
+ display: none;
+}
+.title-container h2 {
+ font-family: Tahoma, Geneva, sans-serif;
+ font-size: 26px;
+ margin-bottom: 5px;
+ line-height: normal;
+}
+h2.size13 { font-size: 13px; }
+h2.size14 { font-size: 14px; }
+h2.size15 { font-size: 15px; }
+h2.size16 { font-size: 16px; }
+h2.size17 { font-size: 17px; }
+h2.size18 { font-size: 18px; }
+h2.size19 { font-size: 19px; }
+h2.size20 { font-size: 20px; }
+h2.size21 { font-size: 21px; }
+h2.size22 { font-size: 22px; }
+h2.size23 { font-size: 23px; }
+h2.size24 { font-size: 24px; }
+h2.size25 { font-size: 25px; }
+h2.size26 { font-size: 26px; }
+h2.size27 { font-size: 27px; }
+h2.size28 { font-size: 28px; }
+h2.size29 { font-size: 29px; }
+h2.size30 { font-size: 30px; }
+h2.size31 { font-size: 31px; }
+h2.size32 { font-size: 32px; }
+h2.size33 { font-size: 33px; }
+h2.size34 { font-size: 34px; }
+h2.size35 { font-size: 35px; }
+h2.size36 { font-size: 36px; }
+h2.size37 { font-size: 37px; }
+h2.size38 { font-size: 38px; }
+h2.size39 { font-size: 39px; }
+h2.size40 { font-size: 40px; }
+h2.size41 { font-size: 41px; }
+h2.size42 { font-size: 42px; }
+h2.size43 { font-size: 43px; }
+h2.size44 { font-size: 44px; }
+h2.size45 { font-size: 45px; }
+h2.size46 { font-size: 46px; }
+h2.size47 { font-size: 47px; }
+h2.size48 { font-size: 48px; }
+h2.size49 { font-size: 49px; }
+h2.size50 { font-size: 50px; }
+h2.size51 { font-size: 51px; }
+h2.size52 { font-size: 52px; }
+h2.size53 { font-size: 53px; }
+h2.size54 { font-size: 54px; }
+h2.size55 { font-size: 55px; }
+h2.size56 { font-size: 56px; }
+h2.size57 { font-size: 57px; }
+h2.size58 { font-size: 58px; }
+h2.size59 { font-size: 59px; }
+h2.size60 { font-size: 60px; }
+h2.size61 { font-size: 61px; }
+h2.size62 { font-size: 62px; }
+h2.size63 { font-size: 63px; }
+h2.size64 { font-size: 64px; }
+h2.size65 { font-size: 65px; }
+h2.size66 { font-size: 66px; }
+h2.size67 { font-size: 67px; }
+h2.size68 { font-size: 68px; }
+h2.size69 { font-size: 69px; }
+h2.size70 { font-size: 70px; }
+h2.size71 { font-size: 71px; }
+h2.size72 { font-size: 72px; }
+h2.size73 { font-size: 73px; }
+h2.size74 { font-size: 74px; }
+h2.size75 { font-size: 75px; }
+h2.size76 { font-size: 76px; }
+h2.size77 { font-size: 77px; }
+h2.size78 { font-size: 78px; }
+h2.size79 { font-size: 79px; }
+h2.size80 { font-size: 80px; }
+h2.size81 { font-size: 81px; }
+h2.size82 { font-size: 82px; }
+h2.size83 { font-size: 83px; }
+h2.size84 { font-size: 84px; }
+h2.size85 { font-size: 85px; }
+h2.size86 { font-size: 86px; }
+h2.size87 { font-size: 87px; }
+h2.size88 { font-size: 88px; }
+h2.size89 { font-size: 89px; }
+h2.size90 { font-size: 90px; }
+h2.size91 { font-size: 91px; }
+h2.size92 { font-size: 92px; }
+h2.size93 { font-size: 93px; }
+h2.size94 { font-size: 94px; }
+h2.size95 { font-size: 95px; }
+h2.size96 { font-size: 96px; }
+h2.size97 { font-size: 97px; }
+h2.size98 { font-size: 98px; }
+h2.size99 { font-size: 99px; }
+h2.size100 { font-size: 100px; }
+
+.cite:before {
+ content: "\201C";
+}
+.cite:after {
+ content: "\201D";
+}
+.cite > .cite:before {
+ content: "\2018";
+}
+.cite > .cite:after {
+ content: "\2019";
+}
+.bullet:before {
+ content: "\2022";
+}
+.dash:after {
+ content: "\2013";
+}
+.hellip:after {
+ content: "\2026";
+}
+.cite:lang(no):before {
+ content: "\00AB";
+}
+.cite:lang(no):after {
+ content: "\00BB";
+}
+/* Meta thingy
+------------------------------------------------------ */
+.breadcrumbs span.delimiter:before {
+ content: "\25BA";
+ margin-right: 8px;
+ font-size: 8px;
+ position: relative;
+ top: -2px;
+ margin: 0 5px 0 3px;
+ color: #00aaad;
+}
+.breadcrumbs {
+ font-size: 12px;
+ margin-bottom: 10px;
+}
+.summary,
+.summary p {
+ font-size: 16px;
+ line-height: 22px;
+ font-weight: 600 !important;
+ margin-bottom: 10px;
+}
+.metainfo { margin: 10px 0; }
+.byline, .meta {
+ color: #888;
+ display: block;
+ font-size: 12px;
+ margin-bottom: 0.8em;
+}
+.byline span.delimiter:before {
+ content: "\2022";
+ margin-right: 8px;
+ font-size: 8px;
+ position: relative;
+ top: -2px;
+ margin: 0 5px 0 5px;
+ color: #00aaad;
+}
+.phototext {
+ margin-top: 5px;
+ line-height: 18px;
+}
+.photoline {
+ margin-top: 5px;
+ font-style: italic;
+ font-size: 12px;
+ float: right;
+}
+.page h1 { margin-top: 10px; }
+.vignette {
+ background-color: #6e6e6e;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ height: 8px;
+ position: relative;
+}
+.vignette span {
+ line-height: 19px;
+}
+div.page .vignette {
+ margin-bottom: 10px;
+}
+div.page .span11 img {
+ max-width: 488px;
+ height: auto;
+}
+.vignette > span {
+ text-transform: lowercase;
+ color: #6e6e6e;
+ display: block;
+ margin-left: 15px;
+ background-color: white;
+ position: absolute;
+ top: -6px;
+ font-size: 12px;
+ padding: 0 3px 0 3px;
+ font-weight: 500;
+}
+div.news33.category-news:nth-child(3n) {
+ clear: left;
+}
+div.portal > h1 {
+ font-size: 20px;
+ padding: 0 10px;
+ color: white;
+}
+h1.portal-creative {
+ background-color: #ec008c;
+}
+h1.portal-game {
+ background-color: #fba51e;
+}
+h1.portal-entertainmentlectures {
+ background-color: #819700;
+}
+div.portal > div.row {
+ margin-bottom: 40px;
+}
+div.category-news h2 a {
+ color: black;
+}
+/*
+ * CSS for The Gathering 2013.
+ * Copyright KANDU and contributors
+ */
+
+/* HTML & BODY
+------------------------------------------------------ */
+body {
+ background: url('/tg13/files/content/design/images/background.jpg') no-repeat;
+ background-position: top center;
+}
+
+html, body {
+ height:100%;
+}
+body.iframe {
+ background-image: none;
+ height: auto;
+}
+
+/* Generic styles
+------------------------------------------------------ */
+
+.hidden { display: none; }
+menu { margin: 0; padding: 0; }
+
+/* Containers and rows
+------------------------------------------------------ */
+.container {
+ width: 1320px;
+ margin: 0 auto;
+ zoom: 1;
+}
+
+.content {
+ width: 840px;
+}
+
+.container:before,
+.container:after {
+ zoom: 1;
+}
+.container:before,
+.container:after,
+.content:before,
+.content:after,
+.row:before,
+.row:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+.container:after,
+.row:after {
+ clear: both;
+}
+.row {
+ margin-left: -40px;
+}
+
+/* Main structure
+------------------------------------------------------ */
+header, header > div.container {
+}
+header {
+ margin-bottom: 40px;
+}
+header > div.container {
+}
+header > div.container .inner {
+ float: left;
+ width: 830px;
+}
+footer a, footer, footer p, footer h4 {
+ color: #2d4f9e;
+}
+footer a:hover {
+ color: #fff;
+}
+header a {
+ color: #c3027b;
+}
+header a:hover {
+ color: #860050;
+}
+header > div.container .logo {
+ float: left;
+ width: 250px;
+}
+header .left, header .left > div {
+ float: right;
+}
+header .right {
+ margin-left: 10px;
+ float: right;
+ width: 180px;
+}
+header .when {
+ background-color: #5a0037;
+ padding: 10px;
+ color: white;
+ border-bottom-right-radius: 6px;
+ border-bottom-left-radius: 6px;
+ font-size: 11px;
+ line-height: 12px;
+ width: 110px;
+ text-align: center;
+}
+header .when-phone .when {
+ width: 120px;
+}
+header .when-phone {
+ float: right;
+}
+header .language {
+ margin-top: 10px;
+ line-height: 25px;
+ font-weight: 300;
+ margin-right: 10px;
+ padding-right: 10px;
+ border-right: 1px solid white;
+ font-size: 12px;
+}
+header ul.promo-menu {
+ padding-top: 40px;
+ margin: 0 0 0 15px;
+}
+header ul.promo-menu a {
+ font-weight: bold;
+ font-size: 13px;
+}
+header ul li:before {
+ margin-top: 2px;
+ content: "\25A0";
+ position: absolute;
+ left: -15px;
+ width: 10px;
+ text-align: right;
+ color: #860050;
+ font-size: 18px;
+ line-height: 13px;
+}
+header .language a {
+ color: white;
+}
+header .language a:hover {
+ color: #2d4f9e;
+}
+footer {
+ margin-top: 80px;
+ background-color: #abdcff;
+ background-image: url('/tg13/files/content/design/images/footerbg.jpg');
+ background-repeat: no-repeat;
+ background-position: center bottom;
+}
+footer > div.container {
+ padding: 0px 0px 150px 0px;
+}
+.footer-about {
+ margin-bottom: 40px;
+ height: 100px;
+ position: relative;
+}
+.footer-about > span {
+ position: absolute !important;
+ bottom: 0; left: 0;
+}
+footer > div.container > div.row {
+ margin-top: 80px;
+}
+footer ul {
+ margin: 0;
+}
+footer h4 {
+ margin-bottom: 20px;
+}
+footer div.full-span2 > iframe {
+ margin: 20px 0px;
+}
+footer a {
+ line-height: 25px;
+}
+footer ul li::before {
+ content: "";
+}
+footer div.row {
+ margin-left: -20px;
+}
+footer div.row div.row {
+ margin-left: -40px;
+}
+.footnote p {
+ font-size: 13px;
+}
+.full-span9 { width: 1360px; }
+.full-span8 { width: 1280px; }
+.full-span7 { width: 1115px; }
+.full-span6 { width: 950px; }
+.full-span5 { width: 785px; }
+.full-span4 { width: 620px; }
+.full-span3 { width: 455px; }
+.full-span2 { width: 290px; }
+.full-span1 { width: 125px; }
+.content, .sidebar {
+ float: left;
+}
+.content {
+ margin: 0 40px 0 40px;
+}
+.sidebar {
+ width: 200px;
+}
+.sidebar.sponsor img {
+ width: 200px;
+}
+.sidebar.sponsor img,
+.sidebar.sponsor > div.vignette {
+ margin-bottom: 20px;
+}
+.sidebar.sponsor img {
+ filter: grayscale(100%);
+ -webkit-filter: grayscale(100%); -moz-filter: grayscale(100%);
+ -ms-filter: grayscale(100%); -o-filter: grayscale(100%);
+ filter: url(/tg13/files/content/design/css/filters.svg#grayscale);
+ filter: gray;
+ -webkit-filter: grayscale(1);
+}
+.sidebar.sponsor img:hover {
+ filter: none;
+ -webkit-filter: grayscale(0%); -moz-filter: grayscale(0%);
+ -ms-filter: grayscale(0%); -o-filter: grayscale(0%);
+}
+.fb-comments, .fb-comments *, .fb_iframe_widget, .fb_iframe_widget * {width: 100% !important;}
+.span4 iframe {
+ width: 100%;
+}
+div.comments_header {
+ padding:8px;
+ background-color: #b1b1b1;
+ color: white;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ margin-bottom: 10px;
+ margin-top: 10px;
+}
+div.comments_header > div {
+ float: left;
+ margin-right: 8px;
+ content:url('/tg13/files/content/design/images/info.png');
+}
+div.comments_header h4 {
+ line-height: 34px;
+ color: white;
+}
+div.comments_header p {
+ clear: both;
+ margin: 8px 0 0 0 !important;
+ font-size: 12px;
+ line-height: 15px;
+}
+.media-page {
+ margin-left: 40px;
+}
+.videoWrapper, #mediaspace {
+ position: relative;
+ padding-bottom: 56.25%; /* 16:9 */
+ padding-top: 25px;
+ height: 0;
+ margin-bottom: 0.8em;
+}
+.videoWrapper iframe, #mediaspace embed {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+.stream-icon {
+ float: left;
+ margin-right: 10px;
+}
+.stream-link { margin-bottom: 8px;}
+#galleria {
+ width: 840px;
+}
+
+/* Menu & Sidebar
+------------------------------------------------------ */
+
+menu {
+ list-style: none;
+}
+menu a {
+ color: #777;
+}
+menu a:hover, li[class^="menu-"] a:hover {
+ color: black;
+}
+li.menu-creative a, li.menu-creative span, li.menu-creative + menu.sub-menu a, li.menu-creative + menu.submenu span {
+ color: #ec008c;
+}
+li.menu-game a, li.menu-game span, li.menu-game + menu.sub-menu a, li.menu-game + menu.submenu span {
+ color: #fba51e;
+}
+li.menu-tickets a, li.menu-tickets span, li.menu-tickets + menu.sub-menu a, li.menu-tickets + menu.submenu span {
+ color: #00aaad;
+}
+li.menu-guide a, li.menu-guide span, li.menu-guide + menu.sub-menu a, li.menu-guide + menu.submenu span {
+ color: #034ea2;
+}
+li.menu-entertainment-lectures a, li.menu-entertainment-lectures span, li.menu-entertainment-lectures + menu.sub-menu a, li.menu-entertainment-lectures + menu.submenu span {
+ color: #819700;
+}
+menu.top-menu > li {
+ margin-bottom: 10px;
+}
+
+div.top-menu-text > span {
+ color: #7595af;
+ font-size: 23px;
+ font-weight: bold;
+ display: table-row;
+ line-height: 23px;
+}
+div.top-menu-text > span.help-text {
+ font-weight: normal;
+ font-size: 14px;
+ display: table-row;
+ color: #a3a3a3;
+ line-height: 15px;
+}
+div.top-menu-text {
+ height: 38px;
+ padding: 6px 0 6px 0;
+ margin: 0 0 0 56px;
+}
+div.top-menu-icon {
+ width: 50px;
+ height: 50px;
+ float: left;
+ background-color: #bfd4e5;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+}
+menu.top-menu a:hover div.top-menu-text > span,
+menu.top-menu a:hover div.top-menu-text > span.help-text {
+ color: #27448b;
+}
+menu.top-menu a:hover div.top-menu-icon {
+ background-color: #3d6db3;
+}
+div.top-menu-icon.icon-schedule {
+ background-image: url('/tg13/files/content/design/images/schedule.png');
+}
+div.top-menu-icon.icon-tgtv {
+ background-image: url('/tg13/files/content/design/images/tgtv.png');
+}
+div.top-menu-icon.icon-tng {
+ background-image: url('/tg13/files/content/design/images/tng.png');
+}
+div.top-menu-icon.icon-forum {
+ background-image: url('/tg13/files/content/design/images/forum.png');
+}
+div.top-menu-icon.icon-compo {
+ background-image: url('/tg13/files/content/design/images/compo.png');
+}
+div.top-menu-icon.icon-news {
+ background-image: url('/tg13/files/content/design/images/news.png');
+}
+menu.section-menu {
+ margin-top: 40px;
+ margin-left: 15px;
+}
+menu.section-menu li {
+ margin-bottom: 15px;
+}
+menu.sub-menu {
+ margin-bottom: 20px;
+ margin-left: 15px;
+}
+span.menu-expand {
+ display: block;
+ float: left;
+ margin-left: -15px;
+ cursor: pointer;
+}
+
+/* Graphical Elements
+------------------------------------------------------ */
+/* Language
+------------------------------------------------------ */
+/* Search
+------------------------------------------------------ */
+.search input {
+ vertical-align: top;
+ line-height: 1;
+}
+.search input[type="search"] {
+ -webkit-appearance: none;
+ box-sizing:content-box;
+ padding: 0;
+ padding-left: 3px;
+ margin: 0;
+ margin-top: 10px;
+ border: none;
+ color: #9dbfd9;
+ height: 25px;
+ width: 200px;
+ font-size: 12px;
+ font-style: italic;
+ border-radius: 3px;
+ line-height: 15px;
+}
+.search input:focus {
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ outline: 0;
+}
+input[type=search]::-webkit-search-decoration {
+ -webkit-appearance:none;
+}
+input::-webkit-input-placeholder,
+isindex::-webkit-input-placeholder,
+textarea::-webkit-input-placeholder,
+input::-moz-placeholder,
+textarea::-moz-placeholder {
+ font-style: italic;
+ color: silver;
+}
+/* News
+------------------------------------------------------ */
+.news { position: relative; }
+
+.news100, .clearer, .span19 { width: 840px; }
+.span18 { width: 796px; }
+.span17 { width: 752px; }
+.span16 { width: 708px; }
+.span15 { width: 664px; }
+.news75, .span14 { width: 620px; }
+.span13 { width: 576px; }
+.news66, .span-two-third { width: 547px; }
+.span12 { width: 532px; }
+.span11 { width: 488px; }
+.span10 { width: 444px; }
+.news50, .span9 { width: 400px; }
+.span8 { width: 356px; }
+.span7 { width: 312px; }
+.span6 { width: 268px; }
+.news33, .span-one-third { width: 253px; }
+.span5 { width: 224px; }
+.news25, .span4 { width: 180px; }
+.span3 { width: 136px; }
+.span2 { width: 92px; }
+.span1 { width: 48px; }
+.clearer { clear: both; margin: 0px 0px 0px 40px !important; }
+
+div[class^="news"] > span,
+div[class^="full-span"] > span,
+div[class^="span"] > span {
+ position: relative;
+ display: block;
+}
+div[class^="news"] p,
+div[class^="full-span"] p,
+div[class^="span"] p {
+ margin: 0;
+}
+.article {
+ float: left;
+ margin: 0px 0px 40px 40px;
+}
+.article a,
+.article a:hover {
+ text-decoration: none;
+ color: #777;
+}
+
+.news_img_100 {
+ width: 100%;
+ margin: 20px 0 10px 0;
+}
+img.news_img_right {
+ width: 50%;
+ float: right;
+ margin: 0 0 20px 40px;
+}
+.span2.social-news div {
+ margin-bottom: 10px;
+}
+.icon-more > a {
+ float: right;
+ font-size: 13px;
+ margin-right: 21px;
+}
+.icon-more {
+ position: relative;
+}
+.icon-more > a::after {
+ margin-top: 2px;
+ padding-left: 3px;
+ padding-top: 2px;
+ padding-bottom: 1px;
+ margin-left: 5px;
+ position: absolute;
+ content: "\25BA";
+ color: white;
+ background-color: black;
+ -webkit-border-radius: 8px;
+ -moz-border-radius: 8px;
+ border-radius: 8px;
+ width: 13px;
+ height: 13px;
+ font-size: 11px;
+ line-height: 11px;
+}
+
+/* Page
+------------------------------------------------------ */
+.page {
+ float: left;
+ margin: 0px 0px 40px 40px;
+}
+.page .page {
+ margin-left: 0px;
+}
+.page .page.news33 {
+ margin-left: 40px;
+}
+div.news-portal-header {
+ width: 840px;
+ margin-left: 40px !important;
+}
+div[class^="full-span"],
+.page div[class^="news"],
+.page div[class^="span"]{
+ float: left;
+ margin-left: 40px;
+}
+.page h3 a,
+.page li a {
+ border: none;
+}
+.page-right {
+ float: right;
+ clear: right;
+ margin-bottom: 40px;
+ margin-left: 40px;
+}
+.page-right a {
+ border: none;
+}
+.page-sidebar {
+ margin-left: 40px;
+}
+.page-right h3,
+.page-sidebar h3 {
+ border-bottom: solid 4px #c0c4c5;
+ position: relative;
+ margin: 0 0 10px 0;
+}
+.page-sidebar .meta {
+ text-transform: uppercase;
+ font-size: 10px;
+}
+.page-sidebar {
+ position: relative;
+}
+.related-news {
+ margin-bottom: 8px;
+}
+.img-container {
+ margin-bottom: -5px;
+}
+.img-container a {
+ display:block;
+}
+/* Article skins
+------------------------------------------------------ */
+div.article.skin-important {
+ background-color: black;
+ color: white;
+}
+div.article.skin-important {
+ padding-bottom: 40px;
+}
+div.article.skin-important > div[class^="news"] > span.content-container,
+div.article.skin-important > div[class^="news"] > span.title-container {
+ margin-left: 40px;
+ margin-right: 40px;
+}
+div.article.skin-important > div[class^="news"] > span.title-container {
+ padding-top: 40px;
+}
+div.article.skin-important p,
+div.article.skin-important h2,
+div.article.skin-important a,
+div.article.skin-important a:hover,
+div.article.skin-important a:visited {
+ color: white;
+}
+div.article.skin-game .vignette,
+div.article.skin-creative .vignette,
+div.article.skin-entertainment .vignette {
+ background-color: #000;
+ margin: 5px 0 5px 0;
+ height: 8px;
+ position: relative;
+}
+div.article.skin-game .vignette span,
+div.article.skin-creative .vignette span,
+div.article.skin-entertainment .vignette span {
+ text-transform: lowercase;
+ color: #000;
+ display: block;
+ margin-left: 15px;
+ background-color: white;
+ position: absolute;
+ top: -6px;
+ font-size: 12px;
+ padding: 0 3px 0 3px;
+ font-weight: 500;
+}
+div.article.skin-game .vignette,
+div.vignette.category-game {
+ background-color: #fba51e;
+}
+div.article.skin-creative .vignette,
+div.vignette.category-creative {
+ background-color: #ec008c;
+}
+div.article.skin-entertainment .vignette,
+div.vignette.category-entertainmentlectures {
+ background-color: #819700;
+}
+div.article.skin-game .vignette span,
+div.vignette.category-game span{
+ color: #fba51e;
+}
+div.article.skin-creative .vignette span,
+div.vignette.category-creative span{
+ color: #ec008c;
+}
+div.article.skin-entertainment .vignette span,
+div.vignette.category-entertainmentlectures span{
+ color: #819700;
+}
+div.article.skin-info {
+ background-color: #E6E7E8;
+ padding-bottom: 40px;
+}
+div.article.skin-info > div[class^="news"] > span.content-container,
+div.article.skin-info > div[class^="news"] > span.title-container {
+ margin-left: 40px;
+ margin-right: 40px;
+}
+div.article.skin-info > div[class^="news"] > span.title-container {
+ padding-top: 40px;
+}
+div.article.skin-important > div[class^="news"] > span.img-container,
+div.article.skin-info > div[class^="news"] > span.img-container {
+ margin-bottom: -25px;
+}
+
+/* Modal
+------------------------------------------------------ */
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000000;
+}
+.modal-backdrop.fade {
+ opacity: 0;
+}
+.modal-backdrop {
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+}
+.modal-c {
+ width: 800px;
+}
+.modal {
+ position: absolute;
+ top: 206px;
+ z-index: 1050;
+ width: 800px;
+ margin: 0 auto;
+ background-color: #ffffff;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+}
+.modal-body {
+ padding: 20px;
+ padding-top: 10px;
+}
+.modal-body .modal-form {
+ margin-bottom: 0;
+}
+.right {
+ float: right;
+}
+
+/* Video
+----------------------------------------------------- */
+
+.video h2 {
+ margin-top: 10px;
+ margin-bottom: 5px;
+}
+.tags span {
+ margin-left: 5px;
+ padding: 3px 4px;
+ border: 1px solid #DDD;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.tags span:hover {
+ background-color: whiteSmoke;
+}
+.tags span:hover a {
+ color: black;
+}
+.tags span a {
+ color: #07A430;
+ border-bottom: none !important;
+}
+.tags span a:hover {
+ border-bottom: none !important;
+}
+.tags {
+ margin-bottom: 20px;
+}
+
+/* Buttons
+----------------------------------------------------- */
+.btn.stage,
+.btn.stage.active,
+.btn.stage:hover,
+.btn.game,
+.btn.game.active,
+.btn.game:hover,
+.btn.creative,
+.btn.creative.active,
+.btn.creative:hover,
+.btn.auditorium,
+.btn.auditorium.active,
+.btn.auditorium:hover {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ color: white;
+}
+.btn.stage {
+ background-color: #ff7800;
+ background-image: -moz-linear-gradient(top, #ff7800, #db4d00);
+ background-image: -ms-linear-gradient(top, #ff7800, #db4d00);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ff7800), to(#db4d00));
+ background-image: -webkit-linear-gradient(top, #ff7800, #db4d00);
+ background-image: -o-linear-gradient(top, #ff7800, #db4d00);
+ background-image: linear-gradient(top, #ff7800, #db4d00);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7800', endColorstr='#db4d00', GradientType=0);
+ border-color: #db4d00 #db4d00 #ca4900;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.btn.stage:hover,
+.btn.stage:active,
+.btn.stage.active,
+.btn.stage.disabled,
+.btn.stage[disabled] {
+ background-color: #db4d00;
+}
+.btn.stage:active, .btn.stage.active {
+ background-color: #e65a99 \9;
+}
+.btn.game {
+ background-color: #49afcd;
+ background-image: -moz-linear-gradient(top, #009cff, #0078c4);
+ background-image: -ms-linear-gradient(top, #009cff, #0078c4);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#009cff), to(#0078c4));
+ background-image: -webkit-linear-gradient(top, #009cff, #0078c4);
+ background-image: -o-linear-gradient(top, #009cff, #0078c4);
+ background-image: linear-gradient(top, #009cff, #0078c4);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#009cff', endColorstr='#0078c4', GradientType=0);
+ border-color: #0078c4 #0078c4 #0062a0;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.btn.game:hover,
+.btn.game:active,
+.btn.game.active,
+.btn.game.disabled,
+.btn.game[disabled] {
+ background-color: #0078c4;
+}
+.btn.game:active, .btn.game.active {
+ background-color: #0089e0 \9;
+}
+.btn.auditorium {
+ background-color: #49afcd;
+ background-image: -moz-linear-gradient(top, #f33183, #dc0c64);
+ background-image: -ms-linear-gradient(top, #f33183, #dc0c64);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f33183), to(#dc0c64));
+ background-image: -webkit-linear-gradient(top, #f33183, #dc0c64);
+ background-image: -o-linear-gradient(top, #f33183, #dc0c64);
+ background-image: linear-gradient(top, #f33183, #dc0c64);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f33183', endColorstr='#dc0c64', GradientType=0);
+ border-color: #dc0c64 #dc0c64 #bb004f;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.btn.auditorium:hover,
+.btn.auditorium:active,
+.btn.auditorium.active,
+.btn.auditorium.disabled,
+.btn.auditorium[disabled] {
+ background-color: #dc0c64;
+}
+.btn.auditorium:active, .btn.auditorium.active {
+ background-color: #e81f74 \9;
+}
+.btn.creative {
+ background-color: #009997;
+ background-image: -moz-linear-gradient(top, #009997, #007170);
+ background-image: -ms-linear-gradient(top, #009997, #007170);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#009997), to(#007170));
+ background-image: -webkit-linear-gradient(top, #009997, #007170);
+ background-image: -o-linear-gradient(top, #009997, #007170);
+ background-image: linear-gradient(top, #009997, #007170);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#009997', endColorstr='#007170', GradientType=0);
+ border-color: #007170 #007170 #004e4d;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.btn.creative:hover,
+.btn.creative:active,
+.btn.creative.active,
+.btn.creative.disabled,
+.btn.creative[disabled] {
+ background-color: #007170;
+}
+.btn.creative:active, .btn.creative.active {
+ background-color: #007f7d \9;
+}
+.btn {
+ display: inline-block;
+ padding: 4px 10px 4px;
+ font-size: 13px;
+ line-height: 18px;
+ color: #333;
+ text-align: center;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ background-color: #FAFAFA;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(white), color-stop(25%, white), to(#E6E6E6));
+ background-image: -webkit-linear-gradient(white, white 25%, #E6E6E6);
+ background-image: -moz-linear-gradient(top, white, white 25%, #E6E6E6);
+ background-image: -ms-linear-gradient(white, white 25%, #E6E6E6);
+ background-image: -o-linear-gradient(white, white 25%, #E6E6E6);
+ background-image: linear-gradient(white, white 25%, #E6E6E6);
+ background-repeat: no-repeat;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
+ border: 1px solid #CCC;
+ border-bottom-color: #BBB;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ cursor: pointer;
+}
+.btn:first-child {
+ *margin-left: 0;
+}
+.btn:hover {
+ color: #333333;
+ text-decoration: none;
+ background-color: #e6e6e6;
+ background-position: 0 -15px;
+ -webkit-transition: background-position 0.1s linear;
+ -moz-transition: background-position 0.1s linear;
+ -ms-transition: background-position 0.1s linear;
+ -o-transition: background-position 0.1s linear;
+ transition: background-position 0.1s linear;
+}
+.btn:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+.btn.active, .btn:active {
+ background-image: none;
+ -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ background-color: #e6e6e6;
+ background-color: #d9d9d9 \9;
+ color: rgba(0, 0, 0, 0.5);
+ outline: 0;
+}
+.btn-group {
+ position: relative;
+ *zoom: 1;
+ *margin-left: .3em;
+}
+.btn-group:before, .btn-group:after {
+ display: table;
+ content: "";
+}
+.btn-group:after {
+ clear: both;
+}
+.btn-group:first-child {
+ *margin-left: 0;
+}
+.btn-group + .btn-group {
+ margin-left: 5px;
+}
+.btn-group .btn {
+ position: relative;
+ float: left;
+ margin-left: -1px;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+.btn-group .btn:first-child {
+ margin-left: 0;
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
+}
+.btn-group .btn:last-child, .btn-group .dropdown-toggle {
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
+}
+.btn-group .btn.large:first-child {
+ margin-left: 0;
+ -webkit-border-top-left-radius: 6px;
+ -moz-border-radius-topleft: 6px;
+ border-top-left-radius: 6px;
+ -webkit-border-bottom-left-radius: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ border-bottom-left-radius: 6px;
+}
+.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle {
+ -webkit-border-top-right-radius: 6px;
+ -moz-border-radius-topright: 6px;
+ border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
+ -moz-border-radius-bottomright: 6px;
+ border-bottom-right-radius: 6px;
+}
+.btn-group .btn:hover,
+.btn-group .btn:focus,
+.btn-group .btn:active,
+.btn-group .btn.active {
+ z-index: 2;
+}
+.page a.btn,
+.page a.btn::hover {
+ border-bottom: 1px solid #CCC;
+}
+
+/* Schedule
+------------------------------------------------------ */
+a.stage {
+ color: white;
+ background-color: #819700;
+}
+a.game {
+ color: white;
+ background-color: #fba51e;
+}
+a.auditorium {
+ color: black;
+ background-color: #d8e600;
+}
+a.creative {
+ color: white;
+ background-color: #ec008c;
+}
+a.agora {
+ color: white;
+ background-color: #2e4f9e;
+}
+a.remove-filter {
+ color: white;
+ background-color: #CCC;
+}
+.filterLink {
+ padding: 3px 6px;
+ margin-right: 5px;
+ line-height: 28px;
+}
+.calendar .stage {
+ color: #819700;
+ font-size: 25px;
+}
+.calendar .game {
+ color: #fba51e;
+ font-size: 25px;
+}
+.calendar .auditorium {
+ color: #d8e600;
+ font-size: 25px;
+}
+.calendar .creative {
+ color: #ec008c;
+ font-size: 25px;
+}
+.calendar .agora {
+ color: #2e4f9e;
+ font-size: 25px;
+}
+.calendar tr td {
+ text-align: left;
+}
+.calendar td, .calendar td {
+ min-width: 0;
+}
+.calendar tbody tr:nth-child(even) td {
+ background-color: transparent;
+}
+.calendar tbody tr.odd td {
+ background-color: #F2F2F2;
+}
+/* Responsive
+------------------------------------------------------ */
+@media (max-width: 1320px) {
+ footer {
+ width: 1320px;
+ }
+}
+@media (max-width: 1094px) {
+ div.news-portal-header {
+ width: 630px;
+ margin-left: 30px !important;
+ }
+ .news100, .clearer, .span19 { width: 630px; }
+ .span18 { width: 597px; }
+ .span17 { width: 564px; }
+ .span16 { width: 531px; }
+ .span15 { width: 498px; }
+ .news75, .span14 { width: 465px; }
+ .span13 { width: 432px; }
+ .news66, .span-two-third { width: 410px; }
+ .span12 { width: 399px; }
+ .span11 { width: 366px; }
+ .span10 { width: 333px; }
+ .news50, .span9 { width: 300px; }
+ .span8 { width: 267px; }
+ .span7 { width: 234px; }
+ .span6 { width: 201px; }
+ .news33, .span-one-third { width: 190px; }
+ .span5 { width: 168px; }
+ .news25, .span4 { width: 135px; }
+ .span3 { width: 102px; }
+ .span2 { width: 69px; }
+ .span1 { width: 36px; }
+ .clearer { margin: 0px 0px 0px 30px !important; }
+ .full-span9 { width: 1094px; }
+ .full-span8 { width: 1034x; }
+ .full-span7 { width: 901px; }
+ .full-span6 { width: 768px; }
+ .full-span5 { width: 635px; }
+ .full-span4 { width: 502px; }
+ .full-span3 { width: 369px; }
+ .full-span2 { width: 236px; }
+ .full-span1 { width: 103px; }
+ .img-container.news100 img { width: 630px; height: auto; }
+ .img-container.news75 img { width: 465px; height: auto; }
+ .img-container.news66 img { width: 410px; height: auto; }
+ .img-container.news50 img { width: 300px; height: auto; }
+ .img-container.news33 img { width: 190px; height: auto; }
+ .img-container.news25 img { width: 135px; height: auto; }
+ .title-container h2 {
+ margin-bottom: 4px;
+ font-size: 19px;
+ }
+ h2.size13 { font-size: 9px; }
+ h2.size14 { font-size: 10px; }
+ h2.size15 { font-size: 11px; }
+ h2.size16 { font-size: 12px; }
+ h2.size17 { font-size: 12px; }
+ h2.size18 { font-size: 13px; }
+ h2.size19 { font-size: 14px; }
+ h2.size20 { font-size: 15px; }
+ h2.size21 { font-size: 15px; }
+ h2.size22 { font-size: 16px; }
+ h2.size23 { font-size: 17px; }
+ h2.size24 { font-size: 18px; }
+ h2.size25 { font-size: 18px; }
+ h2.size26 { font-size: 19px; }
+ h2.size27 { font-size: 20px; }
+ h2.size28 { font-size: 21px; }
+ h2.size29 { font-size: 21px; }
+ h2.size30 { font-size: 22px; }
+ h2.size31 { font-size: 23px; }
+ h2.size32 { font-size: 24px; }
+ h2.size33 { font-size: 24px; }
+ h2.size34 { font-size: 25px; }
+ h2.size35 { font-size: 26px; }
+ h2.size36 { font-size: 27px; }
+ h2.size37 { font-size: 27px; }
+ h2.size38 { font-size: 28px; }
+ h2.size39 { font-size: 29px; }
+ h2.size40 { font-size: 30px; }
+ h2.size41 { font-size: 30px; }
+ h2.size42 { font-size: 31px; }
+ h2.size43 { font-size: 32px; }
+ h2.size44 { font-size: 33px; }
+ h2.size45 { font-size: 33px; }
+ h2.size46 { font-size: 34px; }
+ h2.size47 { font-size: 35px; }
+ h2.size48 { font-size: 36px; }
+ h2.size49 { font-size: 36px; }
+ h2.size50 { font-size: 37px; }
+ h2.size51 { font-size: 38px; }
+ h2.size52 { font-size: 39px; }
+ h2.size53 { font-size: 39px; }
+ h2.size54 { font-size: 40px; }
+ h2.size55 { font-size: 41px; }
+ h2.size56 { font-size: 42px; }
+ h2.size57 { font-size: 42px; }
+ h2.size58 { font-size: 43px; }
+ h2.size59 { font-size: 44px; }
+ h2.size60 { font-size: 45px; }
+ h2.size61 { font-size: 45px; }
+ h2.size62 { font-size: 46px; }
+ h2.size63 { font-size: 47px; }
+ h2.size64 { font-size: 48px; }
+ h2.size65 { font-size: 48px; }
+ h2.size66 { font-size: 49px; }
+ h2.size67 { font-size: 50px; }
+ h2.size68 { font-size: 51px; }
+ h2.size69 { font-size: 51px; }
+ h2.size70 { font-size: 52px; }
+ h2.size71 { font-size: 53px; }
+ h2.size72 { font-size: 54px; }
+ h2.size73 { font-size: 54px; }
+ h2.size74 { font-size: 55px; }
+ h2.size75 { font-size: 56px; }
+ h2.size76 { font-size: 57px; }
+ h2.size77 { font-size: 57px; }
+ h2.size78 { font-size: 58px; }
+ h2.size79 { font-size: 59px; }
+ h2.size80 { font-size: 60px; }
+ h2.size81 { font-size: 60px; }
+ h2.size82 { font-size: 61px; }
+ h2.size83 { font-size: 62px; }
+ h2.size84 { font-size: 63px; }
+ h2.size85 { font-size: 63px; }
+ h2.size86 { font-size: 64px; }
+ h2.size87 { font-size: 65px; }
+ h2.size88 { font-size: 66px; }
+ h2.size89 { font-size: 66px; }
+ h2.size90 { font-size: 67px; }
+ h2.size91 { font-size: 68px; }
+ h2.size92 { font-size: 69px; }
+ h2.size93 { font-size: 69px; }
+ h2.size94 { font-size: 70px; }
+ h2.size95 { font-size: 71px; }
+ h2.size96 { font-size: 72px; }
+ h2.size97 { font-size: 72px; }
+ h2.size98 { font-size: 73px; }
+ h2.size99 { font-size: 74px; }
+ h2.size100 { font-size: 75px; }
+ .content-container p {
+ font-size: 12px !important;
+ line-height: 14px !important;
+ font-weight: 300;
+ }
+ .article, .page, .page-right {
+ margin: 0px 0px 30px 30px;
+ }
+ .page div[class^="news"],
+ div[class^="full-span"],
+ .page div[class^="span"]{
+ margin-left: 30px;
+ }
+ .content {
+ width: 630px;
+ margin: 0 30px 0 30px;
+ }
+ .row {
+ margin-left: -30px;
+ }
+ footer div.row {
+ margin-left: -15px;
+ }
+ .container, footer {
+ width: 1094px;
+ }
+ .sidebar {
+ width: 202px;
+ }
+ .img-container {
+ margin-bottom: 4px;
+ }
+ div[class^="news"] p,
+ div[class^="full-span"] p,
+ div[class^="span"] p {
+ line-height: 18px;
+ }
+ div.article.skin-important {
+ padding-bottom: 30px;
+ }
+ div.article.skin-important > div[class^="news"] > span.content-container,
+ div.article.skin-important > div[class^="news"] > span.title-*,
+ div.article.skin-info > div[class^="news"] > span.content-container,
+ div.article.skin-info > div[class^="news"] > span.title-container {
+ margin-left: 30px;
+ margin-right: 30px;
+ }
+ div.article.skin-important > div[class^="news"] > span.title-container,
+ div.article.skin-info > div[class^="news"] > span.title-container {
+ padding-top: 30px;
+ }
+ .row.news .page img {
+ width: 100%;
+ }
+ header > div.container .inner {
+ width: 640px;
+ }
+ div.page .span11 img {
+ max-width: 366px;
+ height: auto;
+ }
+ footer div.row div.row {
+ margin-left: -30px;
+ }
+ div.content > div.row > div.page > img {
+ width: 630px;
+ height: auto;
+ }
+ div.content > div.row.news > iframe.full {
+ width: 630px;
+ margin-left: 30px;
+ }
+ #galleria {
+ width: 630px;
+ }
+ .media-page {
+ margin-left: 30px;
+ }
+}
+@media (max-width: 767px) {
+ .media-page {
+ margin-left: 0px;
+ }
+ div.page.news33.category-news {
+ margin-bottom: 40px;
+ }
+ div.news-portal-header {
+ width: 100%;
+ margin-left: 0px !important;
+ }
+ .img-container.news100 img,
+ .img-container.news75 img,
+ .img-container.news66 img,
+ .img-container.news50 img,
+ .img-container.news33 img,
+ .img-container.news25 img,
+ div.page .span11 img {
+ width: 100%;
+ height: auto;
+ }
+ .img-container { width: 100%; }
+ .img-container a { display:block; width: 100%; }
+ div[class^="news"],
+ div[class^="span"],
+ div[class^="full-span"],
+ .page div[class^="news"],
+ .page div[class^="span"],
+ .clearer, .content, .container, .sidebar, .page, header > div.container .inner, footer {
+ width: auto;
+ float: none;
+ clear: both;
+ }
+ .content {
+ margin: 0px 20px 20px 20px;
+ }
+ div.article.skin-important {
+ padding-bottom: 20px;
+ }
+ div.article {
+ width: 100% !important;
+ margin-left: 0;
+ }
+ .row.news {
+ margin-left: 0;
+ }
+ div.article.skin-important > div[class^="news"] > span.content-container,
+ div.article.skin-important > div[class^="news"] > span.title-container,
+ div.article.skin-info > div[class^="news"] > span.content-container,
+ div.article.skin-info > div[class^="news"] > span.title-container {
+ width: auto;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+ div.article.skin-important > div[class^="news"] > span.title-container,
+ div.article.skin-info > div[class^="news"] > span.title-container {
+ padding-top: 20px;
+ }
+ .content > div[class^="news"],
+ div[class^="span"] {
+ margin: 0 0 0 20px;
+ }
+ h2[class^="size"] {
+ font-size: 15px;
+ }
+ .sidebar {
+ margin: 0 20px 20px 20px;
+ }
+ header, footer {
+ padding: 0 20px 20px 20px;
+ }
+ .sidebar.sponsor a {
+ margin: 0 10px 10px 0;
+ float: left;
+ }
+ .sidebar.sponsor div.vignette {
+ clear: both;
+ }
+ .footnote > div {
+ width: auto;
+ display: block;
+ text-align: center;
+ }
+ footer div[class^="full-span"] {
+ margin-bottom: 20px;
+ }
+ .social-news > div {
+ float: left;
+ margin-right: 20px;
+ }
+ menu.top-menu {
+ height: 100px;
+ }
+ menu.top-menu li {
+ width: 45%;
+ float: left;
+ background-color: #bfd4e5;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ }
+ menu.top-menu li > a {
+ color: white;
+ }
+ menu.top-menu .top-menu-text {
+ text-align: center;
+ margin: 0;
+ }
+ menu.top-menu .top-menu-text > span:first-child {
+ display: block;
+ font-size: 15px;
+ line-height: 38px;
+ }
+ menu.top-menu > li:nth-child(odd) {
+ margin-right: 10%;
+ }
+ div.top-menu-icon {
+ display: none;
+ }
+ .hidden-phone {
+ display: none;
+ }
+ .visible-phone {
+ display: block;
+ }
+ menu.section-menu {
+ margin: 20px 0px 0px;
+ padding: 60px 10px 10px;
+ background-color: #555;
+ border-radius: 5px;
+ color: white;
+ }
+ menu.section-menu li {
+ padding: 6px;
+ border-radius: 5px;
+ }
+ menu.section-menu a, menu.section-menu a:hover {
+ color: white;
+ }
+ div.top-menu-text > span.help-text {
+ display: none;
+ }
+ th, td {
+ min-width: 0px;
+ }
+ .section-menu-button {
+ float: right;
+ margin-bottom: 15px;
+ }
+ .section-menu-button a {
+ width: 70px;
+ height: 50px;
+ line-height: 50px;
+ display: block;
+ text-align: center;
+ border-radius: 5px;
+ background-color: #555;
+ color: white;
+ }
+ .section-menu-button a:hover, menu.section-menu li:hover {
+ background-color: #6f6f6f;
+ }
+ h1 { font-size: 25px; line-height: 30px; margin-bottom: 10px; }
+ h2 { font-size: 20px; line-height: 25px; margin-bottom: 8px;}
+ h3 { font-size: 15px; line-height: 20px; }
+ h4 { font-size: 12px; line-height: 17px; }
+ h5 { font-size: 12px; line-height: 17px; }
+ h6 { font-size: 12px; line-height: 17px; }
+ .row.news .page {
+ margin: 0px;
+ }
+ header {
+ margin-bottom: 0px;
+ }
+ menu.top-menu a:hover div.top-menu-text > span, menu.top-menu a:hover div.top-menu-text > span.help-text, div.top-menu-text > span {
+ color: white;
+ }
+ div.logo {
+ width: 132px;
+ }
+ div.logo img {
+ height: 100px;
+ }
+ div.inner div.when {
+ display: none;
+ }
+ div.inner div.right {
+ float: left;
+ }
+ footer > div.container > div.row {
+ margin-top: 30px;
+ }
+ div[class^="full-span"] {
+ margin: 0px 0px 0px 15px;
+ }
+ footer .search input[type="search"]{
+ width: 100%;
+ }
+ footer .language {
+ text-align: center;
+ }
+ footer > div.container {
+ padding: 0px 0px 90px 0px;
+ }
+ header ul.promo-menu {
+ padding-top: 20px;
+ }
+ footer div.row div.row {
+ margin-left: -20px;
+ }
+ div.content > div.row > div.page > img {
+ width: 100%;
+ height: auto;
+ }
+ div.content > div.row.news > iframe.full {
+ width: 100%;
+ margin-left: 0px;
+ }
+ #galleria {
+ width: 100%;
+ }
+ div.calendar table,
+ div.calendar table thead,
+ div.calendar table tbody,
+ div.calendar table th,
+ div.calendar table td,
+ div.calendar table tr {
+ display: block;
+ }
+ div.calendar table thead tr {
+ position: absolute;
+ top: -9999px;
+ left: -9999px;
+ }
+ div.calendar table td {
+ border: none;
+ border-bottom: 1px solid #CCC;
+ position: relative;
+ padding-left: 20%;
+ white-space: normal;
+ text-align: left;
+ }
+ div.calendar table td:before {
+ position: absolute;
+ top: 6px;
+ left: 6px;
+ width: 45%;
+ padding-right: 10px;
+ white-space: nowrap;
+ text-align:left;
+ font-weight: bold;
+ content: attr(data-title);
+ }
+ .filterLink {
+ clear: right;
+ display: block;
+ text-align: center;
+ }
+ li.menu-creative a, li.menu-creative span, li.menu-creative + menu.sub-menu a, li.menu-creative + menu.submenu span,
+ li.menu-game a, li.menu-game span, li.menu-game + menu.sub-menu a, li.menu-game + menu.submenu span,
+ li.menu-tickets a, li.menu-tickets span, li.menu-tickets + menu.sub-menu a, li.menu-tickets + menu.submenu span,
+ li.menu-guide a, li.menu-guide span, li.menu-guide + menu.sub-menu a, li.menu-guide + menu.submenu span,
+ li.menu-entertainment-lectures a, li.menu-entertainment-lectures span, li.menu-entertainment-lectures + menu.sub-menu a, li.menu-entertainment-lectures + menu.submenu span {
+ color: white;
+ }
+}
diff --git a/web/stream.tg13.gathering.org/singularity.png b/web/stream.tg13.gathering.org/singularity.png
new file mode 100644
index 0000000..3a13cdf
--- /dev/null
+++ b/web/stream.tg13.gathering.org/singularity.png
Binary files differ
diff --git a/web/stream.tg13.gathering.org/stream.pl b/web/stream.tg13.gathering.org/stream.pl
new file mode 100755
index 0000000..8ccf05c
--- /dev/null
+++ b/web/stream.tg13.gathering.org/stream.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/perl -I /srv/streamlib
+
+use warnings;
+use strict;
+
+use stream;
+use stream::config;
+use CGI;
+my $client = CGI->new;
+
+my $stream = $client->param('stream');
+my $interlaced = $client->param('interlaced');
+my $delivery = $client->param('delivery');
+
+my $v4net = $stream::config::v4net;
+my $v6net = $stream::config::v6net;
+my $multicast_ip = $stream::config::multicast;
+my $tg = $stream::config::tg;
+my $base_url = $stream::config::vlc_base_host;
+my %streams = %stream::config::streams;
+
+
+
+#default
+if (not defined $delivery) {
+ $delivery = "multicast";
+}
+
+if((not defined $stream) or (not defined $delivery)) {
+ print $client->header();
+ die "No stream and/or delivery method, robots unhappy :/\n";
+}
+
+my $url = "";
+my $port_del = "";
+my $port_str = "";
+my $extinf = "";
+my $flash_appendix = "";
+
+my $clip = $client->remote_addr();
+
+if (exists($streams{$stream})) {
+ my $is_multicast = 0;
+ # add force is_ip_local in check?
+ $is_multicast = 1 if (exists($streams{$stream}->{has_multicast}) && $delivery eq "multicast");
+
+ if ($is_multicast) {
+ $port_del = 20;
+ $extinf .= "Multicasted";
+ $url = $streams{$stream}->{multicast_ip};
+ } else {
+ $port_del = 30;
+ $extinf .= "Unicasted";
+ $url = $base_url;
+
+ if ($streams{$stream}->{is_flash}) {
+ $port_del = 50;
+ $flash_appendix = "/stream.flv";
+ }
+ }
+
+ $port_del = $streams{$stream}->{preport} if (defined($streams{$stream}->{preport}));
+ $port_str = $streams{$stream}->{port};
+ $extinf .= " $streams{$stream}->{title}";
+
+} else {
+ &error("No stream and/or delivery method, robots unhappy :-/");
+}
+
+#print out new file
+print $client->header(-type => "application/vlc",
+ "-Content-disposition" => "attachment; filename=tg-".$delivery."-".$stream.".vlc"
+);
+
+print "#EXTM3U\n";
+print "#EXTINF:-1,TG$tg $extinf\n";
+if(defined $interlaced && $interlaced == 1) {
+ print "#EXTVLCOPT:deinterlace=1\n";
+ print "#EXTVLCOPT:deinterlace-mode=linear\n";
+}
+print "$url:$port_del$port_str$flash_appendix\n";
+
+sub error($) {
+ my $message = shift;
+ print $client->header();
+ die($message."\n");
+}
diff --git a/web/stream.tg13.gathering.org/streamstats-fast.pl b/web/stream.tg13.gathering.org/streamstats-fast.pl
new file mode 100755
index 0000000..f4caa24
--- /dev/null
+++ b/web/stream.tg13.gathering.org/streamstats-fast.pl
@@ -0,0 +1,15 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+use POSIX;
+use CGI qw(fatalsToBrowser);
+
+my $port_spec = CGI::param('port');
+my $proto_spec = CGI::param('proto');
+my $audience_spec = CGI::param('audience');
+
+print CGI::header(-type=>'image/png');
+
+# I'm sure this is really safe
+system("/srv/stream.tg13.gathering.org/fix_count.pl | /srv/stream.tg13.gathering.org/streamstats - $port_spec $proto_spec $audience_spec");
+#system("/srv/stream.tg13.gathering.org/streamstats", "/home/techserver/cleaned_datacube.log", $port_spec, $proto_spec, $audience_spec);
diff --git a/web/stream.tg13.gathering.org/streamstats.cpp b/web/stream.tg13.gathering.org/streamstats.cpp
new file mode 100644
index 0000000..e81419f
--- /dev/null
+++ b/web/stream.tg13.gathering.org/streamstats.cpp
@@ -0,0 +1,217 @@
+#include <stdio.h>
+#include <string.h>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <stdlib.h>
+
+using namespace std;
+
+map<string, string> port_desc = {
+ { "3013", "main (3013)" },
+ { "3014", "main-sd (3014)" },
+ { "3015", "webcam (3015)" },
+ { "3016", "webcam-south (3016)" },
+ { "3017", "webcam-south-transcode (3017)" },
+ { "3018", "webcam-fisheye (3018)" },
+ { "5013", "main-transcode (5013)" },
+ { "5015", "webcam-transcode (5015)" },
+};
+
+struct Spec {
+ set<string> incl;
+ bool compare;
+};
+
+Spec parse_spec(const string &spec)
+{
+ Spec ret;
+ ret.compare = false;
+
+ if (spec == "compare") {
+ ret.compare = true;
+ return ret;
+ }
+ if (spec == "dontcare") {
+ return ret;
+ }
+
+ const char *ptr = spec.c_str();
+ if (strncmp(ptr, "compare:", 8) == 0) {
+ ptr += 8;
+ ret.compare = true;
+ }
+
+ for ( ;; ) {
+ const char *end = strchr(ptr, ',');
+ if (end == NULL) {
+ ret.incl.insert(ptr);
+ break;
+ } else {
+ ret.incl.insert(string(ptr, end));
+ ptr = end + 1;
+ }
+ }
+
+ return ret;
+}
+
+bool filter(const string &entry, const Spec &spec)
+{
+ if (spec.incl.empty()) {
+ return false;
+ }
+ return spec.incl.count(entry) == 0;
+}
+
+vector<string> get_stream_id(const string& port, const string &proto, const string &audience,
+ const Spec& port_spec, const Spec &proto_spec, const Spec &audience_spec)
+{
+ vector<string> keys;
+ if (port_spec.compare) {
+ if (port_desc.count(port)) {
+ keys.push_back(port_desc[port]);
+ } else {
+ char buf[256];
+ sprintf(buf, "___%s___", port.c_str());
+ keys.push_back(buf);
+ }
+ }
+ if (proto_spec.compare) {
+ keys.push_back(proto);
+ }
+ if (audience_spec.compare) {
+ keys.push_back(audience);
+ }
+ return keys;
+}
+
+string get_stream_desc(const vector<string> &stream_id)
+{
+ string ret;
+ for (int i = 0; i < stream_id.size(); ++i) {
+ if (i != 0) {
+ ret += ",";
+ }
+ ret += stream_id[i];
+ }
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ Spec port_spec = parse_spec(argv[2]);
+ Spec proto_spec = parse_spec(argv[3]);
+ Spec audience_spec = parse_spec(argv[4]);
+
+ map<string, map<vector<string>, int> > lines;
+ map<vector<string>, int> stream_ids;
+ vector<string> stream_descs;
+
+ // Parse the log.
+ FILE *fp;
+ if (strcmp(argv[1], "-") == 0) {
+ fp = stdin;
+ } else {
+ fp = fopen(argv[1], "r");
+ }
+ while (!feof(fp)) {
+ char buf[1024];
+ fgets(buf, 1024, fp);
+
+ if (buf == NULL) {
+ break;
+ }
+ char *ptr = strchr(buf, '\n');
+ if (ptr != NULL) {
+ *ptr = 0;
+ }
+
+ char *date = strtok(buf, " ");
+ char *port = strtok(NULL, " ");
+ char *proto = strtok(NULL, " ");
+ char *audience = strtok(NULL, " ");
+ char *count = strtok(NULL, " ");
+
+ if (date == NULL || port == NULL || proto == NULL || audience == NULL || count == NULL) {
+ continue;
+ }
+
+ if (filter(port, port_spec)) {
+ continue;
+ }
+ if (filter(proto, proto_spec)) {
+ continue;
+ }
+ if (filter(audience, audience_spec)) {
+ continue;
+ }
+
+ vector<string> stream_id = get_stream_id(port, proto, audience, port_spec, proto_spec, audience_spec);
+ if (stream_ids.count(stream_id) == 0) {
+ int stream_id_num = stream_ids.size();
+ stream_ids.insert(make_pair(stream_id, stream_id_num));
+ stream_descs.push_back(get_stream_desc(stream_id));
+ }
+ lines[date][stream_id] += atoi(count);
+ }
+ fclose(fp);
+
+ // Output.
+ char *data_file = tempnam(NULL, "data");
+ FILE *datafp = fopen(data_file, "w");
+ if (datafp == NULL) {
+ perror(data_file);
+ exit(1);
+ }
+
+ vector<int> cols(stream_ids.size());
+ for (auto& it : lines) {
+ const string& date = it.first;
+
+ for (const auto& it2 : stream_ids) {
+ const vector<string>& stream_id = it2.first;
+ int stream_id_num = it2.second;
+
+ cols[stream_id_num] = it.second[stream_id]; // note: might zero-initialize
+ }
+ fprintf(datafp, "%s", date.c_str());
+ for (int i = 0; i < cols.size(); ++i) {
+ fprintf(datafp, " %d", cols[i]);
+ }
+ fprintf(datafp, "\n");
+ }
+ fclose(datafp);
+
+ // Make gnuplot script.
+ char *plot_file = tempnam(NULL, "plot");
+ FILE *plotfp = fopen(plot_file, "w");
+ if (plotfp == NULL) {
+ perror(plot_file);
+ exit(1);
+ }
+
+ fprintf(plotfp, "set terminal png\n");
+ fprintf(plotfp, "set xdata time\n");
+ fprintf(plotfp, "set timefmt \"20%%y-%%m-%%d-%%H:%%M:%%S\"\n");
+ fprintf(plotfp, "set xtics axis \"2000-00-00-01:00:00\"\n");
+ fprintf(plotfp, "set format x \"%%H\"\n");
+
+ fprintf(plotfp, "plot");
+ for (int i = 0; i < cols.size(); ++i) {
+ if (i == 0) {
+ fprintf(plotfp, " ");
+ } else {
+ fprintf(plotfp, ",");
+ }
+ fprintf(plotfp, "\"%s\" using 1:%d title \"%s\" with lines", data_file, i + 2, stream_descs[i].c_str());
+ }
+ fprintf(plotfp, "\n");
+
+ fclose(plotfp);
+
+ char buf[1024];
+ sprintf(buf, "gnuplot < %s", plot_file);
+ system(buf);
+}
diff --git a/web/stream.tg13.gathering.org/streamstats.html b/web/stream.tg13.gathering.org/streamstats.html
new file mode 100644
index 0000000..5d6adc7
--- /dev/null
+++ b/web/stream.tg13.gathering.org/streamstats.html
@@ -0,0 +1,81 @@
+<html>
+ <head>
+ <script>
+ function construct_url(name, choices) {
+ // port
+ var url = name + '=';
+ if (document.getElementById('split_' + name).checked) {
+ url += 'compare:';
+ }
+ var choices_so_far = 0;
+ for (var i = 0; i < choices.length; ++i) {
+ var check = document.getElementById(name + '_' + choices[i]);
+ if (!check.checked) {
+ continue;
+ }
+ if (choices_so_far++ != 0) {
+ url += ',';
+ }
+ url += choices[i];
+ }
+ return url;
+ }
+
+ function update() {
+ var url = 'http://stream.tg13.gathering.org/streamstats-fast.pl?';
+ url += construct_url('port', [ 3013, 3014, 3015, 3016, 3017, 3018, 5013, 5015 ]);
+ url += '&' + construct_url('proto', [ 'IPv4', 'IPv6' ]);
+ url += '&' + construct_url('audience', [ 'internal', 'external' ]);
+
+ document.getElementById('graph').src = url;
+ }
+ </script>
+ </head>
+ <body>
+ <table>
+ <tr>
+ <th>Ports:</th>
+ <td>
+ <label><input type="checkbox" id="port_3013" checked="checked" onchange="update();" /> 3013 (Main)</label><br />
+ <label><input type="checkbox" id="port_3014" checked="checked" onchange="update();" /> 3014 (Main SD)</label><br />
+ <label><input type="checkbox" id="port_3015" checked="checked" onchange="update();" /> 3015 (Webcam)</label><br />
+ <label><input type="checkbox" id="port_3016" checked="checked" onchange="update();" /> 3016 (Webcam south)</label><br />
+ <label><input type="checkbox" id="port_3017" checked="checked" onchange="update();" /> 3017 (Webcam south transcode)</label><br />
+ <label><input type="checkbox" id="port_3018" checked="checked" onchange="update();" /> 3018 (Fisheye)</label><br />
+ <label><input type="checkbox" id="port_5013" checked="checked" onchange="update();" /> 5013 (Main LQ/Flash)</label><br />
+ <label><input type="checkbox" id="port_5015" checked="checked" onchange="update();" /> 5015 (Webcam LQ/Flash)</label>
+ </td>
+ <td>
+ <label><input type="checkbox" id="split_port" onchange="update();" /> Split</label>
+ </td>
+ </tr>
+ <tr>
+ <th>Protocol:</th>
+ <td>
+ <label><input type="checkbox" id="proto_IPv4" checked="checked" onchange="update();" /> IPv4</label><br />
+ <label><input type="checkbox" id="proto_IPv6" checked="checked" onchange="update();" /> IPv6</label><br />
+ </td>
+ <td>
+ <label><input type="checkbox" id="split_proto" onchange="update();" /> Split</label>
+ </td>
+ </tr>
+ <tr>
+ <th>Audience:</th>
+ <td>
+ <label><input type="checkbox" id="audience_internal" checked="checked" onchange="update();" /> Internal</label><br />
+ <label><input type="checkbox" id="audience_external" checked="checked" onchange="update();" /> External</label><br />
+ </td>
+ <td>
+ <label><input type="checkbox" id="split_audience" onchange="update();" /> Split</label>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3">
+ <input type="button" value="Update display" onclick="update();" />
+ </td>
+ </tr>
+ </table>
+ <p><img src="" id="graph" /></p>
+ <script>update();</script>
+ </body>
+</html>
diff --git a/web/stream.tg13.gathering.org/streamstats.pl b/web/stream.tg13.gathering.org/streamstats.pl
new file mode 100755
index 0000000..e4c20f9
--- /dev/null
+++ b/web/stream.tg13.gathering.org/streamstats.pl
@@ -0,0 +1,116 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+use POSIX;
+use CGI qw(fatalsToBrowser);
+
+my %port_spec = prepare_spec(CGI::param('port'));
+my %proto_spec = prepare_spec(CGI::param('proto'));
+my %audience_spec = prepare_spec(CGI::param('audience'));
+
+#open LOG, "<", "/home/techserver/count_datacube.log"
+open LOG, "-|", "/home/techserver/fix_count.pl"
+#open LOG, "<", "/home/techserver/cleaned_datacube.log"
+ or die "count_datacube.log: $!";
+
+our %desc = (
+ 3013 => 'main (3013)',
+ 3014 => 'main-sd (3014)',
+ 3015 => 'webcam (3015)',
+ 3016 => 'webcam-south (3016)',
+ 3017 => 'webcam-south-transcode (3017)',
+ 3018 => 'webcam-fisheye (3018)',
+ 5013 => 'main-transcode (5013)',
+ 5015 => 'webcam-transcode (5015)',
+);
+
+my $lines = {};
+my %streams = ();
+
+while (<LOG>) {
+ chomp;
+ my ($date, $port, $proto, $audience, $count) = split /\s+/;
+ next if (filter($port, $proto, $audience));
+ my $stream_id = get_stream_id($port, $proto, $audience);
+ $streams{$stream_id} = 1;
+ $lines->{$date}{$stream_id} += $count;
+}
+
+close LOG;
+
+print CGI::header(-type=>'image/png');
+
+my $tmpfile = POSIX::tmpnam();
+open GRAPH, ">", $tmpfile
+ or die "$tmpfile: $!";
+for my $date (sort keys %$lines) {
+ my @cols = ();
+ for my $stream (keys %streams) {
+ push @cols, ($lines->{$date}{$stream} // "0");
+ }
+ print GRAPH "$date ", join(' ', @cols), "\n";
+}
+close GRAPH;
+
+my $tmpfile2 = POSIX::tmpnam();
+open GNUPLOT, ">", $tmpfile2
+ or die "$tmpfile2: $!";
+print GNUPLOT "set terminal png\n";
+print GNUPLOT "set xdata time\n";
+print GNUPLOT "set timefmt \"20%y-%m-%d-%H:%M:%S\"\n";
+print GNUPLOT "set xtics axis \"2000-00-00-01:00:00\"\n";
+print GNUPLOT "set format x \"%H\"\n";
+
+my @plots = ();
+my $idx = 2;
+for my $stream (keys %streams) {
+ push @plots, "\"$tmpfile\" using 1:$idx title \"$stream\" with lines";
+ ++$idx;
+}
+print GNUPLOT "plot ", join(', ', @plots);
+
+# \"$tmpfile\" using 0:2 with lines, \"$tmpfile\" using 0:3 with lines\n";
+close GNUPLOT;
+
+system("gnuplot < $tmpfile2");
+
+sub prepare_spec {
+ my $spec = shift;
+ return () if ($spec eq 'compare' || $spec eq 'dontcare');
+ $spec =~ s/^compare://;
+
+ my %ret = ();
+ for my $s (split /,/, $spec) {
+ $ret{$s} = 1;
+ }
+ return %ret;
+}
+
+sub filter {
+ my ($port, $proto, $audience) = @_;
+ return 1 if (filter_list(\%port_spec, $port));
+ return 1 if (filter_list(\%proto_spec, $proto));
+ return 1 if (filter_list(\%audience_spec, $audience));
+ return 0;
+}
+
+sub filter_list {
+ my ($spec, $candidate) = @_;
+ return 0 if ((scalar keys %$spec) == 0);
+ return !exists($spec->{$candidate});
+}
+
+sub get_stream_id {
+ my ($port, $proto, $audience) = @_;
+ my @keys = ();
+ if (CGI::param('port') =~ /^compare/) {
+ if (exists($desc{$port})) {
+ push @keys, $desc{$port};
+ } else {
+ push @keys, "___" . $port . "___";
+ }
+ }
+ push @keys, $proto if (CGI::param('proto') =~ /^compare/);
+ push @keys, $audience if (CGI::param('audience') =~ /^compare/);
+ return join(',', @keys);
+}
diff --git a/web/stream.tg13.gathering.org/superawesomeness.css b/web/stream.tg13.gathering.org/superawesomeness.css
new file mode 100644
index 0000000..b8c5545
--- /dev/null
+++ b/web/stream.tg13.gathering.org/superawesomeness.css
@@ -0,0 +1,24 @@
+* { font-family: 'Open Sans', sans-serif;
+
+}
+
+body {
+ background: #fff; color: #000; opacity: 1;
+}
+
+#spaceship { background: url('singularity.png'); width: 237px; height: 200px;position:absolute; top: 0; right: 0;z-index: -1}
+
+@media screen and (max-width: 1145px) { /* Min iPad size*/
+ #spaceship {
+ background: #fff;
+ }
+}
+
+
+/* #innhold { position: absolute; left:0px ; top: 50px; margin: 0 50px 0 50px; z-index: 9; width: 520px; }*/
+#innhold { width: 480px; }
+footer { clear: both; width:480px; }
+a { color: #000; }
+h4 { margin: 0; margin-top: 35px;}
+p { margin: 0; padding: 0; }
+li { margin-bottom: 14px; }
diff --git a/web/stream.tg13.gathering.org/test.pl b/web/stream.tg13.gathering.org/test.pl
new file mode 100755
index 0000000..3b440d5
--- /dev/null
+++ b/web/stream.tg13.gathering.org/test.pl
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -I /srv/streamlib
+use warnings;
+use strict;
+use CGI;
+use Geo::IP;
+use NetAddr::IP;
+use Net::IP;
+# apt-get install libnet-ip-perl libnetaddr-ip-perl
+use HTML::Template;
+use stream;
+use stream::config;
+
+my $client = CGI->new;
+
+my $v4net = $stream::config::v4net;
+my $v6net = $stream::config::v6net;
+my $tg = $stream::config::tg;
+my $tg_full = $stream::config::tg_full;
+my %streams = %stream::config::streams;
+
+my $force_unicast = $client->param('forceunicast');
+
+my $location = undef;
+
+print $client->header();
+
+my $clip = $client->remote_addr();
+my $template = HTML::Template->new(filename => 'test.tmpl');
+my $is_local = &is_ip_local($clip, $v4net, $v6net);
+
+my @streams = &html_local_test();
+$template->param(TG => $tg);
+$template->param(TG_FULL => $tg_full);
+$template->param(STREAMS => \@streams);
+print $template->output();
+
+
+sub html_local_test() {
+ my @s = ();
+ foreach my $name (sort { $streams{$a}->{priority} <=> $streams{$b}->{priority} } keys %streams) {
+ my $title_link = "http://stream.tg$tg.gathering.org/stream.pl?delivery=%s&stream=${name}&interlaced=%s";
+ my $multicast_link = $streams{$name}->{has_multicast} ? "multicast" : "unicast";
+ $multicast_link = "unicast" if ($force_unicast == 1 || not $is_local);
+
+ if ($streams{$name}->{external}) {
+ $title_link = $streams{$name}->{url};
+ } else {
+ $title_link = sprintf($title_link, $multicast_link, $streams{$name}->{interlaced});
+ }
+ my %hash = (
+ 'title_link' => $title_link,
+ 'title' => $streams{$name}->{title},
+ 'source' => $streams{$name}->{source},
+ 'quality' => $streams{$name}->{quality},
+ 'location' => $streams{$name}->{location},
+ 'type' => $streams{$name}->{type},
+ 'delivery' => $multicast_link,
+ );
+ if ($multicast_link eq "multicast") {
+ $hash{'is_multicast'} .= 1;
+ my $unicast_link = $title_link;
+ $unicast_link=~s/multicast/unicast/g;
+ $hash{'unicast_link'} .= $unicast_link;
+ }
+ $hash{'description'} .= $streams{$name}->{description} if exists($streams{$name}->{description});
+ push(@s, \%hash);
+
+ }
+ return @s;
+}
diff --git a/web/stream.tg13.gathering.org/test.tmpl b/web/stream.tg13.gathering.org/test.tmpl
new file mode 100644
index 0000000..ea0eaca
--- /dev/null
+++ b/web/stream.tg13.gathering.org/test.tmpl
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <title>The Gathering <TMPL_VAR NAME=TG_FULL> Streams</title>
+ <link rel="stylesheet" type="text/css" href="singularity.css" media="all">
+</head>
+<body>
+ <div id="innhold">
+ <h1>The Gathering <TMPL_VAR NAME=TG_FULL> Streams</h1>
+ <TMPL_LOOP NAME="STREAMS">
+ <div class="stream-link">
+ <div class="stream-icon"><img src="img/icon_<TMPL_VAR NAME=QUALITY>.png" /> <img src="img/icon_<TMPL_VAR NAME=TYPE>.png" /> <TMPL_IF NAME=LOCATION><img src="img/icon_<TMPL_VAR NAME=LOCATION>.png"></TMPL_IF></div>
+ <div class="stream-link-content">
+ <a href="<TMPL_VAR NAME=TITLE_LINK>"><TMPL_VAR NAME=TITLE></a><br>
+ Source: <TMPL_VAR NAME=SOURCE><br>
+ Delivery: <TMPL_VAR NAME=delivery> <TMPL_IF NAME=IS_MULTICAST>(<a href='<TMPL_VAR NAME=UNICAST_LINK>'>problems? try unicast vlc link here</a>)</TMPL_IF>
+ </div>
+ </div>
+ </TMPL_LOOP>
+ <div id="map">
+ <img src="img/cam-map.png">
+ </div>
+
+ </div>
+
+ <p>Problems with the non game streams? The easiest way to get hold of us is on IRC (EFNet); one of ViD, Rockj and Sesse should be available if there's too much traffic on #tg to be heard.</p>
+ <p><a href="http://stream.tg<TMPL_VAR NAME="TG">.gathering.org">http://stream.tg<TMPL_VAR NAME="TG">.gathering.org</a></p>
+
+</body>
+</html>
+
+
diff --git a/web/streamlib/stream.pm b/web/streamlib/stream.pm
new file mode 100644
index 0000000..c28136e
--- /dev/null
+++ b/web/streamlib/stream.pm
@@ -0,0 +1,36 @@
+package stream;
+use strict;
+use warnings;
+
+BEGIN {
+ use Exporter();
+
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ @ISA = qw(Exporter);
+ $VERSION = 1.00;
+ @EXPORT = qw(&is_ip_local);
+
+}
+
+sub is_ip_local($$$) {
+ my $clip = shift;
+ my $v4net = shift;
+ my $v6net = shift;
+ return 0 unless defined($clip);
+
+ my $is_local = 0;
+ if ($clip =~ m/\:/){
+ if (NetAddr::IP->new($clip)->within($v6net)){
+ $is_local = 1;
+ }
+ } else {
+ if (NetAddr::IP->new($clip)->within($v4net)){
+ $is_local = 1;
+ }
+ }
+ return $is_local;
+}
+
+
+1;
diff --git a/web/streamlib/stream/config.pm b/web/streamlib/stream/config.pm
new file mode 100644
index 0000000..7c488b6
--- /dev/null
+++ b/web/streamlib/stream/config.pm
@@ -0,0 +1,160 @@
+package stream::config;
+use strict;
+use warnings;
+use NetAddr::IP;
+
+our $v4net = NetAddr::IP->new("151.216.0.0/17");
+our $v6net = NetAddr::IP->new("2a02:ed02::/32");
+our $multicast = "udp://\@233.191.12.1";
+our $vlc_base_host = "http://stream.tg13.gathering.org";
+our $tg = 13;
+our $tg_full = 2013;
+
+
+# priority = sorting order in streaming list
+# port , "post port number"
+# has_external , shows on OVH/.fr reflector if set
+# external , replaces static url link
+# source , video source pew pew
+# title , title doh \:D/
+our %streams = (
+# Deaktivert 31.mars kl 05.30 iush
+# 'event-ios' => {
+# 'type' => 'event',
+# 'quality' => 'hd',
+# 'priority' => 26,
+# 'external' => 1,
+# 'url' => "$vlc_base_host/ios/event.m3u8",
+# 'source' => 'Event',
+# 'title' => 'Event HD Stream for iOS devices (Apple)',
+# },
+# 'event-hd' => {
+# 'type' => 'event',
+# 'quality' => 'hd',
+# 'priority' => 20,
+# 'port' => 13,
+# 'interlaced' => 0,
+# 'has_multicast' => 1,
+# 'multicast_ip' => 'udp://@[ff7e:a40:2a02:ed02:ffff::13]',
+# 'source' => 'Event',
+# 'title' => 'Event HD (720p50)'
+# },
+# 'event-sd' => {
+# 'type' => 'event',
+# 'quality' => 'sd',
+# 'priority' => 24,
+# 'port' => 14,
+# 'interlaced' => 0,
+# 'has_multicast' => 1,
+# 'multicast_ip' => 'udp://@[ff7e:a40:2a02:ed02:ffff::14]',
+# 'source' => 'Event',
+# 'title' => 'Event SD (576p) (2mbps)'
+# },
+# 'event-flash' => {
+# 'type' => 'event',
+# 'quality' => 'sd',
+# 'priority' => 25,
+# 'interlaced' => 0,
+# 'external' => 1,
+# 'url' => 'http://www.gathering.org/tg13/no/live-tv/',
+# 'source' => 'Event',
+# 'title' => 'Event SD (gathering.org flash player)',
+# },
+#
+
+
+ 'south-raw' => {
+ 'type' => 'camera',
+ 'location' => 3,
+ 'quality' => 'hd',
+ 'priority' => 40,
+ 'port' => 16,
+ 'interlaced' => 1,
+ 'has_multicast' => 0,
+# 'multicast_ip' => "udp://@[ff7e:a40:2a02:ed02:ffff::16]",
+ 'source' => 'Tech',
+ 'title' => 'Webcam South (HD) (1080i25)',
+ },
+
+ 'south-transcode' => {
+ 'type' => 'camera',
+ 'location' => 3,
+ 'quality' => 'hd',
+ 'priority' => 50,
+ 'port' => 17,
+ 'interlaced' => 0,
+ 'has_multicast' => 1,
+ 'multicast_ip' => "udp://@[ff7e:a40:2a02:ed02:ffff::17]",
+ 'source' => 'Tech',
+ 'title' => 'Webcam South (HD) (720p50)',
+ },
+
+
+ 'fuglecam' => {
+ 'type' => 'camera',
+ 'location' => 2,
+ 'quality' => 'hd',
+ 'priority' => 118,
+ 'port' => 15,
+ 'interlaced' => 1,
+ 'has_multicast' => 1,
+ 'multicast_ip' => "udp://\@[ff7e:a40:2a02:ed02:ffff::15]",
+ 'source' => 'Tech',
+ 'title' => 'Webcam Fugleberget (HD) (1080i50)',
+ },
+
+
+
+ 'fuglecam-flv-sd' => {
+ 'location' => 2,
+ 'type' => 'camera',
+ 'quality' => 'sd',
+ 'priority' => 121,
+ 'interlaced' => 1,
+ 'external' => 1,
+ 'url' => 'http://www.gathering.org/tg13/no/webcam/',
+ 'title' => 'Webcam Fugleberget (SD) (gathering.org flash player)',
+ },
+
+ 'noc-fisheye' => {
+ 'type' => 'camera',
+ 'location' => 1,
+ 'quality' => 'hd',
+ 'priority' => 130,
+ 'port' => 18,
+ 'has_multicast' => 1,
+ 'interlaced' => 0,
+ 'multicast_ip' => "udp://@[ff7e:a40:2a02:ed02:ffff::18]:2018",
+ 'source' => "Tech",
+ 'title' => "Webcam NOC Fisheye (HD)"
+ },
+ 'noc-fisheye-transcode' => {
+ 'type' => 'camera',
+ 'location' => 1,
+ 'quality' => 'hd',
+ 'priority' => 131,
+ 'port' => 19,
+ 'has_multicast' => 1,
+ 'interlaced' => 0,
+ 'multicast_ip' => "udp://@[ff7e:a40:2a02:ed02:ffff::19]:2019",
+ 'source' => "Tech",
+ 'title' => "Webcam NOC Fisheye (HD transcoded)"
+ },
+
+
+ 'south-still' => {
+ 'location' => 3,
+ 'type' => 'camera',
+ 'quality' => 'hd',
+ 'priority' => 110,
+ 'external' => 1,
+ 'url' => 'http://stillcam.tg13.gathering.org/',
+ 'title' => 'Webcam South (Image)',
+ 'source' => 'Tech'
+ },
+
+
+ );
+
+
+1;
diff --git a/web/tech.gathering.org/event-720p.mp4.pl b/web/tech.gathering.org/event-720p.mp4.pl
new file mode 100755
index 0000000..631e40d
--- /dev/null
+++ b/web/tech.gathering.org/event-720p.mp4.pl
@@ -0,0 +1,11 @@
+#!/usr/bin/env
+use strict;
+use warnings;
+use Capture::Tiny ':all';
+
+$! = 1;
+print "Content-Type: video/mp4\n\n";
+
+my ($stdout, $stderr) = tee {
+ system('wget', '-qO-', 'http://stream.tg13.gathering.org:3013');
+};
diff --git a/web/tech.gathering.org/index.html b/web/tech.gathering.org/index.html
new file mode 100644
index 0000000..9a5b0ad
--- /dev/null
+++ b/web/tech.gathering.org/index.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<title>Tech resources - The Gathering 2013</title>
+<link rel="stylesheet" type="text/css" href="/styles.css" media="all">
+</head>
+<body>
+
+<h1>Tech resources - The Gathering 2013</h1>
+
+<img id="logo" src="logo.png" alt="The Gathering 2013" />
+
+<h2><a href="http://stats.tg13.gathering.org">stats.tg13.gathering.org (weathermap)</a></h2>
+<h2><a href="http://nms-public.tg13.gathering.org">nms-public.tg13.gathering.org</a></h2>
+<h2><a href="http://stream.tg13.gathering.org">stream.tg13.gathering.org</a></h2>
+
+<h2><a href="http://techserver.gathering.org/ircrules">IRC rules for #tg@EFnet</a></h2>
+
+<p>Enjoy :-)</p>
+</body>
+</html>
diff --git a/web/tech.gathering.org/logo.png b/web/tech.gathering.org/logo.png
new file mode 100644
index 0000000..3a13cdf
--- /dev/null
+++ b/web/tech.gathering.org/logo.png
Binary files differ
diff --git a/web/tech.gathering.org/styles.css b/web/tech.gathering.org/styles.css
new file mode 100644
index 0000000..e690989
--- /dev/null
+++ b/web/tech.gathering.org/styles.css
@@ -0,0 +1,24 @@
+* { font-family: 'Open Sans', sans-serif;
+
+}
+
+body {
+ background: #fff; color: #000; opacity: 1;
+}
+
+#logo { background: url('logo.png'); width: 237px; height: 200px;position:absolute; top: 0; right: 0;z-index: -1}
+
+@media screen and (max-width: 1145px) { /* Min iPad size*/
+ #spaceship {
+ background: #fff;
+ }
+}
+
+/* #innhold { position: absolute; left:0px ; top: 50px; margin: 0 50px 0 50px; z-index: 9; width: 520px; }*/
+#innhold { width: 480px; }
+footer { clear: both; width:480px; }
+a { color: #000; }
+h4 { margin: 0; margin-top: 35px;}
+p { margin: 0; padding: 0; }
+li { margin-bottom: 14px; }
+