if(!a10) {var a10 = {};} //if a10 not defined yet

a10.zoom = {};

a10.zoom.windowHeight = -1; //previous window height used in zoom resize calculation
a10.zoom.items = [];  // Contains references to zoom items.  Used to support arrow key selection in zoom.
a10.zoom.selectedIndex = -1; // Index of the currently selected zoom item in the zoomItem array.  Equals -1 if no zoom item is highlighted
a10.zoom.skipNextArrowKeyEvent = false; //boolean for special handling of safari key events
a10.zoom.bubble = null; //DIV html element for the zoom bubble
a10.zoom.direction="left"; // displays the bubble connector in the direction given, right - zoom results in the RR

// Flag indicating whether bubble was clicked when user clicks anywhere on the page.
// This flag is used to support closing the bubble by clicking outside the bubble.
a10.zoom.bubbleWasClicked = false;

a10.zoom.divIds = null;

// Constants to avoid magic numbers; be sure to keep these associations in tact as logic depends on them;
// the divId array, ovDivId array and moreDivId array must be correlated, as well, the first
// constant type value (int) must be kept correlated with the arrays 
a10.zoom.TYPES = {
    NONE: 0,              NARROW: 1,         EXPAND: 2,         RELATED: 3,              NEWS_RELATED: 4,           NEWS_CAT: 5,          NEWS_FILTER: 6,
    divId:     ['',      'narrow',          'expand',          'relatedNames',          'newsRelatedNames',         'newsCat',            'biasFilter'],
    ovDivId:   ['',      'narrowOverflow',  'expandOverflow',  'relatedOverflow',       'newsRelatedNamesOverflow', 'newsCatOverflow',    'biasFilterOverflow'],
    moreDivId: ['',      'narrowMore',      'expandMore',      'relatedMore',           'newsRelatedNamesMore',     'newsCatMore',        'biasFilterMore']
};


/*
 * Integer indicating the bubble currently shown.
 */
a10.zoom.activeBubble = a10.zoom.TYPES.NONE;

/**
 * This is a hack for Safari where using the arrow key to scroll a Zoom bubble would scroll the result page once
 * the bubble scrolls to its edge.  To fix this, the following event handler is registered for the onkeypress
 * event of document.body.  Special handling is only invoked if the browser is Safari and zooom bubble is shown
 * with scroll bar, so it should be safe.   In all other cases, the function simply returns false to enable the
 * default browser behavior.
 *
 * @addon
 */
a10.zoom.safariKeyPressed = function(event) {
    if (a10.zoom.bubble) { // zoom bubble is shown and ...
        var body = $("zoomBubbleBody");

        if (body.scrollHeight > body.clientHeight ) {  // the vertical scroll bar is shown and ...

            // Note: It's weird that Safari returns 63232 and 63232 instead of 38 and 40 as the keycode for up/down, it's probably another bug in Safari
            if (event.keyCode == 63232 || event.keyCode == 63233) { // the up arrow key or down arrow key was pressed
                if (event.keyCode == 63232) { // scroll up
                    body.scrollTop -= 35;
                } else {  // scroll down
                    body.scrollTop += 35;
                }

                // Prevent the default behavior, which would scroll the page if the bubble has scrolled to the edge.
                event.preventDefault();

                return false;
            }
        }
    }

    // If any of the above condition fail
    return true;
}

//only register hack for safari
if(a10.browser.isSafari()) {
    a10.event.addListener(window, "keypress", a10.zoom.safariKeyPressed);
}

/**
 * Handles key up event in the query box
 *
 * @param event keyup event
 */
a10.zoom.keyup = function(event) {
    if (!event) event = window.event

    // Trap special key event
    switch (event.keyCode ) {
        case 38: // Up Key
        // Handle double firing of arrow event for Safari
            if (navigator.userAgent.indexOf('AppleWebKit') != -1) {
                if (a10.zoom.skipNextArrowKeyEvent) {
                    a10.zoom.skipNextArrowKeyEvent = false;
                    return;
                } else {
                    a10.zoom.skipNextArrowKeyEvent = true;
                }
            }

            a10.zoom.handleUpKey();
            return;
        case 40: // Down key
        // Handle double firing of arrow event for Safari
            if (navigator.userAgent.indexOf('AppleWebKit') != -1) {
                if (a10.zoom.skipNextArrowKeyEvent) {
                    a10.zoom.skipNextArrowKeyEvent = false;
                    return;
                } else {
                    a10.zoom.skipNextArrowKeyEvent = true;
                }
            }

            a10.zoom.handleDownKey();
            return;
        case 13: // Enter key
        // Ignore it.  If don't ignore, will trigger search suggestion on the next result page.
            a10.ss.formSubmitted = true;
            return;
    }
}

/**
 * Handles the up key event by selecting the previous item in zoom
 */
a10.zoom.handleUpKey = function() {
    if($(Const.SEARCH_SUGGESTION_PANE).style.display == 'none') {
        if (a10.zoom.items.length > 0)  {
            // If nothing is selected, backup the original query before we overwrite it.
            if (a10.zoom.selectedIndex == -1) originalQuery = $('q').value;

            // Unhighlight previous selection
            if (a10.zoom.selectedIndex != -1) {
                a10.zoom.items[a10.zoom.selectedIndex].style.borderBottom = "none";
            }

            if (a10.zoom.selectedIndex == 0) { // if the first item is selected
                // Wrap around to nothing selected state.
                a10.zoom.selectedIndex = -1;

                // Restore backed up query
                setValue($('q'), originalQuery);
            }
            else {  // if nothing is selected or something besides the first item is selected.
                // Update selectIndex
                if (a10.zoom.selectedIndex != -1) a10.zoom.selectedIndex--;
                else a10.zoom.selectedIndex = a10.zoom.items.length - 1;  // zoomSelectedIndex == -1

                // Highlight current selection
                var s = a10.zoom.items[a10.zoom.selectedIndex].style;
                s.borderBottom = "1px solid #CC0000";
                if (a10.browser.isIE6()) s.zoom = "1";

                setValue($('q'), a10.zoom.items[a10.zoom.selectedIndex].innerText || a10.zoom.items[a10.zoom.selectedIndex].textContent);
            }
            a10.zoom.operaRedraw();

        }
    }


}

/**
 * Handles the down key event by selecting the next item in zoom
 */
a10.zoom.handleDownKey = function() {
    if($(Const.SEARCH_SUGGESTION_PANE).style.display == 'none') {
        if (a10.zoom.items.length > 0)  {
            // If nothing is selected, backup the original query before we overwrite it.
            if (a10.zoom.selectedIndex == -1) originalQuery = $('q').value;

            // If something is currently selected, unhighlight previous selection
            if (a10.zoom.selectedIndex != -1) {
                a10.zoom.items[a10.zoom.selectedIndex].style.borderBottom = "none";
            }

            if (a10.zoom.selectedIndex == a10.zoom.items.length - 1) { // if the last item is selected
                // Wrap around to nothing selected state.
                a10.zoom.selectedIndex = -1;

                // Restore backed up query
                setValue($('q'), originalQuery);
            }
            else { // if nothing is selected or something besides the last item is selected.
                // Update selectIndex
                a10.zoom.selectedIndex++;

                // Highlight current selection
                var s = a10.zoom.items[a10.zoom.selectedIndex].style;
                s.borderBottom = "1px solid #CC0000";
                if (a10.browser.isIE6()) s.zoom = "1";

                // Set query
                setValue($('q'), a10.zoom.items[a10.zoom.selectedIndex].innerText || a10.zoom.items[a10.zoom.selectedIndex].textContent);
            }

            a10.zoom.operaRedraw();
        }
    }
}

/**
 * Hack to force opera to redraw the zoom pane when border is updated via up/down key arrow
 */
a10.zoom.operaRedraw = function() {
    if(a10.browser.isOpera()) {
        $('zmpad').style.display = 'none';
        $('zmpad').style.display = '';
    }
}

// ----------------------------------------------------  Zoom Bubble

/*
    External Dependencies:
        - Clicking outside of bubble to close is implemented in a body.onclick event handler (mouseClicked())
        - The toggleZoomBubble() assumes the HTML to display within each bubble is stored inside an overflow DIV.
          Right now, the overflow DIVs are assumed to be the divs with id equal to 'narrowOverflow', 'expandOverflow',
          and 'relatedOverflow', 'newsRelatedNamesOverflow' and 'newsCatOverflow'.  These divs are created inside related.jsp.
        - the titles of the overflow popups should be kept in sync with the string properties files in the
          message.related.* set
 */

/**
 * Toggle Zoom bubble on and off.  This is the handler that's invoked when user clicks on the More link in any of the
 * Zoom sections.  It performs all the construction, layout and display/hiding of the bubble.
 *
 * @param   event           JavaScript event object for the click.
 * @param   clickedBubble   Integer indicating the bubble user clicked on.  The values are: 1 for Narrow,
 *                          2 for Expand, 3 for Related, 4 for People in the News. (see relatedType)
 */
a10.zoom.toggle = function(event, clickedBubble) {
    /*
    How Zoom Bubble is Constructed

    The zoom bubble consists of a Bubble Div (zoomBubble), which contains a Body Div (body), a Header Div (header)
    and the top, middle and bottom images of the bubble (bubbleTop, bubbleMiddle and bubbleButtom).  The Header Div
    contains the title (e.g. "Narrow") and the close button.  The Body Div is the scrollable container for the main text,
    and has a gray top border that serves as the divider between header and body.

    Body Text & Height:

    The HTML content of the bubble is stored inside overflow divs (e.g. div with id = "narrowOverflow", etc.)  The height
    of this text as it would be rendered in the bubble is stored in textHeight.  If textHeight is between
    MIN_TEXT_HEIGHT and MAX_TEXT_HEIGHT, then Body Div's height is simply set to textHeight.  Otherwise, Body Div's
    height is set to MIN_TEXT_HEIGHT or MAX_TEXT_HEIGHT as appropriate and a scrollbar is shown in the case MAX_TEXT_HEIGHT
    was used.


    Layout:

    The Bubble Div serves as the container for all the zoom bubble's parts and positions the bubble on screen.
    It is intentially sized very small (20px by 20px) so it wouldn't capture mouse events outside of the visible bubble,
    which we may rely on for mouseover effect in the background content.  Bubble Div positioned from the top
    of the window to make it stay fixed on the page when the window resizes, but the items within it are built from the bottom.

    Within Bubble Div, the bubble images have an zIndex of 0 (default), and is stacked from bottom up.
    The height of bubble's middle image is sized based on the height of the Body Div, which is then adjusted
    with BUBBLE_HEIGHT_OFFSET.  In other words, bubbleMiddle.height = body.style.height + BUBBLE_HEIGHT_OFFSET.

    The Body and Header Div have an zIndex of 1 and are also stacked from the bottom up. However they have bottom
    and left margins (BOTTOM_MARGIN and LEFT_MARGIN) to shift them to the proper location.

    */

    var textHeight; // Height of the body text.

    // Layout Constants
    var MAX_TEXT_HEIGHT = 181; // Maximum height of the body div
    var MIN_TEXT_HEIGHT = 40; // Minimum height of the body div
    var LEFT_MARGIN_BODY = 20; // Left margin of body div
    var LEFT_MARGIN_HEADER = 30; // Left margin of header div
    var BOTTOM_MARGIN = 28; // Bottom margin of the body div.
    var BODY_WIDTH = 228; // Width of the body and header divs
    var BUBBLE_HEIGHT_OFFSET = -30; // The height of the bubble's middle image couldn't simply be equal to the body div's height,
    // since the bubble's top
    // and bottom images also contribute to the area behind body div.  This variable
    // specifies the adjustment that's needed. Increasing this variable increases the
    // bubble image's height.

    // Hide the bubble.
    if (a10.zoom.bubble) {
        if (a10.zoom.bubble.parentNode) a10.zoom.bubble.parentNode.removeChild(a10.zoom.bubble);
        a10.zoom.bubble = null;

        if (a10.browser.isIE6() && a10.zoom.cover) {
            a10.zoom.cover.hide();
            a10.zoom.cover = null;
        }
    }

    // If user clicked a bubble currently shown, simply hides the bubble and return.
    if (clickedBubble == a10.zoom.activeBubble) {
        a10.zoom.activeBubble = a10.zoom.TYPES.NONE;
        return;
    }

    // Otherwise, show the bubble the user clicked on....

    // Close nav bubble if shown.
    a10.nb.close();

    // Set the active bubble
    a10.zoom.activeBubble = clickedBubble;

    // Find the position on screen for the More link that was clicked.

    var srcElement = event.target || event.srcElement;
    //source can be an anchor or the image within the anchor
    if(srcElement.tagName.toLowerCase() != "a") {
        srcElement = srcElement.parentNode;
    }

    var position = a10.util.findPos(srcElement);

    // --------------------- Create the bubble DIV.
    a10.zoom.bubble = document.createElement("div");
    a10.zoom.bubble.style.zIndex = 12; // TRES-5193 needs to be above video result
    a10.zoom.bubble.id = "mainBubbleDiv";
    //a10.zoom.bubble.style.width = "20px";
    //a10.zoom.bubble.style.height = "20px";

    document.body.appendChild(a10.zoom.bubble);


    // -----------------------Construct the Body DIV
    var body = document.createElement("div");
    body.id = "zoomBubbleBody";
    body.className = "lh18";
    body.style.position = "absolute";
    body.style.left = LEFT_MARGIN_BODY + "px";
    body.style.top = 40 + "px";
    body.style.width = BODY_WIDTH + "px";
    body.style.borderTop = "1px solid #D3D3D3";
    body.style.zIndex = "4";
    
    if (a10.browser.isIE6()) { //TRES-16710 
    	var body_frame = document.createElement("iframe");
    	body_frame.id = "zoomBubbleBody_frame";
        body_frame.className = "lh18";
        body_frame.scrolling = "no";
        body_frame.frameborder = "0";
        body_frame.style.position = "absolute";
        body_frame.style.left = LEFT_MARGIN_BODY + "px";
        body_frame.style.top = "20px";
        body_frame.style.width = 11 + BODY_WIDTH + "px";
        body.style.width = 10 + BODY_WIDTH + "px";
        body_frame.style.borderTop = "1px solid #D3D3D3";
        body_frame.style.zIndex = "1";
        body_frame.style.backgroundColor = "white";
        a10.zoom.bubble.appendChild(body_frame);
    }
    // This is a workaround for IE.  Without setting the background color, scrolling using mouse wheel doesn't work when
    // the mouse is pointing at the body's background (non-text area).  Maybe IE let's event pass through transparent
    // elements?
    body.style.backgroundColor = "white";

    // Get the hidden overflow div containing the content markup.
    var overflow;
    if      (clickedBubble == a10.zoom.TYPES.NARROW)       overflow = $(a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NARROW]);
    else if (clickedBubble == a10.zoom.TYPES.EXPAND)       overflow = $(a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.EXPAND]);
    else if (clickedBubble == a10.zoom.TYPES.RELATED)      overflow = $(a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.RELATED]);
    else if (clickedBubble == a10.zoom.TYPES.NEWS_RELATED) overflow = $(a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_RELATED]);
    else if (clickedBubble == a10.zoom.TYPES.NEWS_CAT)     overflow = $(a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_CAT]);
    else if (clickedBubble == a10.zoom.TYPES.NEWS_FILTER)  overflow = $(a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_FILTER]);

    // Set body's content with the overflow's innerHTML.
    body.innerHTML = '<a id="focusAnchor" href="javascript:void(null)" style="cursor: default"></a>' + overflow.innerHTML;

    // Append body to zoomBubble here to order to calculate the height of the text.
    a10.zoom.bubble.appendChild(body);

    // body.offsetHeight equals the full height of the text, since body's style.height hasn't been set yet.
    textHeight = body.offsetHeight;

    // Set body's height and overflow properties according to min and max text height.
    if (textHeight >= MIN_TEXT_HEIGHT && textHeight <= MAX_TEXT_HEIGHT) {
        body.style.height = (textHeight + 2) + "px";
    } else {
        body.style.height = ((textHeight > MAX_TEXT_HEIGHT)? MAX_TEXT_HEIGHT : MIN_TEXT_HEIGHT) + "px";
    }
    if (a10.browser.isIE6()) {
    	if (textHeight >= MIN_TEXT_HEIGHT && textHeight <= MAX_TEXT_HEIGHT) {
    		body_frame.style.height = 20 + (textHeight + 2) + "px";
    	} else {
    		body_frame.style.height = 20 + ((textHeight > MAX_TEXT_HEIGHT)? MAX_TEXT_HEIGHT : MIN_TEXT_HEIGHT) + "px";
    	}
    }


    var bubblePositionTop = (position[1] - parseInt(body.style.height) - 10);
    // Special offset for Opera, which adds additional offset if page is scrolled.
    if (a10.browser.isOpera()) bubblePositionTop -= document.documentElement.scrollTop;

    if (a10.browser.isIE6()) { // Fixed position hack for IE6
        a10.zoom.bubble.style.position = "absolute";

        // Given that zoomBubble uses aboslute positioning, document.body.scrollTop has to be subtracted from bubblePositionTop
        // because we are interested in the position of zoomBubble relative to the top of the client area, not the top of the
        // document.  document.body.scrollTop is then added to this value in the dynamic expression, which would keep the
        // object fixed on screen when the document is scrolled.
        a10.zoom.bubble.style.setExpression("top", "eval(document.body.scrollTop + " +
                                              (bubblePositionTop-document.body.scrollTop) + ")");
    } else {                                                      
        a10.zoom.bubble.style.position = "fixed";
        a10.zoom.bubble.style.top = bubblePositionTop + "px";
    }
    if(this.direction == "right"){      
        var xScrollingOffset; // How much the page has scrolled horizontally.
        if(self.pageYOffset)
        {
            a10.zoom.bubble.style.top = bubblePositionTop -self.pageYOffset + "px";
        }
        if (self.pageXOffset) // all except Explorer
        {
            xScrollingOffset = self.pageXOffset;
        }
        else if (document.documentElement && document.documentElement.scrollLeft) // Explorer 6 Strict
        {
            xScrollingOffset = document.documentElement.scrollLeft;
        }
        else if (document.body) // all other Explorers
        {
            xScrollingOffset = document.body.scrollLeft;
        }
        a10.zoom.bubble.style.left = (position[0] - xScrollingOffset- 280) + "px";
    }else
    {
        a10.zoom.bubble.style.left = (position[0] + 55) + "px";

    }

    // Can now turn on overflow to show the scrollbar if necessary.
    body.style.overflow = "auto"; // Use overflow instead of overflowY since overflowY is not supported in some browsers
    body.style.overflowX = "hidden"; // This is required since FF sometimes shows horizontal scrollbar unnecessarily (see TRES-1995)

    // --------------------Construct the Header DIV
    var header = document.createElement("div");
    header.className = "T2 b";
    header.style.position = "absolute";
    header.style.left = "20px";
    header.style.backgroundColor = "#fff";
    header.style.top = "20px"; //parseInt(body.style.bottom) + parseInt(body.style.height) + "px";
    if (a10.browser.isIE6()) { //TRES-16710 
    	header.style.width = 10 + BODY_WIDTH + "px";
    } else {
    	header.style.width = BODY_WIDTH + "px";
    }   
    header.style.height = "20px";
    header.style.zIndex = "4";

    // Add the title
    header.innerHTML = (a10.zoom.TYPES.title[clickedBubble])/*  + imageHTML*/;

    a10.zoom.bubble.appendChild(header);

    bubble = new a10.Bubble(a10.zoom.bubble, body, BODY_WIDTH+ 15, parseInt(body.style.height), this.direction, true, a10.zoom.closeBubble, 20);

    if(bubble && a10.browser.isIE6()){
    a10.zoom.bubblesize = function (){
    var bubblediv = document.getElementById("mainBubbleDiv");
          a10.zoom.traversel(bubblediv);            
    }

    a10.zoom.traversel = function(bubblesize) {
         body_frame.style.top = "8px";
       if (textHeight >= MIN_TEXT_HEIGHT && textHeight <= MAX_TEXT_HEIGHT) {
    		body_frame.style.height = 38 + (textHeight + 2) + "px";
    	} else {
    		body_frame.style.height = 38 + ((textHeight > MAX_TEXT_HEIGHT)? MAX_TEXT_HEIGHT : MIN_TEXT_HEIGHT) + "px";
    	}
      if (bubblesize.hasChildNodes()) {
        for (var i = 0; i < bubblesize.childNodes.length; i++) {
            if (bubblesize.childNodes[i]) {
                var child = bubblesize.childNodes[i];
                var bubbleRight = document.getElementById("bbRight");
                var bubbleBottom = document.getElementById("bbBottom");
                var bubbleTop = document.getElementById("bbTop");
                var bubbleLeft = document.getElementById("bbLeft");
                var bubbleConp = document.getElementById("bbCon");
               if(bubbleRight || bubbleBottom || bubbleTop || bubbleLeft || bubbleConp ){
                if (child == bubbleRight || child == bubbleBottom || child == bubbleTop || child == bubbleLeft || child == bubbleConp) {
                   child.style.zIndex= "3";
                }
              }
            }
        }
    }
  }

    }

    // set direction to default value 'left', so that others (zoom at left) can continue to use the same code.
    a10.zoom.direction='left';
    
    // Set focus on the body using the dummy anchor
    $('focusAnchor').focus();


    // Capture click events on all elements of the bubble.
/*    body.onclick = header.onclick = bubbleBottom.onclick =
                                    bubbleRight.onclick = bubbleLeft.onclick = bubbleTop.onclick = bubbleClicked;*/

    function bubbleClicked() {
        a10.zoom.bubbleWasClicked = true;
    }

    // Prevent mouseClicked() from closing the bubble we just opened.
    a10.zoom.bubbleWasClicked = true;

    // This IFrameCover seems broken and unnecessary in IE6. CZF TRES-8587
    if (a10.browser.isIE6()) {
        a10.zoom.cover = bubble.cover;
        a10.zoom.cover.show();
        a10.zoom.cover.iframe.style.setExpression("top", "eval(document.body.scrollTop + " +
                                              (bubblePositionTop-document.body.scrollTop+15) + ")");
    }
}

/**
 * Closes any open zoom bubble.
 */
a10.zoom.closeBubble = function() {
    // Hide any bubble currently shown.
    if (a10.zoom.bubble) {
        // Hide the bubble.
        if (a10.zoom.bubble.parentNode) a10.zoom.bubble.parentNode.removeChild(a10.zoom.bubble);
        a10.zoom.bubble = null;
        a10.zoom.activeBubble = a10.zoom.TYPES.NONE;
    }

     if (a10.browser.isIE6() && a10.zoom.cover) {
         a10.zoom.cover.hide();
         a10.zoom.cover = null;
     }
}


/**
 * Resizes the 3 zooms divs base on the amount of vertical space available. Narrow has higher precedence, then expand,
 * and lastly related.
 */
a10.zoom.resize = function() {   
    var lineHeight = 20;
    var winHeight = a10.browser.innerDimension()[1];
    var height = 170; //search, header, etc.
    //no height change, no need to make any calculations
    if(a10.zoom.windowHeight == winHeight) {
        return;
    }


    a10.zoom.closeBubble();

    //update previous height
    a10.zoom.windowHeight = winHeight;

	// add up hieghts of all zoom divs and their more divs
	for (var i=1; i<a10.zoom.TYPES.divId.length; i++ ) {
		var zoomDiv = $(a10.zoom.TYPES.divId[i]);
		if ( zoomDiv ) {
			height += 18; // label
			if( $(a10.zoom.TYPES.moreDivId[i]) ) {
				height += 18; // more
			}

			height += 16; //bottom padding
			var allDivs = zoomDiv.getElementsByTagName("div");
			for(var j=0; j<allDivs.length; j++) {
				height += allDivs[j].offsetHeight;
			}
		}
	}

    height+=40; // leaving some more extra space at bottom

    if($('leftRail')) {
        var offset;
        if($('askmodHeader')){
           offset = winHeight - height - 100;
        }else{
           offset = winHeight - height;
        }
        var slots = Math.abs(offset / lineHeight);
        if(slots > 0) {
            if(offset > 0) {
                slots = Math.floor(slots); //be conservative on expansion, don't wanna push the last link so that it's hidden
                slots -= a10.zoom.expandDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NEWS_CAT], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_CAT], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NEWS_CAT]);
                slots -= a10.zoom.expandDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NEWS_RELATED], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_RELATED], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NEWS_RELATED]);
                slots -= a10.zoom.expandDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NEWS_FILTER], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_FILTER], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NEWS_FILTER]);
                slots -= a10.zoom.expandDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NARROW], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NARROW], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NARROW]);
                slots -= a10.zoom.expandDiv(Math.ceil(slots/2), a10.zoom.TYPES.divId[a10.zoom.TYPES.EXPAND], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.EXPAND], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.EXPAND]);
                slots -= a10.zoom.expandDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.RELATED], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.RELATED], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.RELATED]);
            }
            if (offset < 0) { // zoom is taller than window
                slots = Math.round(slots); //be aggression on contraction, so that last link has lower chance of being hidden
                var prevSlots = slots;
                slots -= a10.zoom.contractDiv(Math.floor(slots/2), a10.zoom.TYPES.divId[a10.zoom.TYPES.RELATED], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.RELATED], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.RELATED], 1); //try to keep expand and related equal, expand should have precedence
                slots -= a10.zoom.contractDiv(Math.ceil(slots/2), a10.zoom.TYPES.divId[a10.zoom.TYPES.EXPAND], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.EXPAND], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.EXPAND], 1);
                if(prevSlots == slots) {
                    slots -= a10.zoom.contractDiv(Math.ceil(slots/2), a10.zoom.TYPES.divId[a10.zoom.TYPES.RELATED], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.RELATED], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.RELATED], 1); //try related again if expand did not contract
                }
                slots -= a10.zoom.contractDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NARROW], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NARROW], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NARROW], 1);
                slots -= a10.zoom.contractDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NEWS_RELATED], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_RELATED], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NEWS_RELATED], 4);
                slots -= a10.zoom.contractDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NEWS_CAT], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_CAT], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NEWS_CAT], 4);
                slots -= a10.zoom.contractDiv(slots, a10.zoom.TYPES.divId[a10.zoom.TYPES.NEWS_FILTER], a10.zoom.TYPES.ovDivId[a10.zoom.TYPES.NEWS_FILTER], a10.zoom.TYPES.moreDivId[a10.zoom.TYPES.NEWS_FILTER], 4);
            }
        }
    }

    //update search suggestion array
    a10.zoom.items = new Array();
    if(typeof a10.zoom.divIds != 'undefined' && a10.zoom.divIds) {
        for(var i = 0; i < a10.zoom.divIds.length; i++) {
            var div = $(a10.zoom.divIds[i]);
            if(div) {
                var elements = div.getElementsByTagName("a");
                for (var j = 0; j < elements.length; j++) a10.zoom.items.push(elements[j]);
            }
        }
    }
}

/**
 * Expands a zoom div html element by determining the number of slots to add until the 10 slots have been reached
 * @param slots number of divs to remove
 * @param id id of html element to remove from
 * @param overflowId id of html element to move the divs to
 * @param moreId id of the more anchor to show or hide
 *
 */
a10.zoom.expandDiv = function(slots, id, overflowId, moreId) {
    a10.debug("expand: " + slots + " " + id + " " + overflowId + " " + moreId);
    var result = 0;

    var overflowDiv = $(overflowId);
    if(slots > 0 && $(id)) {
        var extraSlots = (overflowDiv ? overflowDiv.getElementsByTagName("div").length : 0);
        var count = $(id).getElementsByTagName("div").length;
        if(count < 10 && extraSlots > 0) {
            var num = Math.min(extraSlots, Math.min(10 - count, slots));
            a10.zoom.shiftAnchors(overflowId, id, num, true);
            result = num;
        }
    }

    if(overflowDiv) {
        if(overflowDiv.getElementsByTagName("div").length == 0) {
            $(moreId).style.display = 'none';
        } else {
            $(moreId).style.display = '';
        }
    }

    return result;
}

/**
 * Contracts a zoom div html element by determining the number of slots to remove until the min slots have been reached
 * @param slots number of divs to remove
 * @param id id of html element to remove from
 * @param overflowId id of html element to move the divs to
 * @param moreId id of the more anchor to show or hide
 * @param min minimum number of divs to show
 *
 */
a10.zoom.contractDiv = function(slots, id, overflowId, moreId, min) {
    a10.debug("contract: " + slots + " " + id + " " + overflowId + " " + moreId + " " + min);
    var result = 0;

    var overflowDiv = $(overflowId);
    if(slots > 0 && $(id)) {
        var count = $(id).getElementsByTagName("div").length - min;
        if(count > 0) {
            var num = Math.min(count, slots);
            a10.zoom.shiftAnchors(id, overflowId, num, false);

            result = num;
        }
    }


    if(overflowDiv) {
        if(overflowDiv.getElementsByTagName("div").length > 0) {
            $(moreId).style.display = '';
        } else {
            $(moreId).style.display = 'none';
        }
    }
    return result;
}

/**
 * Moves divs containing anchors tags from one html element to another
 * @param fromId id of html element to remove div from
 * @param toId id of html element to add div to
 * @param num num of divs to move
 * @param shiftFromTop order of the move from top or bottom
 */
a10.zoom.shiftAnchors = function(fromId, toId, num, shiftFromTop) {
    var fromDiv = $(fromId);
    var anchors = fromDiv.getElementsByTagName("div");
    if(shiftFromTop) {
        for(var i = 0; i < num; i++) {
            var nextChild = anchors[0];
            fromDiv.removeChild(nextChild);
            $(toId).appendChild(nextChild);
        }

    } else {
        for(var i = 0; i < num; i++) {
            var nextChild = anchors[anchors.length-1];
            fromDiv.removeChild(nextChild);
            var toDiv = $(toId);
            if(toDiv.childNodes && toDiv.childNodes.length > 0) {
                toDiv.insertBefore(nextChild, toDiv.childNodes[0]);
            } else {
                toDiv.appendChild(nextChild);
            }
        }

    }
}
