YAHOO.namespace("shipwire.util");
YAHOO.shipwire.util = new function()
{
    //used for Salesforce
    this.SHA1=function(){var C=function(E,D,G,F){switch(E){case 0:return(D&G)^(~D&F);case 1:return D^G^F;case 2:return(D&G)^(D&F)^(G&F);case 3:return D^G^F}},B=function(D,E){return(D<<E)|(D>>>(32-E))},A=function(G){var F="",D,E;for(E=7;E>=0;E--){D=(G>>>(E*4))&15;F+=D.toString(16)}return F};return{hash:function(F){F+=String.fromCharCode(128);var I=[1518500249,1859775393,2400959708,3395469782],U=Math.ceil(F.length/4)+2,G=Math.ceil(U/16),H=new Array(G),X=0,Q=1732584193,P=4023233417,O=2562383102,L=271733878,J=3285377520,D=new Array(80),h,g,f,Z,Y,R,V;for(;X<G;X++){H[X]=new Array(16);for(V=0;V<16;V++){H[X][V]=(F.charCodeAt(X*64+V*4)<<24)|(F.charCodeAt(X*64+V*4+1)<<16)|(F.charCodeAt(X*64+V*4+2)<<8)|(F.charCodeAt(X*64+V*4+3))}}H[G-1][14]=((F.length-1)*8)/Math.pow(2,32);H[G-1][14]=Math.floor(H[G-1][14]);H[G-1][15]=((F.length-1)*8)&4294967295;for(X=0;X<G;X++){for(R=0;R<16;R++){D[R]=H[X][R]}for(R=16;R<80;R++){D[R]=B(D[R-3]^D[R-8]^D[R-14]^D[R-16],1)}h=Q;g=P;f=O;Z=L;Y=J;for(R=0;R<80;R++){var S=Math.floor(R/20),E=(B(h,5)+C(S,g,f,Z)+Y+I[S]+D[R])&4294967295;Y=Z;Z=f;f=B(g,30);g=h;h=E}Q=(Q+h)&4294967295;P=(P+g)&4294967295;O=(O+f)&4294967295;L=(L+Z)&4294967295;J=(J+Y)&4294967295}return A(Q)+A(P)+A(O)+A(L)+A(J)}}}();

    this.inEmbedded = false;
    
    // ***DEPRECATED***
    // Use showBtnDlg to achieve the same functionality
    //Valid cfg values
    //   title: <string for heading of dialog>
    //   text: <string for confirm statement>
    //   yesBtnText: <String for "yes" button>
    //   noBtnText: <String for "no" button>
    //   yesBtnColor: <color of yes button> (green|orange)
    //   noBtnColor: <color of no button> (green|orange)
    //   defaultBtn: <default selected button> (yes|no)
    
    this.showConfirmDlg = function(cfg, handleYes, handleNo)
    {
        var config =
        {
            title: cfg.title,
            text: cfg.text,
            close: true
        };
        
        var btns =
        [
            {label: cfg.noBtnText, handler: handleNo, color: cfg.noBtnColor},
            {label: cfg.yesBtnText, handler: handleYes, color: cfg.yesBtnColor}
        ];
        
        if(cfg.defaultBtn && cfg.defaultBtn == "no") {
            btns[1].isDefault = true;
        } else {
            btns[0].isDefault = true;
        }
        this.showBtnDlg(config, btns);
    };

    //Valid cfg values
    //   title: <string for heading of dialog>
    //   text: <string for confirm statement>
    //   close: <set to true to have close box>
    //
    //Valid btns values (btns is a 0-based array of buttons)
    //   btns[x] =
    //      label: <String for button>
    //      handler: <reference to handler for button click>
    //      color: <color of button> (green|orange)
    //      isDefault: <include this and set to true for default button)
    
    this.showBtnDlg = function(cfg, btns) 
    {
        var oSelf = YAHOO.shipwire.util;

        if(!YAHOO.widget.SimpleDialog) //This should never happen!
        {
            alert("This requires YUI's Controller widget.");
            return;
        }
        
        var closeVal = (cfg.close)?(cfg.close):(null);
        
        if(!this.confirmDlg)
        {
            //change position so YUI can calculate the size
            YAHOO.widget.Panel.FOCUSABLE = [];
            document.getElementById("sw_confirmdlg").style.position = "relative";

            var dialogCfg = {
                //effect:{effect:YAHOO.widget.ContainerEffect.FADE,
                //        duration:0.1},
                fixedcenter:true,
                modal:true,
                visible:false,
                draggable:false,
                underlay:"none",
                close: closeVal,
                width: "253px"
            };

            if (oSelf.inEmbedded) {
                dialogCfg.fixedcenter = false;
                dialogCfg.x = (YAHOO.util.Dom.getViewportWidth() / 2) - 127;
                dialogCfg.y = 100;
            }

            this.confirmDlg = new YAHOO.widget.SimpleDialog("sw_confirmdlg", dialogCfg);
            this.confirmDlg.header = YAHOO.util.Dom.getElementsByClassName("hd","div",document.getElementById("sw_confirmdlg"))[0];
            this.confirmDlg.body = YAHOO.util.Dom.getElementsByClassName("bd","div",document.getElementById("sw_confirmdlg"))[0];
            this.confirmDlg.footer = YAHOO.util.Dom.getElementsByClassName("ft","div",document.getElementById("sw_confirmdlg"))[0];
        }
        else
        {
        	this.confirmDlg.hide();
        }
        (cfg.title)?(this.confirmDlg.setHeader(cfg.title)):(this.confirmDlg.setHeader("Are you sure?"));
        (cfg.text)?(this.confirmDlg.setBody(cfg.text)):(this.confirmDlg.setBody("Are you sure you want to do that?"));

        var myButtons = new Array();
        for (i=0; i<btns.length; i++)
        {
            myButtons[i] = {
                text: btns[i].label,
                handler: btns[i].handler,
                isDefault: btns[i].isDefault
            };
        }

        this.confirmDlg.cfg.queueProperty("buttons",myButtons);
        this.confirmDlg.render(document.body);
        
        var elBtns = document.getElementById("sw_confirmdlg").getElementsByTagName("button");
        this.addBtnWrap(elBtns);
        for(i=0; i<elBtns.length; i++)
        {
            elBtns[i].id = "confirmbtn"+i;
            
            if (btns[i] && btns[i].color && btns[i].color=="orange")
            {
                YAHOO.util.Dom.addClass(elBtns[i],"orange");
            }
        }
      
        YAHOO.util.Event.addListener(
            elBtns,
            "click",
            function(){
                YAHOO.shipwire.util.confirmDlg.hide();
            }
        );
        this.confirmDlg.render(document.body);
        this.confirmDlg.show();
    };
    
    this.showAlertDlg = function(title, body)
    {
      var cfg = new Array();
      cfg.title = title;
      cfg.text = body;
      var btns = new Array();
      btns[0] = {label: 'OK', handler: null, color: 'green'};
      YAHOO.shipwire.util.showBtnDlg(cfg, btns);
    };
    
    /*
    *  Helper to wrap YUI Dialog buttons with extra divs for styling
    */
    this.addBtnWrap = function(elBtns)
    {
        var i;
        for(i=0; i<elBtns.length; i++)
        {
            //check for existing wrapper
            if(YAHOO.util.Dom.getElementsByClassName("btncont","div",elBtns[i]).length)
            {
                return;
            }
            elBtns[i].innerHTML = "<div class='btncont'><div class='btnhd'></div><div class='btnbd'><p>"+elBtns[i].innerHTML+"</p></div></div>";
            YAHOO.util.Dom.addClass(elBtns[i],"stdbtn_sm");
        }
    };
    
    /*
    *  Two functions to work with PHP's urlencode/urldecode
    *  http://phpjs.org/functions/view/573 - encode 904.1412
    *  http://phpjs.org/functions/view/572 - decode 904.1412
    */ 
    this.urlencode = function(str)
    {
        var histogram = {}, tmp_arr = [];
        var ret = (str+'').toString();
        
        var replacer = function(search, replace, str)
        {
            var tmp_arr = [];
            tmp_arr = str.split(search);
            return tmp_arr.join(replace);
        };
        
        // The histogram is identical to the one in urldecode.
        histogram["'"]   = '%27';
        histogram['(']   = '%28';
        histogram[')']   = '%29';
        histogram['*']   = '%2A';
        histogram['~']   = '%7E';
        histogram['!']   = '%21';
        histogram['%20'] = '+';
        histogram['\u00DC'] = '%DC';
        histogram['\u00FC'] = '%FC';
        histogram['\u00C4'] = '%D4';
        histogram['\u00E4'] = '%E4';
        histogram['\u00D6'] = '%D6';
        histogram['\u00F6'] = '%F6';
        histogram['\u00DF'] = '%DF';
        histogram['\u20AC'] = '%80';
        histogram['\u0081'] = '%81';
        histogram['\u201A'] = '%82';
        histogram['\u0192'] = '%83';
        histogram['\u201E'] = '%84';
        histogram['\u2026'] = '%85';
        histogram['\u2020'] = '%86';
        histogram['\u2021'] = '%87';
        histogram['\u02C6'] = '%88';
        histogram['\u2030'] = '%89';
        histogram['\u0160'] = '%8A';
        histogram['\u2039'] = '%8B';
        histogram['\u0152'] = '%8C';
        histogram['\u008D'] = '%8D';
        histogram['\u017D'] = '%8E';
        histogram['\u008F'] = '%8F';
        histogram['\u0090'] = '%90';
        histogram['\u2018'] = '%91';
        histogram['\u2019'] = '%92';
        histogram['\u201C'] = '%93';
        histogram['\u201D'] = '%94';
        histogram['\u2022'] = '%95';
        histogram['\u2013'] = '%96';
        histogram['\u2014'] = '%97';
        histogram['\u02DC'] = '%98';
        histogram['\u2122'] = '%99';
        histogram['\u0161'] = '%9A';
        histogram['\u203A'] = '%9B';
        histogram['\u0153'] = '%9C';
        histogram['\u009D'] = '%9D';
        histogram['\u017E'] = '%9E';
        histogram['\u0178'] = '%9F';
        
        // Begin with encodeURIComponent, which most resembles PHP's encoding functions
        ret = encodeURIComponent(ret);
        
        for (search in histogram)
        {
            replace = histogram[search];
            ret = replacer(search, replace, ret); // Custom replace. No regexing
        }
        
        // Uppercase for full PHP compatibility
        return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2)
        {
            return "%"+m2.toUpperCase();
        });
             
        return ret;
    };

    this.urldecode = function(str)
    {
        var histogram = {};
        var ret = str.toString();
        
        var replacer = function(search, replace, str)
        {
            var tmp_arr = [];
            tmp_arr = str.split(search);
            return tmp_arr.join(replace);
        };
        
        // The histogram is identical to the one in urlencode.
        histogram["'"]   = '%27';
        histogram['(']   = '%28';
        histogram[')']   = '%29';
        histogram['*']   = '%2A';
        histogram['~']   = '%7E';
        histogram['!']   = '%21';
        histogram['%20'] = '+';
        histogram['\u00DC'] = '%DC';
        histogram['\u00FC'] = '%FC';
        histogram['\u00C4'] = '%D4';
        histogram['\u00E4'] = '%E4';
        histogram['\u00D6'] = '%D6';
        histogram['\u00F6'] = '%F6';
        histogram['\u00DF'] = '%DF';
        histogram['\u20AC'] = '%80';
        histogram['\u0081'] = '%81';
        histogram['\u201A'] = '%82';
        histogram['\u0192'] = '%83';
        histogram['\u201E'] = '%84';
        histogram['\u2026'] = '%85';
        histogram['\u2020'] = '%86';
        histogram['\u2021'] = '%87';
        histogram['\u02C6'] = '%88';
        histogram['\u2030'] = '%89';
        histogram['\u0160'] = '%8A';
        histogram['\u2039'] = '%8B';
        histogram['\u0152'] = '%8C';
        histogram['\u008D'] = '%8D';
        histogram['\u017D'] = '%8E';
        histogram['\u008F'] = '%8F';
        histogram['\u0090'] = '%90';
        histogram['\u2018'] = '%91';
        histogram['\u2019'] = '%92';
        histogram['\u201C'] = '%93';
        histogram['\u201D'] = '%94';
        histogram['\u2022'] = '%95';
        histogram['\u2013'] = '%96';
        histogram['\u2014'] = '%97';
        histogram['\u02DC'] = '%98';
        histogram['\u2122'] = '%99';
        histogram['\u0161'] = '%9A';
        histogram['\u203A'] = '%9B';
        histogram['\u0153'] = '%9C';
        histogram['\u009D'] = '%9D';
        histogram['\u017E'] = '%9E';
        histogram['\u0178'] = '%9F';
        
        for (replace in histogram)
        {
            search = histogram[replace]; // Switch order when decoding
            ret = replacer(search, replace, ret); // Custom replace. No regexing  
        }
        
        // End with decodeURIComponent, which most resembles PHP's encoding functions
        ret = decodeURIComponent(ret);
        
        return ret;
    };
    
    this.getValue = function(el) {
        if (typeof el == "string") {
            el = YAHOO.util.Dom.get(el);
        }
        var value = this.trim(el.value);
        var placeHolder = YAHOO.util.Dom.getAttribute(el, "placeholder");
        if (placeHolder) {
            if (value == placeHolder) {
                value = "";
            }
        }
        return value;
    };
    
    /*
     *  Generic trim function
     */
    this.trim = function(str)
    {
        return str.replace(/^\s+|\s+$/g,"");
    };

    this.zeroPad = function (num, length)
    {
        if (!length) {
            length = 2;
        }

        while (num.toString().length < length) {
            num = "0"+num;
        }

        return num;
    };
    
    /*
     *  JS equivilent to PHP's number_format
     *  From php.js, v906.1806
     */
    this.number_format = function (number, decimals, dec_point, thousands_sep)
    {
        var n = number;
        var prec = decimals;

        var toFixedFix = function (n,prec) {
            var k = Math.pow(10,prec);
            return (Math.round(n*k)/k).toString();
        };

        n = !isFinite(+n) ? 0 : +n;
        prec = !isFinite(+prec) ? 0 : Math.abs(prec);
        var sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep;
        var dec = (typeof dec_point === 'undefined') ? '.' : dec_point;

        var s = (prec > 0) ? toFixedFix(n, prec) : toFixedFix(Math.round(n), prec); //fix for IE parseFloat(0.55).toFixed(0) = 0;

        var abs = toFixedFix(Math.abs(n), prec);
        var _, i;

        if (abs >= 1000) {
            _ = abs.split(/\D/);
            i = _[0].length % 3 || 3;

            _[0] = s.slice(0,i + (n < 0)) +
                  _[0].slice(i).replace(/(\d{3})/g, sep+'$1');
            s = _.join(dec);
        } else {
            s = s.replace('.', dec);
        }

        var decPos = s.indexOf(dec);
        if (prec >= 1 && decPos !== -1 && (s.length-decPos-1) < prec) {
            s += new Array(prec-(s.length-decPos-1)).join(0)+'0';
        }
        else if (prec >= 1 && decPos === -1) {
            s += dec+new Array(prec).join(0)+'0';
        }
        return s;
    };
    
    //Recursively walks the tree looking for an ancestor where element.id = id
    this.findTargetById = function(elTarget, id)
    {
        if (elTarget.id == id)
        {
            return elTarget;
        }
        else if (elTarget == document.body || !elTarget.parentNode)
        {
            return false;
        }
        else
        {
            return this.findTargetById(elTarget.parentNode, id);
        }
    };
    
    //Recursively walks the tree looking for an ancestor where element.className = className
    this.findTargetByClassName = function(elTarget, className)
    {
        if (YAHOO.util.Dom.hasClass(elTarget, className))
        {
            return elTarget;
        }
        else if (elTarget == document.body || !elTarget.parentNode)
        {
            return false;
        }
        else
        {
            return this.findTargetByClassName(elTarget.parentNode, className);
        }
    };
    
    //Inputs
    //   elId: <string of container's ID>
    //   current: number of current offset
    //   total: total number of records
    //   perPage: number of records per page
    //   handlerFn: function pointer for function to handle all clicks
    //   alwaysDraw: set to true to draw in case where there is only one page
    //
    this.drawPagination = function(elId, current, total, perPage, handlerFn, alwaysDraw, dataObj)
    {
        current = parseInt(current);
        total = parseInt(total);
        
        if(typeof(handlerFn)!=="function") {
            handlerFn = function(e){YAHOO.util.Event.preventDefault(e);};
        }
        if(alwaysDraw !== true) {
            alwaysDraw = false;
        }
        
        var elCont = document.getElementById(elId);
        if(!elCont) {
            return;
        }
        
        if(dataObj && dataObj.maxLinks) {
            var backOffset = Math.floor((dataObj.maxLinks-1)/2);
            var forwardOffset = dataObj.maxLinks-backOffset-1;
        }
        else {
            backOffset = 3;
            forwardOffset = 3;
        }
        
        var currPage = Math.floor(current/perPage)+1;
        var maxPage = Math.ceil(total/perPage);
        var startPage = (currPage-backOffset>0) ? (currPage-backOffset) : (1);
        var endPage = (currPage+forwardOffset<maxPage) ? (currPage+forwardOffset) : (maxPage);
        
        var listCont = YAHOO.util.Dom.getElementsByClassName("sw_paglist","div",elCont)[0];
        var jumpCont = YAHOO.util.Dom.getElementsByClassName("sw_pagjump","div",elCont)[0];

        if(!listCont || !jumpCont) {
            //Wipe out everything and start fresh
            while(elCont.hasChildNodes()) {
                elCont.removeChild(elCont.lastChild);
            }
            
            //Add containers
            listCont = document.createElement("div");
            listCont.className = "sw_paglist";
            
            jumpCont = document.createElement("div");
            jumpCont.className = "sw_pagjump";
            
            //build jump template
            var p = document.createElement("p");
            p.className = "jumptxt";
            p.appendChild(document.createTextNode("Go to page "));
            var input = document.createElement("input");
            input.className = "sw_pagjump_field text";
            input.value = currPage;
            p.appendChild(input);
            p.appendChild(document.createTextNode(" of "));
            var elTotal = document.createElement("span");
            elTotal.className = "sw_pagjump_total";
            elTotal.appendChild(document.createTextNode(maxPage));
            p.appendChild(elTotal);
            jumpCont.appendChild(p);
            var btn = this.drawStdSmButton("Go","","sw_pagejump_btn");
            jumpCont.appendChild(btn);            
            elCont.appendChild(listCont);
            elCont.appendChild(jumpCont);
        }
        else {
            YAHOO.util.Dom.getElementsByClassName("sw_pagjump_field","input",elCont)[0].value=currPage;
            YAHOO.util.Dom.getElementsByClassName("sw_pagjump_total","",elCont)[0].innerHTML=maxPage;

            while(listCont.hasChildNodes()) {
                listCont.removeChild(listCont.lastChild);
            }
        }
        
        var pageJumpButton = YAHOO.util.Dom.getElementsByClassName("sw_pagejump_btn", "button");
        YAHOO.util.Event.removeListener(pageJumpButton, "click");
        YAHOO.util.Event.addListener(pageJumpButton,"click",YAHOO.shipwire.util.handleJumpBtnClick,{"elCont":elCont,"perPage":perPage,"maxPage":maxPage,"handlerFn":handlerFn,"dataObj":dataObj});
        
        if(!alwaysDraw && total <= perPage) {
            elCont.style.display = "none";
        }
        else {
            elCont.style.display = "";
        }
        
        if(!alwaysDraw && total <= perPage*5) {
            jumpCont.style.display = "none";
        }
        else {
            jumpCont.style.display = "";
        }
        
        if (dataObj && dataObj.noJump) {
            YAHOO.util.Dom.getElementsByClassName("sw_pagjump","",elId)[0].style.display = "none";
        }
        else {
            YAHOO.util.Dom.getElementsByClassName("sw_pagjump","",elId)[0].style.display = "";
        }
        
        //check for prev
        var prev = document.createElement("a");
        if(current>0) {
            prev.className="prev";
        }
        else {
            prev.className="prev disabled";
        }
        var index;
        if(current-perPage<0) {
            index = 0;
        }
        else {
            index = current-perPage;
        }
        prev.href="#index="+index;
        prev.appendChild(document.createTextNode("Prev"));
        listCont.appendChild(prev);

        //add first page link
        if (startPage>1) {
            listCont.appendChild(this.drawPagNumLink(1, currPage, perPage));
            
            if (startPage>2) {
                listCont.appendChild(document.createTextNode("..."));
            }
        }

        for(var i=startPage; i<=endPage; i++) {
            listCont.appendChild(this.drawPagNumLink(i, currPage, perPage));
        }
        
        //add last page link
        if (endPage<maxPage) {   
            if (endPage<maxPage-1) {
                listCont.appendChild(document.createTextNode("..."));
            }
            listCont.appendChild(this.drawPagNumLink(maxPage, currPage, perPage));
        }
        
        //check for next
        var next = document.createElement("a");
        if (current+perPage<total) {
            next.className="next";
        }
        else {
            next.className="next disabled";
        }
        next.href="#index="+(current+perPage);
        next.appendChild(document.createTextNode("Next"));
        listCont.appendChild(next);
        
        if(typeof(handlerFn)=="function") {
            YAHOO.util.Event.addListener(listCont.getElementsByTagName("a"),"click",function(e) {
                var offset = this.href.substring(this.href.indexOf("index=")+6);
                YAHOO.util.Event.preventDefault(e);
                handlerFn(offset,dataObj);
            });
        }
    };
    
    this.handleJumpBtnClick = function(e, obj)
    {
        var offset;
        
        var page = parseInt(YAHOO.util.Dom.getElementsByClassName("sw_pagjump_field","input",obj.elCont)[0].value);
        
        if (page <= 0 || isNaN(page)) {
            offset = 0;
        }
        else if (page < obj.maxPage) {
            offset = (page-1) * obj.perPage;
        }
        else {
            offset = (obj.maxPage-1) * obj.perPage;
        }
        obj.handlerFn(offset, obj.dataObj);
    };
    
    this.drawPagNumLink = function(num, current, perPage)
    {
        var numLink;
        
        if (num==current)
        {
            numLink = document.createElement("span");
            numLink.className="currNum";
            numLink.appendChild(document.createTextNode(num));
        }
        else
        {
            numLink = document.createElement("a");
            numLink.href="#index="+((num-1)*perPage);
            numLink.className = "numlink";
            numLink.appendChild(document.createTextNode(num));
        }
        
        return numLink;
    };
    
    this.getHashFromUrl = function(url)
    {
        return url.substring(url.indexOf("#")+1);
    };
        
    this.drawStdSmButton = function(btnLabel, id, className)
    {
        var btn = null;
       // Try the IE way; this fails on standards-compliant browsers
       try {
          btn = document.createElement('<button type="button">');
       } catch (e) {
       }
       if (!btn || btn.nodeName != "BUTTON") {
          // Non-IE browser; use canonical method to create named element
          btn = document.createElement("button");
          btn.type = "button";
       }

        if(id)
        {
            btn.id=id;
        }
        btn.className="stdbtn_sm  ";
        if(className)
        {
            btn.className += " " + className;
        }
        var cont = document.createElement("div");
        cont.className = "btncont";
        var hd = document.createElement("div");
        hd.className = "btnhd";
        var bd = document.createElement("div");
        bd.className = "btnbd";
        var p = document.createElement("p");
        p.appendChild(document.createTextNode(btnLabel));
        bd.appendChild(p);
        cont.appendChild(hd);
        cont.appendChild(bd);
        btn.appendChild(cont);
        
        return btn;
    };

    this.showSignin = function(e)
    {
        YAHOO.util.Event.preventDefault(e);
        ShowContent('signin_open');
        document.getElementById('sw_signin_username').focus();
        YAHOO.util.Dom.addClass("newsmodule", "signinhidden");
        //YAHOO.shipwire.util.help.hideFlyout(e);
    };
    this.hideSignin = function(e)
    {
        YAHOO.util.Event.preventDefault(e);
        HideContent('signin_open');
        YAHOO.util.Dom.removeClass("newsmodule", "signinhidden");
    };

        
    //  Determines how to orient the overlay around the target
    //  element so that the overlay appears in the viewport
    //  
    //  Inputs:
    //     elOverlay: <HTMLElement> Overlay element
    //     elTarget: <HTMLElement> Element around which overlay will be displayed
    //     config: <Array> List of config parameters
    //          offsetX: <Number> | <Array> # of pixels off from edge of target to set overlay,
    //                     where positive is to the outside and negative is to the inside.
    //                     If array, [0] is left, [1] is right.  If number, it is used for both
    //          offsetY: <Number> | <Array> # of pixels off from edge of target to set overlay,
    //                     where positive is to the outside and negative is to the inside.
    //                     If array, [0] is top, [1] is bottom.  If number, it is used for both
    //          defaultX: <String> "left" or "right" for which edge to use for default alignment
    //          defaultY: <String> "top" or "bottom" for which edge to use for default alignment
    //          returnPos: <Bool> If true, the return of the function is an obj with xy and position
    //                         relative to target
    
    this.fitOverlayToViewport = function(elOverlay,elTarget,config)
    {
        var offsetX, offsetY;
        
        if(!config)
        {
            config = new Object();
        }
        //Overlay height/width
        var overHeight = elOverlay.scrollHeight;
        var overWidth = elOverlay.scrollWidth;
        //Click target's top-left corner's XY, target height/width
        var targetX = YAHOO.util.Dom.getX(elTarget);
        var targetY = YAHOO.util.Dom.getY(elTarget);
        var targetHeight = elTarget.offsetHeight;
        var targetWidth = elTarget.offsetWidth;
        //Main container's top left corner's XY, cont height/width
        var contX = YAHOO.util.Dom.getX(document.getElementById("sw_main"));
        var contY = YAHOO.util.Dom.getY(document.getElementById("sw_main"));
        var contHeight = document.getElementById("sw_main").offsetHeight;
        var contWidth = document.getElementById("sw_main").offsetWidth;
        //Viewport height/width
        var viewHeight = YAHOO.util.Dom.getViewportHeight();
        var viewWidth = YAHOO.util.Dom.getViewportWidth();
        //Scroll amount
        var scrollHeight = YAHOO.util.Dom.getDocumentScrollTop();
        var scrollWidth = YAHOO.util.Dom.getDocumentScrollLeft();
        //Determine whether top of container or window is current edge
        var leftEdge = Math.max(scrollWidth,contX);
        var topEdge = Math.max(scrollHeight,contY);
        //Pos relative to target
        var returnPosX = null;
        var returnPosY = null;
        
        //Tracks # of pixels out of bounds for all positions
        //NOTE: left and right refer to the alignment options, so a positive
        //   left value means object is overflowing to the right (because it
        //   occurs when it is aligned with the target's left edge.
        var outofbounds = {"left":0, "right":0, "top":0, "bottom":0};
        
        if (config.offsetX===false || !config.offsetX.length)
        {
            offsetX = [config.offsetX,config.offsetX];
        }
        else
        {
            offsetX = config.offsetX;
        }
        
        if (config.offsetY===false || !config.offsetY.length)
        {
            offsetY = [config.offsetY,config.offsetY];
        }
        else
        {
            offsetY = config.offsetY;
        }
        
        var defaultX = (config.defaultX) ? config.defaultX : "right";
        var defaultY = (config.defaultY) ? config.defaultY : "top";
        
        var returnXY = new Array();

        if (targetX + overWidth - scrollWidth - offsetX[0]>= viewWidth  //right of overlay out of viewport
         || targetX + overWidth - offsetX[0] >= contX + contWidth)  //right  of overlay out of container
        {
            var x1 = (targetX + overWidth - scrollWidth - offsetX[0]) - viewWidth;
            var x2 = (targetX + overWidth - offsetX[0]) - (contX + contWidth);
            outofbounds.left = Math.max(x1,x2);
        }
        if (targetX - overWidth + targetWidth + offsetX[1] <= leftEdge) //left of overlay past edge
        {
            outofbounds.right = leftEdge - (targetX - overWidth + targetWidth + offsetX[1]);
        }

        if((defaultX=="right" && outofbounds.right === 0) //use right default
            || (outofbounds.right === 0 && outofbounds.left>0)) //use right since left out of bounds
        {
            returnXY.push(targetX - overWidth + targetWidth + offsetX[1]);
            returnPosX = "right";
        }
        else if (outofbounds.left>0 && outofbounds.right>0) //both are out, so we need to jiggle
        {
            if(outofbounds.right>outofbounds.left)
            {
                returnXY.push(targetX - offsetX[0] - outofbounds.left);
            }
            else
            {
                returnXY.push(targetX - overWidth + targetWidth + offsetX[1] + outofbounds.right);
            }
            returnPosX = defaultX;
        }
        else
        {
            returnXY.push(targetX - offsetX[0]);
            returnPosX = "left";
        }        
        
        if (targetY + targetHeight + overHeight - scrollHeight - offsetY[1] >= viewHeight //bottom of overlay out of viewport
         || ((config.ignoreTargetHeight == null) && (targetY + targetHeight + overHeight - offsetY[1] >= contY + contHeight)))  //bottom of overlay outside of container
        {
            var y1 = targetY + targetHeight + overHeight - scrollHeight - offsetY[1] - viewHeight;
            var y2 = targetY + targetHeight + overHeight - offsetY[1] - (contY + contHeight);
            outofbounds.bottom = Math.max(y1,y2);
        }
        if (targetY - overHeight + offsetY[0] <= topEdge)  //top of overlay past edge
        {
            outofbounds.top = topEdge - (targetY - overHeight + offsetY[0]);
        }
        
        if((defaultY=="top" && outofbounds.top === 0) //use top default
            || (outofbounds.top === 0 && outofbounds.bottom > 0)) //use top since bottom out of bounds
        {
            returnXY.push(targetY - overHeight - offsetY[0]);
            returnPosY = "top";
        }
        else if (outofbounds.top > 0 && outofbounds.bottom > 0) //both are out, so we need to jiggle
        {
            if(outofbounds.bottom>outofbounds.top)
            {
                returnXY.push(targetY - overHeight - offsetY[0] + outofbounds.top);
            }
            else
            {
                returnXY.push(targetY + targetHeight + offsetY[1] - outofbounds.bottom);
            }
            returnPosY = defaultY;
        }
        else
        {
            returnXY.push(targetY + targetHeight + offsetY[1]);
            returnPosY = "bottom";
        }
        
        //make sure we're on the screen
        if (returnXY[0] < 0)
        {
            returnXY[0] = 0;
        }
        if (returnXY[1] < 0)
        {
            returnXY[1] = 0;
        }
        
        if (config.returnPos)
        {
            return {"xy": returnXY, "pos": [returnPosX, returnPosY]};
        }
        else
        {
            return returnXY;
        }
    };
    
    //Add future page-wide listeners to this method
    this.swHandleClick = function (e)
    {
        var elTarget = YAHOO.util.Event.getTarget(e);
        if(!elTarget.tagName) //we called .click() manually, so we have a bad target
        {
            return;
        }

        var url;
        
        if (YAHOO.util.Dom.hasClass(elTarget, "sw_tooltip")) {
            var key = "";
            if (elTarget.id && elTarget.id.indexOf("sw_tooltip_") == 0) {
                key = elTarget.id.substring(11);
            } else if (elTarget.className && elTarget.className.indexOf("sw_tooltip_") != -1) {
                var tempClass = elTarget.className.substring(elTarget.className.indexOf("sw_tooltip_")+11);
                key = tempClass.split(" ")[0];
            }
            if (key.length > 0) {
                key = key.replace(/_/g, '-');
                YAHOO.shipwire.util.tooltips.showTooltip(key, elTarget);
                YAHOO.util.Event.preventDefault(e);
            }
        }
        else if (elTarget.tagName.toLowerCase() == "a" && YAHOO.util.Dom.hasClass(elTarget,"helpcenterLink") && elTarget.href)
        {
            url = elTarget.href;
            
            while(url.charAt(url.length-1)=="/")
            {
                url = url.substr(0,url.length-1);
            }
            
            if (url.indexOf("shipwire.com/w/support/")>=0) {
                var pieces = url.split("shipwire.com/w/support/");
                var target = pieces[0] + "shipwire.com/w/helpcenter/#" + pieces[1].replace(/\//g,"_");
            } else if (url.indexOf("shipwire.com/help/")>=0) {
                var pieces = url.split("shipwire.com/help/");
                var target = pieces[0] + "shipwire.com/w/helpcenter/#" + pieces[1].replace(/\//g,"_");
            } else {
                return;
            }
            
            YAHOO.shipwire.util.help.openPopup(target);
            elTarget.blur();
            YAHOO.util.Event.preventDefault(e);
        }
        else if (elTarget.tagName.toLowerCase() == "a" && YAHOO.util.Dom.hasClass(elTarget,"externalLink") && elTarget.href)
        {
            url = elTarget.href;
            
            window.open(url);
            YAHOO.util.Event.preventDefault(e);
        }
        else if (elTarget.parentNode && elTarget.parentNode.id == "help_search_more")
        {
            YAHOO.shipwire.util.help.openPopup(elTarget.href);
        }
    };
    YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName("sw_ext_pg"),"click",this.swHandleClick);
    
    this.initTransDlg = function(e)
    {
        var oSelf = YAHOO.shipwire.util;
                       
        var dialogCfg = {
            effect:{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.1},
            fixedcenter:true,
            modal:true,
            visible:false,
            draggable:false,
            underlay:"none",
            close: false,
            iframe: true,
            width: "135px"
        };

        if (oSelf.inEmbedded) {
            dialogCfg.fixedcenter = false;
            dialogCfg.x = (YAHOO.util.Dom.getViewportWidth() / 2) - 53;
            dialogCfg.y = 100;
        }       

        //set up transition dialog
        oSelf.transDlg = new YAHOO.widget.Panel("sw_transdlg", dialogCfg);        
        oSelf.transDlg.render(document.body);
    };
    YAHOO.util.Event.onContentReady("sw_transdlg", this.initTransDlg);

    /*
     *  toggleInline
     *  Hides all items with classname class and shows item with id
     */
    this.toggleInline = function(id, classname) 
    {
        var classdivs = YAHOO.util.Dom.getElementsByClassName(classname);
        for (var counter = 0; counter < classdivs.length; counter++)
        {
            classdivs[counter].style.display = 'none';
        }
        document.getElementById(id).style.display = 'inline';
    };
    
    /*
     *  parseAjaxResponse
     *  Generic AJAX response processor to check for generic errors before handler processing
     *  
     *  Inputs:
     *      o - YAHOO Connection response object.  Should contain o.argument.handler, the handler
     *          to be called when processing is done
     */
    this.parseAjaxResponse = function (o)
    {
        var data = YAHOO.lang.JSON.parse(o.responseText);
        
        if (data && data.session_error=="login") {
            if (YAHOO.shipwire.appmenu)
            {
                YAHOO.shipwire.appmenu.showAjaxLogin();
            }
                
            return;
        }
        
        if (o.argument && o.argument.handler) {
            o.argument.handler(o, data);
        }
    };
    
    /*
     *  centerOverlayAllowScroll
     *  Override the YUI container center prototype for panels that need to be centered but 
     *      might be larger than viewport
     *  
     */
    this.centerOverlayAllowScroll = function()
    {
        var nViewportOffset = YAHOO.widget.Overlay.VIEWPORT_OFFSET,
            elementWidth = this.element.offsetWidth,
            elementHeight = this.element.offsetHeight,
            viewPortWidth = YAHOO.util.Dom.getViewportWidth(),
            viewPortHeight = YAHOO.util.Dom.getViewportHeight(),
            x,
            y;

        if (elementWidth < viewPortWidth) {
            x = (viewPortWidth / 2) - (elementWidth / 2) + YAHOO.util.Dom.getDocumentScrollLeft();
        } else {
            x = nViewportOffset;
        }

        if (elementHeight < viewPortHeight) {
            y = (viewPortHeight / 2) - (elementHeight / 2) + YAHOO.util.Dom.getDocumentScrollTop();
        } else {
            y = nViewportOffset;
        }

        this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
        this.cfg.refireEvent("iframe");
    };

    this.parseVal = function(intval)
    {
        while (intval.charAt(0) == '0') {
            intval = intval.substring(1, intval.length);
        }

        return parseInt(intval);
    };

    this.jumpTo = function(id)
    {
        var pos = YAHOO.util.Dom.getXY(id);
        if (pos) {
            window.scroll(0,pos[1]);
        }
    };

    this.checkAll = function(className)
    {
        var index;
        var checkboxes = YAHOO.util.Dom.getElementsByClassName(className, "input");
        for (index in checkboxes) {
            checkboxes[index].checked = true;
        }
        return true;
    };


    this.getCheckedValue = function (radioObj)
    {
        if(!radioObj) {
            return "";
        }
        var radioLength = radioObj.length;
        if (radioLength == undefined) {
            if (radioObj.checked) {
                return radioObj.value;
            } else {
                return "";
            }
        }
        for(var i = 0; i < radioLength; i++) {
            if(radioObj[i].checked) {
                return radioObj[i].value;
            }
        }
        return "";
    };

    this.setCheckedValue = function (radioObj, val)
    {
        if (!radioObj) {
            return "";
        }
        
        var radioLength = radioObj.length;
        if (radioLength == undefined) {
            if (radioObj.value == val) {
                radioObj.checked = "checked";
                return true;
            } else {
                return false;
            }
        }

        for (var i = 0; i < radioLength; i++) {
            if(radioObj[i].value == val) {
                radioObj[i].checked = "checked";
                return true;
            }
        }
        return false;
    };

    this.html_entity_decode = function (str)
    {
        var ta=document.createElement("textarea");
        ta.innerHTML=str.replace(/</g,"&lt;").replace(/>/g,"&gt;");
        return ta.value;
    };

    this.isInteger = function (s)
    {
        if (parseInt(s, 10) == s) {
            return !isNaN( parseInt( s ) );
        } else {
            return false;
        }
    };

    this.setSelectByValue = function (elemId, compareVal) {
        var selector = document.getElementById(elemId);
        for (var index = 0; index < selector.options.length; index++) {
            if (selector.options[index].value == compareVal) {
                selector.options[index].selected = true;
            }
        }
    };

    this.hideFormElement = function (id)
    {
        var el = document.getElementById(id);
        if (el) {
            YAHOO.util.Dom.addClass(el, "hidden");
            el.disabled = true;
        }
    };

    this.showFormElement = function (id)
    {
        var el = document.getElementById(id);
        if (el) {
            YAHOO.util.Dom.removeClass(el, "hidden");
            el.disabled = false;
        }
    };
    
    /**
     * Context is always passed to this function
     */
    this.renderErrors = function (errors, parentContainer)
    {        
        var errorContainer = YAHOO.util.Selector.query( parentContainer + " .error-container", null, true );
        var errorList = YAHOO.util.Selector.query( parentContainer + " .error-container ul", null, true );
        var oldErrors = YAHOO.util.Selector.query( parentContainer + " .error-field" );
        
        var i;
        
        this.hasError = false;
        YAHOO.util.Dom.removeClass(errorContainer, "active");
        YAHOO.util.Dom.removeClass(oldErrors, "error-field");
        
        if (errors.length == 0) {
            return;
        }
        
        var errorListContent = "";
        var errorMessages = new Array();
        
        for (i = 0; i < errors.length; i++) {
            YAHOO.util.Dom.addClass(YAHOO.util.Dom.get(errors[i]), "error-field");
            errorListContent = errorListContent + "<li>" + this.errorsText[errors[i]] + "</li>";
        }
        errorList.innerHTML = errorListContent;
        YAHOO.util.Dom.addClass(errorContainer, "active");
        this.hasError = true;
    };
};
    
YAHOO.namespace("shipwire.util.help");
YAHOO.shipwire.util.help = new function()
{
    this.reqDelayID = -1;
    this.popup = null;
    this.popup_safari = null;
    this.searchField = "sw_help_search";
    this.maxResults = 6;
    
    this.readQuery = function()
    {
        var query = document.getElementById(this.searchField).value;
        if(query.length>0 && query!=document.getElementById(this.searchField).defaultValue)
        {
            return query;
        }
        else
        {
            return "";
        }
    };
    
    this.buildQuery = function(query, init)
    {
        var qStr = "";
        for (q in query) {
            qStr+=q+"="+query[q]+"&";
        }        
        if (init) {
            qStr += "init=true&";
        }        
        return qStr.slice(0,-1);
    };
    
    this.openPopup = function(url)
    {
        if (window.name == "sw_help_popup")
        {
            if (document.getElementById("sw_helpcanvas"))//if we're already in the popup, let it handle the click if there's a canvas
            {
                return;
            }
            else
            {
                window.location.href=url;
                
                if (window.location.pathname == "/w/helpcenter/") //we just changed the hash
                {
                    window.location.reload();
                }
            }
        }
        
        if(this.popup && this.popup.closed)
        {
            this.popup = null;
        }

        var needsRefresh;
        //see if popup is already open
        if (this.popup && this.popup.window && !this.popup.closed)
        {
            needsRefresh = true;
        }
        else
        {
            needsRefresh = false;
        }
        
        this.popup = window.open(url,"sw_help_popup","location=yes,menubar=no,height=500,width=829,scrollbars=yes,resizable=yes");
        
        if (needsRefresh)
        {
            this.popup.window.location.reload();
        }
        
        this.popup.focus();
    };
    this.handleSearchLinkClick = function(e)
    {
        var oSelf = YAHOO.shipwire.util.help;
        
        var elTarget = YAHOO.util.Event.getTarget(e);
        if(elTarget.tagName.toLowerCase() == "a" && !YAHOO.util.Dom.hasClass(elTarget,"nopop"))
        {
            //oSelf.openPopup(elTarget.href);
            //oSelf.hideFlyout(e);
        }
    };
    
    this.setSearchField = function(field)
    {
        this.searchField = field;
    };
    
    this.setMaxResults = function(maxResults)
    {
        this.maxResults = maxResults;
    };
    
    //YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName("helpflyoutbd","div","sw_helpflyout"),"click",this.handleSearchLinkClick);
};

YAHOO.namespace("shipwire.util.accordion");
YAHOO.shipwire.util.accordion = new function()
{
    this.hdClass="";
    this.hdClassActive="";
    this.bdClass="";
    this.pixelsPerSecond=1500;
    this.minAnimTime=.1;
    
    this.clickEvent = function(e)
    {
        var oSelf = YAHOO.shipwire.util.accordion;
        var elOldHd = YAHOO.util.Dom.getElementsByClassName(oSelf.hdClassActive)[0];
        if(elOldHd)
        {
            var elOldBd = oSelf.findContent(elOldHd);
            oSelf.closeSection(elOldHd, elOldBd);
        }
        
        if(this != elOldHd)
        {
            var elNewBd = oSelf.findContent(this);
            oSelf.openSection(this, elNewBd);
        }
    };
    
    this.findContent = function(el)
    {
        if (!el)
        {
            return null;
        }
        
        el = el.nextSibling;
        while(el.className != this.bdClass)
        {
            el = el.nextSibling;
        }
        
        return el;
    };
    
    this.closeSection = function(elHd, elBd)
    {
        var attributes = {
           height: {to: 0}
        };
        var closeAnim = new YAHOO.util.Anim(elBd, attributes);
        closeAnim.duration = Math.max(elBd.scrollHeight/this.pixelsPerSecond,this.minAnimTime);
        closeAnim.animate();
        YAHOO.util.Dom.removeClass(elHd,this.hdClassActive);
    };
    
    this.openSection = function(elHd, elBd)
    {
        if (!elHd || !elBd)
        {
            return;
        }
        
        var attributes = {
           height: {to: elBd.scrollHeight}
        };
        var openAnim = new YAHOO.util.Anim(elBd, attributes);
        openAnim.duration = Math.max(elBd.scrollHeight/this.pixelsPerSecond,this.minAnimTime);
        openAnim.onComplete.subscribe(function(){
            var el = this.getEl();
            el.style.height="auto";
        });
        openAnim.animate();
        YAHOO.util.Dom.addClass(elHd,this.hdClassActive);
    };

    this.openFirst = function()
    {
        var hd = YAHOO.util.Dom.getElementsByClassName(this.hdClass)[0];
        var bd = YAHOO.util.Dom.getElementsByClassName(this.bdClass)[0];
        this.openSection(hd, bd);
    };
    
    this.openNumber = function(integer)
    {
        var hd = YAHOO.util.Dom.getElementsByClassName(this.hdClass)[integer];
        var bd = YAHOO.util.Dom.getElementsByClassName(this.bdClass)[integer];
        this.openSection(hd, bd);
    };
    
    this.closeNumber = function(integer)
    {
        var hd = YAHOO.util.Dom.getElementsByClassName(this.hdClass)[integer];
        var bd = YAHOO.util.Dom.getElementsByClassName(this.bdClass)[integer];
        this.closeSection(hd, bd);
    };
    
    this.init = function(hdClass, hdClassActive, bdClass)
    {
        this.hdClass = hdClass;
        this.hdClassActive = hdClassActive;
        this.bdClass = bdClass;
        
        YAHOO.util.Event.addListener(
            YAHOO.util.Dom.getElementsByClassName("accordion_toggle"),
            "click",
            this.clickEvent
        );
    };
};

YAHOO.namespace("shipwire.util.tooltips");
YAHOO.shipwire.util.tooltips = new function()
{
    this.parent = YAHOO.shipwire.util;
    this.elTooltip = null;
    this.tooltipData = {};
    
    this.showTooltip = function (key, elTarget)
    {
        var oSelf = YAHOO.shipwire.util.tooltips;
        
        if(!oSelf.elTooltip)
        {
            oSelf.initTooltip();
        }
        oSelf.elTooltip.cfg.setProperty("zIndex", 1111);

        var obj = this.tooltipData[key];

        //fail gracefully if tooltip wasn't fetched
        if (!obj) {
            return;
        }
        
        var title = (obj.title) ? decodeURIComponent(obj.title) : "";
        var text = (obj.text) ? decodeURIComponent(obj.text) : "";
        if (obj.moreLink)
        {
            text += '<div class="learnmore"><a target="_blank" href="' + decodeURIComponent(obj.moreLink) + '">Learn more &raquo;</a></div>';
        }
        else if (obj.hcLink)
        {
            text += '<div class="learnmore"><a class="helpcenterLink" href="' + decodeURIComponent(obj.hcLink) + '">Learn more &raquo;</a></div>';
        }
        
        oSelf.elTooltip.setHeader(title);
        oSelf.elTooltip.setBody(text);
        
        var config = {defaultX: "right", defaultY: "top", offsetX: 20, offsetY: 0};
        var xy = oSelf.parent.fitOverlayToViewport(document.getElementById("sw_tooltipdlg"),elTarget,config);
        oSelf.elTooltip.cfg.setProperty("xy", xy);
        oSelf.elTooltip.show();
    };
    
    this.initTooltip = function()
    {
        this.elTooltip = new YAHOO.widget.Overlay("sw_tooltipdlg", 
        {
            visible:false,
            underlay:"none",
            close: false
        });
        YAHOO.util.Event.addListener("sw_tooltipdlg","click",this.handleTooltipClick);
    };
    
    this.handleTooltipClick = function(e)
    {
        var oSelf = YAHOO.shipwire.util.tooltips;
        
        var elTarget = YAHOO.util.Event.getTarget(e);
        if (elTarget.className == "close")
        {
            oSelf.hideTooltip();
            YAHOO.util.Event.preventDefault(e);
        }
        else if (elTarget.tagName.toLowerCase() == "a" && YAHOO.util.Dom.hasClass(elTarget.parentNode,"learnmore") && !YAHOO.util.Dom.hasClass(elTarget,"helpcenterLink"))
        {
            YAHOO.util.Event.preventDefault(e);
            return helpPopup(elTarget, {target: 'popup', width: 830, height: null});
        }
        return false;
    };
    
    this.hideTooltip = function()
    {
        if (this.elTooltip)
        {
            this.elTooltip.hide();
            this.elTooltip.cfg.setProperty("zIndex", 2);
        }
    };

    this.setTooltipData = function(data)
    {
        var prop;

        for (prop in data) {
            this.tooltipData[prop] = data[prop];
        }
    };

    this.clearTooltipData = function()
    {
        this.tooltipData = {};
    };
};

YAHOO.namespace("shipwire.util.verifyAddr");
YAHOO.shipwire.util.verifyAddr = new function()
{
    this.elFields = null;
    //All inputs are elements, not the values (needed for highlighting)
    this.verify = function(elAddr1,elAddr2,elAddr3,elCity,elState,elZip)
    {
        var callback =
        {
            success: this.success,
            failure: this.failure,
            timeout: 10000,
            argument: {elAddr1: elAddr1,
                        elAddr2: elAddr2,
                        elAddr3: elAddr3,
                        elCity: elCity,
                        elState: elState,
                        elZip: elZip
            }
        };
        var query = "addr1=" + elAddr1.value
                  + "&addr2=" + elAddr2.value
                  + "&addr3=" + elAddr3.value
                  + "&city=" + elCity.value
                  + "&state=" + elState.value
                  + "&zip=" + elZip.value;
        var connection = YAHOO.util.Connect.asyncRequest("POST", '/services/address/verify/', callback, query);
    };
    
    this.success = function(o)
    {
        //debugger;
        var oSelf = YAHOO.shipwire.util.verifyAddr;
        var result = YAHOO.lang.JSON.parse(o.responseText);
        oSelf.elFields = o.argument;
        
        if (result.code==32 || result.code==31)
        {
            //oSelf.setValidIcon();
        }
        else if (result.code==10 || result.code==22 || result.code==25)
        {
            oSelf.setErrorFields(Array(oSelf.elFields.elAddr1,oSelf.elFields.elAddr2,oSelf.elFields.elAddr3));
            //oSelf.setErrorIcon("There is a problem with this street address.  Please correct it or select &quot;Force address&quot; if you are sure it is correct","addr1");
        }
        else if (result.code==11 || result.code==12 || result.code==13)
        {
            oSelf.setErrorFields(Array(oSelf.elFields.elCity,oSelf.elFields.elState,oSelf.elFields.elZip));
            //oSelf.setErrorIcon("There is a problem with this city/state/zip code.  Please correct it or select &quot;Force address&quot; if you are sure it is correct","city");
        }
        else
        {
            oSelf.setErrorFields();
            //oSelf.setErrorIcon("There is a problem with this address.  Please correct it or select &quot;Force address&quot; if you are sure it is correct","addr1");
        }
    };
    
    this.failure = function(o)
    {
        return;
    };
    
    this.setErrorFields = function(fieldList)
    {
        this.clearErrorFields();
     
        if(!fieldList || !fieldList.length)
        {
            fieldList = this.elFields;
        }
        
        //forceAddress.hasError = true;
        
        /*field_list = field_list || "";
        var fields = formElements.getRows(field_list);
        for(var i=0;i<fields.length;i++)
        {
            YAHOO.util.Dom.addClass(fields[i],"error_msg");
        }
        */
        for (var field in fieldList)
        {
            YAHOO.util.Dom.addClass(field,"error");
        }
    };
    
    this.setErrorIcon = function(error, field)
    {
        return;
        var fields = formElements.getFields(Array(field));
        
        errorTooltip = new YAHOO.widget.Tooltip("errorTooltip", {context:"form_alert", text:error} ); 
        fields[0].parentNode.appendChild(document.getElementById("form_alert"));
        errorTooltip.setBody(error);
        document.getElementById("form_alert").style.display="block";
    };
    
    this.setValidIcon = function()
    {
        return;
        this.clearErrorFields();
        
        var fields = formElements.getFields(Array("addr1"));
        YAHOO.util.Dom.addClass(fields[0],"valid_msg");
        document.getElementById("valid_address").style.display="block";
    };
    
    this.clearErrorFields = function()
    {
        for (var field in this.elFields)
        {
            YAHOO.util.Dom.removeClass(field,"error");
        }
        return;
        forceAddress.hasError = false;
        errorTooltip = null;
        var fields = formElements.getRows();
        for(var i=0;i<fields.length;i++)
        {
            YAHOO.util.Dom.removeClass(fields[i],"error_msg");
            YAHOO.util.Dom.removeClass(fields[i],"valid_msg");
        }
        document.getElementById("form_alert").style.display="none";
        document.getElementById("valid_address").style.display="none";
        document.getElementById("verify_addr").style.display="none";
    };
};

//functions used by pricing and custom pricing pages
YAHOO.namespace("shipwire.util.pricing");
YAHOO.shipwire.util.pricing = new function()
{
    this.signUp = function (plan, dlg)
    {
        var signUp = document.getElementById("signuppop");
        var h3s = signUp.getElementsByTagName("h3");
        var h3 = h3s[0];
        h3.replaceChild(document.createTextNode("Sign Up for the " + plan + " Plan"), h3.firstChild);
        document.getElementById("priceplan").value = plan.toLowerCase();
        dlg.show();
        document.getElementById('userpop').focus();
    }

    this.updatePricePlan = function ()
    {
        if (document.getElementById('priceplan').value == 'revert') {
            this.postUpdatePrice();
        } else if (document.getElementById('sw_appcanvas_errorbox_invalid').style.display == 'none') {
            var pricecfg = new Array();
            pricecfg.title = 'Confirm Pricing Plan ' + YAHOO.shipwire.util.customPricingAction;
            pricecfg.text = YAHOO.shipwire.util.updatePriceMsg;
            pricecfg.noBtnText = 'Cancel';
            pricecfg.yesBtnText = 'Save';
            pricecfg.yesBtnColor = 'green';
            pricecfg.noBtnColor = 'green';
            YAHOO.shipwire.util.showConfirmDlg(pricecfg,this.postUpdatePrice,null);
        } else {
            YAHOO.shipwire.util.showAlertDlg('Cannot Change Plan', document.getElementById('errorbox_div_invalid').innerHTML);
        }
    };

    this.postUpdatePrice = function ()
    {
        document.getElementById('update_price').click();
    };
    
    this.priceHandler = function (o)
    {
        var oSelf = YAHOO.shipwire.util.pricing;
        
        var jsonObj = eval("(" + o.responseText + ")");
        var newPrice = jsonObj.price;
        var price1 = document.getElementById("price1");
        var price2 = document.getElementById("price2");
        var subtotal_storage = document.getElementById("subtotal_storage");
        var subtotal_handling = document.getElementById("subtotal_handling");
        var overplan_price = document.getElementById("overplan_price");
        var per_item_price = document.getElementById("per_item_price");
        var num_monthly_items = document.getElementById("num_monthly_items");
        var errorclass;

        if (price1) {
            price1.innerHTML = '$' + newPrice;
            var price1Anim = new YAHOO.util.ColorAnim(price1, {color: {from: '#ff9519', to: '#4A8797'}}, 1, YAHOO.util.Easing.easeOut);
            price1Anim.animate();
            document.getElementById('permonthspan1').innerHTML = jsonObj.permonthspan1;
        }

        if (price2) {
            price2.innerHTML = '$' + newPrice;
            var price2Anim = new YAHOO.util.ColorAnim(price2, {color: {from: '#ff9519', to: '#4A8797'}}, 1, YAHOO.util.Easing.easeOut);
            price2Anim.animate();
            document.getElementById('permonthspan2').innerHTML = jsonObj.permonthspan2;
        }

        if (subtotal_storage) {
            subtotal_storage.innerHTML = '$' + jsonObj.price_storage;
            var subtotal_storageAnim = new YAHOO.util.ColorAnim(subtotal_storage, {color: {from: '#ff9519', to: '#4A8797'}}, 1, YAHOO.util.Easing.easeOut);
            subtotal_storageAnim.animate();
        }

        if (subtotal_handling) {
            subtotal_handling.innerHTML = '$' + jsonObj.price_handling;
            var subtotal_handlingAnim = new YAHOO.util.ColorAnim(subtotal_handling, {color: {from: '#ff9519', to: '#4A8797'}}, 1, YAHOO.util.Easing.easeOut);
            subtotal_handlingAnim.animate();
        }

        if (overplan_price) {
            overplan_price.innerHTML = '$' + jsonObj.price_additional_items;
            var overplan_priceAnim = new YAHOO.util.ColorAnim(overplan_price, {color: {from: '#ff9519', to: '#4A8797'}}, 1, YAHOO.util.Easing.easeOut);
            overplan_priceAnim.animate();
        }

        if (per_item_price) {
            per_item_price.innerHTML = '$' + jsonObj.price_per_item;
            var per_item_priceAnim = new YAHOO.util.ColorAnim(per_item_price, {color: {from: '#ff9519', to: '#4A8797'}}, 1, YAHOO.util.Easing.easeOut);
            per_item_priceAnim.animate();
        }

        if (num_monthly_items) {
            num_monthly_items.innerHTML = jsonObj.num_monthly_items;
        }
  
        for (var jsonfield in jsonObj) {
            if (jsonfield != 'price') {
                if (jsonfield.indexOf('delta') != -1 && document.getElementById(jsonfield)) {
                    document.getElementById(jsonfield).innerHTML = oSelf.upsellFormat(jsonObj[jsonfield], jsonfield);
                }
            }
        }

        YAHOO.shipwire.util.updatePriceMsg = jsonObj.updatePriceMsg;
        YAHOO.shipwire.util.customPricingAction = jsonObj.customPricingAction;
        
        if (document.getElementById('sw_appcanvas_errorbox_ach')) {
            errorclass = new ErrorClass('custompricingform');
            if (parseInt(newPrice) >= 300) {
                errorclass.adderror('ach', 1, 'This pricing plan requires you to change your billing method to bank direct deposit or PayPal');
                errorclass.errordialog();
            } else {
                YAHOO.shipwire.appmenu.hideErrorBox('ach');
            }
        }

        if (document.getElementById('sw_appcanvas_errorbox_invalid')) {
            errorclass = new ErrorClass('custompricingform');
            if (jsonObj['invalidupgrade'] == 'lowbalance') {
                errorclass.adderror('invalid', 1, 'Your available balance is less than the amount needed to complete this upgrade. Please go to Add Money (under My Account) to add the necessary funds.');
                errorclass.errordialog();
                YAHOO.util.Dom.addClass("signup_btn","off");
            } else if (jsonObj['invalidupgrade'] == 'skus') {
                errorclass.adderror('invalid', 1, 'You have too many active SKUs for this plan');
                errorclass.errordialog();
                YAHOO.util.Dom.addClass("signup_btn","off");
            } else if (jsonObj['invalidupgrade'] == 'storage') {
                errorclass.adderror('invalid', 1, 'You are using too much storage space for this plan');
                errorclass.errordialog();
                YAHOO.util.Dom.addClass("signup_btn","off");
            } else if (jsonObj['invalidupgrade'] == 'nochange') {
                errorclass.adderror('invalid', 1, 'You have not made any changes');
                errorclass.errordialog();
                YAHOO.util.Dom.addClass("signup_btn","off");
            } else {
                YAHOO.shipwire.appmenu.hideErrorBox('invalid');
                YAHOO.util.Dom.removeClass("signup_btn","off");
            }
        }
    };

    this.runCompute = function (e)
    {
        if (e) {  //if we're changing a value
            var elTarget = YAHOO.util.Event.getTarget(e);
            if (elTarget && elTarget.id == "twelvemo" && elTarget.checked) {
                document.getElementById('threemo').checked = false;
            } else if (elTarget && elTarget.id == "threemo" && elTarget.checked) {
                document.getElementById('twelvemo').checked = false;
            }
        }

        if (document.getElementById('insurance_1')) {
            if (document.getElementById('insurance_1').checked) {
                YAHOO.util.Dom.removeClass("insurance_details", "hidden");
                YAHOO.shipwire.util.showFormElement("insurance_coverage_select");
                YAHOO.shipwire.util.showFormElement("insurance_deductable_select");
            } else {
                YAHOO.util.Dom.addClass("insurance_details", "hidden");
                YAHOO.shipwire.util.hideFormElement("insurance_coverage_select");
                YAHOO.shipwire.util.hideFormElement("insurance_deductable_select");
            }
        }

        if (this.type=="radio" && !this.checked) {
            return false;
        }

        var callback =
        {
            success: YAHOO.shipwire.util.pricing.priceHandler,
            failure: function (o) {},
            timeout: 5000
        };
        var pricingForm = document.getElementById("custompricingform");
        var proc = "/custompricing/compute"; // should return something like "{ 'price': '$200' }"
        YAHOO.shipwire.util.pricing.checkOptions();
        YAHOO.util.Connect.setForm(pricingForm);
        var connection = YAHOO.util.Connect.asyncRequest("POST", proc, callback);
        return true;
    };

    this.checkOptions = function ()
    {
        if (document.getElementById("storageunits_2").checked) {
            YAHOO.shipwire.util.setSelectByValue("max_storage_ft3", document.getElementById("max_storage_pallets").value*64);
        } else {
            YAHOO.shipwire.util.setSelectByValue("max_storage_pallets", document.getElementById("max_storage_ft3").value/64);
        }
    };

    this.upsellFormat = function (cost, field)
    {
        var minusvar = 'Save ';
        var checkid = field.replace('delta','');
        if (checkid == field) {
            return '';
        }
        if (field == 'standarddelta' || field == 'silverdelta' || field == 'golddelta') {
            minusvar = 'Save ';
        }
        if (cost < 0) {
            return minusvar + '$<strong>' + Math.abs(cost) + '</strong>/month';
        } else if (cost > 0) {
            return '<strong>$' + cost + '</strong>/month';
        } else if (document.getElementById(checkid).checked) {
            return '<span class="included">(included)</span>';
        } else {
            return '<strong>$0</strong>/month';
        }
    };
};

//functions used by free trial and clicknship signup pages
YAHOO.namespace("shipwire.util.signup");
YAHOO.shipwire.util.signup = new function()
{
    this.validate = function (e, data)
    {
        var oSelf = YAHOO.shipwire.util.signup;
        var elTarget = YAHOO.util.Event.getTarget(e);
        var errorElem;
        var errorMsg = "";

        if (!oSelf.isValidEmail(elTarget.username.value)) {
            errorMsg = "Please enter a valid e-mail address";
        } else if (!oSelf.isValidPassword(elTarget.password.value)) {
            errorMsg = "Please enter a password at least four characters long";
        } else if (!oSelf.isValidRetype(elTarget.retype.value, elTarget.password.value)) {
            errorMsg = "Your passwords do not match";
        }

        if (errorMsg != "") {
            errorElem = document.getElementById(data.errorid);
            errorMsg = document.createTextNode(errorMsg);
            if (errorElem) {
                errorElem.replaceChild(errorMsg, errorElem.firstChild);
            } else {
                errorElem = document.createElement("p");
                errorElem.id = data.errorid;
                document.getElementById(data.anchorid).appendChild(errorElem);
                errorElem.appendChild(errorMsg);
            }
            YAHOO.util.Event.preventDefault(e);
            return false;
        }
        return true;
    };

    this.isValidEmail = function (value)
    {
        var emailPattern = new RegExp(/^(("[\w-+\s]+")|([\w-+]+(?:\.[\w-+]+)*)|("[\w-+\s]+")([\w-+]+(?:\.[\w-+]+)*))(@((?:[\w-+]+\.)*\w[\w-+]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][\d]\.|1[\d]{2}\.|[\d]{1,2}\.))((25[0-5]|2[0-4][\d]|1[\d]{2}|[\d]{1,2})\.){2}(25[0-5]|2[0-4][\d]|1[\d]{2}|[\d]{1,2})\]?$)/i);
        return emailPattern.test(value);
    };

    this.isValidPassword = function (value)
    {
        return (value.length >= 4);
    };

    this.isValidRetype = function (value1, value2)
    {
        return (value1 == value2);
    };
};

// TODO: rename to toggleBlock
function toggleDiv(id, classname) {
    var classdivs = YAHOO.util.Dom.getElementsByClassName(classname);
    for (var counter = 0; counter < classdivs.length; counter++) {
        classdivs[counter].style.display = 'none';
    }
    var divobj = document.getElementById(id);
    if (divobj) divobj.style.display = 'block';
}

function genericAjax(successaction, form, proc, params)
{
  var callback =
   {
      success: successaction,
      failure: function(o) {}, 
      timeout: 5000
   };
   
  if (form)
      YAHOO.util.Connect.setForm(form);
  else
      YAHOO.util.Connect.resetFormState();
      
  return YAHOO.util.Connect.asyncRequest("POST", proc, callback, params);
}

    
function HideContent(d) {
    var el = document.getElementById(d);
    if (el)
    {
        el.style.display = "none";
    }
}
function ShowContent(d,value) {
    if(!value)
    {
        value="block";
    }
    var el = document.getElementById(d);
    if (el)
    {
        el.style.display = value;
    }
}

/**
 * Raise a help popup window, defaulting to "standard" size and name.
 *
 * (If your project is using GXPs, consider using {@link PopUpLink.gxp}.)
 *
 * @param {Object} linkRef if this is a String, it will be used as the URL
 * of the popped window; otherwise it's assumed to be an HTMLAnchorElement
 * (or some other object with "target" and "href" properties).
 *
 * @param {Object} options supports the following options:
 *  target: (Object) target (window name). If null, linkRef.target will
 *          be used. If *that's* null, the default is "popup".
 *  width: (Number) window width. If null, the default is 690.
 *  height: (Number) window height. If null, the default is 500.
 *  toolbar: (Boolean) show toolbar
 *  scrollbars: (Boolean) show scrollbars
 *  location: (Boolean) show location
 *  statusbar: (Boolean) show statusbar
 *  menubar: (Boolean) show menubar
 *  resizable: (Boolean) resizable
 *
 * @return {Boolean} true if the window was not popped up, false if it was.
 *
 */
helpPopup = function(linkRef, options) {
 var DEFAULT_POPUP_TARGET = 'popup';
 var DEFAULT_POPUP_HEIGHT = 500;
 var DEFAULT_POPUP_WIDTH = 690;

 if (!window.focus) return true;

 var default_options = {
   width: DEFAULT_POPUP_WIDTH,
   height: DEFAULT_POPUP_HEIGHT,
   toolbar: 1,
   scrollbars: 1,
   location: 1,
   statusbar: 1,
   menubar: 1,
   resizable: 1
 };

 options = options || {};
 for (var option in default_options) {
   if ((! (option in options)) || options[option] === null) {
     options[option] = default_options[option];
   }
 }

 var href = typeof linkRef == 'string' ? linkRef : linkRef.href;
 var target = options.target || linkRef.target || DEFAULT_POPUP_TARGET;
 delete options['target'];

 var optionString = '';
 for (option in options) {
   if (optionString != '') optionString += ',';
   optionString += option + '=' +
     (options[option] === true ? '1' :
        (options[option] === false ? '0' : options[option]));
 }

 var newWin = window.open(href, target, optionString);
 newWin.focus();

 return false;
};

YAHOO.namespace("shipwire.passwordReset");
YAHOO.shipwire.passwordReset = {
        
        hasError: false,
        modal: null,
        
        init: function() {
            if (this.modal != null) {
                return;
            }
            this.modal = new Modal ("reset-password", ".show-password-reset-dialogue");
            var forgotPassword = yuiSelector.query("a.show-password-reset-dialogue");
            YAHOO.util.Event.addListener("reset-password-form", "submit", this.submitForm);
            YAHOO.util.Event.addListener(forgotPassword, "click", YAHOO.shipwire.passwordReset.click);
            this.modal.overlayOutAnim.onComplete.subscribe(function(){
                YAHOO.shipwire.util.renderErrors.apply(self, [[], "#reset-password"]);
            });
        },
        
        click: function(e){
            YAHOO.util.Event.preventDefault(e);
            var self = YAHOO.shipwire.passwordReset;
            var callback = {
                success: function(o) {
                    var response = YAHOO.lang.JSON.parse(o.responseText);
                    YAHOO.util.Dom.get("password_captcha").innerHTML = response.img;
                    YAHOO.util.Dom.get("cid").value = response.id;
                    
                    var c = YAHOO.util.Dom.get("forgot_captcha");
                    var u = YAHOO.util.Dom.get("forgot_username");
                    
                    if (c.getAttribute("placeholder") != c.value) {
                        c.value = "";
                    }
                    if (u.getAttribute("placeholder") != u.value) {
                        u.value = "";
                    }
                    
                    YAHOO.util.Dom.addClass("reset-password-input", "active");
                    YAHOO.util.Dom.removeClass("reset-password-done", "active");
                    self.modal.open(new YAHOO.util.CustomEvent("null"));
                },
                failure: function(o) {}
            };
            YAHOO.util.Connect.asyncRequest("GET", "/documents/captcha", callback);
        },
        
        submitForm: function (e) {
            YAHOO.util.Event.preventDefault(e);
            var submitButton = YAHOO.util.Selector.query("#reset-password button.cta-button", null, true);
            if ( YAHOO.util.Dom.hasClass(submitButton, "disabled") == true ) {
                return;
            }
            YAHOO.util.Dom.addClass(submitButton, "disabled");
            
            var self = YAHOO.shipwire.passwordReset;
            
            var callback = {
                success: self.submitFormHandler,
                failure: function(o) {}
            };
            
            this.forgot_captcha.value = YAHOO.shipwire.util.getValue("forgot_captcha");
            this.forgot_username.value = YAHOO.shipwire.util.getValue("forgot_username");
                                    
            YAHOO.util.Connect.setForm(this);            
            var connection = YAHOO.util.Connect.asyncRequest("POST", this.action, callback);
        },
        
        submitFormHandler: function (o) {
            var response = YAHOO.lang.JSON.parse(o.responseText);
            
            if (response.status == "ERR") {
                YAHOO.util.Dom.get("password_captcha").innerHTML = response.captcha.img;
                YAHOO.util.Dom.get("cid").value = response.captcha.id;
                YAHOO.util.Dom.get("forgot_captcha").value = "";
                
                if (YAHOO.env.ua.ie || (YAHOO.env.ua.gecko && YAHOO.env.ua.gecko < 2)) {
                    YAHOO.util.Dom.get("forgot_captcha").focus();
                    YAHOO.util.Dom.get("forgot_captcha").blur();
                    YAHOO.util.Dom.get("forgot_username").focus();
                    YAHOO.util.Dom.get("forgot_username").blur();
                }
                
                YAHOO.shipwire.util.renderErrors.apply(YAHOO.shipwire.passwordReset, [response.data, "#reset-password"]);
                
            } else {
                YAHOO.util.Dom.removeClass("reset-password-input", "active");
                YAHOO.util.Dom.addClass("reset-password-done", "active");
                var timeout = setTimeout(function(){YAHOO.shipwire.passwordReset.modal.close(new YAHOO.util.CustomEvent('dummy'))}, 5000);
            }
            
            YAHOO.util.Dom.removeClass(YAHOO.util.Selector.query("#reset-password button.cta-button", null, true), "disabled");
        },
        
        errorsText: {
            "forgot_username" : "<p>E-mail address <span>is invalid or unrecognized.</span></p>",
            "forgot_captcha" : "<p>Characters <span>did not match the ones in the image.</span></p>"
        }        
};
