#! /usr/bin/perl -w

# This is a Perl script that reads an Exim run-time configuration file and
# checks for settings that were valid prior to release 3.00 but which were
# obsoleted by that release. It writes a new file with suggested changes to
# the standard output, and commentary about what it has done to stderr.

# It is assumed that the input is a valid Exim configuration file.


##################################################
#             Analyse one line                   #
##################################################

# This is called for the main and the driver sections, not for retry
# or rewrite sections (which are unmodified).

sub checkline{
my($line) = $_[0];

return "comment" if $line =~ /^\s*(#|$)/;
return "end"     if $line =~ /^\s*end\s*$/;

# Macros are recognized only in the first section of the file.

return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/;

# Pick out the name at the start and the rest of the line (into global
# variables) and return whether the start of a driver or not.

($i1,$name,$i2,$rest) = $line =~ /^(\s*)([a-z0-9_]+)(\s*)(.*?)\s*$/;
return ($rest =~ /^:/)? "driver" : "option";
}




##################################################
#       Add transport setting to a director      #
##################################################

# This function adds a transport setting to an aliasfile or forwardfile
# director if a global setting exists and a local one does not. If neither
# exist, it adds file/pipe/reply, but not the directory ones.

sub add_transport{
my($option) = @_;

my($key) = "$prefix$driver.${option}_transport";
if (!exists $o{$key})
  {
  if (exists $o{"address_${option}_transport"})
    {
    print STDOUT "# >> Option added by convert4r3\n";
    printf STDOUT "${i1}${option}_transport = %s\n",
      $o{"address_${option}_transport"};
    printf STDERR
      "\n%03d ${option}_transport added to $driver director.\n",
      ++$count;
    }
  else
    {
    if ($option eq "pipe" || $option eq "file" || $option eq "reply")
      {
      print STDOUT "# >> Option added by convert4r3\n";
      printf STDOUT "${i1}${option}_transport = address_${option}\n";
      printf STDERR
        "\n%03d ${option}_transport added to $driver director.\n",
        ++$count;
      }
    }
  }
}




##################################################
#       Negate a list of things                  #
##################################################

sub negate {
my($list) = $_[0];

return $list if ! defined $list;

($list) = $list =~ /^"?(.*?)"?\s*$/s;

# Under Perl 5.005 we can split very nicely at colons, ignoring double
# colons, like this:
#
# @split = split /\s*(?<!:):(?!:)\s*(?:\\\s*)?/s, $list;
#
# However, we'd better make this work under Perl 5.004, since there is
# a lot of that about.

$list =~ s/::/>%%%%</g;
@split = split /\s*:\s*(?:\\\s*)?/s, $list;
foreach $item (@split)
  {
  $item =~ s/>%%%%</::/g;
  }

$" = " : \\\n    ! ";
return "! @split";
}





##################################################
#          Skip blank lines                      #
##################################################

# This function is called after we have generated no output for an option;
# it skips subsequent blank lines if the previous line was blank.

sub skipblanks {
my($i) = $_[0];
if ($last_was_blank)
  {
  $i++ while $c[$i+1] =~ /^\s*$/;
  }
return $i;
}





##################################################
#       Get base name of data key                #
##################################################

sub base {
return "$_[0]" if $_[0] !~ /^(?:d|r|t)\.[^.]+\.(.*)/;
return $1;
}



##################################################
#     Amalgamate accept/reject/reject_except     #
##################################################

# This function amalgamates the three previous kinds of
# option into a single list, using negation for the middle one if
# the final argument is "+", or for the outer two if the final
# argument is "-".

sub amalgamate {
my($accept,$reject,$reject_except,$name);
my($last_was_negated) = 0;
my($join) = "";

$accept = $o{$_[0]};
$reject = $o{$_[1]};
$reject_except = $o{$_[2]};
$name = $_[3];

if ($_[4] eq "+")
  {
  ($accept) = $accept =~ /^"?(.*?)"?\s*$/s if defined $accept;
  $reject = &negate($reject) if defined $reject;
  ($reject_except) = $reject_except =~ /^"?(.*?)"?\s*$/s if defined $reject_except;
  }
else
  {
  $accept = &negate($accept) if defined $accept;
  ($reject) = $reject =~ /^"?(.*?)"?\s*$/s if defined $reject;
  $reject_except = &negate($reject_except) if defined $reject_except;
  }

print STDOUT "# >> Option rewritten by convert4r3\n";
print STDOUT "${i1}$name = \"";

if (defined $reject_except)
  {
  print STDOUT "$reject_except";
  $join = " : \\\n    ";
  $last_was_negated = ($_[4] ne "+");
  }
if (defined $reject)
  {
  print STDOUT "$join$reject";
  $join = " : \\\n    ";
  $last_was_negated = ($_[4] eq "+");
  }
if (defined $accept)
  {
  print STDOUT "$join$accept";
  $last_was_negated = ($_[4] ne "+");
  $join = " : \\\n    ";
  }

print STDOUT "$join*" if $last_was_negated;

print STDOUT "\"\n";

my($driver_name);
my($driver_type) = "";

if ($_[0] =~ /^(d|r|t)\.([^.]+)\./ ||
    $_[1] =~ /^(d|r|t)\.([^.]+)\./ ||
    $_[2] =~ /^(d|r|t)\.([^.]+)\./)
  {
  $driver_type = ($1 eq 'd')? "director" : ($1 eq 'r')? "router" : "transport";
  $driver_name = $2;
  }

my($x) = ($driver_type ne "")? " in \"$driver_name\" $driver_type" : "";

my($l0) = &base($_[0]);
my($l1) = &base($_[1]);
my($l2) = &base($_[2]);


if ($l2 eq "")
  {
  if ($l0 eq "")
    {
    printf STDERR "\n%03d $l1 converted to $name$x.\n", ++$count;
    }
  else
    {
    printf STDERR "\n%03d $l0 and $l1\n    amalgamated into $name$x.\n",
      ++$count;
    }
  }
else
  {
  if ($l1 eq "")
    {
    printf STDERR "\n%03d $l0 and $l2\n    amalgamated into $name$x.\n",
      ++$count;
    }
  else
    {
    printf STDERR "\n%03d $l0, $l1 and $l2\n    amalgamated into " .
      "$name$x.\n", ++$count;
    }
  }
}




##################################################
#         Join two lists, if they exist          #
##################################################

sub pair{
my($l1) = $o{"$_[0]"};
my($l2) = $o{"$_[1]"};

return $l2 if (!defined $l1);
return $l1 if (!defined $l2);

($l1) = $l1 =~ /^"?(.*?)"?\s*$/s;
($l2) = $l2 =~ /^"?(.*?)"?\s*$/s;

return "$l1 : $l2";
}




##################################################
#  Amalgamate accept/reject/reject_except pairs  #
##################################################

# This is like amalgamate, but it combines pairs of arguments, and
# doesn't output commentary (easier to write a generic one for the few
# cases).

sub amalgamatepairs {
my($accept) = &pair($_[0], $_[1]);
my($reject) = &pair($_[2], $_[3]);
my($reject_except) = &pair($_[4], $_[5]);
my($last_was_negated) = 0;
my($join) = "";

if ($_[7] eq "+")
  {
  ($accept) = $accept =~ /^"?(.*?)"?\s*$/s if defined $accept;
  $reject = &negate($reject) if defined $reject;
  ($reject_except) = $reject_except =~ /^"?(.*?)"?\s*$/s if defined $reject_except;
  }
else
  {
  $accept = &negate($accept) if defined $accept;
  ($reject) = $reject =~ /^"?(.*?)"?$/s if defined $reject;
  $reject_except = &negate($reject_except) if defined $reject_except;
  }

print STDOUT "# >> Option rewritten by convert4r3\n";
print STDOUT "${i1}$_[6] = \"";

if (defined $reject_except)
  {
  print STDOUT "$reject_except";
  $join = " : \\\n    ";
  $last_was_negated = ($_[7] ne "+");
  }
if (defined $reject)
  {
  print STDOUT "$join$reject";
  $join = " : \\\n    ";
  $last_was_negated = ($_[7] eq "+");
  }
if (defined $accept)
  {
  print STDOUT "$join$accept";
  $last_was_negated = ($_[7] ne "+");
  $join = " : \\\n    ";
  }

print STDOUT "$join*" if $last_was_negated;
print STDOUT "\"\n";
}



##################################################
#      Amalgamate boolean and exception list(s)  #
##################################################

sub amalgboolandlist {
my($name,$bool,$e1,$e2) = @_;

print STDOUT "# >> Option rewritten by convert4r3\n";
if ($bool eq "false")
  {
  printf STDOUT "$i1$name =\n";
  }
else
  {
  printf STDOUT "$i1$name = ";
  my($n1) = &negate($o{$e1});
  my($n2) = &negate($o{$e2});
  if (!defined $n1 && !defined $n2)
    {
    print STDOUT "*\n";
    }
  elsif (!defined $n1)
    {
    print STDOUT "\"$n2 : \\\n    *\"\n";
    }
  elsif (!defined $n2)
    {
    print STDOUT "\"$n1 : \\\n    *\"\n";
    }
  else
    {
    print STDOUT "\"$n1 : \\\n    $n2 : \\\n    *\"\n";
    }
  }
}



##################################################
#             Convert mask format                #
##################################################

# This function converts an address and mask in old-fashioned dotted-quad
# format into an address plus a new format mask.

@byte_list = (0, 128, 192, 224, 240, 248, 252, 254, 255);

sub mask {
my($address,$mask) = @_;
my($length) = 0;
my($i, $j);

my(@bytes) = split /\./, $mask;

for ($i = 0; $i < 4; $i++)
  {
  for ($j = 0; $j <= 8; $j++)
    {
    if ($bytes[$i] == $byte_list[$j])
      {
      $length += $j;
      if ($j != 8)
        {
        for ($i++; $i < 4; $i++)
          {
          $j = 9 if ($bytes[$i] != 0);
          }
        }
      last;
      }
    }

  if ($j > 8)
    {
    print STDERR "*** IP mask $mask cannot be converted to /n format. ***\n";
    return "$address/$mask";
    }
  }

if (!defined $masks{$mask})
  {
  printf STDERR "\n%03d IP address mask $mask converted to /$length\n",
    ++$count, $mask, $length;
  $masks{$mask} = 1;
  }

return sprintf "$address/%d", $length;
}





##################################################
#                  Main program                  #
##################################################

print STDERR "Exim pre-release 3.00 configuration file converter.\n";

$count = 0;
$seen_helo_accept_junk = 0;
$seen_hold_domains = 0;
$seen_receiver_unqualified = 0;
$seen_receiver_verify_except = 0;
$seen_receiver_verify_senders = 0;
$seen_rfc1413_except = 0;
$seen_sender_accept = 0;
$seen_sender_accept_recipients = 0;
$seen_sender_host_accept = 0;
$seen_sender_host_accept_recipients = 0;
$seen_sender_host_accept_relay = 0;
$seen_sender_unqualified = 0;
$seen_sender_verify_except_hosts = 0;
$seen_smtp_etrn = 0;
$seen_smtp_expn = 0;
$seen_smtp_reserve = 0;
$semicomma = 0;

# Read the entire file into an array

chomp(@c = <STDIN>);

# First, go through the input and covert any net masks in the old dotted-quad
# style into the new /n style.

for ($i = 0; $i < scalar(@c); $i++)
  {
  $c[$i] =~
    s"((?:\d{1,3}\.){3}\d{1,3})/((?:\d{1,3}\.){3}\d{1,3})"&mask($1,$2)"eg;
  }

# We now make two more passes over the input. In the first pass, we place all
# the option values into an associative array. Main options are keyed by their
# names; options for drivers are keyed by a driver type letter, the driver
# name, and the option name, dot-separated. In the second pass we modify
# the options if necessary, and write the output file.

for ($pass = 1; $pass < 3; $pass++)
  {
  $prefix = "";
  $driver = "";
  $last_was_blank = 0;

  for ($i = 0; $i < scalar(@c); $i++)
    {
    # Everything after the router section is just copied in pass 2 and
    # ignored in pass 1.

    if ($prefix eq "end")
      {
      print STDOUT "$c[$i]\n" if $pass == 2;
      next;
      }

    # Analyze the line

    $type = &checkline($c[$i]);

    # Skip comments in pass 1; copy in pass 2

    if ($type eq "comment")
      {
      $last_was_blank = ($c[$i] =~ /^\s*$/)? 1 : 0;
      print STDOUT "$c[$i]\n" if $pass == 2;
      next;
      }

    # Skip/copy macro definitions, but must handle continuations

    if ($type eq "macro")
      {
      print STDOUT "$c[$i]\n" if $pass == 2;
      while ($c[$i] =~ /\\\s*$/)
        {
        $i++;
        print STDOUT "$c[$i]\n" if $pass == 2;
        }
      $last_was_blank = 0;
      next;
      }

    # Handle end of section

    if ($type eq "end")
      {
      $prefix = "end"if $prefix eq "r.";
      $prefix = "r." if $prefix eq "d.";
      $prefix = "d." if $prefix eq "t.";
      $prefix = "t." if $prefix eq "";
      print STDOUT "$c[$i]\n" if $pass == 2;
      $last_was_blank = 0;
      next;
      }

    # Handle start of a new driver

    if ($type eq "driver")
      {
      $driver = $name;
      print STDOUT "$c[$i]\n" if $pass == 2;
      $last_was_blank = 0;
      $seen_domains = 0;
      $seen_local_parts = 0;
      $seen_senders = 0;
      $seen_mx_domains = 0;
      $seen_serialize = 0;
      next;
      }

    # Handle definition of an option

    if ($type eq "option")
      {
      # Handle continued strings

      if ($rest =~ /^=\s*".*\\$/)
        {
        for (;;)
          {
          $rest .= "\n$c[++$i]";
          last unless $c[$i] =~ /(\\\s*$|^\s*#)/;
          }
        }

      # Remove any terminating commas and semicolons in pass 2

      if ($pass == 2 && $rest =~ /[;,]\s*$/)
        {
        $rest =~ s/\s*[;,]\s*$//;
        if (!$semicomma)
          {
          printf STDERR
            "\n%03d Terminating semicolons and commas removed from driver " .
            "options.\n", ++$count;
          $semicomma = 1;
          }
        }

      # Convert all booleans to "x = true/false" format, but save the
      # original so that it can be reproduced unchanged for options that
      # are not of interest.

      $origname = $name;
      $origrest = $rest;

      if ($name =~ /^not?_(.*)/)
        {
        $name = $1;
        $rest = "= false";
        }
      elsif ($rest !~ /^=/)
        {
        $rest = "= true";
        }

      # Set up the associative array key, and get rid of the = on the data

      $key = ($prefix eq "")? "$name" : "$prefix$driver.$name";
      ($rest) = $rest =~ /^=\s*(.*)/s;

      # Create the associative array of values in pass 1

      if ($pass == 1)
        {
        $o{$key} = $rest;
        }

      # In pass 2, test for interesting options and do the necessary; copy
      # all the rest.

      else
        {
        ##########  Global configuration ##########

        # These global options are abolished

        if ($name eq "address_directory_transport" ||
            $name eq "address_directory2_transport" ||
            $name eq "address_file_transport" ||
            $name eq "address_pipe_transport" ||
            $name eq "address_reply_transport")
          {
          ($n2) = $name =~ /^address_(.*)/;
          printf STDERR "\n%03d $name option deleted.\n", ++$count;
          printf STDERR "    $n2 will be added to appropriate directors.\n";
          $i = &skipblanks($i);
          next;
          }

        # This debugging option is abolished

        elsif ($name eq "sender_verify_log_details")
          {
          printf STDERR "\n%03d $name option deleted.\n", ++$count;
          printf STDERR "    (Little used facility abolished.)\n";
          }

        # This option has been renamed

        elsif ($name eq "check_dns_names")
          {
          $origname =~ s/check_dns/dns_check/;
          print STDOUT "# >> Option rewritten by convert4r3\n";
          print STDOUT "$i1$origname$i2$origrest\n";
          printf STDERR "\n%03d check_dns_names renamed as dns_check_names.\n",
            ++$count;
          }

        # helo_accept_junk_nets is abolished

        elsif ($name eq "helo_accept_junk_nets" ||
               $name eq "helo_accept_junk_hosts")
          {
          if (!$seen_helo_accept_junk)
            {
            &amalgamate("helo_accept_junk_nets", "",
              "helo_accept_junk_hosts", "helo_accept_junk_hosts", "+");
            $seen_helo_accept_junk = 1;
            }
          else
            {
            $i = &skipblanks($i);
            next;
            }
          }

        # helo_verify_except_{hosts,nets} are abolished, and helo_verify
        # is now a host list instead of a boolean.

        elsif ($name eq "helo_verify")
          {
          &amalgboolandlist("helo_verify", $rest, "helo_verify_except_hosts",
            "helo_verify_except_nets");
          printf STDERR "\n%03d helo_verify converted to host list.\n",
            ++$count;
          }
        elsif ($name eq "helo_verify_except_hosts" ||
               $name eq "helo_verify_except_nets")
          {
          $i = &skipblanks($i);
          next;
          }

        # helo_verify_nets was an old synonym for host_lookup_nets; only
        # one of them will be encountered. Change to a new name.

        elsif ($name eq "helo_verify_nets" ||
               $name eq "host_lookup_nets")
          {
          print STDOUT "# >> Option rewritten by convert4r3\n";
          print STDOUT "${i1}host_lookup$i2$origrest\n";
          printf STDERR "\n%03d $name renamed as host_lookup.\n", ++$count;
          }

        # hold_domains_except is abolished; add as negated items to
        # hold_domains.

        elsif ($name eq "hold_domains_except" ||
               $name eq "hold_domains")
          {
          if ($seen_hold_domains)         # If already done with these
            {                             # omit, and following blanks.
            $i = &skipblanks($i);
            next;
            }
          $seen_hold_domains = 1;

          if (exists $o{"hold_domains_except"})
            {
            &amalgamate("hold_domains", "hold_domains_except", "",
              "hold_domains", "+");
            }
          else
            {
            print STDOUT "$i1$origname$i2$origrest\n";
            }
          }

        # ignore_fromline_nets is renamed as ignore_fromline_hosts

        elsif ($name eq "ignore_fromline_nets")
          {
          $origname =~ s/_nets/_hosts/;
          print STDOUT "# >> Option rewritten by convert4r3\n";
          print STDOUT "$i1$origname$i2$origrest\n";
          printf STDERR
            "\n%03d ignore_fromline_nets renamed as ignore_fromline_hosts.\n",
            ++$count;
          }

        # Output a warning for message filters with no transports set

        elsif ($name eq "message_filter")
          {
          print STDOUT "$i1$origname$i2$origrest\n";

          if (!exists $o{"message_filter_directory_transport"} &&
              !exists $o{"message_filter_directory2_transport"} &&
              !exists $o{"message_filter_file_transport"} &&
              !exists $o{"message_filter_pipe_transport"} &&
              !exists $o{"message_filter_reply_transport"})
            {
            printf STDERR
              "\n%03d message_filter is set, but no message_filter transports "
              . "are defined.\n"
              . "    If your filter generates file or pipe deliveries, or "
              . "auto-replies,\n"
              . "    you will need to define "
              . "message_filter_{file,pipe,reply}_transport\n"
              . "    options, as required.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\n", ++$count;
            }
          }

        # queue_remote.\