I've played with this enough.  I've added more features than this wishlist.

Here's the broad idea of what's changed.
1) 3 clicks to zoom has been replaced with drag'n'drop style selecting.
2) Ability to turn off fields (exception, cannot turn all fields off).
        The graph total is not considered a field, but is able to be turned
        off as well.  Fields turned off will not be shown in the graph
        legend.
3) When a field is listed in the graph legend and has been unchecked, a gray
        out bar is shown over the field in the legend.
4) As a convenience, the field line in the graph legend is clickable.
5) Original dynazoom.html did not work with IE8.  This version works to an
        extent with IE8 with 1 known bug.  If the paged is scrolled to the
        horizontally, the zoom selection will be wrong.
6) Added a second submit button just below the graph for convenience.
7) Limit low/high also will accept 'none' and will let rrdtool pick it's own
        limits.  Could possibly change this to 'auto' instead.
8) Added ability to force area draw type to line.
9) Added ability to disable stacking.  I found these 2 items to be useful
        when looking at the memory graph.

Patch is attached.  It should apply cleanly to munin 2.0 (untested), but this
was done against 2.1.1.  I don't believe there was enough changes in 2.1.2 to
make a difference.
diff -ruN /root/munin/usr/lib/munin/cgi/munin-cgi-graph ./munin-cgi-graph
--- /root/munin/usr/lib/munin/cgi/munin-cgi-graph       2013-05-27 
15:52:30.000000000 -0400
+++ ./munin-cgi-graph   2013-06-29 12:08:40.166711000 -0400
@@ -102,6 +102,7 @@
     my $path = $ENV{PATH_INFO} || "";
 
     DEBUG "Request path is $path";
+    DEBUG "Request query is $ENV{QUERY_STRING}";
 
     # The full URL looks like this:
     # Case 1:
@@ -342,6 +343,8 @@
     my $scale   = shift;
     my $fileext = shift;
     my $params  = shift;
+    my $filename_base;
+    my $filename;
 
     # XXX - hack to fix cgitmpdir default 
     $config->{cgitmpdir} ||= "$Munin::Common::Defaults::MUNIN_CGITMPDIR";
@@ -350,7 +353,17 @@
     $params = $params ? "?$params" : "";
     $params =~ tr/\//_/; # / are forbidden in a filename
     $params = $1 if $params =~ m/(.*)/; # XXX - Q&D untaint
-    return "$cgi_tmp_dir/$domain/$name/$service-$scale.$fileext" . $params;
+    $filename_base = "$cgi_tmp_dir/$domain/$name/$service-$scale.$fileext";
+    $filename = $filename_base . $params;
+
+    # Due to the ability to graph specific fields, the filename can now be way
+    # too long.  Exploit -f to see if the name is too long.
+    if (! -f $filename && $!{ENAMETOOLONG})
+    {
+        $filename = $filename_base . Digest::MD5::md5_hex($params);
+    }
+DEBUG "[DEBUG] Using $filename as image name";
+    return $filename;
 }
 
 sub has_offending_chars {
@@ -480,6 +493,19 @@
     push @params, "--debug"
       if (CGI::param("debug"));
 
+    # Limit fields
+    push @params, map {('--field' => $_)} CGI::param("field");
+
+    # Graph total
+    push @params, "--nototal" if CGI::param("nototal");
+
+    # Force draw to line1
+    push @params, "--force-line" if CGI::param("force_line");
+
+    # Disable stacking
+    push @params, "--nostack" if CGI::param("nostack");
+
+DEBUG "graph_main(\"" . join('", "', @params) . "\");";
     graph_main(\@params);
 
     return $filename;
diff -ruN /root/munin/usr/share/perl5/Munin/Master/GraphOld.pm ./GraphOld.pm
--- /root/munin/usr/share/perl5/Munin/Master/GraphOld.pm        2013-05-27 
15:51:16.000000000 -0400
+++ ./GraphOld.pm       2013-06-29 12:14:23.694711000 -0400
@@ -94,6 +94,9 @@
 my $skip_locking   = 0;
 my $skip_stats     = 0;
 my $stdout         = 0;
+my $nototal        = 0;
+my $nostack        = 0;
+my $force_line     = 0;
 my $force_run_as_root = 0;
 my $conffile       = $Munin::Common::Defaults::MUNIN_CONFDIR . "/munin.conf";
 my $libdir         = $Munin::Common::Defaults::MUNIN_LIBDIR;
@@ -162,6 +165,7 @@
 # Limit graphing to certain hosts and/or services
 my @limit_hosts    = ();
 my @limit_services = ();
+my @limit_fields = ();
 my $only_fqn = '';
 
 my $watermark = "Munin " . $Munin::Common::Defaults::MUNIN_VERSION;
@@ -183,6 +187,7 @@
 
 my @init_limit_hosts = @limit_hosts;
 my @init_limit_services = @limit_services;
+my @init_limit_fields = @limit_fields;
 
 sub process_pinpoint {
     my ($pinpoint, $arg_name, $arg_value) = @_;     
@@ -225,6 +230,7 @@
     %draw = %init_draw;
     @limit_hosts = @init_limit_hosts;
     @limit_services = @init_limit_services;
+    @limit_fields = @init_limit_fields;
 
     $pinpoint       = undef;
     my $pinpointopt    = undef;
@@ -240,6 +246,9 @@
     $skip_locking   = 0;
     $skip_stats     = 0;
     $stdout         = 0;
+    $nototal        = 0;
+    $nostack        = 0;
+    $force_line     = 0;
 
     $size_x        = undef;
     $size_y         = undef;
@@ -265,9 +274,13 @@
                 "lazy!"         => \$force_lazy,
                 "host=s"        => \@limit_hosts,
                 "service=s"     => \@limit_services,
+                "field=s"       => \@limit_fields,
                 "only-fqn=s"    => sub{ $only_fqn = process_fqn(@_); },
                 "config=s"      => \$conffile,
                 "stdout!"       => \$stdout,
+                "nototal"      => \$nototal,
+                "nostack"      => \$nostack,
+                "force-line"   => \$force_line,
                 "force-run-as-root!" => \$force_run_as_root,
                 "day!"          => \$draw{'day'},
                 "week!"         => \$draw{'week'},
@@ -370,7 +383,10 @@
     # The loaded $config is stale within 5 minutes.
     # So, we need to reread it when this happens.
     $config = munin_readconfig_part('datafile');
-   
+
+    # Reset limit fields.
+    @limit_fields   = ();
+
     # Reset an eventual custom size
     $size_x        = undef;
     $size_y         = undef;
@@ -380,6 +396,9 @@
     $lower_limit    = undef;
     $upper_limit    = undef;
     $pinpoint       = undef;
+    $nototal        = 0;
+    $nostack        = 0;
+    $force_line     = 0;
 
     $fileext        = "png";
 
@@ -388,6 +407,10 @@
 
     GetOptions (
                 "host=s"        => \@limit_hosts,
+                "field=s"       => \@limit_fields,
+                "nototal"      => \$nototal,
+                "nostack"      => \$nostack,
+                "force-line"   => \$force_line,
                 "only-fqn=s"    => sub { $only_fqn = process_fqn(@_); },
                 "day!"          => \$draw{'day'},
                 "week!"         => \$draw{'week'},
@@ -903,6 +926,7 @@
     DEBUG "[DEBUG] Node name: $sname\n";
 
     my $field_count   = 0;
+    my $field_skip_count = 0;
     my $max_field_len = 0;
     my @field_order   = ();
     my $rrdname;
@@ -958,7 +982,19 @@
     my %total_neg;
     my $autostacking = 0;
 
+    # When a field is skipped by using --fields, there is a possibility to
+    # skip a field that is the bottom of a stack.  last_draw is the
+    # line type of the bottom of the stack.  When the drawn bottom field is
+    # set as a stack, it's line type will be set to the skipped bottom's type.
+    my $last_draw;
+
+    # If the bottom field is skipped, this is set to 1.
+    my $bottom_skipped = 0;
+
     DEBUG "[DEBUG] Treating fields \"" . join("\",\"", @field_order) . "\".";
+    DEBUG "[DEBUG] Graph only these fields: \"" . join("\",\"", @limit_fields) 
. "\"."
+        if (@limit_fields);
+
     for my $fname (@field_order) {
         my $path  = undef;
         my $field = undef;
@@ -968,18 +1004,83 @@
         }
         $field = munin_get_node($service, [$fname]);
 
+        my $fielddraw = munin_get($field, "draw", "LINE1");
+
+        # Force line to be LINE1 if it is an AREA type.
+        if ($force_line)
+        {
+            if ($fielddraw eq 'AREA')
+            {
+                $fielddraw = 'LINE1';
+            }
+            elsif ($fielddraw eq 'ARASTACK')
+            {
+                $fielddraw = 'LINESTACK1';
+            }
+        }
+
+        if ($nostack)
+        {
+            DEBUG "[DEBUG] No stacking option";
+
+            # Disable stacking.
+            if ($fielddraw eq 'STACK')
+            {
+                $fielddraw = $last_draw || $fielddraw;
+            }
+            elsif ($fielddraw eq 'AREASTACK')
+            {
+                $fielddraw = 'AREA';
+            }
+            elsif ($fielddraw =~ /LINESTACK(\d+(?:.\d+)?)/)
+            {
+                $fielddraw = "LINE$1";
+            }
+            else
+            {
+                $last_draw = $fielddraw;
+            }
+        }
+
+        if (@limit_fields)
+        {
+            my $skip_this_field = !grep {$fname eq $_} @limit_fields;
+
+            if ($fielddraw ne 'STACK')
+            {
+                DEBUG "[DEBUG] Non stack, Set bottom_skipped to 
'$skip_this_field' and last_draw to '$fielddraw'";
+                $bottom_skipped = $skip_this_field;
+                $last_draw = $fielddraw;
+            }
+            # This is a STACK.  Check if bottom was skipped.
+            elsif ($bottom_skipped)
+            {
+                DEBUG "[DEBUG] Stacked field (bottom was skipped and field 
count > 0).  Last draw '$last_draw'";
+                # The bottom was skipped so this becomes the bottom.
+                $fielddraw = $last_draw;
+                $bottom_skipped = 0 unless $skip_this_field;
+               DEBUG "[DEBUG] bottom_skipped is now '$bottom_skipped'";
+            }
+
+            if ($skip_this_field)
+            {
+                DEBUG "[DEBUG] Skipping field $fname";
+                $field_skip_count++;
+                next;
+            }
+        }
+
         next if (!defined $field or !$field or !process_field($field));
         DEBUG "[DEBUG] Processing field \"$fname\" ["
             . munin_get_node_name($field) . "].";
 
-        my $fielddraw = munin_get($field, "draw", "LINE1");
-
         if ($field_count == 0 and $fielddraw eq 'STACK') {
-
             # Illegal -- first field is a STACK
+            # Ignore if fields have been skipped.
             DEBUG "ERROR: First field (\"$fname\") of graph "
                 . join(' :: ', munin_get_node_loc($service))
-                . " is STACK. STACK can only be drawn after a LINEx or AREA.";
+                . " is STACK. STACK can only be drawn after a LINEx or AREA."
+                if ($field_skip_count == 0);
             $fielddraw = "LINE1";
         }
 
@@ -1116,7 +1217,9 @@
        }
        
        # Select a default colour if no explict one
-       $colour ||= ($single_value) ? $single_colour : $COLOUR[$field_count % 
@COLOUR];
+       # Add field_skip_count to keep the colors in the graph the same as
+       # graphs that show all fields.
+       $colour ||= ($single_value) ? $single_colour : $COLOUR[($field_count + 
$field_skip_count) % @COLOUR];
 
         # colour needed for transparent predictions and trends
         munin_set($field, "colour", $colour);
@@ -1278,7 +1381,7 @@
     }
 
     my $graphtotal = munin_get($service, "graph_total");
-    if (defined $graphtotal and $graphtotal eq "undef") {
+    if ($nototal or (defined $graphtotal and $graphtotal eq "undef")) {
         $graphtotal = undef;
     }
 
@@ -1418,22 +1521,34 @@
        my ($upper_limit_overrided, $lower_limit_overrided);
        for (my $index = 0; $index <= $#complete; $index++) {
                if ($complete[$index] =~ /^(--upper-limit|-u)$/ && (defined 
$upper_limit)) {
+                       $upper_limit_overrided = 1;
+                       if ($upper_limit eq 'none')
+                       {
+                               splice(@complete, $index, 2);
+                               $index--;
+                               next;
+                       }
                        $upper_limit = get_scientific($upper_limit);
                        $complete[$index + 1] = $upper_limit;
-                       $upper_limit_overrided = 1;
                }
                if ($complete[$index] =~ /^(--lower-limit|-l)$/ && (defined 
$lower_limit)) {
+                       $lower_limit_overrided = 1;
+                       if ($lower_limit eq 'none')
+                       {
+                               splice(@complete, $index, 2);
+                               $index--;
+                               next;
+                       }
                        $lower_limit = get_scientific($lower_limit);
                        $complete[$index + 1] = $lower_limit;
-                       $lower_limit_overrided = 1;
                }
        }
 
        # Add the limit if not present
-       if (defined $upper_limit && ! $upper_limit_overrided) {
+       if (defined $upper_limit && $upper_limit ne 'none' && ! 
$upper_limit_overrided) {
                push @complete, "--upper-limit", $upper_limit;
        }
-       if (defined $lower_limit && ! $lower_limit_overrided) {
+       if (defined $lower_limit && $lower_limit ne 'none' && ! 
$lower_limit_overrided) {
                push @complete, "--lower-limit", $lower_limit;
        }
 
@@ -1979,6 +2094,11 @@
                        in Munin.)
     --host <host>       Limit graphed hosts to <host>. Multiple --host options
                         may be supplied.
+    --field <field>    Limit graphed fields to <field>. Multiple --field 
options
+                        may be supplied.
+    --nototal           Skip graphing total for graphs that have it.
+    --nostack           Disable stacking of fields.
+    --force-line       Force draw type to be LINE if the draw type is AREA.
     --only-fqn <FQN>    For internal use with CGI graphing.  Graph only a
                         single fully qualified named graph, e.g. --only-fqn
                           root/Backend/dafnes.example.com/diskstats_iops
@@ -1997,8 +2117,10 @@
     --pinpoint <start,stop> Create custom-graphs. <start,stop> is the standard 
unix Epoch. [not active]
     --size_x <pixels>   Sets the X size of the graph in pixels [175]
     --size_y <pixels>   Sets the Y size of the graph in pixels [400]
-    --lower_limit <lim> Sets the lower limit of the graph
-    --upper_limit <lim> Sets the upper limit of the graph
+    --lower_limit <lim> Sets the lower limit of the graph.
+    --upper_limit <lim> Sets the upper limit of the graph.
+                        NOTE: Use 'none' to not set upper/lower limit.  Over-
+                        rides limits for the service.
 
 NOTE! --pinpoint and --only-fqn must not be combined with
 --[no]<day|week|month|year> options.  The result of doing that is
diff -ruN /root/munin/usr/share/perl5/Munin/Master/HTMLConfig.pm ./HTMLConfig.pm
--- /root/munin/usr/share/perl5/Munin/Master/HTMLConfig.pm      2013-05-27 
15:51:16.000000000 -0400
+++ ./HTMLConfig.pm     2013-06-27 21:30:20.962711000 -0400
@@ -12,6 +12,7 @@
 use Getopt::Long;
 use Time::HiRes;
 use Scalar::Util qw( weaken );
+use URI::Escape;
 
 use Munin::Master::Logger;
 use Munin::Master::Utils;
@@ -491,6 +492,20 @@
 
     # Compute the ZOOM urls
     {
+        my @fields;
+        my $has_stack = 0;
+        my $has_area = 0;
+
+        # Personally, I don't like code preceeding "my" declarations.
+        foreach my $f (@{munin_get_field_order($service)}) {
+               my $draw = munin_get($service->{$f}, "draw", $f);
+                push @fields, "$f:" . munin_get($service->{$f}, "label", $f)
+                       if munin_draw_field($service->{$f});
+                
+                $has_stack++ if $draw eq "STACK";
+                $has_area++ if $draw eq "AREA";
+        }
+
         my $epoch_now = time;
        # The intervals are a bit larger, just like the munin-graph
        my $start_day = $epoch_now - (3600 * 30);
@@ -499,7 +514,19 @@
        my $start_year = $epoch_now - (3600 * 24 * 400);
        my $size_x = 800;
        my $size_y = 400;
-       my $common_url = 
"$root_path/static/dynazoom.html?cgiurl_graph=$config->{'cgiurl_graph'}&plugin_name=$path&size_x=$size_x&size_y=$size_y";
+       my $common_url = 
"$root_path/static/dynazoom.html?cgiurl_graph=$config->{'cgiurl_graph'}&plugin_name=$path&size_x=$size_x&size_y=$size_y&fields="
 . uri_escape(join(",", @fields));
+
+        my $graphtotal = munin_get($service, "graph_total");
+        if (defined $graphtotal and $graphtotal ne "undef") {
+            $common_url .= "&hastotal=1";
+        }
+        if ($has_stack) {
+            $common_url .= "&hasstack=1";
+        }
+        if ($has_area) {
+            $common_url .= "&hasarea=1";
+        }
+
        $srv{zoomday} = 
"$common_url&start_epoch=$start_day&stop_epoch=$epoch_now";
        $srv{zoomweek} = 
"$common_url&start_epoch=$start_week&stop_epoch=$epoch_now";
        $srv{zoommonth} = 
"$common_url&start_epoch=$start_month&stop_epoch=$epoch_now";
diff -ruN /root/munin/etc/munin/static/dynazoom.html ./dynazoom.html
--- /root/munin/etc/munin/static/dynazoom.html  2013-05-27 15:52:29.000000000 
-0400
+++ ./dynazoom.html     2013-06-30 08:07:02.106711000 -0400
@@ -1,6 +1,9 @@
+<!doctype html>
+<html>
 <head>
        <script language="JavaScript" src="formatdate.js"></script>
        <script language="JavaScript" src="querystring.js"></script>
+       <script language="JavaScript" src="dynazoom.js"></script>
        <link rel="stylesheet" href="./style-new.css" type="text/css" />
 </head>
 <body>
@@ -8,30 +11,24 @@
        <h1><a href="/munin/"><span class="logo"></span></a> <span 
class="currentpage">Dynamic Graph Zoom</span></h1>
 </div>
        
-<div style="position:relative;">
+<div id="imagediv" style="position:relative;">
        <img id="image" />
-<div id="overlayDiv" />
-
+       <div id="graphdiv">
+               <div id="overlayDiv"></div>
+       </div>
 </div>
-<table>
-<tr>
-<td>
-
-</td>
-<td>
-       Zooming is very easy, it's done in 3 clicks (regular clicks, not drag 
&amp; drop):
+<div id="zoomhelp">
+       Zooming is very easy.
        <ul>
-    <ol>
-               <li> click to define the start.
-               <li> click to define the end.
-               <li> click inside the shaded area to zoom (outside to cancel).
-    </ol>
+               <ol>
+                       <li> click and drag to highlight the time range.
+                       <li> click inside the shaded area to zoom or outside to 
cancel.
+               </ol>
        </ul>
-<td>
-</tr>
-</table>
+</div>
 
 <form name="myNewForm" id="myNewForm">
+       <input type=submit />
 <table>
        <!-- Plugin Name : "domain/hostname" -->
        <tr>
@@ -49,9 +46,21 @@
                </td>
        </tr>
 
+       <!-- Limit fields -->
+       <tr id="field_row" style="display: none;">
+               <td>Limit fields to</td>
+               <td id="field_list"></td>
+       </tr>
+
+       <!-- Options -->
+       <tr id="option_row" style="display: none;">
+               <td>Options</td>
+               <td id="option_box"></td>
+       </tr>
+
        <!-- Limit high & low -->
        <tr>
-               <td>Limit low/high :</td>
+               <td>Limit low/high : (use <i>none</i> to override limit)</td>
                <td>
 
                        <input type="text" name="lower_limit" size="10"> /  
<input type="text" name="upper_limit" size="10">
@@ -77,195 +86,182 @@
        </tr>
 </table>
        <input type=hidden name="cgiurl_graph" />
+       <input type=hidden name="fields" />
        <input type=submit />
        <input type=button name="btnZoomOut" value="Zoom Out x2" />
 </form>
 
-</body>
-
 <script>
 
+var initial_left;
+
 // Insert values in the form
 var qs = new Querystring();
 
 var form = document.getElementById("myNewForm");
 var image = document.getElementById("image");
 var divOverlay = document.getElementById("overlayDiv");
+var divgraph = document.getElementById("graphdiv");
+var fields = qs.get("fields");
+var active_fields = [];
+var divbar = [];
+
+// Hold all the original info for the graph.  The original placed these in
+// the form and used those values in places it shouldn't have been used.
+// size is a perfect example of this.  If the size_y is chagned, say from
+// 400 to 40, the selection will only be 40 px tall instead of the actual 400
+var graph = {
+       offset: { // According to rrd graphv, the x/y offsets are 33,67
+                 // It would be better to get this from rrd graphv
+                 // dynamically.
+               x: 67,  // Atleast on the systems I've installed on.
+               y: 33
+       },
+       limit: {
+               lower: qs.get("lower_limit", ""),
+               upper: qs.get("upper_limit", "")
+       },
+       epoch: { // The values here were original, not sure why these
+                // values were chosen.
+               start: (+qs.get("start_epoch", "1236561663")),
+               stop: (+qs.get("stop_epoch", "1237561663"))
+       },
+       size: { // Changed the default of "","" to "800","400"
+               x: (+qs.get("size_x", "800")),
+               y: (+qs.get("size_y", "400"))
+       },
+       step: qs.get("step", "")
+};
+
+// Array of options.  Each option will have a checkbox added to the element
+// named option_box.  If atleast 1 option is available, the option_row will
+// be visible.
+var options = [{
+       // CGI query string.
+       qs: {
+               // Parameter name passed to dynazoom.html.  Option is created
+               // if this is a true value (eg 1)
+               html: "hastotal",
+               // Parameter name to be passed to munin-graph cgi.
+               // This will also be the name of the checkbox in the form.
+               graph: "nototal",
+               // Value if option is checked.
+               // checked: ,
+               // Value if option not checked.
+               unchecked: "1",
+               // NOTE: if checked or unchecked is not defined, parameter
+               // will not be passed depending on the checkbox status.
+               // This is the default when there is no matching parameter
+               // passed to the .html with the same name as the graph value
+               // above.  (This case it is "nototal")
+               def: true,
+       },
+       label: "Graph total",
+       // init is called when the checkbox is created.
+       // The checkbox object is passed as the parameter.
+       // Not required.
+       init: init_graph_total,
+},{
+       qs: {
+               html: "hasstack",
+               graph: "nostack",
+               checked: "1",
+               def: false,
+       },
+       label: "Disable stacking",
+},{
+       qs: {
+               html: "hasarea",
+               graph: "force_line",
+               checked: "1",
+               def: false,
+       },
+       label: "Force all area fields to a line",
+}];
 
+var fieldtr = document.getElementById("field_row");
+var optiontr = document.getElementById("option_row");
 
 form.cgiurl_graph.value = qs.get("cgiurl_graph", "/munin-cgi/munin-cgi-graph");
 form.plugin_name.value = qs.get("plugin_name", 
"localdomain/localhost.localdomain/if_eth0");
-form.start_epoch.value = qs.get("start_epoch", "1236561663");
-form.stop_epoch.value = qs.get("stop_epoch", "1237561663");
-form.lower_limit.value = qs.get("lower_limit", "");
-form.upper_limit.value = qs.get("upper_limit", "");
-form.size_x.value = qs.get("size_x", "");
-form.size_y.value = qs.get("size_y", "");
-form.step.value = qs.get("step", "");
+form.start_epoch.value = graph.epoch.start;
+form.stop_epoch.value = graph.epoch.stop;
+form.lower_limit.value = graph.limit.lower;
+form.upper_limit.value = graph.limit.upper;
+form.size_x.value = graph.size.x;
+form.size_y.value = graph.size.y;
+form.step.value = graph.step;
 
 form.btnMaj.onclick = majDates;
 form.btnZoomOut.onclick = zoomOut;
 
+init_field_list();
+init_options(options, "option_row", "option_box");
+
 // Refresh the image with the selected params
 var scale = refreshImg();
 
-function refreshImg() {
-       image.src = form.cgiurl_graph.value + "/"
-               + form.plugin_name.value 
-               + "-pinpoint=" + parseInt(form.start_epoch.value) + "," + 
parseInt(form.stop_epoch.value)
-               + ".png"
-               + "?" 
-               + "&lower_limit=" + form.lower_limit.value
-               + "&upper_limit=" + form.upper_limit.value
-               + "&size_x=" + form.size_x.value
-               + "&size_y=" + form.size_y.value
-               + "&step=" + form.step.value
-       ;
-
-       return ((+form.stop_epoch.value) - (+form.start_epoch.value)) / 
(+form.size_x.value);
-}
-
-var start_epoch = (+form.start_epoch.value);
-var stop_epoch = (+form.stop_epoch.value);
-var initial_left;
-var initial_top;
-
 updateStartStop();
 
-function updateStartStop() {
-       form.start_iso8601.value = new Date(form.start_epoch.value * 
1000).formatDate(Date.DATE_ISO8601);
-       form.stop_iso8601.value = new Date(form.stop_epoch.value * 
1000).formatDate(Date.DATE_ISO8601);
-}
-
-function divMouseMove(mouseMouveEvent) {
-       var delta_x;
-       var size_x;
-
-       // Handling the borders (X1>X2 ou X1<X2)
-       var current_width = mouseMouveEvent.pageX - initial_left;
-       if (current_width < 0) {
-               divOverlay.style.left = mouseMouveEvent.pageX;
-               delta_x = mouseMouveEvent.pageX - 63; // the Y Axis is 63px 
from the left border
-               divOverlay.style.width = size_x = - current_width;
-       } else {
-               divOverlay.style.left = initial_left;
-               delta_x = initial_left - 63; // the Y Axis is 63px from the 
left border
-               divOverlay.style.width = size_x = current_width;
+// When scale is 1 or less, each pixel in the graph image = 1 second or less.
+// Millisecond graphs are not possible with munin.  Even less than 300 is not
+// trivial as I understand it.
+if (scale > 1)
+{
+       // Set the handlers.
+       divgraph.onmousedown = dragstart;
+       // Clear these.  dragstart will setup anything needed.
+       divgraph.onmousemove = null;
+       divgraph.onmouseup = null;
+       divgraph.onclick = null;
+}
+else
+       // setup the graph click to this function.  Alert the user once that
+       // the operation is not permitted.
+       divgraph.onclick = function ()
+       {
+               alert("Already at maximum zoom.\n" + 
+                       "Each pixel is " + scale.toPrecision(3) + " seconds"
+               );
+               // Alert only once.
+               divgraph.onclick = null;
        }
-       
-       // Compute the epochs UNIX (only for horizontal)
-       form.start_epoch.value = start_epoch + scale * delta_x;
-       form.stop_epoch.value = start_epoch + scale * ( delta_x + size_x );
-       
-       // update !
-       updateStartStop();
-}
-
-function startZoom(mouseMouveEvent) {
-       initial_left = mouseMouveEvent.pageX;
-       initial_top = mouseMouveEvent.pageY;
-       
-       // Fixed, since zoom is only horizontal
-       divOverlay.style.top = image.style.top.replace("px", "") + 29;
-       divOverlay.style.height = (+form.size_y.value) + 1;
-
 
-       // Show the div
-       divOverlay.style.visibility = 'visible';
-       divOverlay.style.backgroundColor = '#555'; 
-
-       // Initial show
-       divOverlay.style.left = mouseMouveEvent.pageX;
-       //divOverlay.style.width = (+form.size_x.value) / 4;
-       divOverlay.style.width = 40;
-       
-       // Fix the handles
-       image.onmousemove = divMouseMove;
-       divOverlay.onmousemove = divMouseMove;
-       divOverlay.onclick = image.onclick;
-
-}
-
-function endZoom(event) {
-       divOverlay.style.backgroundColor = '#000'; 
-       image.onmousemove = undefined;
-       divOverlay.onmousemove = undefined;
-       divOverlay.onclick = doZoom;
-}
-
-function clearZoom(event) {
-       divOverlay.style.visibility = 'hidden';
-       divOverlay.style.width = 0;
-       
-       // reset the zoom
-       form.start_epoch.value = start_epoch;
-       form.stop_epoch.value = stop_epoch;
-
-       updateStartStop();
-}
+</script>
 
-function doZoom(event) {
-       // Navigate !
-       form.submit();
+<style>
+#overlayDiv { 
+       opacity: .55;
+       filter: alpha(opacity=55);
+       background-color:#EEE; 
+       position: absolute; 
+       z-index: 3;
 }
 
-function zoomOut(event) {
-       form.start_epoch.value = start_epoch - scale * form.size_x.value;
-       form.stop_epoch.value= stop_epoch + scale * form.size_y.value;
-       form.submit();
+#graphdiv {
+       background-color: rgba(0,0,0,0);
+       position: absolute;
+       background-image: url(file:///);
+       left: 0px;
+       z-index: 2;
 }
 
-function fillDate(date, default_date) {
-       return date + default_date.substring(date.length, default_date.length);
+#zoomhelp ul ol {
+       margin: 0px;
+       padding: 0px;
 }
 
-function majDates(event) {
-       var default_date = "2009-01-01T00:00:00+0100";
-
-       var start_manual = fillDate(form.start_iso8601.value, default_date);
-       var stop_manual = fillDate(form.stop_iso8601.value, default_date);
-       
-       var dateRegex = 
/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{4})/;
-       
-       if (dateRegex.test(start_manual)) {
-               var date_parsed = new Date(start_manual.replace(dateRegex, "$2 
$3, $1 $4:$5:$6"));
-               form.start_epoch.value = date_parsed.getTime() / 1000;
-       }
-
-       if (dateRegex.test(stop_manual)) {
-               var date_parsed = new Date(stop_manual.replace(dateRegex, "$2 
$3, $1 $4:$5:$6"));
-               form.stop_epoch.value = date_parsed.getTime() / 1000;
-       }
-
-       form.submit();
+#zoomhelp ul {
+       margin: 5px;
+       padding: 0px 0px 0px 3em;
 }
 
-// Sets the onClick handler
-divOverlay.onclick = image.onclick = click;
-var clickCounter = 1;
-function click(event) {
-       switch ((clickCounter++) % 3) {
-               case 0: 
-                       clearZoom(event);
-                       break;
-               case 1: 
-                       startZoom(event);
-                       break;
-               case 2: 
-                       endZoom(event);
-                       break;                  
-       }
+#zoomhelp {
+       padding-left: 1em;
 }
 
-</script>
-
-<style>
-#overlayDiv { 
-       opacity: .55; 
-       filter: alpha(opacity=55); 
-       background-color:#EEE; 
-       position: absolute; 
-       z-index: 2;
-}
 </style>
 
+
+</body>
+</html>
diff -ruN /root/munin/etc/munin/static/dynazoom.js ./dynazoom.js
--- /root/munin/etc/munin/static/dynazoom.js    1969-12-31 19:00:00.000000000 
-0500
+++ ./dynazoom.js       2013-06-30 08:07:39.114711000 -0400
@@ -0,0 +1,609 @@
+// Set the width of the divs after image has loaded.
+function imageonload()
+{
+       var w = this.width + "px";
+       divgraph.style.width = w;
+
+       for (var i = 0; i < divbar.length; i++)
+               divbar[i].style.width = w;
+}
+
+// Apparently called only once above.  Use values from graph instead of form.
+function refreshImg() {
+       var cgip = [];
+
+       // Test for a number or the string 'none'.
+       // NOTE: the value null is considered a number is not an empty
+       // string.  However, this value cannot be null.
+       if (!isNaN(graph.limit.lower) && graph.limit.lower != '' ||
+               graph.limit.lower == "none")
+               cgip.push("lower_limit=" + graph.limit.lower);
+       if (!isNaN(graph.limit.upper) && graph.limit.upper != '' ||
+               graph.limit.upper == "none")
+               cgip.push("upper_limit=" + graph.limit.upper);
+
+       // Graph size (x, y)
+       if (graph.size.x > 0)
+               cgip.push("size_x=" + graph.size.x);
+       if (graph.size.y > 0)
+               cgip.push("size_y=" + graph.size.y);
+
+       // Graph step
+       if (graph.step > 0)
+               cgip.push("step=" + graph.step);
+
+       // Compile the fields
+       if (typeof form.field !== "undefined")
+       {
+               var unchecked = 0;
+               var field = [];
+
+               for (var i = 0; i < form.field.length; i++)
+               {
+                       var box = form.field[i];
+
+                       if (box.checked)
+                               field.push("field=" + box.value);
+                       else
+                               unchecked++;
+               }
+               // If all fields were checked, don't send any fields.
+               if (unchecked)
+                       cgip = cgip.concat(field);
+       }
+
+       // Compile the options.
+       cgip = cgip.concat(options_compile(options));
+
+       // Convert to a string.
+       cgip = cgip.length > 0 ? "?" + cgip.join("&") : "";
+
+       image.onload = imageonload;
+       image.src = form.cgiurl_graph.value + "/"
+               + form.plugin_name.value 
+               + "-pinpoint=" 
+               + parseInt(graph.epoch.start) + "," 
+               + parseInt(graph.epoch.stop)
+               + ".png"
+               + cgip
+       ;
+
+       divgraph.style.top = graph.offset.y + "px";
+       divgraph.style.height = graph.size.y + "px";
+
+       return ((+form.stop_epoch.value) - (+form.start_epoch.value)) / 
(+form.size_x.value);
+}
+
+function updateStartStop() {
+       form.start_iso8601.value = new Date(form.start_epoch.value * 
1000).formatDate(Date.DATE_ISO8601);
+       form.stop_iso8601.value = new Date(form.stop_epoch.value * 
1000).formatDate(Date.DATE_ISO8601);
+}
+
+function doZoom(event) {
+       if (typeof event === "undefined")
+               event = window.event;
+
+       event.cancelBubble = true;
+
+       if (typeof event.stopPropagation !== "undefined")
+               event.stopPropagation();
+       // Navigate !
+       form.submit();
+}
+
+function zoomOut() {
+       form.start_epoch.value = graph.epoch.start - scale * graph.size.x;
+       form.stop_epoch.value= graph.epoch.stop + scale * graph.size.x;
+       form.submit();
+}
+
+function fillDate(date, default_date) {
+       return date + default_date.substring(date.length, default_date.length);
+}
+
+function majDates(event) {
+       var default_date = "2009-01-01T00:00:00+0100";
+
+       var start_manual = fillDate(form.start_iso8601.value, default_date);
+       var stop_manual = fillDate(form.stop_iso8601.value, default_date);
+       
+       var dateRegex = 
/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{4})/;
+       
+       if (dateRegex.test(start_manual)) {
+               var date_parsed = new Date(start_manual.replace(dateRegex, "$2 
$3, $1 $4:$5:$6"));
+               form.start_epoch.value = date_parsed.getTime() / 1000;
+       }
+
+       if (dateRegex.test(stop_manual)) {
+               var date_parsed = new Date(stop_manual.replace(dateRegex, "$2 
$3, $1 $4:$5:$6"));
+               form.stop_epoch.value = date_parsed.getTime() / 1000;
+       }
+
+       form.submit();
+}
+
+function getXY(event, object, debug)
+{
+       var x, y, p;
+
+       if (typeof object === "undefined" &&
+               typeof event.offsetX !== "undefined" &&
+               typeof event.offsetY !== "undefined")
+               return {x: event.offsetX, y: event.offsetY};
+
+       if (typeof event.pageX !== "undefined" &&
+               typeof event.pageY !== "undefined")
+       {
+               x = event.pageX;
+               y = event.pageY;
+       }
+       else
+       {
+               x = event.clientX;
+               y = event.clientY;
+       }
+       p = (typeof object === "object") ? 
+               object : 
+               (typeof event.srcElement === "object") ?
+                       event.srcElement :
+                       event.target;
+       do
+       {
+               x -= p.offsetLeft;
+               y -= p.offsetTop;
+               p = p.offsetParent;
+       } while (p !== null);
+
+       return {x: x, y: y};
+}
+
+function dragstart(event)
+{
+       var button1;
+       var coords;
+       var target;
+
+       if (typeof event === "undefined")
+       {
+               event = window.event;
+               button1 = event.button == 1;
+       }
+       else
+               button1 = event.button == 0;
+
+       target = (typeof event.srcElement === "object") ? 
+               event.srcElement :
+               event.target;
+
+       // Cancel if the target object is not this object or mouse button1.
+       // was not the one pressed.
+       if (this !== target || button1 === false)
+               return false;
+
+       coords = getXY(event);
+
+       initial_left = coords.x;
+       
+       // Reset mouse movement.
+       divOverlay.mouse_has_moved = false;
+
+       // Fixed, since zoom is only horizontal
+       // According to rrdgraphv on my system, the top of the graph is 33
+       // pixel offset
+       divOverlay.style.height = divgraph.style.height;
+
+       // Show the div
+       divOverlay.style.visibility = 'visible';
+       divOverlay.style.backgroundColor = '#555'; 
+
+       // Initial show
+       divOverlay.style.left = coords.x + "px";
+       //divOverlay.style.width = (+form.size_x.value) / 4;
+       //divOverlay.style.width = 40;
+       // I find that the initial width was visually irritating.  Change to 1
+       // px.
+       divOverlay.style.width = "1px";
+       
+       // Fix the handles
+       divgraph.onmousemove = dragmove;
+       divgraph.onmouseup = dragstop;
+}
+
+function dragmove(event)
+{
+       var delta_x;
+       var size_x;
+       var coords;
+
+       if (typeof event === "undefined")
+               event = window.event;
+
+       // It's possible we can be called with the divOverlay as the target
+       // instead of the divgraph.  Force divgraph.
+       coords = getXY(event, divgraph);
+
+       // Handling the borders (X1>X2 ou X1<X2)
+       var current_width = coords.x - initial_left;
+
+       if (current_width < 0) {
+               divOverlay.style.left = (coords.x + 1) + "px";
+               delta_x = coords.x - graph.offset.x;
+               size_x = - current_width;
+               divOverlay.style.width = size_x + "px"
+       } else {
+               divOverlay.style.left = initial_left + "px";
+               delta_x = initial_left - graph.offset.x;
+               size_x = current_width;
+               divOverlay.style.width = size_x + "px"
+       }
+
+       // Record the fact the mouse moved.  Less than 2 pixels can be jitter
+       // or some kind of click (ie single or double) where mousedown and up
+       // happen without movement.  This causes it to be canceled.
+       if (divOverlay.mouse_has_moved === false && delta_x > 2)
+               divOverlay.mouse_has_moved = true;
+
+       // Compute the epochs UNIX (only for horizontal)
+       form.start_epoch.value = graph.epoch.start + scale * delta_x;
+       form.stop_epoch.value = graph.epoch.start + scale * ( delta_x + size_x 
);
+       
+       // update !
+       updateStartStop();
+}
+
+function dragstop(event)
+{
+       if (typeof event === "undefined")
+               event = window.event;
+
+       divgraph.onmousemove = null;
+       divgraph.onmousedown = null;
+       divgraph.onmouseup = null;
+       divgraph.onmousedown = dragstart;
+       divgraph.onmouseup = null;
+
+       divOverlay.style.backgroundColor = '#000'; 
+       divOverlay.onclick = doZoom;
+
+       // Cancel the whole thing if the mouse hasn't moved.
+       if (divOverlay.mouse_has_moved === false)
+       {
+               divgraph.onmousemove = null;
+               divgraph.onmouseup = null;
+               divgraph.onclick = null;
+               divOverlay.onclick = null;
+
+               // hide the overlay
+               divOverlay.style.visibility = 'hidden';
+               divOverlay.style.width = "0px";
+
+               // reset the zoom
+               form.start_epoch.value = graph.epoch.start;
+               form.stop_epoch.value = graph.epoch.stop;
+
+               updateStartStop();
+       }
+
+       return false;
+}
+
+// IE doesn't have Array.indexOf().
+function myIndexOf(a, s, o)
+{
+       if (typeof o === "undefined")
+               o = 0;
+
+       // Call if indexOf is indeed available.
+       if (typeof a.indexOf === "function")
+               return a.indexOf(s, o);
+
+       for (var i = o, j = a.length; i < j; i++)
+               if (a[i] === s)
+                       return i;
+
+       return -1;
+}
+
+function togglebox()
+{
+       this.box.checked = !this.box.checked;
+       if (typeof this.box.onchange === "function")
+               this.box.onchange();
+       else if (typeof this.box.onclick === "function")
+               this.box.onclick();
+}
+
+function toggle_fields()
+{
+       for (var i = 0; i < this.boxes.length; i++)
+       {
+               var f = this.boxes[i];
+               f.checked = !f.checked;
+               if (typeof f.onchange === "function")
+                       f.onchange();
+               else if (typeof f.onclick === "function")
+                       f.onclick();
+       }
+}
+
+// Shows or hides the gray bar over the field.  This is a visual indicator
+// that the shown field has been unchecked.
+function show_hide_bar()
+{
+       var opaque = this.checked ? 0 : 30;
+
+       this.bar.style.opacity = opaque / 100;
+       this.bar.style.filter = "alpha(opacity=" + opaque + ")";
+}
+
+// Creates the elements needed for field checkboxes and sets up the
+// objects that work with it.
+function init_field_list()
+{
+       // No field list, no checkboxes.
+       if (typeof fields === "undefined")
+               return;
+
+       // Element to create the checkboxes in.
+       var list = document.getElementById("field_list");
+
+       // This is the list of fields that should be checked.  If none,
+       // all fields will be checked.
+       var checked_fields = qs.get("field");
+
+       var checked = [];
+       var f = fields.split(",");
+       var boxes = [];
+
+       // Less than 2 fields, no checkboxes.
+       if (f.length < 2)
+       {
+               // Add something here so that if there is a total, the bar
+               // will be in the correct place.
+               active_fields.push(null);
+               return;
+       }
+       // The template for the divs that will cover the fields in the image.
+       var div_template = document.createElement("div");
+       div_template.style.left = "0px";
+       // This is the offset from the top of the image to the list of fields
+       // minus the height of the graph.
+       div_template.style.top = 65 + graph.size.y + "px";
+       // Let the image onload function handle will set this.
+       //div_template.style.width = "0px";
+       // Assume the text is about this tall in pixels.
+       div_template.style.height = "11px";
+       div_template.style.zindex = 2;
+       div_template.style.backgroundColor = "#000";
+       div_template.style.opacity = 0;
+       div_template.style.filter = "alpha(opacity=0)";
+       div_template.style.position = "absolute";
+
+       // Set the hidden field to the list of fields and their labels.
+       form.fields.value = fields;
+
+       if (typeof checked_fields === "object" && 
+               checked_fields.constructor === Array)
+               for (i = 0; i < checked_fields.length; 
checked.push(checked_fields[i++]));
+       else if (typeof checked_fields == "string")
+               checked = [checked_fields];
+
+       // Add the checkboxes and labels.  Create divs to grey out the field
+       // in the image.
+       for (var i = 0; i < f.length; i++)
+       {
+               // This checkbox
+               var cb = document.createElement("input");
+               // The field name
+               var fn = f[i].split(":", 1)[0]
+               // The field label
+               var text = f[i].substr(fn.length + 1);
+               // The label element
+               var label = document.createElement("label");
+
+               cb.type = "checkbox";
+               cb.name = "field";
+               cb.value = fn;
+               cb.id = "field_" + fn;
+               cb = list.appendChild(cb);
+               if (checked.length == 0 || myIndexOf(checked, fn) != -1)
+               {
+                       // The grey bar over the field
+                       var bar = div_template.cloneNode(false);
+
+                       cb.onclick = show_hide_bar;
+                       bar.style.top = parseInt(bar.style.top) + 
(active_fields.length * 12) + "px";
+                       bar.id = "field" + i + "grey";
+                       active_fields.push(i);
+                       cb.checked = "true";
+
+                       // Make sure the checkbox object and bar object have
+                       // each other as a property.
+                       cb.bar = bar;
+                       bar.box = cb;
+
+                       // onclick isn't cloneable.  Need to define per
+                       // object.
+                       bar.onclick = togglebox;
+                       document.getElementById("imagediv").appendChild(bar);
+
+                       // The list of grey bars.  Used by the image onload
+                       // function.
+                       divbar.push(bar);
+               }
+
+               label.htmlFor = "field_" + fn;
+               label.innerHTML = text;
+               list.appendChild(label);
+
+               list.appendChild(document.createElement("br"));
+
+               boxes.push(cb);
+       }
+
+       // Create the toggle all button.
+       var toggle = document.createElement("input");
+       toggle.type = "button";
+       toggle.onclick = toggle_fields;
+       toggle.value = "Toggle";
+       toggle.boxes = boxes;
+       list.appendChild(toggle);
+
+       // Show the field limit in the page.
+       fieldtr.style.display = "";
+}
+
+// Sets up the bar for the total option
+function init_graph_total(cb)
+{
+       if (!cb.checked)
+               return;
+
+       // Create the bar.
+       var bar = document.createElement("div");
+
+       // Setup the grey bar for total.
+       bar.style.left = "0px";
+       // This is the offset from the top of the image to the total field
+       // minus the height of the graph.
+       bar.style.top = 65 + graph.size.y + (active_fields.length * 12) + "px";
+       // Let the image onload function handle will set this.
+       //bar.style.width = "0px";
+       // Assume the text is about this tall in pixels.
+       bar.style.height = "11px";
+       bar.style.zindex = 2;
+       bar.style.backgroundColor = "#000";
+       bar.style.opacity = 0;
+       bar.style.filter = "alpha(opacity=0)";                
+       bar.style.position = "absolute";
+       bar.onclick = togglebox;
+       document.getElementById("imagediv").appendChild(bar);
+       divbar.push(bar);
+
+       cb.bar = bar;
+       bar.box = cb;
+       cb.onclick = show_hide_bar;
+}
+
+// Creates the options.
+// opts                Array of option objects.
+//             The checkbox object is added as opts[i].checkbox.
+// row         Id of the element that needs to have it's visibility
+//             changed.
+// box         Id of the element that the checkboxes are added to.
+function init_options(opts, row, box)
+{
+       var row = document.getElementById(row);
+       var box = document.getElementById(box);
+       var count = 0;
+
+       for (var i = 0; i < opts.length; i++)
+       {
+               var o = opts[i];
+               var oqs = o.qs;
+               var checked;
+
+               // If this is set, create the checkbox.
+               if (qs.get(o.qs.html, 0) == 0)
+                       continue;
+
+               if (count)
+                       box.appendChild(document.createElement("br"));
+       
+               // cb = checkbox, h = html parameter
+               var cb = document.createElement("input");
+               var h = document.createElement("input");
+               var l = document.createElement("label");
+
+               // Checkbox values.
+               cb.type = "checkbox";
+               cb.name = oqs.graph;
+               cb.id = oqs.graph;
+               cb = box.appendChild(cb);
+               checked = qs.get(oqs.graph, oqs.def);
+
+               if (checked == "on")
+                       checked = true;
+
+               cb.checked = !!+checked;
+               o.checkbox = cb;
+
+               // Label for checkbox.
+               l.htmlFor = cb.id;
+               l.innerHTML = o.label;
+               box.appendChild(l);
+
+               // Hidden input.  Makes sure we get this option again.
+               h.type = "hidden";
+               h.name = oqs.html;
+               h.value = 1;
+               box.appendChild(h);
+
+               if (typeof o.init === "function")
+                       o.init(cb);
+
+               // Make sure that unchecked boxes get sent on the query
+               // string if the default is checked.
+               // I didn't like doing this, but I need a way for default
+               // checked to stay unchecked.
+               if (oqs.def)
+               {
+
+                       // Make sure that the original onclick works.
+                       // NOTE: must use cb here because onclick may
+                       // reference "this".
+                       cb.onclick_real = cb.onclick;
+                       var hidden = document.createElement("input");
+
+                       hidden.type = "hidden";
+                       hidden.name = cb.name;
+                       hidden.value = 0;
+
+                       if (!cb.checked)
+                               box.appendChild(hidden);
+
+                       // When the box is clicked, add or remove the hidden
+                       // element created above
+                       cb.onclick = function ()
+                       {
+                               if (this.checked)
+                                       box.removeChild(hidden);
+                               else
+                                       box.appendChild(hidden);
+
+                               // If there was an onclick before, use it
+                               if (typeof cb.onclick_real === "function")
+                                       cb.onclick_real();
+                       };
+               }
+
+               count++;
+       }
+
+       // If any items were found, 
+       if (count)
+               row.style.display = "";
+}
+
+// Compiles options and returns an array of strings in the format of
+// "var=val" suitable for use in the CGI query string.
+function options_compile(opts)
+{
+       var ret = [];
+
+       for (var i = 0; i < opts.length; i++)
+       {
+               var o = opts[i];
+               var oqs = o.qs;
+               var val;
+
+               if (typeof o.checkbox === "undefined")
+                       continue;
+
+               val = o.checkbox.checked ? oqs.checked : oqs.unchecked;
+               if (typeof val === "string")
+                       ret.push(oqs.graph + "=" + val);
+       }
+
+       return ret;
+}
diff -ruN /root/munin/etc/munin/static/querystring.js ./querystring.js
--- /root/munin/etc/munin/static/querystring.js 2013-05-27 15:52:30.000000000 
-0400
+++ ./querystring.js    2013-06-08 23:08:14.126711000 -0400
@@ -26,8 +26,13 @@
                var value = (pair.length==2)
                        ? decodeURIComponent(pair[1])
                        : name;
-               
-               this.params[name] = value;
+
+               if (typeof this.params[name] == "undefined")
+                       this.params[name] = value;
+               else if (typeof this.params[name] == "string")
+                       this.params[name] = [this.params[name], value];
+               else
+                       this.params[name].push(value);
        }
 }
 

Reply via email to