<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>Makefile.PL</filename>
    </added>
    <added>
      <filename>bin/moonin-poller</filename>
    </added>
    <added>
      <filename>conf/moonin.conf</filename>
    </added>
    <added>
      <filename>extra/VeraMono.ttf</filename>
    </added>
    <added>
      <filename>lib/Moonin/Config.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Config/Store.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Domain.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Exception.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Graph.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Node.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Role/Exception.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web/Controller/Graph.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web/Controller/Node.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web/Controller/Root.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web/Model/Config.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web/Model/Graph.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web/Model/Node.pm</filename>
    </added>
    <added>
      <filename>lib/Moonin/Web/View/TT.pm</filename>
    </added>
    <added>
      <filename>log/.emptyfile</filename>
    </added>
    <added>
      <filename>moonin_web.yml</filename>
    </added>
    <added>
      <filename>root/favicon.ico</filename>
    </added>
    <added>
      <filename>root/index.tt</filename>
    </added>
    <added>
      <filename>root/node/show.tt</filename>
    </added>
    <added>
      <filename>root/static/images/btn_120x50_built.png</filename>
    </added>
    <added>
      <filename>root/static/images/btn_120x50_built_shadow.png</filename>
    </added>
    <added>
      <filename>root/static/images/btn_120x50_powered.png</filename>
    </added>
    <added>
      <filename>root/static/images/btn_120x50_powered_shadow.png</filename>
    </added>
    <added>
      <filename>root/static/images/btn_88x31_built.png</filename>
    </added>
    <added>
      <filename>root/static/images/btn_88x31_built_shadow.png</filename>
    </added>
    <added>
      <filename>root/static/images/btn_88x31_powered.png</filename>
    </added>
    <added>
      <filename>root/static/images/btn_88x31_powered_shadow.png</filename>
    </added>
    <added>
      <filename>root/static/images/catalyst_logo.png</filename>
    </added>
    <added>
      <filename>rrds/.emptyfile</filename>
    </added>
    <added>
      <filename>script/moonin_web_cgi.pl</filename>
    </added>
    <added>
      <filename>script/moonin_web_create.pl</filename>
    </added>
    <added>
      <filename>script/moonin_web_fastcgi.pl</filename>
    </added>
    <added>
      <filename>script/moonin_web_server.pl</filename>
    </added>
    <added>
      <filename>script/moonin_web_test.pl</filename>
    </added>
    <added>
      <filename>t/01app.t</filename>
    </added>
    <added>
      <filename>t/02pod.t</filename>
    </added>
    <added>
      <filename>t/03podcoverage.t</filename>
    </added>
    <added>
      <filename>t/04moonin-graph.pm</filename>
    </added>
    <added>
      <filename>t/controller_Graph.t</filename>
    </added>
    <added>
      <filename>t/controller_Node.t</filename>
    </added>
    <added>
      <filename>t/model_ConfigStore.t</filename>
    </added>
    <added>
      <filename>t/view_TT.t</filename>
    </added>
    <added>
      <filename>tmp/.emptyfile</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -24,7 +24,7 @@ has 'config'      =&gt; ( is =&gt; 'rw', isa =&gt; 'HashRef', required =&gt; 0 );
 has 'config_file' =&gt; ( is =&gt; 'rw', isa =&gt; 'Str',     required =&gt; 1 );
 has 'missingok' =&gt; ( is =&gt; 'rw', isa =&gt; 'Bool', required =&gt; 0, default =&gt; 0 );
 has 'corruptok' =&gt; ( is =&gt; 'rw', isa =&gt; 'Bool', required =&gt; 0, default =&gt; 0 );
-has 'store'     =&gt; ( is =&gt; 'ro', isa =&gt; 'Object', required =&gt; 0 );
+has 'store' =&gt; ( is =&gt; 'ro', isa =&gt; 'Object', required =&gt; 0 );
 has 'legal' =&gt; (
   is      =&gt; 'ro',
   isa     =&gt; 'ArrayRef',
@@ -108,7 +108,7 @@ sub BUILD {
   $self-&gt;config-&gt;{'htmldir'} ||= &quot;/usr/share/munin/html&quot;;
 
   # Set up all the methods for our config object.
-  foreach my $attr (@{$self-&gt;legal}) {
+  foreach my $attr ( @{ $self-&gt;legal } ) {
     $self-&gt;meta-&gt;add_method(
       $attr =&gt; sub {
         my $obj = shift;
@@ -116,13 +116,61 @@ sub BUILD {
       }
     );
   }
-  
-  $self-&gt;log-&gt;debug(&quot;Adding &quot; . $self-&gt;dbdir . &quot;/moonin-config.db&quot;);
-  $self-&gt;{store} = Moonin::Config::Store-&gt;new(file =&gt; $self-&gt;dbdir . &quot;moonin-config.db&quot;);
-  
+
+  $self-&gt;log-&gt;debug( &quot;Adding &quot; . $self-&gt;dbdir . &quot;/moonin-config.db&quot; );
+  $self-&gt;{store} =
+    Moonin::Config::Store-&gt;new( file =&gt; $self-&gt;dbdir . &quot;moonin-config.db&quot; );
+
   # $self-&gt;log-&gt;debug(dump($self-&gt;config));
 }
 
+sub get_domains {
+  my $self   = shift;
+  my @result = sort( keys( %{ $self-&gt;domain } ) );
+  return \@result;
+}
+
+sub get_nodes {
+  my $self   = shift;
+  my $domain = shift;
+  my @result = sort( keys( %{ $self-&gt;store-&gt;dbm-&gt;{node}-&gt;{$domain} } ) );
+  return \@result;
+}
+
+sub get_graph_categories {
+  my $self   = shift;
+  my $domain = shift;
+  my $name   = shift;
+
+  my $clients = $self-&gt;store-&gt;dbm-&gt;{node}-&gt;{$domain}-&gt;{$name}-&gt;{client};
+
+  my @graph_categories;
+  foreach my $thing ( keys( %{$clients} ) ) {
+    if ( exists $clients-&gt;{$thing}-&gt;{'graph_category'} ) {
+      my $gc = ucfirst($clients-&gt;{$thing}-&gt;{'graph_category'});
+      push( @graph_categories, $gc )
+        unless ( grep /^$gc$/, @graph_categories );
+    }
+  }
+  return \@graph_categories;
+}
+
+sub get_graphs_by_category {
+  my $self = shift;
+  my $domain = shift;
+  my $name = shift;
+  
+  my $clients = $self-&gt;store-&gt;dbm-&gt;{node}-&gt;{$domain}-&gt;{$name}-&gt;{client};
+  my $graphs = {};
+  foreach my $thing ( keys( %{$clients} ) ) {
+    if ( exists $clients-&gt;{$thing}-&gt;{'graph_category'} ) {
+      my $gc = ucfirst($clients-&gt;{$thing}-&gt;{'graph_category'});
+      push( @{$graphs-&gt;{$gc}}, { name =&gt; $thing, data =&gt; $clients-&gt;{$thing} });
+    }
+  }
+  return $graphs;
+}
+
 sub _parse_config {
   my $self     = shift;
   my $lines    = shift;
@@ -243,7 +291,7 @@ sub _set_var_path {
 }
 
 sub domain {
-  my ( $self ) = @_;
+  my ($self) = @_;
   return $self-&gt;config-&gt;{domain};
 }
 </diff>
      <filename>lib/moonin/Config.pm</filename>
    </modified>
    <modified>
      <diff>@@ -27,8 +27,7 @@ sub BUILD {
   $self-&gt;{dbm} = DBM::Deep-&gt;new(
     file =&gt; $self-&gt;file,
     locking =&gt; 1,
-    autoflush =&gt; 1,
-    num_txns =&gt; 5
+    autoflush =&gt; 1
   );
   $self;
 }</diff>
      <filename>lib/moonin/Config/Store.pm</filename>
    </modified>
    <modified>
      <diff>@@ -28,7 +28,7 @@ has 'config'  =&gt; ( is =&gt; 'rw', isa =&gt; 'Object', required =&gt; 1 );
 sub BUILD {
   my $self = shift;
   
-  $self-&gt;{domain} = $self-&gt;config-&gt;domain($self-&gt;name)
+  $self-&gt;{domain} = $self-&gt;config-&gt;domain-&gt;{$self-&gt;name};
 }
 
 sub process {
@@ -36,12 +36,12 @@ sub process {
   $self-&gt;log-&gt;debug(&quot;Processing domain &quot; . $self-&gt;name);
   for my $key ( keys %{ $self-&gt;domain-&gt;{node} } ) {
     $self-&gt;log-&gt;debug(&quot;Processing node $key&quot;);
-   # my $node = Moonin::Node-&gt;new( 
-   #   domain =&gt; $self-&gt;name,
-   #   node   =&gt; $key,
-   #   config =&gt; $self-&gt;config
-   # );
-   # $node-&gt;process;
+    my $node = Moonin::Node-&gt;new( 
+      domain =&gt; $self-&gt;name,
+      node   =&gt; $key,
+      config =&gt; $self-&gt;config
+    );
+    $node-&gt;process;
   }
 }
 </diff>
      <filename>lib/moonin/Domain.pm</filename>
    </modified>
    <modified>
      <diff>@@ -29,8 +29,13 @@ has 'domain'      =&gt; ( is =&gt; 'rw', isa =&gt; 'Str',     required =&gt; 1 );
 has 'config'      =&gt; ( is =&gt; 'rw', isa =&gt; 'Object',  required =&gt; 1 );
 has 'node_config' =&gt; ( is =&gt; 'ro', isa =&gt; 'HashRef', required =&gt; 0 );
 has 'timeout' =&gt; ( is =&gt; 'rw', isa =&gt; 'Int', required =&gt; 1, default =&gt; 180 );
-has 'limit_services' =&gt;
-  ( is =&gt; 'rw', required =&gt; 0, default =&gt; undef );
+has 'limit_services' =&gt; ( is =&gt; 'rw', required =&gt; 0, default =&gt; undef );
+has 'copy_fields' =&gt; (
+  is       =&gt; 'rw',
+  required =&gt; 0,
+  defualt =&gt;
+    sub { [ &quot;label&quot;, &quot;draw&quot;, &quot;type&quot;, &quot;rrdfile&quot;, &quot;fieldname&quot;, &quot;info&quot; ] }
+);
 
 sub BUILD {
   my $self = shift;
@@ -98,7 +103,7 @@ sub process {
   } else {
     next
       unless ( $self-&gt;configure($socket) );
-    $self-&gt;fetch( $socket );
+    $self-&gt;fetch($socket);
 
     #		Net::SSLeay::free ($tls) if ($tls); # Shut down TLS
     close $socket;
@@ -124,7 +129,9 @@ sub fetch {
     next
       if ( exists( $node-&gt;{client}-&gt;{$service}-&gt;{update} )
       and $node-&gt;{client}-&gt;{$service}-&gt;{update} ne &quot;yes&quot; );
-    next if ( $self-&gt;limit_services and !grep ( /^$service$/, @{$self-&gt;limit_services} ) );
+    next
+      if ( $self-&gt;limit_services
+      and !grep ( /^$service$/, @{ $self-&gt;limit_services } ) );
     my $realservname =
       ( $node-&gt;{client}-&gt;{$service}-&gt;{realservname} || $service );
     delete $node-&gt;{client}-&gt;{$service}-&gt;{realservname}
@@ -186,7 +193,8 @@ sub fetch {
       sprintf( &quot;%.2f&quot;, ( Time::HiRes::time - $servicefetch_time ) );
     $self-&gt;log-&gt;debug(
       &quot;Fetched service: $name -&gt; $service ($servicefetch_time sec)&quot;);
-    $self-&gt;config-&gt;store-&gt;dbm-&gt;{FS}-&gt;{$domain}-&gt;{$name}-&gt;{$service} = $servicefetch_time;
+    $self-&gt;config-&gt;store-&gt;dbm-&gt;{FS}-&gt;{$domain}-&gt;{$name}-&gt;{$service} =
+      $servicefetch_time;
   }
   $nodefetch_time =
     sprintf( &quot;%.2f&quot;, ( Time::HiRes::time - $nodefetch_time ) );
@@ -202,7 +210,7 @@ sub configure {
   my $name    = $self-&gt;name;
   my $node    = $self-&gt;node_config;
   my $oldnode = $self-&gt;config-&gt;store-&gt;get(&quot;node-$domain-$name&quot;);
-  
+
   my $clientdomain = $self-&gt;_read_socket_single($socket);
   my $fetchdomain;
   chomp($clientdomain) if $clientdomain;
@@ -368,9 +376,10 @@ sub configure {
       $node-&gt;{client}-&gt;{$servname}-&gt;{graph_order} = join( ' ', @graph_order );
     }
 
-     $serviceconf_time =
-       sprintf( &quot;%.2f&quot;, ( Time::HiRes::time - $serviceconf_time ) );
-    $self-&gt;config-&gt;store-&gt;dbm-&gt;{'CS'}-&gt;{$domain}-&gt;{$name}-&gt;{$servname} = $serviceconf_time;
+    $serviceconf_time =
+      sprintf( &quot;%.2f&quot;, ( Time::HiRes::time - $serviceconf_time ) );
+    $self-&gt;config-&gt;store-&gt;dbm-&gt;{'CS'}-&gt;{$domain}-&gt;{$name}-&gt;{$servname} =
+      $serviceconf_time;
     $self-&gt;log-&gt;debug(
       &quot;Configured service: $name -&gt; $servname ($serviceconf_time sec)&quot;);
   }
@@ -382,6 +391,416 @@ sub configure {
   return 1;
 }
 
+sub get_node_config {
+  my $self = shift;
+  return $self-&gt;config-&gt;store-&gt;dbm-&gt;{node}-&gt;{ $self-&gt;domain }
+    -&gt;{ $self-&gt;name };
+}
+
+sub get_field_order {
+  my $self    = shift;
+  my $service = shift;
+  my $node    = $self-&gt;get_node_config;
+  my $config  = $self-&gt;config;
+  my $domain  = $self-&gt;domain;
+  my $result  = [];
+
+  if ( $node-&gt;{client}-&gt;{$service}-&gt;{graph_sources} ) {
+    foreach
+      my $gs ( split /\s+/, $node-&gt;{client}-&gt;{$service}-&gt;{'graph_sources'} ) {
+      push( @$result, &quot;-&quot; . $gs );
+    }
+  }
+  if ( $node-&gt;{client}-&gt;{$service}-&gt;{graph_order} ) {
+    push( @$result,
+      split /\s+/, $node-&gt;{client}-&gt;{$service}-&gt;{'graph_order'} );
+  }
+
+  for my $key ( keys %{ $node-&gt;{client}-&gt;{$service} } ) {
+    my ( $client, $type ) = &quot;&quot;;
+    ( $client, $type ) = split /\./, $key;
+    if ( defined $type and $type eq &quot;label&quot; ) {
+      push @$result, $client if !grep /^\Q$client\E(?:=|$)/, @$result;
+    }
+  }
+  $self-&gt;log-&gt;debug( &quot;Field order for $service: &quot; . dump($result) );
+  return $result;
+}
+
+sub get_max_label_length {
+  my $self    = shift;
+  my $node    = $self-&gt;get_node_config;
+  my $service = shift;
+  my $order   = shift;
+  my $result  = 0;
+
+  for my $field (@$order) {
+    my $path = undef;
+    ( my $f = $field ) =~ s/=.+//;
+    next
+      if (exists $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.process&quot; }
+      and $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.process&quot; }
+      and $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.process&quot; } ne &quot;yes&quot; );
+    next if ( exists $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.skipdraw&quot; } );
+    next
+      unless ( !exists $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.graph&quot; }
+      or !$node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.graph&quot; }
+      or $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.graph&quot; } eq &quot;yes&quot; );
+    if ( $result &lt;
+      length( $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.label&quot; } || $f ) ) {
+      $result =
+        length( $node-&gt;{client}-&gt;{$service}-&gt;{ $f . &quot;.label&quot; } || $f );
+    }
+    if ( exists $node-&gt;{client}-&gt;{$service}-&gt;{graph_total}
+      and length $node-&gt;{client}-&gt;{$service}-&gt;{graph_total} &gt; $result ) {
+      $result = length $node-&gt;{client}-&gt;{$service}-&gt;{graph_total};
+    }
+  }
+  return $result;
+}
+
+sub process_field {
+  my $self    = shift;
+  my $service = shift;
+  my $field   = shift;
+  my $node    = $self-&gt;get_node_config;
+  return ( $self-&gt;get_bool_val( $service, $field . &quot;.process&quot;, 1 ) );
+}
+
+sub get_bool_val {
+  my $self       = shift;
+  my $service    = shift;
+  my $field_name = shift;
+  my $default    = shift;
+  my $node       = $self-&gt;get_node_config;
+  my $field      = $node-&gt;{client}-&gt;{$service}-&gt;{$field_name};
+
+  if ( !defined $field ) {
+    if ( !defined $default ) {
+      return 0;
+    } else {
+      return $default;
+    }
+  }
+
+  if ( $field =~ /^yes$/i
+    or $field =~ /^true$/i
+    or $field =~ /^on$/i
+    or $field =~ /^enable$/i
+    or $field =~ /^enabled$/i ) {
+    return 1;
+  } elsif ( $field =~ /^no$/i
+    or $field =~ /^false$/i
+    or $field =~ /^off$/i
+    or $field =~ /^disable$/i
+    or $field =~ /^disabled$/i ) {
+    return 0;
+  } elsif ( $field !~ /\D/ ) {
+    return $field;
+  } else {
+    return undef;
+  }
+}
+
+sub get_stack_command {
+  my $self    = shift;
+  my $service = shift;
+  my $field   = shift;
+  my $node    = $self-&gt;get_node_config;
+
+  if ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.special_stack&quot; } ) {
+    return $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.special_stack&quot; };
+  } elsif ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.stack&quot; } ) {
+    return $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.stack&quot; };
+  }
+
+  return undef;
+}
+
+sub get_sum_command {
+  my $self    = shift;
+  my $service = shift;
+  my $field   = shift;
+  my $node    = $self-&gt;get_node_config;
+
+  if ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.special_sum&quot; } ) {
+    return $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.special_sum&quot; };
+  } elsif ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.sum&quot; } ) {
+    return $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.sum&quot; };
+  }
+
+  return undef;
+}
+
+sub get_filename {
+  my $self    = shift;
+  my $config  = $self-&gt;config;
+  my $domain  = $self-&gt;domain;
+  my $node    = $self-&gt;get_node_config;
+  my $service = shift;
+  my $field   = shift;
+
+  return (
+    $config-&gt;dbdir . &quot;/$domain/&quot; . $self-&gt;name . &quot;-$service-$field-&quot;
+      . lc substr(
+      ( $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.type&quot; } || &quot;GAUGE&quot; ),
+      0, 1 )
+      . &quot;.rrd&quot;
+  );
+
+}
+
+sub get_rrd_filename {
+  my $self    = shift;
+  my $node    = $self-&gt;get_node_config;
+  my $config  = $self-&gt;config;
+  my $domain  = $self-&gt;domain;
+  my $name    = $self-&gt;name;
+  my $service = shift;
+  my $field   = shift;
+  my $path    = shift;
+  my $result  = &quot;unknown&quot;;
+
+  if ( $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.filename&quot; } ) {
+    $result = $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.filename&quot; };
+  } elsif ($path) {
+    if ( !defined( $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.label&quot; } ) ) {
+      $self-&gt;log-&gt;debug(&quot;Setting label: $field\n&quot;);
+      $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.label&quot; } = $field;
+    }
+
+    if ( $path =~ /^\s*([^:;]+)[:;]([^:]+):([^:\.]+)[:\.]([^:\.]+)\s*$/ ) {
+      $result = $self-&gt;get_filename( $config, $3, $4 );
+      $self-&gt;log-&gt;debug(&quot;Expanding $path...\n&quot;);
+      if ( !defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;label&quot; } ) {
+        for my $f ( @{ $self-&gt;copy_fields } ) {
+          if ( not exists $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;}
+            and
+            exists $config-&gt;{'domain'}-&gt;{$1}-&gt;{'node'}-&gt;{$2}-&gt;{'client'}-&gt;{$3}
+            -&gt;{&quot;$4.$f&quot;} ) {
+            $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;} =
+              $config-&gt;{'domain'}-&gt;{$1}-&gt;{'node'}-&gt;{$2}-&gt;{'client'}-&gt;{$3}
+              -&gt;{&quot;$4.$f&quot;};
+          }
+        }
+      }
+    } elsif ( $path =~ /^\s*([^:]+):([^:\.]+)[:\.]([^:\.]+)\s*$/ ) {
+      $self-&gt;log-&gt;debug(&quot;Expanding $path...\n&quot;);
+      $result = $self-&gt;get_filename( $2, $3 );
+      for my $f ( @{ $self-&gt;copy_fields } ) {
+        if ( not exists $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;}
+          and
+          exists $config-&gt;{'domain'}-&gt;{$domain}-&gt;{'node'}-&gt;{$1}-&gt;{'client'}
+          -&gt;{$2}-&gt;{&quot;$3.$f&quot;} ) {
+          $self-&gt;log-&gt;debug(&quot;Copying $f...\n&quot;);
+          $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;} =
+            $config-&gt;{'domain'}-&gt;{$domain}-&gt;{'node'}-&gt;{$1}-&gt;{'client'}-&gt;{$2}
+            -&gt;{&quot;$3.$f&quot;};
+        }
+      }
+    } elsif ( $path =~ /^\s*([^:\.]+)[:\.]([^:\.]+)\s*$/ ) {
+      $self-&gt;log-&gt;debug(&quot;Expanding $path...\n&quot;);
+      $result = $self-&gt;get_filename( $1, $2 );
+      for my $f ( @{ $self-&gt;copy_fields } ) {
+        if ( not exists $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;}
+          and exists $node-&gt;{client}-&gt;{$1}-&gt;{&quot;$2.$f&quot;} ) {
+          $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;} =
+            $node-&gt;{client}-&gt;{$1}-&gt;{&quot;$2.$f&quot;};
+        }
+      }
+    } elsif ( $path =~ /^\s*([^:\.]+)\s*$/ ) {
+      $self-&gt;log-&gt;debug(&quot;Expanding $path...\n&quot;);
+      $result = $self-&gt;get_filename( $service, $1 );
+      for my $f ( @{ $self-&gt;copy_fields } ) {
+        if ( not exists $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;}
+          and exists $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$1.$f&quot;} ) {
+          $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$field.$f&quot;} =
+            $node-&gt;{client}-&gt;{$service}-&gt;{&quot;$1.$f&quot;};
+        }
+      }
+    }
+  } else {
+    $self-&gt;log-&gt;debug(&quot;\nDEBUG5: Doing path...\n&quot;);
+    $result = $self-&gt;get_filename( $service, $field );
+  }
+  return $result;
+}
+
+sub single_value {
+  my $self    = shift;
+  my $node    = $self-&gt;get_node_config;
+  my $service = shift;
+  my $field   = shift;
+  my $order   = shift;
+
+  return 1 if @$order == 1;
+  return 1
+    if (@$order == 2
+    and $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.negative&quot; } );
+
+  my $graphable = 0;
+  if ( !defined $node-&gt;{client}-&gt;{$service}-&gt;{&quot;graphable&quot;} ) {
+
+    #	foreach my $field (keys %{$node-&gt;{client}-&gt;{$service}})
+    foreach my $field ( $self-&gt;get_field_order($service) ) {
+      $self-&gt;log-&gt;debug(&quot;single_value: Checking field \&quot;$field\&quot;.\n&quot;);
+      if ( $field =~ /^([^\.]+)\.label/ or $field =~ /=/ ) {
+        $graphable++ if $self-&gt;draw_field( $service, $1 );
+      }
+    }
+    $node-&gt;{client}-&gt;{$service}-&gt;{&quot;graphable&quot;} = $graphable;
+  }
+  return 1 if ( $node-&gt;{client}-&gt;{$service}-&gt;{&quot;graphable&quot;} == 1 );
+
+  return 0;
+}
+
+sub draw_field {
+  my $self    = shift;
+  my $node    = $self-&gt;get_node_config;
+  my $service = shift;
+  my $field   = shift;
+
+  $field =~ s/=.*//;
+
+  $self-&gt;log-&gt;debug( &quot;munin_draw_field: Checking $service -&gt; $field: &quot;
+      . $self-&gt;get_bool_val( $service, $field . &quot;.graph&quot;, 1 )
+      . &quot;.\n&quot; );
+  return 0
+    if ( exists $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.skipdraw&quot; } );
+  return ( $self-&gt;get_bool_val( $service, $field . &quot;.graph&quot;, 1 ) );
+}
+
+sub expand_specials {
+  my $self    = shift;
+  my $service = shift;
+  my $preproc = shift;
+  my $order   = shift;
+  my $node    = $self-&gt;get_node_config;
+  my $config  = $self-&gt;config;
+  my $domain  = $self-&gt;domain;
+  my $single  = shift;
+  my $result  = [];
+
+  my $fieldnum = 0;
+  for my $field (@$order) {    # Search for 'specials'...
+
+    if ( $field =~ /^-(.+)$/ ) {
+      $field = $1;
+      unless ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.graph&quot; }
+        or defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.skipdraw&quot; } ) {
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.graph&quot; } = &quot;no&quot;;
+      }
+    }
+
+    $fieldnum++;
+    my $tmp_field;
+    if (
+      defined( $tmp_field = $self-&gt;get_stack_command( $service, $field ) ) ) {
+      $self-&gt;log-&gt;debug(&quot;Doing special_stack...\n&quot;);
+      my @spc_stack = ();
+      foreach my $pre ( split( /\s+/, $tmp_field ) ) {
+        ( my $name = $pre ) =~ s/=.+//;
+        if ( !@spc_stack ) {
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.draw&quot; } =
+            $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.draw&quot; };
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.process&quot; } = &quot;no&quot;;
+        } else {
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.draw&quot; } = &quot;STACK&quot;;
+        }
+        push( @spc_stack, $name );
+        push( @$preproc,  $pre );
+        push @$result, &quot;$name.label&quot;;
+        push @$result, &quot;$name.draw&quot;;
+        push @$result, &quot;$name.cdef&quot;;
+
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.label&quot; } = $name;
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.cdef&quot; } =
+          &quot;$name,UN,0,$name,IF&quot;;
+        if ( exists $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.cdef&quot; }
+          and !
+          exists $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.onlynullcdef&quot; } ) {
+          $self-&gt;log-&gt;debug(&quot;NotOnlynullcdef ($field)...\n&quot;);
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.cdef&quot; } .=
+            &quot;,&quot; . $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.cdef&quot; };
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.cdef&quot; } =~
+            s/\b$field\b/$name/g;
+        } else {
+          $self-&gt;log-&gt;debug(&quot;Onlynullcdef ($field)...\n&quot;);
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.onlynullcdef&quot; } = 1;
+          push @$result, &quot;$name.onlynullcdef&quot;;
+        }
+      }
+    } elsif (
+      defined( $tmp_field = $self-&gt;get_sum_command( $service, $field ) ) ) {
+      my @spc_stack = ();
+      my $last_name = &quot;&quot;;
+      $self-&gt;log-&gt;debug(&quot;Doing special_sum...\n&quot;);
+
+      if ( @$order == 1
+        or @$order == 2
+        &amp;&amp; $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.negative&quot; } ) {
+        $single = 1;
+      }
+
+      foreach my $pre ( split( /\s+/, $tmp_field ) ) {
+        ( my $path = $pre ) =~ s/.+=//;
+        my $name = &quot;z&quot; . $fieldnum . &quot;_&quot; . scalar(@spc_stack);
+        $last_name = $name;
+
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.cdef&quot; } =
+          &quot;$name,UN,0,$name,IF&quot;;
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.graph&quot; } = &quot;no&quot;;
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $name . &quot;.label&quot; } = $name;
+        push @$result, &quot;$name.cdef&quot;;
+        push @$result, &quot;$name.graph&quot;;
+        push @$result, &quot;$name.label&quot;;
+
+        push( @spc_stack, $name );
+        push( @$preproc,  &quot;$name=$pre&quot; );
+      }
+      $node-&gt;{client}-&gt;{$service}-&gt;{ $last_name . &quot;.cdef&quot; } .=
+        &quot;,&quot; . join( ',+,', @spc_stack[ 0 .. @spc_stack - 2 ] ) . ',+';
+      if ( exists $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.cdef&quot; }
+        and length $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.cdef&quot; } )
+      {    # Oh bugger...
+        my $tc = $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.cdef&quot; };
+        $self-&gt;log-&gt;debug(&quot;Oh bugger...($field)...\n&quot;);
+        $tc =~
+          s/\b$field\b/$node-&gt;{client}-&gt;{$service}-&gt;{$last_name.&quot;.cdef&quot;}/;
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $last_name . &quot;.cdef&quot; } = $tc;
+      }
+      $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.process&quot; } = &quot;no&quot;;
+      $node-&gt;{client}-&gt;{$service}-&gt;{ $last_name . &quot;.draw&quot; } =
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.draw&quot; };
+      $node-&gt;{client}-&gt;{$service}-&gt;{ $last_name . &quot;.label&quot; } =
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.label&quot; };
+      if ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.graph&quot; } ) {
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $last_name . &quot;.graph&quot; } =
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.graph&quot; };
+      } else {
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $last_name . &quot;.graph&quot; } = &quot;yes&quot;;
+      }
+      if ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.negative&quot; } ) {
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $last_name . &quot;.negative&quot; } =
+          $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.negative&quot; };
+      }
+      $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.realname&quot; } = $last_name;
+      $self-&gt;log-&gt;debug(
+&quot;Setting node-&gt;{client}-&gt;{$service}-&gt;{$field} -&gt; realname = $last_name...\n&quot;
+      );
+    } elsif ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.negative&quot; } )
+    {
+      my $nf = $node-&gt;{client}-&gt;{$service}-&gt;{ $field . &quot;.negative&quot; };
+      unless ( defined $node-&gt;{client}-&gt;{$service}-&gt;{ $nf . &quot;.graph&quot; }
+        or defined $node-&gt;{client}-&gt;{$service}-&gt;{ $nf . &quot;.skipdraw&quot; } ) {
+        $node-&gt;{client}-&gt;{$service}-&gt;{ $nf . &quot;.graph&quot; } = &quot;no&quot;;
+      }
+    }
+  }
+  return $result;
+}
+
 sub _sanitise_fieldname {
   my $self  = shift;
   my $lname = shift;</diff>
      <filename>lib/moonin/Node.pm</filename>
    </modified>
    <modified>
      <diff>@@ -51,3 +51,4 @@ isa_ok( $mn, 'Moonin::Node' );
 is($mn-&gt;node_config, $cfg-&gt;domain-&gt;{ &quot;sfo.v2green.com&quot; }-&gt;{node}-&gt;{ &quot;ops1prod.sfo.v2green.com&quot; }, &quot;Node Config is correct&quot; 
  );
 $mn-&gt;process;
+is(ref($mn-&gt;get_field_order(&quot;cpu&quot;)), 'ARRAY', &quot;CPU returns array&quot;) </diff>
      <filename>t/02moonin-node.pm</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>5ea61532076d0c5a43a4ab0bd256d054cfd4ac52</id>
    </parent>
  </parents>
  <author>
    <name>Adam Jacob</name>
    <email>adam@hjksolutions.com</email>
  </author>
  <url>http://github.com/adamhjk/moonin/commit/83399f46aa421ca62097a773ca8d3dcd4834ad35</url>
  <id>83399f46aa421ca62097a773ca8d3dcd4834ad35</id>
  <committed-date>2007-12-03T15:22:41-08:00</committed-date>
  <authored-date>2007-12-03T15:22:41-08:00</authored-date>
  <message>First real pass at moonin</message>
  <tree>05dbb69eb101df395b46be1118282cec069c5615</tree>
  <committer>
    <name>Adam Jacob</name>
    <email>adam@hjksolutions.com</email>
  </committer>
</commit>
