// -----------------------------------------------------------------------------
// Version.

var zPoll_version = 1;

// Locs.

var zPoll_test_f = false;
if ( zPoll_test_f ) {
   zPoll_server_loc  = "http://rosexp/zPoll";
   zPoll_php_extension = "php";
} else {
   zPoll_server_loc  = "http://zfacts.com/metaPage/progZPoll";
   zPoll_php_extension = "php5";
}

// Debug routine.  Can set debug booleans true in calling page.

if ( window.zPoll_debug1_b == undefined ) {
   var zPoll_debug1_b = false;
}
if ( window.debug2_b == undefined ) {
   var debug2_b = false;
}

function zPoll_debug( label, item ) {
   if ( zPoll_debug1_b ) {
      document.forms.debugform.debug.value += label + ": " + item + "X\n";
   }
}


// For multiple polls on a page.  Also, only run javascript once.

if ( ! window.zPollA ) {
   var zPollA = [];

   var zPoll_head = document.getElementsByTagName( "head" )[0];

   var zPoll_styleSheet;

   new zPoll();
}

// =============================================================================
// zPoll 

function zPoll( zPollDivs ) {

   // Need this here for timing purposes -- if need to write a div, need to do
   // it before page is done loading.  But don't want to wait for all of script
   // to turn up (do that after we've written the div).

   this.getTagsByNameAndClass = function( node, tagNames, searchPat ) {
      var regex = new RegExp( searchPat );

      var classTags = [];
      for ( var i = 0; i<tagNames.length; i++ ) {
         var tags = node.getElementsByTagName( tagNames[i] );
         for ( var j=0; j<tags.length; j++ ) {
            if ( regex.test( tags[j].className ) ) {
               classTags.push( tags[j] );
            }
         }
      }

      return classTags;
   }

   // Sample code for overriding defaults with page javascript.

   if ( window.url_of_file_to_load != undefined ) {
      this.url_of_file_to_load = url_of_file_to_load;
   }

   // Associate initial zPoll object with first appropriate div.  Then look for
   // other divs of class zPoll, and create new zPoll objects to associate
   // Add needed divs.  First get div.

   if ( ! zPollDivs ) {

      // First pass.

      var zPollDivs = this.getTagsByNameAndClass( document, ["div"], 
                                                  "^zPoll(\\s|$)" );
      if ( ! zPollDivs || zPollDivs.length == 0 ) {

         // No div present.  Write one.  Set flag that have done so.

         document.write( '<div class="zPoll"></div>' );
         var zPollDivs = this.getTagsByNameAndClass( document, ["div"], 
                                                     "^zPoll(\\s|$)" );
         if ( zPoll_debug1_b ) {
            zPoll_debug( "zPollDivs[0]", zPollDivs[0] );
         }
      }
   }

   // Set div of this object,  See if any more divs.

   this.zPollDiv = zPollDivs[0];
   zPollDivs.shift();
   if ( zPollDivs.length ) {
      if ( zPoll_debug1_b ) {
         zPoll_debug( "starting new zPoll", zPollDivs.length );
      }
      new zPoll( zPollDivs );
   }

   iZPoll = zPollA.length;
   this.iZPoll = iZPoll;
   zPollA.push( this );

   // Now need to make sure all of script is available.

   if ( window.zPollDummyLast ) {
      this.initZPoll();
   } else {
      if ( zPoll_debug1_b ) {
         zPoll_debug( "waiting...", "" );
      }
      setTimeout ( 'zPollA['+iZPoll+'].initZPoll()', 100 );
   }
}


zPoll.prototype.is_pct_truncated = function() {

   // Detect whether browser (e.g., Safari 2.0.4) truncates CSS percent measures
   // to integer.  First create a 300-pixel wide div.
   
   var div300 = document.createElement( "div" );
   document.body.appendChild( div300 );
   div300.style.visibility = "hidden";
   div300.style.width      = "300px";

   // Now create child with % width.

   divChild = document.createElement( "div" );
   div300.appendChild( divChild );
   divChild.style.visibility = "hidden";
   divChild.style.width      = "99.9%";

   // Now measure child's width in pixels.  It's truncated if it's less than
   // 299.

   var childWidthPx = divChild.offsetWidth;
   var is_truncated_f = childWidthPx < 299;

   // Clean up - delete these divs.

   document.body.removeChild( div300 );

   if ( zPoll_debug1_b ) {
      zPoll_debug( "is_truncated_f", is_truncated_f );
   }
   return is_truncated_f;
}


zPoll.prototype.initZPoll = function( redisplay_f ) {

   // Initialization.  Based on site/ID, get settings from database.
   // Called from: zPoll()
   //              createUpdateZPoll.php (when new poll created: redisplay_f is
   //                                     set)

   if ( ! redisplay_f ) {

      // Set flag to provide options - graph, etc.

      this.options_f = true;

      // One-time initializations.

      if ( this.iZPoll == 0 ) {

         // Provide version for sake of createEditZPoll.php.

         this.version = zPoll_version;

         // Identify Macs.

         //var agt = navigator.userAgent.toLowerCase();
         //this.is_mac = agt.indexOf( "mac" ) != -1;

         // Preliminaries: test whether fractional % measure truncated (Safari
         // truncates to integer percentages -- e.g., 1.8% --> 1%).

         //this.pct_truncated_f = this.is_pct_truncated();

         // If styleSheet already there, use it.

         zPoll_styleSheet = this.getStylesheet( "zPoll" );
         if ( ! zPoll_styleSheet ) {
            var styleNode = document.createElement("style");

            styleNode.type  = "text/css";
            styleNode.rel   = "stylesheet";
            styleNode.media = "screen";
            styleNode.title = "zPoll";

            // Must be in head for Safari.

            zPoll_head.appendChild( styleNode );

            // Find our stylesheet.

            zPoll_styleSheet = this.getStylesheet( "zPoll" );
         }
         zPoll_styleSheet.disabled = false;

         // Write default styles.

         this.initStyle();
      } else {
         //this.is_mac          = zPollA[0].is_mac;
         //this.pct_truncated_f = zPollA[0].pct_truncated_f;
      }

      // Required links and link words correspond to zPoll version (formerly,
      // serial no.).  Version hard-coded at top.  Retrieve here.
      // Query database -- will return to initZPoll2() with required link and
      // link words.

      var data = zPoll_version;
      this.srcData( "linkData", data, this.iZPoll );
   } else {
      this.initZPoll3();
   }
}


zPoll.prototype.initZPoll2 = function() {

   // Callback from src_data_linkData.php.  Sets acceptable links, and required
   // link words.  Validate -- check that link and words are in HTML.

   var ok_f = this.validateLink();
   if ( ! ok_f ) {
      return;
   }
   this.initZPoll3();
}


zPoll.prototype.initZPoll3 = function() {

   // Identify poll.  If no zPoll_id, then based on host, path, and myPoll_id.

   this.external_full_poll_id = this.zPollDiv.getAttribute( "zPoll_id" );
   if ( zPoll_debug1_b ) {
      zPoll_debug( "this.external_full_poll_id", this.external_full_poll_id );
   }
   if ( ! this.external_full_poll_id ) {
      if ( window.zPoll_id != undefined ) {
         this.external_full_poll_id = window.zPoll_id;
      }
   }
   if ( ! this.external_full_poll_id ) {

      // Not given.  Will retrieve existing poll for this host, path, and 
      // myPoll_id, or will provide option to create new poll.

      var data = "none" + "&q_and_a_f=1";

      var myPoll_id = this.zPollDiv.getAttribute( "myPoll_id" );
      if ( zPoll_debug1_b ) {
         zPoll_debug( "myPoll_id", myPoll_id );
      }
      if ( myPoll_id ) {
         this.enc_myPoll_id = encodeURIComponent( myPoll_id );
         data += "&myPoll_id=" + this.enc_myPoll_id;
      } else {
         this.enc_myPoll_id = "";
      }

   } else {

      // Get specific poll data: question, answer choices, current vote totals.
      // Also, src_data_pollData script will get browser cookie of any previous 
      // vote for this poll, if set.  Callback is displayPoll().

      var data = this.external_full_poll_id + "&q_and_a_f=1";
   }

   // While we're at it, record that this poll was loaded, and by who (same
   // as vote, but for every page load).

   this.enc_host = encodeURIComponent( window.location.hostname );
   this.enc_path = encodeURIComponent( window.location.pathname );
   data += "&host=" + this.enc_host + "&path=" + this.enc_path;
   this.srcData( "pollData", data, this.iZPoll );
}


zPoll.prototype.displayPoll = function() {

   // Callback from src_data_pollData.php.  Sets question, alternative array,
   // vote_total array, and vote_choice (previous vote, if any; zero if not).
   // (vote_choice gleaned from cookie).  Also sets poll style and default
   // width.

   var iZ = this.iZPoll;
   var eID = this.external_full_poll_id;

   var zPollDiv = this.zPollDiv;
   var dflt_classname = "zPoll-iZ"+iZ;
   if ( zPollDiv.className.indexOf( dflt_classname ) == -1 ) {
      zPollDiv.className = dflt_classname + " zPoll-" + eID + " " 
                                                           + zPollDiv.className;
   }

   // In case redisplaying (createEditZPoll page).

   this.qheight_f = false;
   if ( this.tryitTimeout ) {
      clearTimeout( this.tryitTimeout );
   }

   // Local alternatives and votes list -- may be different order, may leave
   // some out.  Also, set up correspondence back to database index.

   this.alternative          = [];
   this.vote_total           = [];
   this.DbAlt_correspondence = [];
   for ( var iDb=0; iDb<this.DbAlternative.length; iDb++ ) {
      var i = this.alt_correspondence[iDb];
      if ( i >= 0 ) {
         this.alternative[i]          = this.DbAlternative[iDb];
         this.vote_total[i]           = this.DbVote_total[iDb];
         this.DbAlt_correspondence[i] = iDb;
      }
   }

   // Record previous vote.

   if ( this.DbVote_choice ) {
      this.DbPrev_choice_id = this.DbVote_choice;
      var iDb = this.DbVote_choice-1;
      var i = parseInt( this.alt_correspondence[iDb] );
      if ( i >= 0 ) {
         this.vote_choice = i + 1;
      }
      this.radioSelected = true;
   } else {
      this.vote_choice = 0;
   }

   // Calculate total.

   this.total_votes = 0;
   for ( var i=0; i<this.alternative.length; i++ ) {
      this.total_votes += parseInt( this.vote_total[i] );
   }


   // See if attributes or variables set for size, font, or background colors.
   // Attributes override variables.

   // Size.

   var zPoll_size = zPollDiv.getAttribute( "zPoll_size" );
   if ( ! zPoll_size ) {
      if ( window.zPoll_size != undefined ) {
         zPoll_size = window.zPoll_size;
      }
   }
   if ( zPoll_debug1_b ) {
      zPoll_debug( eID + ": zPoll_size", zPoll_size );
   }
   switch ( parseInt( zPoll_size ) ) {
      case 1:
         var widthMult = 0.8;
         var fontMult  = 0.8;
         break;
      case 3:
         var widthMult = 1.3;
         var fontMult  = 1.3;
         break;
      default:
         var widthMult = 1.0;
         var fontMult  = 1.0;
         break;
   }

   // Add css rule for default classname for this poll.

   dflt_classname = "." + dflt_classname;
   var style_zPoll = this.getCSSRule( dflt_classname );
   if ( ! style_zPoll ) {
      style_zPoll = this.addCSSRule( zPoll_styleSheet, dflt_classname );
   }
   style_zPoll.style.position   = "relative";
   var width = this.defaultWidth * widthMult;
   style_zPoll.style.width      = width + "px";
   var fontsize = 12 * fontMult;
   style_zPoll.style.fontSize   = fontsize + "px";
   style_zPoll.style.fontFamily = "arial, verdana, sans-serif";

   // Set style info from database.  Don't overwrite style/property given on 
   // current page, however.

   for( var i=0; i<this.poll_style.length; i++ ) {
      var classname = this.poll_style[i]["classname"];
      var property  = this.poll_style[i]["property"];
      var value     = this.poll_style[i]["value"];

      // Handle zPoll_size change to fontSize.

      if ( property == "fontSize" ) {
         if ( fontMult != 1.0 ) {

            // Take off "pt", multiply and add back.

            var num = value.slice( 0, -2 );
            num = parseInt( num );
            value = Math.round( num*fontMult ) + "pt";
         }
      }
      this.setCSSRule( classname, property, value, true );
   }

   // Question row.

   var qColor = "";
   var color = zPollDiv.getAttribute( "qfontcolor" );
   if ( color ) {
      qColor = "color: " + color + ";";
   } else if ( window.qfontcolor != undefined ) {
      qColor = "color: " + window.qfontcolor + ";";
   }
   var qBackgroundColor = "";
   var backgroundColor = zPollDiv.getAttribute( "qbgcolor" );
   if ( backgroundColor ) {
      qBackgroundColor = "background-color: " + backgroundColor + "; ";
   } else if ( window.qbgcolor != undefined ) {
      qBackgroundColor = "background-color: " + window.qbgcolor + "; ";
   }
   if ( qColor || qBackgroundColor ) {
      var qStyle = 'style="' + qColor + qBackgroundColor + '" ';
   } else {
      var qStyle = '';
   }

   // For alternatives rows.

   var aColor = "";
   var color = zPollDiv.getAttribute( "afontcolor" );
   if ( color ) {
      aColor = "color: " + color + ";";
   } else if ( window.afontcolor != undefined ) {
      aColor = "color: " + window.afontcolor + ";";
   }
   var aBackgroundColor = "";
   var backgroundColor = zPollDiv.getAttribute( "abgcolor" );
   if ( backgroundColor ) {
      aBackgroundColor = "background-color: " + backgroundColor + "; ";
   } else if ( window.abgcolor != undefined ) {
      aBackgroundColor = "background-color: " + window.abgcolor + "; ";
   }
   if ( aColor || aBackgroundColor ) {
      var aStyle = 'style="' + aColor + aBackgroundColor + '" ';
   } else {
      var aStyle = "";
   }

   // If options, set up panel for those.

   if ( this.options_f ) {
      var optionsDiv = document.createElement( "div" );
      this.optionsDiv = optionsDiv;
      setTimeout( 'zPollA['+iZ+'].zPollDiv.'
                                   + 'appendChild( zPollA['+iZ+'].optionsDiv )',
                  100 );
      optionsDiv.className = 'zPoll-options-dflt zPoll-options';
      var iHTML = '<a href="javascript:zPollA['+iZ+'].graphByDate(\'vote\')">'
                 +   'Votes by date</a>'
                 +   '<br />'
                 +'<a href="javascript:zPollA['+iZ+'].graphByDate(\'pct\')">'
                 +   'Vote percentages by date</a>'
                 +   '<br />'
                 +'<a href="javascript:zPollA['+iZ+'].graphClose()">'
                 +   'Close graph</a>';
      optionsDiv.innerHTML = iHTML;

      // Functions to hide panel when mouseout, but keep if accompanied by
      // mouseover (as when hover on anchor).

      var zP = this;
      optionsDiv.onmouseout = function() {
         zP.optionsDelayHide();
      }

      optionsDiv.onmouseover = function() {
         zP.optionsShow();
      }
   }

   // Create table/poll -- varies with option.

   if ( this.pollDesign != "user" ) {

      // Transfer styles given with zPoll div to table -- except for border,
      // position, float, width.  Set width to 100%.

      var zPoll_style = this.zPollDiv.getAttribute( "style" );
      if ( ! zPoll_style ) {
         zPoll_style = "";
      } else {
         if ( typeof( zPoll_style ) != "string" ) {

            // IE.

            zPoll_style = zPoll_style.cssText;
         }
         if ( zPoll_debug1_b ) {
            zPoll_debug( "zPoll_style", zPoll_style );
         }
         zPoll_style = zPoll_style.replace( /border[^:]*:[^;]+;/gi, "" );
         zPoll_style = zPoll_style.replace( /position\s*:[^;]+;/gi, "" );
         zPoll_style = zPoll_style.replace( /float\s*:[^;]+;/gi, "" );
         zPoll_style = zPoll_style.replace( /(^|\s)width\s*:[^;]+;/gi, "" );
         if ( zPoll_debug1_b ) {
            zPoll_debug( "zPoll_style", zPoll_style );
         }
      }
      zPoll_style += ' width: 100%; border: 0px';
      zPoll_style = 'style="' + zPoll_style + '"';

      if ( this.pollDesign == "alts-down-text" ) {
         var colspan = 3;
      } else {
         var colspan = this.alternative.length * 2;
      }

      // Poll is in this table.

      var table 
             = '<table class="zPoll-'+eID+'-dflt zPoll" border="0" '
               +      'cellspacing="0" cellpadding="0" '+zPoll_style+'>\n'
               +       '<td colspan="'+colspan+'">';

      // Nested table for question plus vote button.

      table +=            '<table class="zPoll-iZ'+iZ+' '
               +                        'zPoll" '
               +                 'border="0" cellspacing="0" cellpadding="0" '
               +                 zPoll_style+'>\n'
               +             '<tr>'
               +                '<td ' + qStyle
               +                    'class="zPoll-question0 '
               +                           'zPoll-question-dflt '
               +                           'zPoll-question '
               +                           'zPoll-question-iZ'+iZ+' '
               +                           'zPoll-question-'+eID+'">\n'
               +                '</td>';

      // Vote button -- turn off if "display: none" given.  Look for more-
      // specific rule first.

      this.voteButton_f = true;

      var zPoll_voteButton = this.getCSSRule(".zPoll-voteButton-"+eID);
      if ( ! zPoll_voteButton ) {
         zPoll_voteButton = this.getCSSRule(".zPoll-voteButton");
      }

      if ( ! zPoll_voteButton ) {

         // This is the rule (actually, one of three created, for each of "div",
         // "span", and "td") from the database, except it won't even be created
         // if .zPoll-voteButton-abcd12 is given.

         var sp_classname = "div.zPoll-voteButton-"+eID;
         var zPoll_voteButton = this.getCSSRule( sp_classname );
      }
      if ( zPoll_voteButton ) {
         if ( zPoll_voteButton.style.display == "none" ) {
            this.voteButton_f = false;
            if ( zPoll_debug1_b ) {
               zPoll_debug( "this.voteButton_f", this.voteButton_f );
            }
         }
      }

      var onclick = 'zPollA['+iZ+'].voteButtonClick()';
      table +=                  '<td align="right" valign="center" '
              +                      qStyle
              +                     'class="zPoll-question-dflt '
              +                            'zPoll-question '
              +                            'zPoll-question-iZ'+iZ+' '
              +                            'zPoll-question-'+eID+'">\n'
              +                    '<div class="zPoll-thankyou-dflt '
              +                                'zPoll-thankyou '
              +                                'zPoll-thankyou-'+eID+'">'
              +                    'Thanks!'
              +                    '</div>'
              +                    '<span class="zPoll-voteButton-dflt ' 
              +                                 'zPoll-voteButton '
              +                                 'zPoll-voteButton-'+eID+'">'
              +                       '<input class="zPoll-voteButton-dflt ' 
              +                                     'zPoll-voteButton '
              +                                     'zPoll-voteButton-'+eID+'" '
              +                              'type="button" '
              +                              'onclick="'+onclick+'" '
              +                              'value="Vote" />'
              +                    '</span>'
              +                 '</td>\n';
      table +=               '</tr>\n'
              +           '</table>\n';

      // End of single-cell row for nested table.

      table +=         '</td>\n'
              +     '</tr>\n';
   }

   // Alternatives across or down.

   var radioName = 'zPoll-altRadio-' + iZ;
   if ( this.pollDesign == "alts-down-text" ) {
      for ( var i=0; i<this.alternative.length; i++ ) {

         // Row for each alternative.

         table +=   '<tr>\n';

         // Radio button.

         var onclick  = 'zPollA['+iZ+'].updateVote(this.value)';
         if ( this.vote_choice == i+1 ) {
            var checked = 'checked';
         } else {
            var checked = '';
         }
         table +=      '<td class="zPoll-alts-dflt zPoll-alts '
                 +                'zPoll-alts-iZ'+iZ+' '
                 +                'zPoll-alts-'+eID+'" '
                 +          aStyle
                 +         'width="15" valign="top">\n'
                 +        '<input type="radio" '
                 +               'name="'+radioName+'" '
                 +               'class="zPoll-radio-down-dflt '
                 +                      'zPoll-radio '
                 +                      'zPoll-radio-'+eID+'" '
                 +               'onclick="'+onclick+'" '
                 +               'value="'+i+'" '
                 +               checked+' />\n'
                 +     '</td>\n';

         // Choice/alternative (answer).  Need the first class (distinguished by
         // choice i) for user-defined HTML.

         table +=      '<td class="zPoll-alts-dflt zPoll-alts '
                 +                'zPoll-alts-iZ'+iZ+' '
                 +                'zPoll-alts-'+eID+'" '
                 +          aStyle + '>\n'
                 +        '<div class="zPoll-alt-'+i+' zPoll-alt '
                 +                    'zPoll-alt-'+eID+' '
                 +                    'zPoll-color-'+iZ+'-'+i+'">'
                 +            this.alternative[i]
                 +        '</div>\n';
                 +     '</td>';

         // Results (vote).

         table +=      '<td class="zPoll-alts-dflt zPoll-alts '
                 +                'zPoll-alts-iZ'+iZ+' '
                 +                'zPoll-alts-'+eID+'" '
                 +          aStyle
                 +         'align="right" valign="top">\n'
                 +        '<div class="zPoll-vote-down-dflt '
                 +                    'zPoll-vote '
                 +                    'zPoll-vote-'+eID+'">\n'
                 +           '<span class="zPoll-votePercent-down-dflt '
                 +                        'zPoll-votePercent '
                 +                        'zPoll-votePercent-'+eID+'">'
                 +              '(<span class="zPoll-votePercent-'+i+'">'
                 +                  this.votePercent( this.vote_total[i] )
                 +              '</span>%)&nbsp;&nbsp;'
                 +           '</span>'
                 +           '<span class="zPoll-voteTotal-'+i+' '
                 +                        'zPoll-voteTotal '
                 +                        'zPoll-voteTotal-'+eID+'">'
                 +               this.vote_total[i]
                 +           '</span>'
                 +        '</div>\n';
                 +     '</td>';

         // End row.

         table +=   '</tr>\n';
      }
   } else if ( this.pollDesign == "alts-across-text" ) {

      // Two rows with cells for each alternative.  First row: radio button
      // and text.  Second row: vote and percent.

      table +=      '<tr>\n';
      for ( var i=0; i<this.alternative.length; i++ ) {

         // Radio button.

         var onclick  = 'zPollA['+iZ+'].updateVote(this.value)';
         if ( this.vote_choice == i+1 ) {
            var checked = 'checked';
         } else {
            var checked = '';
         }
         table +=      '<td class="zPoll-alts-dflt zPoll-alts '
                 +                'zPoll-alts-iZ'+iZ+' '
                 +                'zPoll-alts-'+eID+'" '
                 +          aStyle
                 +         'valign="top">\n'
                 +        '<input type="radio" name="'+radioName+'" '
                 +               'class="zPoll-radio zPoll-radio-'+eID+'" '
                 +               'onclick="'+onclick+'" '
                 +               'value="'+i+'" '
                 +               checked+' />\n'
                 +     '</td>\n';

         // Choice/alternative (answer).

         table +=      '<td class="zPoll-alts-dflt zPoll-alts '
                 +                'zPoll-alts-iZ'+iZ+' '
                 +                'zPoll-alts-'+eID+'" '
                 +          aStyle
                 +         'valign="top">\n'
                 +        '<span class="zPoll-alt-'+i+' '
                 +                     'zPoll-alt-across-dflt '
                 +                     'zPoll-alt '
                 +                     'zPoll-alt-'+eID+' '
                 +                     'zPoll-color-'+iZ+'-'+i+'">'
                 +            this.alternative[i]
                 +        '</span>\n'
                 +     '</td>\n';
      }
      table +=      '</tr>\n';

      // Second row.

      table +=      '<tr>\n';
      for ( var i=0; i<this.alternative.length; i++ ) {

         // Results (vote).

         table +=      '<td class="zPoll-alts-dflt zPoll-alts '
                 +                'zPoll-alts-iZ'+iZ+' '
                 +                'zPoll-alts-'+eID+'" '
                 +          aStyle
                 +         'colspan="2" align="center" valign="top">\n'
                 +        '<div class="zPoll-vote '
                 +                    'zPoll-vote-'+eID+'">\n'
                 +           '<nobr>'
                 +           '<span class="zPoll-voteTotal-'+i+' '
                 +                        'zPoll-voteTotal '
                 +                        'zPoll-voteTotal-'+eID+'">'
                 +               this.vote_total[i]
                 +           '</span>'
                 +           '&nbsp;|&nbsp;'
                 +           '<span class="zPoll-votePercent '
                 +                        'zPoll-votePercent-'+eID+'">'
                 +              '<span class="zPoll-votePercent-'+i+'">'
                 +                  this.votePercent( this.vote_total[i] )
                 +              '</span>%'
                 +           '</span>'
                 +           '</nobr>'
                 +        '</div>\n'
                 +     '</td>\n';
      }
      table +=      '</tr>\n';
   }

   // Extra, invisible radio buttion, so can unset vote if we want.

   this.extra_radioID = 'extra_zPoll-altRadio-' + iZ;
   table += '<input type="radio" name="'+radioName+'" '
           +       'style="display: none;" '
           +       'id="'+this.extra_radioID+'" />\n';

   // If graph options, one more row for graph.

   if ( this.options_f ) {
      if ( this.pollDesign == "alts-down-text" ) {
         var colspan = 3;
      } else {
         var colspan = this.alternative.length * 2;
      }
      table +=      '<tr>\n'
              +        '<td colspan="'+colspan+'">'
              +           '<div class="zPoll-graph-dflt zPoll-graph">'
              +           '</div>'
              +        '</td>'
              +     '</tr>\n';
   }
   if ( this.pollDesign != "user" ) {
      table +=      '</table>\n';

      // Load table into div.

      zPollDiv.innerHTML = table;
   }

   // Find question div, fill if there.

   var questionSearch = '^zPoll-question0';
   var nodeList = this.getTagsByNameAndClass( zPollDiv, ["td", "div", "span"], 
                                              questionSearch ); 
   this.questionDiv = nodeList[0];
   if ( this.questionDiv ) {
      var qHTML = '<span class="zPoll-optionsLink-dflt zPoll-optionsLink">';
      if ( this.options_f ) {
         qHTML += '<a href="javascript:zPollA['+iZ+'].optionsShow()" '
                +    'title="Show graph of votes over time">'
                +    'Graphs</a>&nbsp ';
         var URL = 'http://zfacts.com/p/1024.html';
         qHTML += '<a href="'+URL+'" target="_blank" '
                +    'title="About this poll widget">'
                +    'Info</a>';
      }

      // Show admin link on createEditZPoll and createUpdateZPoll pages, but
      // disabled.

      var editPage_f =    this.enc_path.indexOf('createEditZPoll') != -1
                       || this.enc_path.indexOf('createUpdateZPoll') != -1;
      if ( this.administrator_f || editPage_f ) {
         if ( editPage_f ) {
            qHTML += '&nbsp; '
                     + '<span style="color: blue; text-decoration: underline;">'
                     +    'Admin</span>';
         } else {
            var URL = zPoll_server_loc 
                                    + '/createEditZPoll.' + zPoll_php_extension
                                    + '?version='  + zPoll_version
                                    + '&zPoll_id=' + this.external_full_poll_id
                                    + '&poll_id='  + this.internal_full_poll_id
                                    + '&iZPoll='   + this.iZPoll;
            qHTML += '&nbsp; '
                     + '<a href="'+URL+'" target="_blank" ' 
                     +    'title="Edit your poll\'s text, colors, etc.">'
                     +    'Admin</a>';
         }
      }
      qHTML += '</span>';
      this.questionDiv.innerHTML = qHTML + '<br />' + this.question;
   }

   // Also find vote button (not a div!) and thank-you div if there.

   var voteButtonSearch = '^zPoll-voteButton';
   nodeList = this.getTagsByNameAndClass( zPollDiv, ["span"],
                                          voteButtonSearch );
   this.voteButtonDiv = nodeList[0];
   if ( ! this.voteButtonDiv ) {
      this.voteButton_f = false;
   }

   var thankyouSearch = '^zPoll-thankyou';
   nodeList = this.getTagsByNameAndClass( zPollDiv, ["div", "span"], 
                                          thankyouSearch ); 
   this.thankyouDiv = nodeList[0];

   // Setup for "Try it!" message, whether or not there.
   // If there is a message, appears periodically.  First mouseover hides and
   // halts the periodic messages.

   tryitDiv = document.createElement( "div" );
   this.tryitDiv = tryitDiv;
   setTimeout('zPollA['+iZ+'].zPollDiv.appendChild(zPollA['+iZ+'].tryitDiv)',
               100 );
   tryitDiv.className = "zPoll-tryit-dflt zPoll-tryit zPoll-tryit-" + eID;
   tryitDiv.innerHTML = this.tryit_message;

   var zP = this;
   zPollDiv.onmouseover = function() {
      zP.tryitMouseover();
   }

   // Start period display if there's a message.

   if ( this.tryit_message ) {
      this.tryitTimeout = setTimeout( 'zPollA['+iZ+'].tryitShow()', 
                                      3000+iZ*1000 );
   }

   // Get graph div.

   if ( this.options_f ) {
      var graphSearch = '^zPoll-graph';
      var nodeList = this.getTagsByNameAndClass( zPollDiv, ["div"], 
                                                 graphSearch ); 
      this.graphDiv = nodeList[0];
   }

   // Apparently need to wait to finish writing to alternativesDiv.innerHTML
   // to get these div objects properly.

   this.alternativeDiv = [];
   this.voteTotalDiv   = [];
   this.votePercentDiv = [];
   for ( var i=0; i<this.alternative.length; i++ ) {
      var altSearch          = '^zPoll-alt-' + i + '(\\s|$)';
      var nodeList           = this.getTagsByNameAndClass( zPollDiv, 
                                                           ["div", "span"], 
                                                           altSearch ); 
      this.alternativeDiv[i] = nodeList[0];

      var voteTotalSearch    = '^zPoll-voteTotal-' + i + '(\\s|$)';
      nodeList               = this.getTagsByNameAndClass( zPollDiv, 
                                                           ["div", "span"], 
                                                           voteTotalSearch ); 
      this.voteTotalDiv[i]   = nodeList[0];

      var votePercentSearch  = '^zPoll-votePercent-' + i + '(\\s|$)';
      nodeList               = this.getTagsByNameAndClass( zPollDiv,
                                                           ["div", "span"], 
                                                           votePercentSearch ); 
      this.votePercentDiv[i] = nodeList[0];
   }


   if ( this.pollDesign == "user" ) {

      // User-designed poll.  Find radio buttons, set up function to call 
      // appropriate poll object when radio button clicked.  Use 
      // getElementsByTagName() so can be sure these are the radio buttons
      // for this zPoll instance (in case multiple polls on one page).

      var zP = this;
      var radios = zPollDiv.getElementsByTagName( "input" );
      for ( var i=0; i<radios.length; i++ ) {
         var radio = radios[i];
         var name = radio.getAttribute( "name" );
         if ( name == "zPoll-altRadio" ) {

            // Select this radio button if user has already voted and has right
            // value.

            var iAlt = radio.value;
            if ( iAlt == this.vote_choice-1 ) {
               radio.click();
            }

            // Set up function.

            radio.onclick = function() {
               var iAlt = this.value;
               if ( iAlt == "" || iAlt == "on" ) {
                  alert( "HTML error: value= not given for radio button" );
               } else {
                  zP.updateVote( iAlt );
               }
            }
         }
      }

      // Similarly, set up function for vote button.  (In user HTML, 
      // voteButtonDiv actually is the <input...> tag.

      if ( this.voteButtonDiv ) {
         this.voteButtonDiv.onclick = function() {
            zP.voteButtonClick();
         }
      }

      // Load vote totals and percents.

      this.updateDisplay();
   }

   // If user has voted, change to thank-you (same as having clicked button --
   // had to wait until here, since button also updates display), but only if
   // there is such a button.

   if ( this.vote_choice != 0 ) {
      if ( this.voteButton_f ) {
         this.voteButtonClick();
      }
   }
}


zPoll.prototype.newPollLink = function( vote_total ) {
   var URL = zPoll_server_loc 
                        + '/createEditZPoll.' + zPoll_php_extension
                        + '?version='   + zPoll_version
                        + '&zPoll_id='  + '-2'
                        + '&host='      + this.enc_host
                        + '&path='      + this.enc_path
                        + '&myPoll_id=' + this.enc_myPoll_id
                        + '&iZPoll='    + this.iZPoll;
   this.zPollDiv.innerHTML = '<div style="border: 1px solid black;'
                            +            'padding: 5px; width: 200px;'
                            +            'text-align: center;">'
                            +   '<a href="'+URL+'" target="_blank">'
                            +      'Create new zPoll</a>'
                            +'</div>';
}


zPoll.prototype.votePercent = function( vote_total ) {
   if ( this.total_votes > 0 ) {
      var vote_percent = vote_total/this.total_votes * 100;
   } else {
      var vote_percent = 0;
   }
   vote_percent = Math.round( vote_percent );

   return vote_percent;
}


zPoll.prototype.initStyle = function() {

   // Default styles.  Save each rule so can update from database.

   var styleSheet = zPoll_styleSheet;

   var zPoll_tryit = this.addCSSRule( styleSheet, ".zPoll-tryit-dflt" );
   zPoll_tryit.style.display            = "none";
   zPoll_tryit.style.position           = "absolute";
   zPoll_tryit.style.top                = "0px";
   zPoll_tryit.style.width              = "100%";
   zPoll_tryit.style.textAlign          = "center";
   zPoll_tryit.style.fontWeight         = "bold";
   zPoll_tryit.style.backgroundColor    = "white";

   var zPoll_options = this.addCSSRule( styleSheet, ".zPoll-options-dflt" );
   zPoll_options.style.position        = "absolute";
   zPoll_options.style.display         = "none";
   zPoll_options.style.top             = "0px";
   zPoll_options.style.backgroundColor = "white";
   zPoll_options.style.padding         = "8px";
   zPoll_options.style.lineHeight      = "16pt";
   zPoll_options.style.border          = "1px solid black";

   var zPoll_graph = this.addCSSRule( styleSheet, ".zPoll-graph-dflt" );
   //zPoll_graph.style.position          = "absolute";
   zPoll_graph.style.display           = "none";
   zPoll_graph.style.backgroundColor   = "white";
   zPoll_graph.style.paddingTop        = "5px";
   zPoll_graph.style.fontWeight        = "bold";
   zPoll_graph.style.fontSize          = "10pt";
   zPoll_graph.style.textAlign         = "center";

   var zPoll_graph_close = this.addCSSRule( styleSheet, 
                                            ".zPoll-graph-close-dflt" );
   zPoll_graph_close.style.cssFloat    = "right";
   zPoll_graph_close.style.styleFloat  = "right"; // IE

   var zPoll_optionsLink = this.addCSSRule( styleSheet, 
                                            ".zPoll-optionsLink-dflt" );
   zPoll_optionsLink.style.fontFamily  = "arial, verdana, sans-serif";
   zPoll_optionsLink.style.fontWeight  = "normal";
   zPoll_optionsLink.style.fontSize    = "9px";

   var zPoll_question = this.addCSSRule( styleSheet, ".zPoll-question-dflt" );
   zPoll_question.style.fontWeight      = "bold";
   zPoll_question.style.padding         = "2px";

   var zPoll_voteButton = this.addCSSRule( styleSheet, 
                                           ".zPoll-voteButton-dflt" );
   zPoll_voteButton.style.fontSize      = "9px";
   zPoll_voteButton.style.marginLeft    = ".5em";

   var zPoll_thankyou = this.addCSSRule( styleSheet, ".zPoll-thankyou-dflt" );
   zPoll_thankyou.style.display         = "none";
   zPoll_thankyou.style.fontWeight      = "normal";
   zPoll_thankyou.style.marginLeft      = ".5em";

   var zPoll_alts = this.addCSSRule( styleSheet, ".zPoll-alts-dflt" );
   zPoll_alts.style.padding             = "2px";

   // Rules which vary by poll design.

   // Down.

   var zPoll_votePercent = this.addCSSRule( styleSheet, 
                                            ".zPoll-votePercent-down-dflt" );
   zPoll_votePercent.style.fontSize  = "80%";

   // Across.

   var zPoll_alt = this.addCSSRule( styleSheet, ".zPoll-alt-across-dflt" );
   zPoll_alt.style.fontWeight        = "bold";
}


zPoll.prototype.srcData = function( page, send_data, alt_script_id ) {

   // Add script to this page -- retrieves data via src=.  Delete previous, if
   // there.

   var script_id = "srcData-" + this.iZPoll;
   if ( alt_script_id ) {
      script_id += "-" + alt_script_id ;
   }
   var script = document.getElementById( script_id );
   if ( script ) {
      if ( zPoll_head ) {
         zPoll_head.removeChild( script );
      } else {
         document.body.removeChild( script );
      }
   }
   var script = document.createElement( "script" );
   script.id = script_id;
   script.setAttribute("charset", "utf-8");

   // Always send which widget.

   send_data += "&iZPoll=" + this.iZPoll;

   // Add something unique each time, so IE will re-retrieve javascript!

   dNow = new Date();
   var msec = dNow.getTime();
   send_data += "&msec=" + msec;

   // Send user_id, if set.

   if ( this.user_id ) {
      send_data += "&user_id=" + this.user_id;
   }

   // Send sitepage_id, if set.

   //if ( this.sitepage_id ) {
   //   send_data += "&sitepage_id=" + this.sitepage_id;
   //}

   var server_page = zPoll_server_loc + "/src_data_" + page + '.' 
                     + zPoll_php_extension;
   script.src = server_page + "?data=" + send_data;

   // IE7 couldn't stand script appended to body in a complicated page.
   
   // PERHAPS CHANGE TO SOMETHING SPECIFIC TO THIS VIEWER INSTANCE.

   if ( zPoll_head ) {
      zPoll_head.appendChild( script );
   } else {
      document.body.appendChild( script );
   }

}


zPoll.prototype.voteButtonClick = function() {

   // Vote button clicked.  If user hadn't previously "voted," update display.
   // However, alert if never clicked a radio button.

   if ( ! this.voted ) {
      if ( ! this.radioSelected ) {
         alert( "Please make a selection first" );
         return;
      }
      this.updateDisplay();
   }

   // Record that user "voted."

   if ( zPoll_debug1_b ) {
      zPoll_debug( "[voteButtonClick] this.voteButtonDiv", this.voteButtonDiv );
   }
   this.voted = true;

   // Change to thank-you.

   if ( this.voteButton_f ) {
      this.voteButtonDiv.style.display = "none";
   }
   if ( this.thankyouDiv ) {
      this.thankyouDiv.style.display = "block";
   }

   // Reset ability to vote and thank-you and vote button after 
   // time_until_revote (plus a second or so for time_until_revote = 0).

   var iZ = this.iZPoll;
   var time_millisec = this.time_until_revote*1000 + 1500;
   setTimeout( 'zPollA['+iZ+'].resetVoted()', time_millisec );
}


zPoll.prototype.resetVoted = function() {

   // Reset signals that voted.

   this.DbPrev_choice_id = 0;
   this.voted = false;

   if ( this.thankyouDiv ) {
      this.thankyouDiv.style.display = "none";
   }
   if ( this.voteButton_f ) {
      this.voteButtonDiv.style.display = "block";
   }

   // Click the non-displayed radio button in order to "unclick" the others.

   var extra_radioButton = document.getElementById( this.extra_radioID );
   extra_radioButton.click();
   this.radioSelected = false;
}


zPoll.prototype.updateVote = function( iAlternative ) {

   // Vote -- either new or changed.  If changed from previous, need to
   // decrement earlier choice.  Don't allow if not yet in database.

   if ( this.external_full_poll_id == -1 ) {
      return;
   }

   // Translate back to database's index.

   var DbIAlternative = this.DbAlt_correspondence[iAlternative];
   var DbChoice_id = parseInt( DbIAlternative ) + 1;
   this.radioSelected = true;

   // If clicked on same as before (IE7 appears to mishandle onchange), nothing
   // to do.

   if ( DbChoice_id == this.DbPrev_choice_id ) {
      return;
   }

   var enc_jaz = encodeURIComponent( this.jaz );
   var data = this.internal_full_poll_id + "&jaz="       + enc_jaz
                                         + "&choice_id=" + DbChoice_id;

   // Update local record of totals, and send previous choice, if any, to
   // db.

   this.vote_total[iAlternative]++;
   if ( this.DbPrev_choice_id ) {
      data += "&prev_choice_id=" + this.DbPrev_choice_id;
      var DbIPrevAlternative = this.DbPrev_choice_id - 1;
      var iPrevAlternative = this.alt_correspondence[DbIPrevAlternative];
      if ( iPrevAlternative >= 0 ) {
         this.vote_total[iPrevAlternative]--;
      }
   } else {
      data += "&prev_choice_id=0";
      this.total_votes++;
   }

   // Update display -- but don't do if there's a vote button and user hasn't
   // voted.  If there is, and user has voted, change thank-you back to button.

   if ( this.voteButton_f ) {
      if ( this.voted ) {
         this.updateDisplay();
         if ( this.voteButtonDiv ) {
            this.voteButtonDiv.style.display = "block";
         }
         if ( this.thankyouDiv ) {
            this.thankyouDiv.style.display = "none";
         }
      }
   } else {
      this.updateDisplay();

      // Reset radio after revote period (plus a second or so for 
      // time_until_revote = 0).

      var iZ = this.iZPoll;
      var time_millisec = this.time_until_revote*1000 + 1500;
      setTimeout( 'zPollA['+iZ+'].resetVoted()', time_millisec );
   }

   // Update local (this object) record of previous vote.  Don't do so if
   // time_until_revote is zero.

   if ( this.time_until_revote != 0 ) {
      this.DbPrev_choice_id = DbChoice_id;
   }


   // Also send host and path.

   data += "&host=" + this.enc_host + "&path=" + this.enc_path;

   // Update database -- increments and decrements.  Five different script IDs,
   // in case clicks in rapid succession.

   this.srcData( "updateVote", data, this.total_votes%5+1 );
}


zPoll.prototype.updateDisplay = function() {
   for ( var i=0; i<this.vote_total.length; i++ ) {
      if ( this.voteTotalDiv[i] ) {
         this.voteTotalDiv[i].innerHTML   = this.vote_total[i];
      }
      if ( this.votePercentDiv[i] ) {
         this.votePercentDiv[i].innerHTML 
                                       = this.votePercent( this.vote_total[i] );
      }
   }
}


zPoll.prototype.tryitMouseover = function() {

   // On first mouseover of div, hide message, set flag to halt further message
   // rotation.

   if ( ! this.tryitRotationHalt_f ) {
      this.tryitRotationHalt_f = true;
      this.tryitDiv.style.display = "none";
   }
}


zPoll.prototype.tryitShow = function() {

   // Show message for a while, and set to show again after a longer while.

   if ( ! this.tryitRotationHalt_f ) {
      this.tryitDiv.style.display = "block";
      var iZ = this.iZPoll;

      if ( ! this.qheight_f ) {
         this.qheight_f = true;
         if ( this.questionDiv ) {

            // Find height of question <td>, set height of tryit overlay to
            // that.

            var qheight = this.questionDiv.offsetHeight;
            this.tryitDiv.style.height = qheight + "px";
         }
      }
      setTimeout( 'zPollA['+iZ+'].tryitHide()', 2000 );
      this.tryitTimeout = setTimeout( 'zPollA['+iZ+'].tryitShow()', 7000 );
   }
}


zPoll.prototype.tryitHide = function() {
   this.tryitDiv.style.display = "none";
}


zPoll.prototype.optionsShow = function() {
   if ( zPoll_debug1_b ) {
      zPoll_debug( "[optionsShow] this.optionsTimeout", this.optionsTimeout );
   }
   if ( this.optionsTimeout ) {
      clearTimeout( this.optionsTimeout );
   }
   this.optionsDiv.style.display = "block";
}


zPoll.prototype.optionsDelayHide = function() {
   if ( zPoll_debug1_b ) {
      zPoll_debug( "[optionsDelayHide] this.optionsTimeout", 
                   this.optionsTimeout );
   }
   var iZ = this.iZPoll;
   this.optionsTimeout = setTimeout( 'zPollA['+iZ+'].optionsHide()', 500 );
}


zPoll.prototype.optionsHide = function() {
   this.optionsDiv.style.display = "none";
}


zPoll.prototype.graphByDate = function( graphType ) {

   // Create graph image (gnuplot), also change colors of answers temporarily
   // to match graph.

   // First close menu.

   this.optionsHide();

   // Add specific color rule for each answer.

   this.graphColor = [ "#f03232", "#6699ff", "#f055f0", "#00ffff", "#ffa07a",
                       "#ffa500" ];
   var passColor = "";
   var iZ = this.iZPoll;
   var n_alts = this.alternative.length;
   for ( var i=0; i<n_alts; i++ ) {
      colorRule = this.addCSSRule( zPoll_styleSheet, ".zPoll-color-"+iZ+"-"+i );
      var color = this.graphColor[i%n_alts];
      colorRule.style.color = color;
      passColor += "&color[]=" + encodeURIComponent( color );
   }

   // Produce graph.  Callback is displayGraph().

   this.graphType = graphType;
   var pollWidth = this.zPollDiv.offsetWidth - 4;
   var data = this.internal_full_poll_id 
              + "&n_alts="        + n_alts
              + "&poll_width_px=" + pollWidth
              + "&graph_type="    + graphType
              + passColor;
   this.srcData( "graph", data );
}


zPoll.prototype.displayGraph = function( imgFilename ) {
   var graphDiv = this.graphDiv;
   var imgURL = zPoll_server_loc + '/tmp/' + imgFilename;
   var btnURL = zPoll_server_loc + '/btn_close_mini.gif';
   var onclick = 'onclick="zPollA['+this.iZPoll+'].graphClose()" ';

   switch(  this.graphType ) {
      case "vote":
         var graphTitle = "Votes by week";
         break;
      case "pct":
         var graphTitle = "Vote percentages by week";
         break;
   }

   var iHTML = '<img src="'+btnURL+'" border="0" '
             +      'class="zPoll-graph-close-dflt" '+onclick+' />'
             + graphTitle
             + '<br clear="both" />'
             + '<img src="'+imgURL+'" border="0" />';
   graphDiv.innerHTML = iHTML;
   graphDiv.style.top     = this.zPollDiv.offsetHeight + "px";
   graphDiv.style.display = "block";
}


zPoll.prototype.graphClose = function() {

   // Hide options menu, in case called from there.

   this.optionsHide();

   // Hide graph.

   this.graphDiv.style.display = "none";

   // Colors back to previous -- delete most-specific rule.

   var iZ = this.iZPoll;
   for ( var i=0; i<this.alternative.length; i++ ) {
      this.deleteCSSRule( ".zPoll-color-"+iZ+"-"+i );
   }
}


zPoll.prototype.validateLink = function() {

   // Find all <a ...> tags.  Check that an acceptable href is present, and
   // that required link words are present.

   var links = document.getElementsByTagName( "a" );
   var n_links = links.length;
   var n_alt_links = this.acceptableLink.length;
   if ( zPoll_debug1_b ) {
      zPoll_debug( "n_alt_links", n_alt_links );
   }
   if ( n_alt_links > 0 ) {
      var link_ok_f = false;
      var n_linkWords = this.requiredLinkWord.length;
      var neededWords = [];
      for ( var i=0; i<n_links; i++ ) {

         // Loop over alternate acceptable link refs.

         for ( var j=0; j<n_alt_links; j++ ) {
            var linkElement = links[i];
            if ( zPoll_debug1_b ) {
               zPoll_debug( "linkElement.href"+this.iZPoll, linkElement.href );
               zPoll_debug( "acceptableLink[j]"+this.iZPoll, 
                            this.acceptableLink[j] );
            }
            if ( linkElement.href.toLowerCase() == this.acceptableLink[j] ) {
               if ( ! link_ok_f ) {

                  // Check that required text is there for at least one link.
                  // Need all required words.

                  neededWords = [];
                  var linkText = linkElement.innerHTML.toLowerCase();
                  if ( n_linkWords == 0 ) {
                     var regex = /\S/;
                     if ( ! regex.test( linkText ) ) {
                        neededWords.push( "non-blank" );
                     }
                  } else {
                     for ( var j=0; j<n_linkWords; j++ ) {
                        if (linkText.indexOf( this.requiredLinkWord[j]) == -1) {
                           neededWords.push( this.requiredLinkWord[j] );
                        }
                     }
                  }
                  link_ok_f = neededWords.length == 0;
               }
               break;
            }
         }
      }
      if ( ! link_ok_f ) {
         if ( neededWords.length == 0 ) {

            // Required link not present.

            this.zPollDiv.innerHTML = 'Sorry, poll not available ( needs link '
                   + 'like href="' + this.acceptableLink[0] + '").';
         } else {

            // Link was there, but didn't get required words.

            neededWords = neededWords.join( ", " );
            this.zPollDiv.innerHTML = 'Sorry, poll not available (link text '
                   + 'must include: ' + neededWords  + ').';
         }
      }
   }
   return link_ok_f;
}


zPoll.prototype.getStylesheet = function( title ) {
   var styleSheet;
   var n_styleSheets = document.styleSheets.length;
   for ( var i_sheet=0; i_sheet<n_styleSheets; i_sheet++ ) {
      var styleSheet_i = document.styleSheets[i_sheet];
      try {
         if ( styleSheet_i.title.toLowerCase() == title.toLowerCase() ) {
            styleSheet = styleSheet_i;
         }
      } catch(e) {}
   }

   return styleSheet;
}


zPoll.prototype.getCSSRule = function( ruleName, delete_f ) {

   // delete_f - delete rule rather than returning it.

   var cssRule;
   var cssRules;
   for ( var i_sheet=0; i_sheet<document.styleSheets.length; i_sheet++ ) {
      var styleSheet_i = document.styleSheets[i_sheet];

      // Avoid linked sheets -- if not this site, may run afoul of security
      // restriction.

      try {
         if ( ! cssRules ) {
            if ( document.styleSheets[i_sheet].cssRules ) {
               cssRules = "cssRules";
            } else {
               cssRules = "rules";   // IE.
            }
         }
         for ( var i_rule=0; i_rule<styleSheet_i[cssRules].length; i_rule++ ) {
            var rule_i = styleSheet_i[cssRules][i_rule];
            if ( rule_i.selectorText.toLowerCase() == ruleName.toLowerCase() ) {
               cssRule = rule_i;
               break;
            }
         }
      } catch(e) {}
      if ( cssRule ) {
         break;
      }
   }

   if ( delete_f ) {
      if ( cssRule ) {
         if ( styleSheet_i.removeRule ) {
            styleSheet_i.removeRule( i_rule );   // IE
         } else {
            styleSheet_i.deleteRule( i_rule );
         }
      }
   } else {
      return cssRule;
   }
}


zPoll.prototype.addCSSRule = function ( styleSheet, ruleName ) {
   if ( styleSheet.addRule ) {
      styleSheet.addRule(ruleName);   // IE
   } else {
      styleSheet.insertRule(ruleName+" { }", 0);
   }
   return this.getCSSRule( ruleName );
}


zPoll.prototype.deleteCSSRule = function ( ruleName ) {
   this.getCSSRule( ruleName, true );
}


// "Global" var to keep pointers to CSS rules.

zPoll.prototype.cssRule = new Object();

zPoll.prototype.setCSSRule = function ( classname, property, value, 
                                                               noOverwrite_f ) {
   if ( zPoll_debug1_b ) {
      zPoll_debug( "[setCSSRule] classname", classname );
      zPoll_debug( "[setCSSRule] property", property );
      zPoll_debug( "[setCSSRule] value", value );
   }

   var tag = [ "div", "span", "td" ];
   g_classname = classname.replace( /-[^-]+$/, "" );
   for ( var i in tag ) {

      // Let the specific classname be not only specific to this tag, but also
      // to this poll instance.

      var sp_classname = tag[i] + g_classname + '-iZ' + this.iZPoll;
      if ( ! this.cssRule[sp_classname] ) {

         // Not in list of rules.  Create if needed, add to list.

         var cssRule_i = this.getCSSRule( sp_classname );
         if ( ! cssRule_i ) {
            cssRule_i = this.addCSSRule( zPoll_styleSheet, sp_classname );
         }
         this.cssRule[sp_classname] = cssRule_i;
      }
   }

   // If flag set, don't write these more-specific rules if user has provided a
   // general rule.

   if ( noOverwrite_f ) {

      // Check for more general rule.

      var g_rule = this.getCSSRule( classname );
      if ( zPoll_debug1_b ) {
         zPoll_debug( "[setCSSRule] sp_classname classname g_rule", 
                      sp_classname+" "+classname+" "+g_rule);
      }
      if ( ! g_rule ) {

         // And even more general rule.

         g_rule = this.getCSSRule( g_classname );
         if ( zPoll_debug1_b ) {
            zPoll_debug( "[setCSSRule] g_classname g_rule", 
                         g_classname+" "+g_rule);
         }
      }
   }
   for ( var i in tag ) {
      var sp_classname = tag[i] + g_classname + '-iZ' + this.iZPoll;
      if ( ! noOverwrite_f ) {
         this.cssRule[sp_classname].style[property] = value;
      } else {
         if ( ! g_rule ) {
            this.cssRule[sp_classname].style[property] = value;
         } else {
            if ( ! g_rule.style[property] ) {
               this.cssRule[sp_classname].style[property] = value;
            }
         }
      }
   }
}


zPollDummyLast = function() {
}


