summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Legler <a3li@gentoo.org>2012-02-28 02:03:25 +0100
committerAlex Legler <a3li@gentoo.org>2012-02-28 02:03:25 +0100
commit0c9fbb16e6d3c0eea805958aad4f0b7f35b0e4ce (patch)
tree19d87887fd10d64053f7f53233f85169ab18d835
downloadinfra-status-0c9fbb16e6d3c0eea805958aad4f0b7f35b0e4ce.tar.gz
infra-status-0c9fbb16e6d3c0eea805958aad4f0b7f35b0e4ce.tar.bz2
infra-status-0c9fbb16e6d3c0eea805958aad4f0b7f35b0e4ce.zip
Initial commit
-rw-r--r--.gitignore2
-rw-r--r--Rules80
-rw-r--r--config.yaml79
-rw-r--r--content/atom.xml.erb7
-rw-r--r--content/css/1140.css130
-rw-r--r--content/css/ie.css43
-rw-r--r--content/css/screen.css142
-rw-r--r--content/img/feed.pngbin0 -> 688 bytes
-rw-r--r--content/img/information.pngbin0 -> 621 bytes
-rw-r--r--content/img/maintenance.pngbin0 -> 558 bytes
-rw-r--r--content/img/na.pngbin0 -> 308 bytes
-rw-r--r--content/img/notice.pngbin0 -> 435 bytes
-rw-r--r--content/img/outage.pngbin0 -> 748 bytes
-rw-r--r--content/img/site_logo.pngbin0 -> 5984 bytes
-rw-r--r--content/img/status_down.pngbin0 -> 588 bytes
-rw-r--r--content/img/status_up.pngbin0 -> 605 bytes
-rw-r--r--content/img/status_warning.pngbin0 -> 585 bytes
-rw-r--r--content/index.haml93
-rw-r--r--content/js/css3-mediaqueries.js779
-rw-r--r--content/notices/.gitignore1
-rw-r--r--example.md25
-rw-r--r--layouts/_post.haml21
-rw-r--r--layouts/default.haml38
-rw-r--r--lib/default.rb2
-rw-r--r--lib/helpers.rb136
-rw-r--r--lib/service-dsl.rb73
-rw-r--r--lib/services.rb93
27 files changed, 1744 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c019529
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+tmp
+output
diff --git a/Rules b/Rules
new file mode 100644
index 0000000..59f16a9
--- /dev/null
+++ b/Rules
@@ -0,0 +1,80 @@
+#!/usr/bin/env ruby
+
+# A few helpful tips about the Rules file:
+#
+# * The string given to #compile and #route are matching patterns for
+# identifiers--not for paths. Therefore, you can’t match on extension.
+#
+# * The order of rules is important: for each item, only the first matching
+# rule is applied.
+#
+# * Item identifiers start and end with a slash (e.g. “/about/” for the file
+# “content/about.html”). To select all children, grandchildren, … of an
+# item, use the pattern “/about/*/”; “/about/*” will also select the parent,
+# because “*” matches zero or more characters.
+
+compile '/css/*/' do
+ # don’t filter or layout
+end
+
+compile '/js/*/' do
+ # don’t filter or layout
+end
+
+compile '/atom' do
+ filter :erb
+end
+
+compile '*' do
+ ext = item[:extension].nil? ? nil : item[:extension].split('.').last
+
+ if item.binary?
+ # don’t filter binary items
+ elsif ext == 'md' || ext == 'markdown'
+ filter :erb
+ filter :rdiscount
+
+ if item[:kind] == 'article'
+ layout '_post'
+ snapshot :single_post
+ end
+
+ layout 'default'
+ elsif ext == 'haml'
+ filter :haml
+ layout 'default'
+ else
+ filter :erb
+ layout 'default'
+ end
+end
+
+route '/css/*/' do
+ item.identifier.chop + '.css'
+end
+
+route '/js/*/' do
+ item.identifier.chop + '.js'
+end
+
+route '/atom' do
+ item.identifier.chop + '.xml'
+end
+
+route '/notices/*' do
+ item.identifier.chop + '.html'
+end
+
+route '*' do
+ if item.binary?
+ # Write item with identifier /foo/ to /foo.ext
+ item.identifier.chop + '.' + item[:extension]
+ else
+ # Write item with identifier /foo/ to /foo/index.html
+ item.identifier + 'index.html'
+ end
+end
+
+layout '*', :haml
+
+# vim: et sw=2 ts=2:
diff --git a/config.yaml b/config.yaml
new file mode 100644
index 0000000..18d2280
--- /dev/null
+++ b/config.yaml
@@ -0,0 +1,79 @@
+base_url: http://infra-status.gentoo.org
+
+# A list of file extensions that nanoc will consider to be textual rather than
+# binary. If an item with an extension not in this list is found, the file
+# will be considered as binary.
+text_extensions: [ 'css', 'erb', 'haml', 'htm', 'html', 'js', 'less', 'markdown', 'md', 'php', 'rb', 'sass', 'scss', 'txt', 'xhtml', 'xml', 'coffee' ]
+
+# The path to the directory where all generated files will be written to. This
+# can be an absolute path starting with a slash, but it can also be path
+# relative to the site directory.
+output_dir: output
+
+# A list of index filenames, i.e. names of files that will be served by a web
+# server when a directory is requested. Usually, index files are named
+# “index.html”, but depending on the web server, this may be something else,
+# such as “default.htm”. This list is used by nanoc to generate pretty URLs.
+index_filenames: [ 'index.html' ]
+
+# Whether or not to generate a diff of the compiled content when compiling a
+# site. The diff will contain the differences between the compiled content
+# before and after the last site compilation.
+enable_output_diff: false
+
+prune:
+ # Whether to automatically remove files not managed by nanoc from the output
+ # directory. For safety reasons, this is turned off by default.
+ auto_prune: false
+
+ # Which files and directories you want to exclude from pruning. If you version
+ # your output directory, you should probably exclude VCS directories such as
+ # .git, .svn etc.
+ exclude: [ '.git', '.hg', '.svn', 'CVS' ]
+
+# The data sources where nanoc loads its data from. This is an array of
+# hashes; each array element represents a single data source. By default,
+# there is only a single data source that reads data from the “content/” and
+# “layout/” directories in the site directory.
+data_sources:
+ -
+ # The type is the identifier of the data source. By default, this will be
+ # `filesystem_unified`.
+ type: filesystem_unified
+
+ # The path where items should be mounted (comparable to mount points in
+ # Unix-like systems). This is “/” by default, meaning that items will have
+ # “/” prefixed to their identifiers. If the items root were “/en/”
+ # instead, an item at content/about.html would have an identifier of
+ # “/en/about/” instead of just “/about/”.
+ items_root: /
+
+ # The path where layouts should be mounted. The layouts root behaves the
+ # same as the items root, but applies to layouts rather than items.
+ layouts_root: /
+
+ # Whether to allow periods in identifiers. When turned off, everything
+ # past the first period is considered to be the extension, and when
+ # turned on, only the characters past the last period are considered to
+ # be the extension. For example, a file named “content/about.html.erb”
+ # will have the identifier “/about/” when turned off, but when turned on
+ # it will become “/about.html/” instead.
+ allow_periods_in_identifiers: false
+
+# Configuration for the “watch” command, which watches a site for changes and
+# recompiles if necessary.
+watcher:
+ # A list of directories to watch for changes. When editing this, make sure
+ # that the “output/” and “tmp/” directories are _not_ included in this list,
+ # because recompiling the site will cause these directories to change, which
+ # will cause the site to be recompiled, which will cause these directories
+ # to change, which will cause the site to be recompiled again, and so on.
+ dirs_to_watch: [ 'content', 'layouts', 'lib' ]
+
+ # A list of single files to watch for changes. As mentioned above, don’t put
+ # any files from the “output/” or “tmp/” directories in here.
+ files_to_watch: [ 'config.yaml', 'Rules' ]
+
+ # When to send notifications (using Growl or notify-send).
+ notify_on_compilation_success: true
+ notify_on_compilation_failure: true
diff --git a/content/atom.xml.erb b/content/atom.xml.erb
new file mode 100644
index 0000000..6439efb
--- /dev/null
+++ b/content/atom.xml.erb
@@ -0,0 +1,7 @@
+---
+title: Gentoo Linux Infrastructure Status
+author_name: Gentoo Infrastructure Team
+author_uri: http://infra-status.gentoo.org/
+is_hidden: true
+---
+<%= atom_feed(:content_proc => feed_proc, :articles => feed_articles) %>
diff --git a/content/css/1140.css b/content/css/1140.css
new file mode 100644
index 0000000..b8d6fa2
--- /dev/null
+++ b/content/css/1140.css
@@ -0,0 +1,130 @@
+/* CSS Resets */
+
+html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,address,cite,code,del,dfn,em,img,ins,q,small,strong,sub,sup,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{border:0;margin:0;padding:0}article,aside,figure,figure img,figcaption,hgroup,footer,header,nav,section,video,object{display:block}a img{border:0}figure{position:relative}figure img{width:100%}
+
+
+/* ==================================================================================================================== */
+/* ! The 1140px Grid V2 by Andy Taylor \ http://cssgrid.net \ http://www.twitter.com/andytlr \ http://www.andytlr.com */
+/* ==================================================================================================================== */
+
+.container {
+padding-left: 20px;
+padding-right: 20px;
+}
+
+.row {
+width: 100%;
+max-width: 1140px;
+min-width: 755px;
+margin: 0 auto;
+overflow: hidden;
+}
+
+.onecol, .twocol, .threecol, .fourcol, .fivecol, .sixcol, .sevencol, .eightcol, .ninecol, .tencol, .elevencol {
+margin-right: 3.8%;
+float: left;
+min-height: 1px;
+}
+
+.row .onecol {
+width: 4.85%;
+}
+
+.row .twocol {
+width: 13.45%;
+}
+
+.row .threecol {
+width: 22.05%;
+}
+
+.row .fourcol {
+width: 30.75%;
+}
+
+.row .fivecol {
+width: 39.45%;
+}
+
+.row .sixcol {
+width: 48%;
+}
+
+.row .sevencol {
+width: 56.75%;
+}
+
+.row .eightcol {
+width: 65.4%;
+}
+
+.row .ninecol {
+width: 74.05%;
+}
+
+.row .tencol {
+width: 82.7%;
+}
+
+.row .elevencol {
+width: 91.35%;
+}
+
+.row .twelvecol {
+width: 100%;
+float: left;
+}
+
+.last {
+margin-right: 0px;
+}
+
+img, object, embed {
+max-width: 100%;
+}
+
+img {
+ height: auto;
+}
+
+
+/* Smaller screens */
+
+@media only screen and (max-width: 1023px) {
+
+ body {
+ font-size: 0.8em;
+ line-height: 1.5em;
+ }
+
+ }
+
+
+/* Mobile */
+
+@media handheld, only screen and (max-width: 767px) {
+
+ body {
+ font-size: 16px;
+ -webkit-text-size-adjust: none;
+ }
+
+ .row, body, .container {
+ width: 100%;
+ min-width: 0;
+ margin-left: 0px;
+ margin-right: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ }
+
+ .row .onecol, .row .twocol, .row .threecol, .row .fourcol, .row .fivecol, .row .sixcol, .row .sevencol, .row .eightcol, .row .ninecol, .row .tencol, .row .elevencol, .row .twelvecol {
+ width: auto;
+ float: none;
+ margin-left: 0px;
+ margin-right: 0px;
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+
+} \ No newline at end of file
diff --git a/content/css/ie.css b/content/css/ie.css
new file mode 100644
index 0000000..530c113
--- /dev/null
+++ b/content/css/ie.css
@@ -0,0 +1,43 @@
+.onecol {
+width: 4.7%;
+}
+
+.twocol {
+width: 13.2%;
+}
+
+.threecol {
+width: 22.05%;
+}
+
+.fourcol {
+width: 30.6%;
+}
+
+.fivecol {
+width: 39%;
+}
+
+.sixcol {
+width: 48%;
+}
+
+.sevencol {
+width: 56.75%;
+}
+
+.eightcol {
+width: 61.6%;
+}
+
+.ninecol {
+width: 74.05%;
+}
+
+.tencol {
+width: 82%;
+}
+
+.elevencol {
+width: 91.35%;
+} \ No newline at end of file
diff --git a/content/css/screen.css b/content/css/screen.css
new file mode 100644
index 0000000..c3970c9
--- /dev/null
+++ b/content/css/screen.css
@@ -0,0 +1,142 @@
+/* ============================== */
+/* ! Layout for desktop version */
+/* ============================== */
+
+body {
+ font-family: 'Open Sans', sans-serif;
+ padding-bottom: 3em;
+}
+
+a:link, a:visited {
+ color: #54487A;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+.right {
+ float: right;
+}
+
+.header {
+ background-color: #E8E8E8;
+ border-top: 2px solid #54487A;
+ border-bottom: 1px solid #dcdcdc;
+}
+
+.header .row {
+ padding-top: .25em;
+ padding-bottom: .25em;
+}
+
+h1 {
+ font-size: 1.5em;
+}
+
+h2 {
+ font-size: 1.25em;
+}
+
+h3 {
+ font-size: 1.1em;
+ font-weight: 600;
+}
+
+.site-title {
+ background-color: #f5f5f5;
+ border-bottom: 1px solid #e8e8e8;
+ margin-bottom: 1em;
+}
+
+.site-title .row {
+ padding-top: .25em;
+ padding-bottom: .25em;
+}
+
+table.statustable {
+ width: 100%;
+ border-spacing: 0 2px;
+}
+
+table.statustable td {
+ padding-bottom: 1px;
+ border-bottom: 1px solid #e8e8e8;
+}
+
+table.statustable tr.last td {
+ border: none !important;
+}
+
+table.statustable td.status {
+ text-align: right;
+}
+
+table.statustable tr.down {
+ color: #a40000;
+}
+
+table.statustable tr.warning {
+ color: #ac4a00;
+}
+
+.grey {
+ background-color: #F5F5F5;
+}
+
+.bottomline {
+ border-bottom: 1px solid #e8e8e8;
+ padding-bottom: 1em;
+ margin-bottom: 1em;
+}
+
+p {
+ margin-top: .5em;
+ margin-bottom: .5em;
+}
+
+.post {
+ margin-top: .5em;
+ margin-bottom: .5em;
+ border-top: 1px solid #dcdcdc;
+}
+
+table.dates {
+ margin-left: 1em;
+ font-style: italic;
+}
+
+td {
+ padding-left: 0.25em;
+ padding-right: 0.25em;
+}
+
+#footer {
+ border-top: 1px solid #dcdcdc;
+ position: fixed;
+ width: 100%;
+ bottom: 0;
+ background-color: #E8E8E8;
+ padding-left: 0;
+ padding-right: 0;
+ padding-top: .5em;
+ padding-bottom: .5em;
+ font-size: .75em;
+}
+
+/* ============================= */
+/* ! Layout for mobile version */
+/* ============================= */
+
+@media handheld, only screen and (max-width: 767px) {
+
+ body {
+ padding-bottom: 0;
+ }
+
+ #footer {
+ position: relative !important;
+ }
+
+}
diff --git a/content/img/feed.png b/content/img/feed.png
new file mode 100644
index 0000000..cdf4e8f
--- /dev/null
+++ b/content/img/feed.png
Binary files differ
diff --git a/content/img/information.png b/content/img/information.png
new file mode 100644
index 0000000..4ecaf37
--- /dev/null
+++ b/content/img/information.png
Binary files differ
diff --git a/content/img/maintenance.png b/content/img/maintenance.png
new file mode 100644
index 0000000..8347aa8
--- /dev/null
+++ b/content/img/maintenance.png
Binary files differ
diff --git a/content/img/na.png b/content/img/na.png
new file mode 100644
index 0000000..93807bc
--- /dev/null
+++ b/content/img/na.png
Binary files differ
diff --git a/content/img/notice.png b/content/img/notice.png
new file mode 100644
index 0000000..adaf4f0
--- /dev/null
+++ b/content/img/notice.png
Binary files differ
diff --git a/content/img/outage.png b/content/img/outage.png
new file mode 100644
index 0000000..413291d
--- /dev/null
+++ b/content/img/outage.png
Binary files differ
diff --git a/content/img/site_logo.png b/content/img/site_logo.png
new file mode 100644
index 0000000..8ff911e
--- /dev/null
+++ b/content/img/site_logo.png
Binary files differ
diff --git a/content/img/status_down.png b/content/img/status_down.png
new file mode 100644
index 0000000..933272b
--- /dev/null
+++ b/content/img/status_down.png
Binary files differ
diff --git a/content/img/status_up.png b/content/img/status_up.png
new file mode 100644
index 0000000..3b0e3fc
--- /dev/null
+++ b/content/img/status_up.png
Binary files differ
diff --git a/content/img/status_warning.png b/content/img/status_warning.png
new file mode 100644
index 0000000..e792fb0
--- /dev/null
+++ b/content/img/status_warning.png
Binary files differ
diff --git a/content/index.haml b/content/index.haml
new file mode 100644
index 0000000..129f3e4
--- /dev/null
+++ b/content/index.haml
@@ -0,0 +1,93 @@
+---
+title: Index
+---
+.container.bottomline
+ .row
+ .twelvecol.last
+ %h2 Service Availability Overview
+ %p
+ This data is aggregated from our automated service monitoring system as well as the outage and maintenance notices posted below.
+ .row
+ .fourcol
+ %h3 Community Services
+ %table.statustable
+ %tr.up
+ %td gentoo.org Website
+ %td.status
+ = service_icons 'www'
+ %tr
+ %td Forums
+ %td.status
+ = service_icons 'forums'
+ %tr
+ %td Wiki
+ %td.status
+ = service_icons 'wiki'
+ %tr
+ %td Planet Gentoo
+ %td.status
+ = service_icons 'planet'
+ %tr
+ %td Packages Database
+ %td.status
+ = service_icons 'pgo'
+ %tr
+ %td Mailing Lists
+ %td.status
+ = service_icons 'lists'
+ %tr.last
+ %td Mailing List Archives
+ %td.status
+ = service_icons 'archives'
+ .fourcol
+ %h3 Development Services
+ %table.statustable
+ %tr
+ %td cvs.gentoo.org
+ %td.status
+ = service_icons 'cvs'
+ %tr
+ %td Bugzilla
+ %td.status
+ = service_icons 'bugzilla'
+ %tr
+ %td Devmanual
+ %td.status
+ = service_icons 'devmanual'
+ %tr
+ %td Overlays
+ %td.status
+ = service_icons 'overlays'
+ %tr
+ %td tinderbox.dev.gentoo.org
+ %td.status
+ = service_icons 'tinderbox'
+ %tr.last
+ %td sources.gentoo.org
+ %td.status
+ = service_icons 'sources'
+ .fourcol.last
+ %h3 Developer Resources
+ %table.statustable
+ %tr
+ %td dev.gentoo.org shell access
+ %td.status
+ = service_icons 'dgo_ssh'
+ %tr
+ %td dev.gentoo.org web hosting
+ %td.status
+ = service_icons 'dgo_http'
+ %tr
+ %td In-/Outbound Email (SMTP)
+ %td.status
+ = service_icons 'dgo_smtp'
+ %tr.last
+ %td Mailbox access (POP/IMAP)
+ %td.status
+ = service_icons 'dgo_mbox'
+
+.container
+ .row
+ .twelvecol.last
+ %h2 Maintenance and Outage Notices
+ = notices
diff --git a/content/js/css3-mediaqueries.js b/content/js/css3-mediaqueries.js
new file mode 100644
index 0000000..1ea806d
--- /dev/null
+++ b/content/js/css3-mediaqueries.js
@@ -0,0 +1,779 @@
+if(typeof Object.create!=="function"){
+Object.create=function(o){
+function F(){
+};
+F.prototype=o;
+return new F();
+};
+}
+var ua={toString:function(){
+return navigator.userAgent;
+},test:function(s){
+return this.toString().toLowerCase().indexOf(s.toLowerCase())>-1;
+}};
+ua.version=(ua.toString().toLowerCase().match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1];
+ua.webkit=ua.test("webkit");
+ua.gecko=ua.test("gecko")&&!ua.webkit;
+ua.opera=ua.test("opera");
+ua.ie=ua.test("msie")&&!ua.opera;
+ua.ie6=ua.ie&&document.compatMode&&typeof document.documentElement.style.maxHeight==="undefined";
+ua.ie7=ua.ie&&document.documentElement&&typeof document.documentElement.style.maxHeight!=="undefined"&&typeof XDomainRequest==="undefined";
+ua.ie8=ua.ie&&typeof XDomainRequest!=="undefined";
+var domReady=function(){
+var _1=[];
+var _2=function(){
+if(!arguments.callee.done){
+arguments.callee.done=true;
+for(var i=0;i<_1.length;i++){
+_1[i]();
+}
+}
+};
+if(document.addEventListener){
+document.addEventListener("DOMContentLoaded",_2,false);
+}
+if(ua.ie){
+(function(){
+try{
+document.documentElement.doScroll("left");
+}
+catch(e){
+setTimeout(arguments.callee,50);
+return;
+}
+_2();
+})();
+document.onreadystatechange=function(){
+if(document.readyState==="complete"){
+document.onreadystatechange=null;
+_2();
+}
+};
+}
+if(ua.webkit&&document.readyState){
+(function(){
+if(document.readyState!=="loading"){
+_2();
+}else{
+setTimeout(arguments.callee,10);
+}
+})();
+}
+window.onload=_2;
+return function(fn){
+if(typeof fn==="function"){
+_1[_1.length]=fn;
+}
+return fn;
+};
+}();
+var cssHelper=function(){
+var _3={BLOCKS:/[^\s{][^{]*\{(?:[^{}]*\{[^{}]*\}[^{}]*|[^{}]*)*\}/g,BLOCKS_INSIDE:/[^\s{][^{]*\{[^{}]*\}/g,DECLARATIONS:/[a-zA-Z\-]+[^;]*:[^;]+;/g,RELATIVE_URLS:/url\(['"]?([^\/\)'"][^:\)'"]+)['"]?\)/g,REDUNDANT_COMPONENTS:/(?:\/\*([^*\\\\]|\*(?!\/))+\*\/|@import[^;]+;)/g,REDUNDANT_WHITESPACE:/\s*(,|:|;|\{|\})\s*/g,MORE_WHITESPACE:/\s{2,}/g,FINAL_SEMICOLONS:/;\}/g,NOT_WHITESPACE:/\S+/g};
+var _4,_5=false;
+var _6=[];
+var _7=function(fn){
+if(typeof fn==="function"){
+_6[_6.length]=fn;
+}
+};
+var _8=function(){
+for(var i=0;i<_6.length;i++){
+_6[i](_4);
+}
+};
+var _9={};
+var _a=function(n,v){
+if(_9[n]){
+var _b=_9[n].listeners;
+if(_b){
+for(var i=0;i<_b.length;i++){
+_b[i](v);
+}
+}
+}
+};
+var _c=function(_d,_e,_f){
+if(ua.ie&&!window.XMLHttpRequest){
+window.XMLHttpRequest=function(){
+return new ActiveXObject("Microsoft.XMLHTTP");
+};
+}
+if(!XMLHttpRequest){
+return "";
+}
+var r=new XMLHttpRequest();
+try{
+r.open("get",_d,true);
+r.setRequestHeader("X_REQUESTED_WITH","XMLHttpRequest");
+}
+catch(e){
+_f();
+return;
+}
+var _10=false;
+setTimeout(function(){
+_10=true;
+},5000);
+document.documentElement.style.cursor="progress";
+r.onreadystatechange=function(){
+if(r.readyState===4&&!_10){
+if(!r.status&&location.protocol==="file:"||(r.status>=200&&r.status<300)||r.status===304||navigator.userAgent.indexOf("Safari")>-1&&typeof r.status==="undefined"){
+_e(r.responseText);
+}else{
+_f();
+}
+document.documentElement.style.cursor="";
+r=null;
+}
+};
+r.send("");
+};
+var _11=function(_12){
+_12=_12.replace(_3.REDUNDANT_COMPONENTS,"");
+_12=_12.replace(_3.REDUNDANT_WHITESPACE,"$1");
+_12=_12.replace(_3.MORE_WHITESPACE," ");
+_12=_12.replace(_3.FINAL_SEMICOLONS,"}");
+return _12;
+};
+var _13={mediaQueryList:function(s){
+var o={};
+var idx=s.indexOf("{");
+var lt=s.substring(0,idx);
+s=s.substring(idx+1,s.length-1);
+var mqs=[],rs=[];
+var qts=lt.toLowerCase().substring(7).split(",");
+for(var i=0;i<qts.length;i++){
+mqs[mqs.length]=_13.mediaQuery(qts[i],o);
+}
+var rts=s.match(_3.BLOCKS_INSIDE);
+if(rts!==null){
+for(i=0;i<rts.length;i++){
+rs[rs.length]=_13.rule(rts[i],o);
+}
+}
+o.getMediaQueries=function(){
+return mqs;
+};
+o.getRules=function(){
+return rs;
+};
+o.getListText=function(){
+return lt;
+};
+o.getCssText=function(){
+return s;
+};
+return o;
+},mediaQuery:function(s,mql){
+s=s||"";
+var not=false,_14;
+var exp=[];
+var _15=true;
+var _16=s.match(_3.NOT_WHITESPACE);
+for(var i=0;i<_16.length;i++){
+var _17=_16[i];
+if(!_14&&(_17==="not"||_17==="only")){
+if(_17==="not"){
+not=true;
+}
+}else{
+if(!_14){
+_14=_17;
+}else{
+if(_17.charAt(0)==="("){
+var _18=_17.substring(1,_17.length-1).split(":");
+exp[exp.length]={mediaFeature:_18[0],value:_18[1]||null};
+}
+}
+}
+}
+return {getList:function(){
+return mql||null;
+},getValid:function(){
+return _15;
+},getNot:function(){
+return not;
+},getMediaType:function(){
+return _14;
+},getExpressions:function(){
+return exp;
+}};
+},rule:function(s,mql){
+var o={};
+var idx=s.indexOf("{");
+var st=s.substring(0,idx);
+var ss=st.split(",");
+var ds=[];
+var dts=s.substring(idx+1,s.length-1).split(";");
+for(var i=0;i<dts.length;i++){
+ds[ds.length]=_13.declaration(dts[i],o);
+}
+o.getMediaQueryList=function(){
+return mql||null;
+};
+o.getSelectors=function(){
+return ss;
+};
+o.getSelectorText=function(){
+return st;
+};
+o.getDeclarations=function(){
+return ds;
+};
+o.getPropertyValue=function(n){
+for(var i=0;i<ds.length;i++){
+if(ds[i].getProperty()===n){
+return ds[i].getValue();
+}
+}
+return null;
+};
+return o;
+},declaration:function(s,r){
+var idx=s.indexOf(":");
+var p=s.substring(0,idx);
+var v=s.substring(idx+1);
+return {getRule:function(){
+return r||null;
+},getProperty:function(){
+return p;
+},getValue:function(){
+return v;
+}};
+}};
+var _19=function(el){
+if(typeof el.cssHelperText!=="string"){
+return;
+}
+var o={mediaQueryLists:[],rules:[],selectors:{},declarations:[],properties:{}};
+var _1a=o.mediaQueryLists;
+var ors=o.rules;
+var _1b=el.cssHelperText.match(_3.BLOCKS);
+if(_1b!==null){
+for(var i=0;i<_1b.length;i++){
+if(_1b[i].substring(0,7)==="@media "){
+_1a[_1a.length]=_13.mediaQueryList(_1b[i]);
+ors=o.rules=ors.concat(_1a[_1a.length-1].getRules());
+}else{
+ors[ors.length]=_13.rule(_1b[i]);
+}
+}
+}
+var oss=o.selectors;
+var _1c=function(r){
+var ss=r.getSelectors();
+for(var i=0;i<ss.length;i++){
+var n=ss[i];
+if(!oss[n]){
+oss[n]=[];
+}
+oss[n][oss[n].length]=r;
+}
+};
+for(i=0;i<ors.length;i++){
+_1c(ors[i]);
+}
+var ods=o.declarations;
+for(i=0;i<ors.length;i++){
+ods=o.declarations=ods.concat(ors[i].getDeclarations());
+}
+var ops=o.properties;
+for(i=0;i<ods.length;i++){
+var n=ods[i].getProperty();
+if(!ops[n]){
+ops[n]=[];
+}
+ops[n][ops[n].length]=ods[i];
+}
+el.cssHelperParsed=o;
+_4[_4.length]=el;
+return o;
+};
+var _1d=function(el,s){
+el.cssHelperText=_11(s||el.innerHTML);
+return _19(el);
+};
+var _1e=function(){
+_5=true;
+_4=[];
+var _1f=[];
+var _20=function(){
+for(var i=0;i<_1f.length;i++){
+_19(_1f[i]);
+}
+var _21=document.getElementsByTagName("style");
+for(i=0;i<_21.length;i++){
+_1d(_21[i]);
+}
+_5=false;
+_8();
+};
+var _22=document.getElementsByTagName("link");
+for(var i=0;i<_22.length;i++){
+var _23=_22[i];
+if(_23.getAttribute("rel").indexOf("style")>-1&&_23.href&&_23.href.length!==0&&!_23.disabled){
+_1f[_1f.length]=_23;
+}
+}
+if(_1f.length>0){
+var c=0;
+var _24=function(){
+c++;
+if(c===_1f.length){
+_20();
+}
+};
+var _25=function(_26){
+var _27=_26.href;
+_c(_27,function(_28){
+_28=_11(_28).replace(_3.RELATIVE_URLS,"url("+_27.substring(0,_27.lastIndexOf("/"))+"/$1)");
+_26.cssHelperText=_28;
+_24();
+},_24);
+};
+for(i=0;i<_1f.length;i++){
+_25(_1f[i]);
+}
+}else{
+_20();
+}
+};
+var _29={mediaQueryLists:"array",rules:"array",selectors:"object",declarations:"array",properties:"object"};
+var _2a={mediaQueryLists:null,rules:null,selectors:null,declarations:null,properties:null};
+var _2b=function(_2c,v){
+if(_2a[_2c]!==null){
+if(_29[_2c]==="array"){
+return (_2a[_2c]=_2a[_2c].concat(v));
+}else{
+var c=_2a[_2c];
+for(var n in v){
+if(v.hasOwnProperty(n)){
+if(!c[n]){
+c[n]=v[n];
+}else{
+c[n]=c[n].concat(v[n]);
+}
+}
+}
+return c;
+}
+}
+};
+var _2d=function(_2e){
+_2a[_2e]=(_29[_2e]==="array")?[]:{};
+for(var i=0;i<_4.length;i++){
+_2b(_2e,_4[i].cssHelperParsed[_2e]);
+}
+return _2a[_2e];
+};
+domReady(function(){
+var els=document.body.getElementsByTagName("*");
+for(var i=0;i<els.length;i++){
+els[i].checkedByCssHelper=true;
+}
+if(document.implementation.hasFeature("MutationEvents","2.0")||window.MutationEvent){
+document.body.addEventListener("DOMNodeInserted",function(e){
+var el=e.target;
+if(el.nodeType===1){
+_a("DOMElementInserted",el);
+el.checkedByCssHelper=true;
+}
+},false);
+}else{
+setInterval(function(){
+var els=document.body.getElementsByTagName("*");
+for(var i=0;i<els.length;i++){
+if(!els[i].checkedByCssHelper){
+_a("DOMElementInserted",els[i]);
+els[i].checkedByCssHelper=true;
+}
+}
+},1000);
+}
+});
+var _2f=function(d){
+if(typeof window.innerWidth!="undefined"){
+return window["inner"+d];
+}else{
+if(typeof document.documentElement!="undefined"&&typeof document.documentElement.clientWidth!="undefined"&&document.documentElement.clientWidth!=0){
+return document.documentElement["client"+d];
+}
+}
+};
+return {addStyle:function(s,_30){
+var el=document.createElement("style");
+el.setAttribute("type","text/css");
+document.getElementsByTagName("head")[0].appendChild(el);
+if(el.styleSheet){
+el.styleSheet.cssText=s;
+}else{
+el.appendChild(document.createTextNode(s));
+}
+el.addedWithCssHelper=true;
+if(typeof _30==="undefined"||_30===true){
+cssHelper.parsed(function(_31){
+var o=_1d(el,s);
+for(var n in o){
+if(o.hasOwnProperty(n)){
+_2b(n,o[n]);
+}
+}
+_a("newStyleParsed",el);
+});
+}else{
+el.parsingDisallowed=true;
+}
+return el;
+},removeStyle:function(el){
+return el.parentNode.removeChild(el);
+},parsed:function(fn){
+if(_5){
+_7(fn);
+}else{
+if(typeof _4!=="undefined"){
+if(typeof fn==="function"){
+fn(_4);
+}
+}else{
+_7(fn);
+_1e();
+}
+}
+},mediaQueryLists:function(fn){
+cssHelper.parsed(function(_32){
+fn(_2a.mediaQueryLists||_2d("mediaQueryLists"));
+});
+},rules:function(fn){
+cssHelper.parsed(function(_33){
+fn(_2a.rules||_2d("rules"));
+});
+},selectors:function(fn){
+cssHelper.parsed(function(_34){
+fn(_2a.selectors||_2d("selectors"));
+});
+},declarations:function(fn){
+cssHelper.parsed(function(_35){
+fn(_2a.declarations||_2d("declarations"));
+});
+},properties:function(fn){
+cssHelper.parsed(function(_36){
+fn(_2a.properties||_2d("properties"));
+});
+},broadcast:_a,addListener:function(n,fn){
+if(typeof fn==="function"){
+if(!_9[n]){
+_9[n]={listeners:[]};
+}
+_9[n].listeners[_9[n].listeners.length]=fn;
+}
+},removeListener:function(n,fn){
+if(typeof fn==="function"&&_9[n]){
+var ls=_9[n].listeners;
+for(var i=0;i<ls.length;i++){
+if(ls[i]===fn){
+ls.splice(i,1);
+i-=1;
+}
+}
+}
+},getViewportWidth:function(){
+return _2f("Width");
+},getViewportHeight:function(){
+return _2f("Height");
+}};
+}();
+domReady(function enableCssMediaQueries(){
+var _37;
+var _38={LENGTH_UNIT:/[0-9]+(em|ex|px|in|cm|mm|pt|pc)$/,RESOLUTION_UNIT:/[0-9]+(dpi|dpcm)$/,ASPECT_RATIO:/^[0-9]+\/[0-9]+$/,ABSOLUTE_VALUE:/^[0-9]*(\.[0-9]+)*$/};
+var _39=[];
+var _3a=function(){
+var id="css3-mediaqueries-test";
+var el=document.createElement("div");
+el.id=id;
+var _3b=cssHelper.addStyle("@media all and (width) { #"+id+" { width: 1px !important; } }",false);
+document.body.appendChild(el);
+var ret=el.offsetWidth===1;
+_3b.parentNode.removeChild(_3b);
+el.parentNode.removeChild(el);
+_3a=function(){
+return ret;
+};
+return ret;
+};
+var _3c=function(){
+_37=document.createElement("div");
+_37.style.cssText="position:absolute;top:-9999em;left:-9999em;"+"margin:0;border:none;padding:0;width:1em;font-size:1em;";
+document.body.appendChild(_37);
+if(_37.offsetWidth!==16){
+_37.style.fontSize=16/_37.offsetWidth+"em";
+}
+_37.style.width="";
+};
+var _3d=function(_3e){
+_37.style.width=_3e;
+var _3f=_37.offsetWidth;
+_37.style.width="";
+return _3f;
+};
+var _40=function(_41,_42){
+var l=_41.length;
+var min=(_41.substring(0,4)==="min-");
+var max=(!min&&_41.substring(0,4)==="max-");
+if(_42!==null){
+var _43;
+var _44;
+if(_38.LENGTH_UNIT.exec(_42)){
+_43="length";
+_44=_3d(_42);
+}else{
+if(_38.RESOLUTION_UNIT.exec(_42)){
+_43="resolution";
+_44=parseInt(_42,10);
+var _45=_42.substring((_44+"").length);
+}else{
+if(_38.ASPECT_RATIO.exec(_42)){
+_43="aspect-ratio";
+_44=_42.split("/");
+}else{
+if(_38.ABSOLUTE_VALUE){
+_43="absolute";
+_44=_42;
+}else{
+_43="unknown";
+}
+}
+}
+}
+}
+var _46,_47;
+if("device-width"===_41.substring(l-12,l)){
+_46=screen.width;
+if(_42!==null){
+if(_43==="length"){
+return ((min&&_46>=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44));
+}else{
+return false;
+}
+}else{
+return _46>0;
+}
+}else{
+if("device-height"===_41.substring(l-13,l)){
+_47=screen.height;
+if(_42!==null){
+if(_43==="length"){
+return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44));
+}else{
+return false;
+}
+}else{
+return _47>0;
+}
+}else{
+if("width"===_41.substring(l-5,l)){
+_46=document.documentElement.clientWidth||document.body.clientWidth;
+if(_42!==null){
+if(_43==="length"){
+return ((min&&_46>=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44));
+}else{
+return false;
+}
+}else{
+return _46>0;
+}
+}else{
+if("height"===_41.substring(l-6,l)){
+_47=document.documentElement.clientHeight||document.body.clientHeight;
+if(_42!==null){
+if(_43==="length"){
+return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44));
+}else{
+return false;
+}
+}else{
+return _47>0;
+}
+}else{
+if("device-aspect-ratio"===_41.substring(l-19,l)){
+return _43==="aspect-ratio"&&screen.width*_44[1]===screen.height*_44[0];
+}else{
+if("color-index"===_41.substring(l-11,l)){
+var _48=Math.pow(2,screen.colorDepth);
+if(_42!==null){
+if(_43==="absolute"){
+return ((min&&_48>=_44)||(max&&_48<_44)||(!min&&!max&&_48===_44));
+}else{
+return false;
+}
+}else{
+return _48>0;
+}
+}else{
+if("color"===_41.substring(l-5,l)){
+var _49=screen.colorDepth;
+if(_42!==null){
+if(_43==="absolute"){
+return ((min&&_49>=_44)||(max&&_49<_44)||(!min&&!max&&_49===_44));
+}else{
+return false;
+}
+}else{
+return _49>0;
+}
+}else{
+if("resolution"===_41.substring(l-10,l)){
+var res;
+if(_45==="dpcm"){
+res=_3d("1cm");
+}else{
+res=_3d("1in");
+}
+if(_42!==null){
+if(_43==="resolution"){
+return ((min&&res>=_44)||(max&&res<_44)||(!min&&!max&&res===_44));
+}else{
+return false;
+}
+}else{
+return res>0;
+}
+}else{
+return false;
+}
+}
+}
+}
+}
+}
+}
+}
+};
+var _4a=function(mq){
+var _4b=mq.getValid();
+var _4c=mq.getExpressions();
+var l=_4c.length;
+if(l>0){
+for(var i=0;i<l&&_4b;i++){
+_4b=_40(_4c[i].mediaFeature,_4c[i].value);
+}
+var not=mq.getNot();
+return (_4b&&!not||not&&!_4b);
+}
+};
+var _4d=function(mql){
+var mqs=mql.getMediaQueries();
+var t={};
+for(var i=0;i<mqs.length;i++){
+if(_4a(mqs[i])){
+t[mqs[i].getMediaType()]=true;
+}
+}
+var s=[],c=0;
+for(var n in t){
+if(t.hasOwnProperty(n)){
+if(c>0){
+s[c++]=",";
+}
+s[c++]=n;
+}
+}
+if(s.length>0){
+_39[_39.length]=cssHelper.addStyle("@media "+s.join("")+"{"+mql.getCssText()+"}",false);
+}
+};
+var _4e=function(_4f){
+for(var i=0;i<_4f.length;i++){
+_4d(_4f[i]);
+}
+if(ua.ie){
+document.documentElement.style.display="block";
+setTimeout(function(){
+document.documentElement.style.display="";
+},0);
+setTimeout(function(){
+cssHelper.broadcast("cssMediaQueriesTested");
+},100);
+}else{
+cssHelper.broadcast("cssMediaQueriesTested");
+}
+};
+var _50=function(){
+for(var i=0;i<_39.length;i++){
+cssHelper.removeStyle(_39[i]);
+}
+_39=[];
+cssHelper.mediaQueryLists(_4e);
+};
+var _51=0;
+var _52=function(){
+var _53=cssHelper.getViewportWidth();
+var _54=cssHelper.getViewportHeight();
+if(ua.ie){
+var el=document.createElement("div");
+el.style.position="absolute";
+el.style.top="-9999em";
+el.style.overflow="scroll";
+document.body.appendChild(el);
+_51=el.offsetWidth-el.clientWidth;
+document.body.removeChild(el);
+}
+var _55;
+var _56=function(){
+var vpw=cssHelper.getViewportWidth();
+var vph=cssHelper.getViewportHeight();
+if(Math.abs(vpw-_53)>_51||Math.abs(vph-_54)>_51){
+_53=vpw;
+_54=vph;
+clearTimeout(_55);
+_55=setTimeout(function(){
+if(!_3a()){
+_50();
+}else{
+cssHelper.broadcast("cssMediaQueriesTested");
+}
+},500);
+}
+};
+window.onresize=function(){
+var x=window.onresize||function(){
+};
+return function(){
+x();
+_56();
+};
+}();
+};
+var _57=document.documentElement;
+_57.style.marginLeft="-32767px";
+setTimeout(function(){
+_57.style.marginTop="";
+},20000);
+return function(){
+if(!_3a()){
+cssHelper.addListener("newStyleParsed",function(el){
+_4e(el.cssHelperParsed.mediaQueryLists);
+});
+cssHelper.addListener("cssMediaQueriesTested",function(){
+if(ua.ie){
+_57.style.width="1px";
+}
+setTimeout(function(){
+_57.style.width="";
+_57.style.marginLeft="";
+},0);
+cssHelper.removeListener("cssMediaQueriesTested",arguments.callee);
+});
+_3c();
+_50();
+}else{
+_57.style.marginLeft="";
+}
+_52();
+};
+}());
+try{
+document.execCommand("BackgroundImageCache",false,true);
+}
+catch(e){
+}
+
diff --git a/content/notices/.gitignore b/content/notices/.gitignore
new file mode 100644
index 0000000..dd44972
--- /dev/null
+++ b/content/notices/.gitignore
@@ -0,0 +1 @@
+*.md
diff --git a/example.md b/example.md
new file mode 100644
index 0000000..64da7c9
--- /dev/null
+++ b/example.md
@@ -0,0 +1,25 @@
+---
+title: Example Notice
+active: true
+type: maintenance
+created_at: 2012-02-20 10:00
+eta: 2012-02-22 10:00
+expire: 2012-03-20 10:00
+kind: article
+affects: [overlays, forums, bugzilla]
+force_state: maintenance
+---
+
+Here you can add text in the markdown format.
+
+Parameters above:
+title: self-explanatory
+active: set this to false to completely hide the notice
+type: (maintenance|information|outage) sets the icon
+created_at: self-explanatory
+eta: estimated time the service is restored (optional)
+expire: when to hide the notice. defaults to one week (optional)
+kind: set to 'article' (mandatory!)
+affects: array of services this notice affects (TODO list, optional)
+force_state: (maintenance|up|down) force the state of all services this notice applies to to this state (optional)
+
diff --git a/layouts/_post.haml b/layouts/_post.haml
new file mode 100644
index 0000000..16c7ff3
--- /dev/null
+++ b/layouts/_post.haml
@@ -0,0 +1,21 @@
+.row.post
+ %h3
+ =item_icon(item[:type])
+ =item[:title]
+ .grey
+ %table.dates
+ %tr
+ %td Posted at
+ %td=item[:created_at]
+ - if item.attributes.has_key? :eta
+ %tr
+ %td Estimated time of recovery
+ %td=item[:eta]
+ - if is_expired? item
+ %tr{ :colspan => '2'}
+ %td
+ %img{ :src => base_url + 'img/information.png', :alt => 'information'}
+ This notice is
+ %strong expired.
+ The service has been restored.
+ ~ yield
diff --git a/layouts/default.haml b/layouts/default.haml
new file mode 100644
index 0000000..e5f5938
--- /dev/null
+++ b/layouts/default.haml
@@ -0,0 +1,38 @@
+!!! 5
+%html
+ %head
+ %title Gentoo Linux Infrastructure status
+ %meta{ :charset => 'utf-8' }
+ %meta{ :name => 'viewport', :content => 'width=device-width, initial-scale=1.0' }
+ /[if lte IE 9]
+ %link{ :rel => 'stylesheet', :href => '/css/ie.css', :type => 'text/css', :media => 'screen' }
+ %link{ :rel => 'stylesheet', :href => '/css/1140.css', :type => 'text/css', :media => 'screen' }
+ %link{ :rel => 'stylesheet', :href => '/css/screen.css', :type => 'text/css', :media => 'screen' }
+ %link{ :rel => 'stylesheet', :href => 'http://fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,700italic,600', :type => 'text/css' }
+ %link{ :rel => 'alternate', :href => '/atom.xml', :type => 'application/atom+xml', :title => 'Atom Feed' }
+ %script{ :src => '/js/css3-mediaqueries.js', :type => 'text/javascript'}
+ %body
+ .container.header
+ .row
+ .twelvecol.last
+ %img{ :src => '/img/site_logo.png', :alt => 'Gentoo Linux Infrastructure status' }
+ .container.site-title
+ .row
+ .twelvecol.last
+ %span.right
+ %a{ :href => '/atom.xml', :title => 'Subscribe to the Atom feed' }
+ %img{ :src => '/img/feed.png', :alt => 'Atom feed' }
+ %h1 Gentoo Linux Infrastructure Status
+
+ = yield
+ .container#footer
+ .row
+ .sixcol
+ Copyright &copy; Gentoo Foundation, Inc. &middot; Contents licensed under the CC-BY-SA 3.0 license
+ .sixcol.last
+ This site is powered by:
+ %a{ :href => 'http://nanoc.stoneship.org/'} nanoc
+ &middot;
+ %a{ :href => 'http://p.yusukekamiyamane.com/'} the Fugue iconset
+ &middot;
+ %a{ :href => 'http://cssgrid.net/' } the 1140 grid
diff --git a/lib/default.rb b/lib/default.rb
new file mode 100644
index 0000000..a4df0cc
--- /dev/null
+++ b/lib/default.rb
@@ -0,0 +1,2 @@
+# All files in the 'lib' directory will be loaded
+# before nanoc starts compiling.
diff --git a/lib/helpers.rb b/lib/helpers.rb
new file mode 100644
index 0000000..a66457f
--- /dev/null
+++ b/lib/helpers.rb
@@ -0,0 +1,136 @@
+include Nanoc::Helpers::Blogging
+include Nanoc::Helpers::Rendering
+require 'date'
+
+# Defining state constants
+module State
+ UP=1
+ DOWN=2
+ WARNING=3
+end
+
+def service_icons(service)
+ content = ""
+
+ if service_has_notices?(service)
+ content << notice_icon + " "
+ end
+
+ unless (forced_state = get_forced_state(service)) == nil
+ content << status_icon(forced_state)
+ return content
+ end
+
+ case ServiceRegistry.instance.services[service]
+ when State::UP
+ content << status_icon('up')
+ when State::WARNING
+ content << status_icon('warning')
+ when State::DOWN
+ content << status_icon('down')
+ else
+ content << status_icon('na')
+ end
+
+ content
+end
+
+def status_icon(status)
+ case status.to_s
+ when 'up'
+ return '<img src="/img/status_up.png" alt="The service is up and running." title="The service is up and running." />'
+ when 'down'
+ return '<img src="/img/status_down.png" alt="The service is down." title="The service is down." />'
+ when 'warning'
+ return '<img src="/img/status_warning.png" alt="There are issues with the service." title="There are issues with the service." />'
+ when 'maintenance'
+ return '<img src="/img/maintenance.png" alt="The service is undergoing scheduled maintenance." title="The service is undergoing scheduled maintenance." />'
+ else
+ return '<img src="/img/na.png" alt="No data available." title="No data available." />'
+ end
+end
+
+def notice_icon
+ return '<img src="/img/notice.png" alt="There are notices regarding this service posted below." title="There are notices regarding this service posted below." />'
+end
+
+def item_icon(type)
+ case type.to_s
+ when 'maintenance'
+ return '<img src="' + base_url + 'img/maintenance.png" alt="Scheduled maintenance" title="Scheduled maintenance" />'
+ when 'outage'
+ return '<img src="' + base_url + '/img/outage.png" alt="Unplanned outage" title="Unplanned outage" />'
+ when 'information'
+ return '<img src="' + base_url + '/img/information.png" alt="General information" title="General information" />'
+ end
+end
+
+# Compiles all active notices into one piece of HTML
+def notices
+ content=""
+
+ sorted_articles.each do |notice|
+ next if is_expired? notice
+
+ content += notice.compiled_content(:snapshot => :single_post)
+ end
+
+ content
+end
+
+# Are there any notices for the service?
+def service_has_notices?(service)
+ articles.each do |notice|
+ next if is_expired? notice
+
+ if notice.attributes.has_key? :affects and notice[:affects].include? service
+ return true
+ end
+ end
+
+ false
+end
+
+def get_forced_state(service)
+ return nil unless service_has_notices?(service)
+
+ sorted_articles.each do |notice|
+ next if is_expired? notice
+
+ if notice.attributes.has_key? :affects and notice[:affects].include? service
+ return notice[:force_state] if notice.attributes.has_key? :force_state
+ end
+ end
+end
+
+# Filters expired items and items w/o expiration date that are older than a week.
+def is_expired?(notice)
+ if notice.attributes.has_key? :active
+ return true if notice[:active] != true
+ end
+
+ if notice.attributes.has_key? :expire
+ expire_date = DateTime.parse(notice[:expire])
+
+ DateTime.now > expire_date
+ else
+ creation_date = DateTime.parse(notice[:created_at])
+ date_diff = DateTime.now - creation_date
+
+ date_diff.to_i > 7
+ end
+end
+
+def feed_proc
+ lambda do |notice|
+ notice.compiled_content(:snapshot => :single_post)
+ end
+end
+
+def feed_articles
+ articles.select {|n| not is_expired? n}
+end
+
+def base_url
+ @site.config[:base_url] + '/'
+end
diff --git a/lib/service-dsl.rb b/lib/service-dsl.rb
new file mode 100644
index 0000000..42f94d4
--- /dev/null
+++ b/lib/service-dsl.rb
@@ -0,0 +1,73 @@
+require 'singleton'
+require 'json'
+
+module HelperMethods
+ # Checks if all hosts are up
+ def all_hosts_up?(hosts)
+ hosts.each do |host|
+ return false unless status_data['hosts'][host]['current_state'] == 0
+ end
+
+ true
+ end
+
+ def host_up?(host)
+ status_data['hosts'][host]['current_state'] == 0
+ end
+
+ def host_flapping?(host)
+ status_data['hosts'][host]['is_flapping'] != 0
+ end
+
+ # Checks if the service is up
+ def service_up?(host, service)
+ status_data['services'][host][service]['current_state'] == 0
+ end
+
+ def service_flapping?(host, service)
+ status_data['services'][host][service]['is_flapping'] != 0
+ end
+
+ def default(host, service = nil)
+ if service == nil
+ if host_flapping? host
+ State::WARNING
+ elsif host_up? host
+ State::UP
+ else
+ State::DOWN
+ end
+ else
+ if service_flapping? host, service
+ State::WARNING
+ elsif service_up? host, service
+ State::UP
+ else
+ State::DOWN
+ end
+ end
+ end
+end
+
+class ServiceRegistry
+ StatusSource = "/tmp/status.json"
+
+ include Singleton
+ include HelperMethods
+ attr_reader :services, :status_data
+
+
+ def initialize
+ @services = {}
+
+ @status_data = JSON.parse(File.read(StatusSource))
+ end
+
+ def service(name, &block)
+ @services[name] = block.call
+ end
+end
+
+def Services(&block)
+ ServiceRegistry.instance.instance_eval(&block)
+end
diff --git a/lib/services.rb b/lib/services.rb
new file mode 100644
index 0000000..35b1127
--- /dev/null
+++ b/lib/services.rb
@@ -0,0 +1,93 @@
+# Accessing JSON data works via status_data
+# Return State::UP, State::Down, or State::Warning
+# Nagios states: 0 (ok), 1 (warning), 2 (critical), 3 (unknown), 4 (dependent)
+
+Services do
+ service 'www' do
+ if service_flapping? 'ani', 'http_www' and service_flapping? 'auklet', 'http_www' and service_flapping? 'loon', 'http_www'
+ State::WARNING
+ elsif service_up? 'ani', 'http_www' or service_up? 'auklet', 'http_www' or service_up? 'loon', 'http_www'
+ State::UP
+ else
+ State::DOWN
+ end
+ end
+
+ service 'forums' do
+ if service_flapping? 'godwit', 'http_forums' or service_flapping? 'gannet', 'http_forums'
+ State::WARNING
+ elsif service_up? 'godwit', 'http_forums' or service_up? 'gannet', 'http_forums'
+ State::UP
+ else
+ State::DOWN
+ end
+ end
+
+ service 'wiki' do
+ default 'bittern', 'http_wiki'
+ end
+
+ service 'planet' do
+ default 'barbet', 'http_planet'
+ end
+
+ service 'pgo' do
+ default 'barbet', 'http_packages'
+ end
+
+ service 'lists' do
+ default 'pigeon'
+ end
+
+ service 'archives' do
+ default 'finch'
+ end
+
+ service 'cvs' do
+ default 'flycatcher', 'ssh_cvs'
+ end
+
+ service 'devmanual' do
+ default 'barbet', 'http_devmanual'
+ end
+
+ service 'overlays' do
+ default 'hornbill', 'http_overlays'
+ end
+
+ service 'tinderbox' do
+ default 'tinderbox.dev'
+ end
+
+ service 'sources' do
+ default 'motmot', 'http_sources'
+ end
+
+ service 'bugzilla' do
+ if service_flapping? 'yellowbishop', 'http_bugs' or service_flapping? 'yellowleg', 'http_bugs'
+ State::WARNING
+ elsif service_up? 'yellowbishop', 'http_bugs' and service_up? 'yellowleg', 'http_bugs'
+ State::UP
+ elsif service_up? 'yellowbishop', 'http_bugs' or service_up? 'yellowleg', 'http_bugs'
+ State::WARNING
+ else
+ State::DOWN
+ end
+ end
+
+ service 'dgo_ssh' do
+ default 'woodpecker', 'ssh_dgo'
+ end
+
+ service 'dgo_http' do
+ nil
+ end
+
+ service 'dgo_smtp' do
+ nil
+ end
+
+ service 'dgo_mbox' do
+ nil
+ end
+end