// DLM class
// Params: (parameters dlmParams, containerId and linkId are optional)
//    cid - customer ID number
//    url - URL of a file to be downloaded
//    dlmParams - associative array (object) of DLM properties to be set for this download, 
//                such as downloadName, i.e., {"downloadName":"DLM"};
//                can be skipped completely or left empty {} if following params are needed
//    containerId - optional parameter specifying a DIV element's ID
//                  into which this DLM will be automatically deployed
//    linkId - optional parameter specifying link or button element's ID
//             the onclick event of which is going to be used to start the download
function DLM( cid, url, dlmParams, containerId, linkId )
{
    // Internal state variables.
    var me                = document.createElement( "div" );
    me.prototype          = DLM;
    me.urlSetId           = null; 
    me.registeredUrl      = false;   
    me.initialized        = false;
    me.style.display      = "none";
    me.className          = "DLM";
    me.intendedState      = "STOPPED";
    me.polling            = false;
    me.computedLanguage   = "en"; // Set by calling 'me.setLanguage';
    me.pauseBlackout      = false;
    me.shouldWait        = false;   // If true we will start out paused.

    me.clientWasAlreadyInstalled = false;

    // Time estimation state variables.
    me.lastETA = 0;
    me.mult    = 0.80;

    // User configuration variables.
    me.openOnComplete    = true;
    me.cid               = cid;
    me.downloadName      = "";
    me.exeName           = "";
    me.languageDefault   = "en";
    me.language          = "auto";
    me.targetSpeed       = "";
    me.url               = url;
    me.ignoreQueryString = false;
    me.downloadPath      = ""; // "prompt"|empty string (for cache)
    me.originOnly        = true;
    me.cookiestring      = "";
    me.queryauth         = "";
    me.basicauth_username = "";
    me.basicauth_password = "";
    me.resumable         = false;
    me.resumeURL         = "";
    me.autopause         = true;
    me.onComplete        = null;
    me.onCancel          = null;
    me.onProgress        = null;
    me.onStatusUpdate    = null;

    me.requireEULA       = false;
    me.eulaVersion       = "DLM3/2008-07-01v1.0";

    // Set up the defaults for the file we'll be downloading.
    me.file            = new Object();
    me.file.dlrate     = 0;
    me.file.path       = "";
    me.file.size       = 0;
    me.file.dlStatus   = "WAITING";
    me.file.uniquerecv = 0;

    // Set user-specified parameters
    if ( dlmParams && typeof( dlmParams ) == "object" ) {
        for ( par in dlmParams ) me[ par ] = dlmParams[ par ];
    }

    // We put ourself in the global list of DLMs and keep track of where we are in that list.
    me.dlmId = DLMHelper.register( me );

    // Message shown to explain paused status (e.g., file not found) 
    me.pausedStatusReason = "";

    // ################################################################################################################
    me.setCookieAuth = function( cookieString ) {
      me.cookiestring = cookieString;
      if ( !cookieString ) {
        me.cookiestring = "";
      }
    }

    // ################################################################################################################
    me.setQueryAuth = function( queryAuth ) {
      me.queryauth = queryAuth;
      if ( !queryAuth ) {
        me.queryauth = "";
      }
    }

    // ################################################################################################################
    me.setBasicAuth = function( basicAuthUsername, basicAuthPassword ) {
      me.basicauth_username = basicAuthUsername;
      me.basicauth_password = basicAuthPassword;
      if ( !basicAuthUsername && !basicAuthPassword ) {
        me.basicauth_username = "";
        me.basicauth_password = "";
      }
    }

    // ################################################################################################################
    me.beginDownload = function(){
        DLMHelper.log( "downloadClicked" );

        // Make sure that we've initialized all our localized strings, and that the window is visible.
        me.setLanguage();
        me.style.display = "block";

        // Hack for IE, since it doesn't like setting this for elements not already in the DOM.
        // Presumably we're in the DOM by now (hopefully).
        me._autoStartCheckbox.checked = me.openOnComplete ? true : false; 

        // "STOPPED" is the state that new DLMs are in before ever being requested to download anything. If we're in
        // this state, we check to see if the client's installed, and if so, try and download our file. If not, we
        // tell the helper library to install it for us and wait for the client to get installed.
        if ( me.intendedState == "STOPPED" || me.intendedState == "CANCELLED") {
            
            // If EULA Unaccepted and required...
            if ( !DLMHelper.acceptedEULA && me.requireEULA ) {
                me.intendedState = "EULAPROMPT";
                me.setUIState( "EULAPROMPT" );
            }
            // If we're not installed...
            else if ( !DLMHelper.installed ) {
                me.intendedState = "DOWNLOADING";
                me.setUIState( "WAITING" );
                DLMHelper.startInstall( me.exeName );
            }
            // Must be installed and EULA accepted or not required...
            else {
              if ( me.shouldWait ) {
                me.intendedState = "PAUSED";
                me._pauseImg.className = "DLMResume";
              } else {
                me.intendedState = "DOWNLOADING";
                me._pauseImg.className = "DLMpause";
              }
              me.setUIState( "DOWNLOADING" );
              me.clientWasAlreadyInstalled = true;
              me.download( );
              if ( !me.polling ) {
                me.poll();
              }
            }
        }

        // If the state is anything other than "STOPPED", then we've already done all
        // this, so we just silently return.
    }

    // ################################################################################################################
    me.beginDownloadPaused = function() {
      me.shouldWait = true;
      me.beginDownload();
    }

    // ################################################################################################################
    me.unpause = function() {
      me.shouldWait = false;
      if ( me.intendedState == "PAUSED") {
        me.pauseResume();
      }
    }

    // ################################################################################################################
    me.createElement = function( type, className, attribs ) {
        var e = document.createElement( type );
        e.className = "DLM" + className;
        for ( a in attribs ) e.setAttribute( a, attribs[ a ] );
        return e;
    }

    // ################################################################################################################
    // Tells the client to start downloading the current value of 'me.url'.
    me.download = function(){
        if ( !DLMHelper.installed ) return;

        var dlURL  = "";
        // Get a url set id
        if ( !me.urlSetId ) {
          dlURL = "http://127.0.0.1:9421/api?function=createUrlSet&cid=" + me.cid;
          DLMHelper.sendRequest( me.dlmId, "CREATE_URL_SET", dlURL );
          return;
        }

        var dlPath = "";
        var iqs    = "";
        var ts     = "";
        var cs     = "";
        var qa     = "";
        var ba     = "";
        var saveAs = "";
        var oo     = "";
        var url    = me.url;
        var res    = "";
        var resurl = "";
        var resfilename = "";
        var autopause = "";
        var wait = "";

        if ( me.ignoreQueryString ) {
            iqs = "&originurl=" + encodeURIComponent( me.url );
            url = url.replace( /\?.*$/, "" );
        }
        if ( me.originOnly               ) oo     = "&originonly";
        if ( me.targetSpeed              ) ts     = "&targetspeed=" + me.targetSpeed;
        if ( me.downloadPath == "prompt" ) saveAs = "&saveas=true";
        if ( me.cookiestring             ) cs     = "&cookiestring=" + encodeURIComponent( me.cookiestring );
        if ( me.queryauth                ) qa     = "&queryauth=" + encodeURIComponent( me.queryauth );
        if ( me.basicauth_username && me.basicauth_password ) {
            ba = "&basicauth=" + encodeURIComponent( me.authString( me.basicauth_username, me.basicauth_password ) );
        }
        if ( me.resumable && me.resumeURL ) {
          res    = "&resumable=true";
          resurl = "&resumeurl=" + encodeURIComponent( me.resumeURL );
          if ( me.downloadName )
          {
            resfilename = "&resumefilename=" + encodeURIComponent( me.downloadName );
          }
        }
        if ( me.autopause             ) autopause = "&autopause=30";
        if ( me.shouldWait              ) wait = "&wait=true"; 

        dlURL = "http://127.0.0.1:9421/api?function=downloadFile" + autopause + "&cid=" + me.cid + "&url=" + 
          encodeURIComponent( url ) + ts + iqs + saveAs + dlPath + oo + cs + qa + ba + res + resurl + 
          resfilename + wait + "&urlSetId=" + me.urlSetId;
        if ( !me.registeredUrl ) {
          DLMHelper.sendRequest( me.dlmId, "REGISTER", dlURL );
        } else if ( ! me.initialized ) {
          // Note: if neither wait nor saveas is set, this will start the download
          dlURL = "http://127.0.0.1:9421/api?function=closeUrlSet" + wait + "&cid=" + me.cid + 
            "&urlSetId=" + me.urlSetId;
          if ( me.downloadPath == "prompt" ) {
            dlURL += "&saveas=true";
          }
          DLMHelper.sendRequest( me.dlmId, "CLOSE_URL_SET", dlURL );
          // Note: if wait is not set but saveas is, this will start the download
        } else {
          // Note: we are only normally here because of pause/resume
          DLMHelper.sendRequest( me.dlmId, "DOWNLOAD", dlURL );
        }
    }

    // ################################################################################################################
    // Take a number of seconds and create a nicely formatted, localized string representing the same amount of time.
    me.formatTime = function( seconds ) {
        if ( seconds <= 0 ) return "";
        seconds = Math.round( seconds );
        if ( seconds == 1 ) return "1 " + me.localize( "second" );
        if ( seconds < 60 ) return seconds + " " + me.localize( "seconds" );
        if ( seconds < ( 60 * 60 ) ) {
            if ( Math.round( seconds / 60 ) == 1 ) return "1 " + me.localize( "minute" );
            else return ( Math.round( seconds / 60 ) ) + " " + me.localize( "minutes" );
        }
        var minutes = Math.floor( seconds / 60 );
        var hours =   Math.floor( minutes / 60 );
        minutes %= 60;
        if ( isNaN( hours ) || isNaN( minutes ) ) return "";
        return hours + me.localize( "hourAbbr" ) + ", " + minutes + me.localize( "minAbbr" );
    }
    
    // ################################################################################################################
    // Returns base64 encoded credentials for HTTP Basic Authentication
    me.authString = function( username, password ) {
        var base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        var output = "";
        var input = username + ":" + password;
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var pos = 0;
        do {
            chr1 = input.charCodeAt(pos++);
            chr2 = input.charCodeAt(pos++);
            chr3 = input.charCodeAt(pos++);
            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;
            if (isNaN(chr2)) enc3 = enc4 = 64; else if (isNaN(chr3)) enc4 = 64;
            output = output + base64chars.charAt(enc1) + base64chars.charAt(enc2) + base64chars.charAt(enc3) + 
                base64chars.charAt(enc4);
        } while (pos < input.length);
        return output;
    }

    // ################################################################################################################
    // Estimates time remaining for the current download.
    me.getETA = function( speed, size, progress ){
        if ( me.file.dlStatus == "PAUSED" ) return me.lastETA;
        if ( ! ( speed && size && progress ) ) return -1;

        var newETA = ( size - progress ) / speed;

        if ( me.lastETA == 0 ) me.lastETA = newETA;
        else me.lastETA = me.lastETA - ( me.mult * ( me.lastETA - newETA ) );

        if ( me.mult >= 0.06 ) me.mult -= 0.05;
        return me.lastETA;
    }

    // ################################################################################################################
    // This function gets called by DLMHelper's response handler, it passes a request type as sent to
    // DLMHelper.sendRequest, as well as the json response from the client.
    me.handleResponse = function( type, json ) {
        switch ( type ) {
            case "UPDATE":
                me.handleUpdate( json );
                break;
            case "CREATE_URL_SET":
                if ( json[ "urlSetId" ] ) {
                  me.urlSetId = json[ "urlSetId" ];
                  me.download();
                }
                break;
            case "REGISTER":
                me.handleRegister( json );
                break;
            case "CLOSE_URL_SET":
                me.initialized = true;
                break;
            case "DOWNLOAD":
                // just keep the warning from firing.
                break;
            case "PAUSE":
                // just keep the warning from firing.
                break;
            case "OPEN":
                for ( var url in json ) if ( json[ url ] ) throw( json[ url ] );
                break;
            default:
                DLMHelper.warn( "Unknown type sent to 'handleResponse()': " + type );
        }
    }

    // ################################################################################################################
    // This handles responses to 'update' requests sent to the client.
    me.handleUpdate = function( json ) {

        // This iterates across a list of files, even though we only expect to have one.
        // As such, the data we keep will be for the last file in the list, if more than
        // one were returned.

        for ( var i in json ) {
            me.file.size       = json[ i ][ "size"         ];
            me.file.dlStatus   = json[ i ][ "status"       ];
            me.file.dlrate     = json[ i ][ "downloadrate" ];
            me.file.uniquerecv = json[ i ][ "uniquerecv"   ];
            me.file.path       = json[ i ][ "path"         ];
        }

        // Check if we are not downloading the file at all (This can happen if the saveas 
        // dialog is canceled or cache was cleared out or any other event occured and we have 
        // simply deleted the download.)
        if ( typeof( me.file.dlStatus ) == "undefined" ) {
            // Reinitialize the download and hide the DLM
            me.polling = false;
            me.file.dlrate     = 0;
            me.file.path       = "";
            me.file.size       = 0;
            me.file.dlStatus   = "WAITING";
            me.file.uniquerecv = 0;
            me.intendedState = "STOPPED";
            me.setUIState( "WAITING" );
            me._pauseImg.className = "DLMpause";
            me.style.display  = "none";
            return;
        }

        me.pausedStatusReason = ""; // Clear the error description        

        if (me.onStatusUpdate) {
          me.onStatusUpdate(me.url, me.file.dlStatus);
        }

        var dlStatus = me.file.dlStatus;

        switch(dlStatus)
        {
            case "COMPLETE":
            {
                var oldIntendedState = me.intendedState;
                me.intendedState = "COMPLETE";
                DLMHelper.log( "downloadCompleted" );
                me.setUIState( "COMPLETE" );
                if (oldIntendedState != "COMPLETE" && me.onComplete)
                {
                    me.onComplete(); // run the onComplete callback if defined
                }
                if (oldIntendedState != "COMPLETE" && me.openOnComplete)
                {
                    me.openFile(); // open the file if requested
                }
                return;
            }
            case "PAUSED":
            case "INITIALIZING":
            case "WAITING":
            case "DOWNLOADING":
            {
                // Set the progress regardless of our blacked-outedness.
                var percent = 0;
                if (me.file.size > 0)
                {
                    percent = (me.file.uniquerecv / me.file.size) * 100;
                }
                percent = Math.round(percent * 100) / 100;
                me._progressDiv.style.width = percent + "%";
                
                if (me.onProgress) {
                  me.onProgress(me.url, percent);
                }

                if(!me.pauseBlackout)
                {
                    if(dlStatus == "PAUSED")
                    {
                        me.intendedState = "PAUSED";
                        me._pauseImg.className = "DLMresume";
                    }
                    else
                    {
                        me.intendedState = "DOWNLOADING";
                        me._pauseImg.className = "DLMpause";
                    }
                }
                break;
            }
            case "NOTFOUND":
            case "INSUFFICIENTDISKSPACE":
            case "FORBIDDEN":
            {
                me._pauseImg.className = "DLMresume";
                var strings = {
                    "NOTFOUND": "pausedNotFound",
                    "INSUFFICIENTDISKSPACE": "pausedInsufficientDiskSpace",
                    "FORBIDDEN": "pausedForbidden"
                };
                me.pausedStatusReason = me.localize(strings[dlStatus]);                
                if (me.intendedState != "PAUSED") 
                {
                    me.intendedState = "PAUSED";
                    if (me.onError)
                    {
                        me.onError(dlStatus);          
                    }
                }
                break;
            }
            case "DISCONNECTED":
            {
                me.pausedStatusReason = me.localize("pausedDisconnected");
                break;
            }
            default:
                // ??? We should add specific handling here for new states.
        }

        // Update the status text message.
        me.writeStatusText();
    }

    // ################################################################################################################
    me.handleRegister = function( json ) {
      me.registeredUrl = true;
      me.download();
    }

    // ################################################################################################################
    me.localize = function( key ) {
        if(!DLMHelper.languages[me.computedLanguage])
            return key;
        else if(!DLMHelper.languages[me.computedLanguage][key] && DLMHelper.languages[me.computedLanguage][key] !== "")
            return key;
        else{
            var val = DLMHelper.languages[me.computedLanguage][key];
            // Do substitution on our list of arguments.
            var argIdx = 1;
            var args = arguments;
            val = val.replace(/%s/g, function(){
                if(argIdx >= args.length) return "";
                else return args[argIdx++];
            });
            return val;
        }
    }

    // ################################################################################################################
    // This is a pseudo-event-handler that lets the DLMHelper object send us messages that we can
    // act on. Notably, the DLMHelper can let us know as soon as the client has been installed so
    // we can proceed with our download.
    me.notify = function( message ){
        switch ( message ) {
            case "INSTALLED":
                // If the EULA is accepted or we don't require one, start downloading.
                if( !me.requireEULA || DLMHelper.acceptedEULA ){
                    me.setUIState( "DOWNLOADING" );
                    if( me.intendedState == "DOWNLOADING" ) {
                        me.download();
                        if ( !me.polling ) me.poll();
                    }
                }
                break;
            case "EULAACCEPTED":
                // If we're installed but simply sitting at the 'accept eula' screen, then as soon as we get this
                // message we're ready to go and can start downloading.
                if( DLMHelper.installed  && me.intendedState == "EULAPROMPT") {
                    me.intendedState = "DOWNLOADING";
                    me._pauseImg.className = "DLMpause";
                    me.setUIState( "DOWNLOADING" );
                    me.download();
                    if ( !me.polling ) me.poll();
                }
                // If we're not installed, the DLM helper will kick off the install process for us when the EULA's been
                // accepted, we have to go into the 'waiting' state until that finishes.
                else if(!DLMHelper.installed){
                    me.setUIState( "WAITING" );
                }
                break;
            default:
                DLMHelper.warn( "'notify()' called with unsupported message: " + message );
        }
    }

    // ################################################################################################################
    me.openFile = function( evt ){
        DLMHelper.sendRequest(
            me.dlmId,
            "OPEN",
            "http://127.0.0.1:9421/api?function=openFile&cid=" + me.cid + "&url=" + encodeURIComponent( me.url )
        );

        // Prevent following links in the case that this function was called via an onclick handler.
        if ( evt && evt.preventDefault ) evt.preventDefault();
        else if ( window.event ) window.event.returnValue = false;
    }

    // ################################################################################################################
    me.pauseResume = function() {
        var blackoutMS = 3000; // Number of milliseconds we're blacked out for after calling this function.
        switch( me.intendedState ) {
            case "STOPPED":
            case "PAUSED":
                me.intendedState = "DOWNLOADING";
                me._pauseImg.className = "DLMpause";
                me.shouldWait = false;
                me.writeStatusText();
                me.download();
                if (!me.polling)
                {
                    me.poll();
                }
                me.pauseBlackout = true;
                setTimeout(function(){me.pauseBlackout = false}, blackoutMS);
                break;
            case "DOWNLOADING":
                me.intendedState = "PAUSED";
                me._pauseImg.className = "DLMresume";
                if(me.url)
                {
                    DLMHelper.sendRequest(
                        me.dlmId,
                        "PAUSE",
                        "http://127.0.0.1:9421/api?function=pauseFile&cid=" + me.cid + "&url=" +
                            encodeURIComponent(me.url)
                    );
                }
                me.writeStatusText();
                me.pauseBlackout = true;
                setTimeout(function(){me.pauseBlackout = false}, blackoutMS);
                break;
            case "CANCELLED":
            case "COMPLETE":
            case "EULAPROMPT":
                break;
            default:
                DLMHelper.warn( "In unsupported state: " + me.intendedState );
        }
        return false; // To ignore standard event when invoked from onclick event on anchor
    }
    // ################################################################################################################
    me.poll = function() {
        if (!me.polling)
        {
            me.polling = true;
            setTimeout( me.poll, 1000 );
            return;
        }
        if ( me.file.dlStatus == "COMPLETE" ) return;
        DLMHelper.sendRequest(
            me.dlmId,
            "UPDATE",
            "http://127.0.0.1:9421/api?cid=" + me.cid +
            "&function=getFileAttributes&complete&url=" + encodeURIComponent( me.url )
        );
        setTimeout( me.poll, 1000 );
    }

    // ################################################################################################################
    // Promts the user to download the installer exe again.
    me.reopenInstaller = function( evt ){
        DLMHelper.startInstall( me.exeName );
        if ( evt && evt.preventDefault ) evt.preventDefault();
        else if ( window.event ) window.event.returnValue = false;
    }
    // ################################################################################################################
    me.setDownloadName = function( name ){
        me.downloadName = name;
        me.setLanguage();
    }

    // ################################################################################################################
    me.setExeName = function( name ){
        me.exeName = name;
        me.setLanguage();
    }

    // ################################################################################################################
    me.setLanguageDefault = function( lang ){
        me.languageDefault = lang;
        me.setLanguage();
    }

    // ################################################################################################################
    me.setLanguage = function() {
        var l = me.language;
        if(l != "auto" && !DLMHelper.languages[l]){
            DLMHelper.warn("Language set to '" + l + "', but we don't have that translation, trying 'auto'.");
            l = "auto";
        }
        if(l == "auto"){
            var lvars = [navigator.browserLanguage, navigator.userLanguage, navigator.systemLanguage,
                navigator.language];
            for(var i = 0; i < lvars.length; i++){
                if(lvars[i]){
                    if(DLMHelper.languages[lvars[i]]){
                        l = lvars[i];
                        break;
                    } else if(DLMHelper.languages[lvars[i].substr(0,2)]){
                        l = lvars[i].substr(0, 2);
                        break;
                    }
                    else
                        DLMHelper.warn("Browser wanted language '" + i + "', but no translation available.");
                }
            }
        }
        // Couldn't figure out which language to use.
        if(!DLMHelper.languages[l]){
            if(DLMHelper.languages[me.defaultLanguage]){
                DLMHelper.warn("Couldn't determine language from browser, using default: " + me.defaultLanguage);
                l = me.defaultLanguage;
            }
            else if(DLMHelper.languages["en"]){
                DLMHelper.warn("No translation for default language '" + me.defaultLanguage + "', using English.");
                l = "en";
            }
        }
        me.computedLanguage = l;

        // Clear everything out before we reset it.
        var nodes = [
            me._startMsgDiv, me._relaunchMsgStart, me._relaunchLink, me._relaunchMsgEnd,
            me._titleDiv, me._autoStartLabel, me._completeTitle, me._completeLink, me._completeText, me._eulaOK,
            me._eulaNO, me._eulaText, me._eulaDeniedText, me._eulaDeniedLink, me._cancelledTitle, me._cancelledMsg
        ];
        for ( var i = 0; i < nodes.length; i++ )
            while ( nodes[ i ].childNodes.length ) nodes[ i ].removeChild( nodes[ i ].childNodes[ 0 ] );
        
        // Get the name of the download.
        var dlName = ( me.downloadName ) ? me.downloadName : me.url.replace( /^.*\//, "" );

        // 'WAITING' state strings.
        me._startMsgDiv.appendChild(      document.createTextNode( me.localize( "startTitle"       ) ) );
        me._relaunchMsgStart.appendChild( document.createTextNode( me.localize( "relaunchMsgStart" ) ) );
        me._relaunchLink.appendChild(     document.createTextNode( me.localize( "relaunchLink"     ) ) );
        me._relaunchMsgEnd.appendChild(   document.createTextNode( me.localize( "relaunchMsgEnd"   ) ) );

        // 'DOWNLOADING' state strings.
        me._titleDiv.appendChild(       document.createTextNode( me.localize( "title", dlName    ) ) );
        me._autoStartLabel.appendChild( document.createTextNode( me.localize( "autoStart" )        ) );
        me.writeStatusText();
        
        // 'COMPLETE' state strings.
        me._completeTitle.appendChild( document.createTextNode( me.localize( "completeTitle" )        ) );
        me._completeLink.appendChild(  document.createTextNode( me.localize( "completeText", dlName ) ) );

        // 'EULAPROMPT' state strings.
        me._eulaOK.innerHTML = me.localize( "acceptEULA" );
        me._eulaNO.innerHTML = me.localize( "rejectEULA" );

        me._eulaText.innerHTML = me.localize("EULA1");
        me._eulaText2.innerHTML = me.localize("EULA2");

        // 'EULAFAILED' state strings.
        me._eulaDeniedText.appendChild( document.createTextNode( me.localize( "EULADeniedText" ) ) );
        me._eulaDeniedLink.appendChild( document.createTextNode( me.localize( "EULADeniedLink" ) ) );

        // 'CANCELLED' state strings.
        me._cancelledTitle.appendChild( document.createTextNode( me.localize( "cancelledTitle", dlName ) ) );
        me._cancelledMsg.appendChild( document.createTextNode( me.localize( "cancelledMsg" ) ) );
    }

    // ################################################################################################################
    me.setTargetSpeed = function( speed ){
        me.targetSpeed = speed;
    }

    // ################################################################################################################
    // This function is called to set the UI to one of it's three primary states, which are "WAITING" when we're
    // waiting for installation to complete, "DOWNLOADING" while we're in the process of download a file (including
    // while we're paused), and "COMPLETE" after the file has finished.
    me.setUIState = function( state, extraElements ) {
        var a, i, setTo, activationArray;

        // Downloading elements.
        var downloading = [
            me._titleDiv,
            me._progressBarDiv,
            me._pauseImg,
            me._statusDiv,
            me._autoStartDiv
        ];

        // Waiting elements.
        var waiting = [
            me._startDiv
        ];

        // Complete elements.
        var complete = [
            me._completeDiv
        ];

        // EULA Prompt elements.
        var eulap = [
            me._eulaOK,
            me._eulaNO,
            me._eulaText,
            me._eulaText2
        ];

        // Eula Failed elements.
        var eulaf = [
            me._eulaDeniedText,
            me._eulaDeniedLink
        ];

        // Cancelled elements.
        var cancelled = [

        ];

        // Add any user-specified extra elements. This is here for extending the DLM class.
        if(extraElements){
            var lists = ["downloading", "waiting", "complete", "eulap", "eulaf", "cancelled"];
            for(var ii = 0; ii < lists.length; ii++){
                var current;
                eval("current = " + lists[ii]);
                if(extraElements[lists[ii]]){
                    if(extraElements[lists[ii]].length){
                        for(var jj = 0; jj < extraElements[lists[ii]].length; jj++)
                            current.push(extraElements[lists[ii]][jj]);
                    }
                    else
                        current.push(extraElements[lists[ii]]);
                }
            }
        }

        switch( state ) {
            case "WAITING":     activationArray = waiting;     break;
            case "DOWNLOADING": activationArray = downloading; break;
            case "COMPLETE":    activationArray = complete;    break;
            case "EULAPROMPT":  activationArray = eulap;       break;
            case "EULAFAILED":  activationArray = eulaf;       break;
            case "CANCELLED":   activationArray = cancelled;   break;
            default:
                activationArray = waiting;
                DLMHelper.warn( "Tried to set UI State to unsupported state: " + state );
        }
        var all = [ waiting, downloading, complete, eulap, eulaf, cancelled ];
        for( var a = 0; a < all.length; a++ ) {
            setTo = ( all[ a ] === activationArray ) ? null : "none";
            for ( i = 0; i < all[ a ].length; i++ ) {
                // If we're setting display to 'none', we save the current display property, and then do the set, but
                // multiple calls to this shouldn't break our old display style, so we don't do this multiple times.
                if( setTo == "none" && all[ a ][ i ].style.display != "none" ){
                        all[ a ][ i ].old_style_display = all[ a ][ i ].style.display;
                        all[ a ][ i ].style.display = "none";
                }
                // If setTo is the default value (null), we set the element back to it's old display value, unless
                // it's not set, in which case we use the empty string (which should act as default).
                else if( setTo == null ) {
                    var osd = ( all[ a ][ i ].old_style_display == undefined ) ? "" : all[ a ][ i ].old_style_display; 
                    all[ a ][ i ].style.display = osd;
                }
            }
        }
    }

    // ################################################################################################################
    me.writeStatusText = function() {
        var statusText = "";
        switch ( me.intendedState ){
            case "STOPPED":
                statusText = me.localize( "waiting" );
                break;
            case "PAUSED":
                statusText = me.localize( "paused" );
                if ( me.pausedStatusReason ) statusText += " " + me.pausedStatusReason;  
                break;
            case "DOWNLOADING":
                if( me.pausedStatusReason )
                {
                    statusText = me.pausedStatusReason;
                }
                else
                {                
                    var timestring = me.formatTime( me.getETA( me.file.dlrate, me.file.size, me.file.uniquerecv ) );                    
                    if (timestring != "") statusText = me.localize( "timeLabel", timestring );                    
                    else statusText = me.localize( "calcTime" );
                }
                break;
            case "COMPLETE":
                statusText = "";
                break;
            case "EULAPROMPT":
                statusText = "";
                break;
            default:
                DLMHelper.warn( "Couldn't write status text for state " + me.intendedState );
                break;
        }
        while ( me._statusDiv.childNodes.length ) me._statusDiv.removeChild( me._statusDiv.childNodes[ 0 ] );
        me._statusDiv.appendChild( document.createTextNode( statusText ) );
    }

    // Set the default contents of our div element. ###################################################################

    // Downloading state elements.
    me._titleDiv          = me.createElement( "div",   "title"            );
    me._progressBarDiv    = me.createElement( "div",   "progressBar"      );
    me._progressDiv       = me.createElement( "div",   "progress"         );
    me._pauseImg          = me.createElement( "div",   "pause"            ); // Div instead of IMG to allow full css control of the image src (IE shows blank icon when src not set and we don't have a transparent image)
    me._pauseImgClick     = me.createElement( "span",  "pauseclick"       ); // This is a hack for IE8 to make the div parent clickable
    me._statusDiv         = me.createElement( "div",   "status"           );
    me._autoStartDiv      = me.createElement( "div",   "autoStart"        );
    me._autoStartCheckbox = me.createElement( "input", "autoStartCB",
                            { "type": "checkbox", "id": "DLM" + me.dlmId + "ascb", "checked": "checked" } );
    me._autoStartLabel    = me.createElement( "label", "autoStartLabel",
                            { "for": "DLM" + me.dlmId + "ascb" } );

    // Complete state elements.
    me._completeDiv       = me.createElement( "div",   "complete" );
    me._completeTitle     = me.createElement( "div",   "completeTitle"    );
    me._completeText      = me.createElement( "div",   "completeText"     );
    me._completeLink      = me.createElement( "a",     "completeLink",
                            { "href": "" } );

    // Waiting state elements.
    me._startDiv          = me.createElement( "div",   "start" );
    me._startMsgDiv       = me.createElement( "div",   "startMsg"         );
    me._relaunchDiv       = me.createElement( "div",   "relaunch"         );
    me._relaunchMsgStart  = me.createElement( "span",  "relaunchMsgStart" );
    me._relaunchLink      = me.createElement( "a",     "relaunchLink",
                            { "href": "" } );
    me._relaunchMsgEnd    = me.createElement( "span",  "relaunchMsgEnd"   );

    // Eula Prompt state elements.
    me._eulaOK = me.createElement( "a", "eulaOK",   { "href": "#" } );
    me._eulaNO = me.createElement( "a", "eulaFAIL", { "href": "#" } );
    me._eulaText     = me.createElement( "div", "eulaText" );
    me._eulaText2    = me.createElement( "div", "eulaText2" );

    // Eula denied state elements.
    me._eulaDeniedText = me.createElement( "div", "eulaDeniedText" );
    me._eulaDeniedLink = me.createElement( "a"  , "eulaDeniedLink", { "href": url } );

    // TODO: these exist solely for BundledDLM support at the moment. They should also be made to function with a
    // single-file DLM.
    me._cancelledTitle = me.createElement("div", "cancelledTitle");
    me._cancelledMsg = me.createElement("a", "cancelledMsg");

    // Build a tree.
    me._relaunchDiv.appendChild(    me._relaunchMsgStart  );
    me._relaunchDiv.appendChild(    me._relaunchLink      );
    me._relaunchDiv.appendChild(    me._relaunchMsgEnd    );
    me._startDiv.appendChild(       me._startMsgDiv       );
    me._startDiv.appendChild(       me._relaunchDiv       );
    me._completeDiv.appendChild(    me._completeTitle     );
    me._completeDiv.appendChild(    me._completeText      );
    me._completeDiv.appendChild(    me._completeLink      );
    me._progressBarDiv.appendChild( me._progressDiv       );
    me._autoStartDiv.appendChild(   me._autoStartCheckbox );
    me._autoStartDiv.appendChild(   me._autoStartLabel    );
    me.appendChild(                 me._titleDiv          );
    me.appendChild(                 me._progressBarDiv    );
    me.appendChild(                 me._pauseImg          );
    me._pauseImg.appendChild(       me._pauseImgClick     );
    me.appendChild(                 me._statusDiv         );
    me.appendChild(                 me._autoStartDiv      );
    me.appendChild(                 me._completeDiv       );
    me.appendChild(                 me._startDiv          );
    me.appendChild(                 me._eulaText          );
    me.appendChild(                 me._eulaOK      );
    // me.appendChild(                 me._eulaNO      ); // Currently off.
    me.appendChild(                 me._eulaText2         );
    me.appendChild(                 me._eulaDeniedText    );
    me.appendChild(                 me._eulaDeniedLink    );

    // Minor event handlers.
    me._rejectEULA = function(){ me.setUIState( "EULAFAILED" ) };
    me._acceptEULA = function(){
        DLMHelper.log( "eulaAccepted" );
        DLMHelper.acceptEULA( me.cid, me.eulaVersion );
        if(!DLMHelper.installed){
            DLMHelper.startInstall( me.exeName );
            me.setUIState("WAITING");
        }
    };

    // Attach event handlers.
    if ( window.attachEvent ) {
        me._pauseImg.attachEvent(          "onclick", me.pauseResume                                       );
        me._completeLink.attachEvent(      "onclick", me.openFile                                          );
        me._autoStartCheckbox.attachEvent( "onclick", function(){ me.openOnComplete = !me.openOnComplete } );
        me._relaunchLink.attachEvent(      "onclick", me.reopenInstaller                                   );
        me._eulaOK.attachEvent(      "onclick", function (){ me._acceptEULA(); return false; }       );
        me._eulaNO.attachEvent(      "onclick", function (){ me._rejectEULA(); return false; }       );
    }
    else if ( window.addEventListener ) {
        me._pauseImg.addEventListener(          "click", me.pauseResume, false                                       );
        me._completeLink.addEventListener(      "click", me.openFile, false                                          );
        me._autoStartCheckbox.addEventListener( "click", function(){ me.openOnComplete = !me.openOnComplete }, false );
        me._relaunchLink.addEventListener(      "click", me.reopenInstaller, false                                   );
        me._eulaOK.addEventListener(      "click", function (){ me._acceptEULA(); return false; }, false       );
        me._eulaNO.addEventListener(      "click", function (){ me._rejectEULA(); return false; }, false       );
    }

    // If the client is installed, default to the downloading state.
    if ( DLMHelper.installed ) {
        me.setUIState( "DOWNLOADING" );
        me._pauseImg.className = "DLMresume";
    }
    // Otherwise, default to the waiting state.
    else {
        me.setUIState( "WAITING" );
    }

    // Call 'setLanguage' to localize our strings.
    me.setLanguage();

    // (Optional) deployment into DLM-container
    if ( containerId ) {
        var dlmContainer = document.getElementById( containerId );
        if ( dlmContainer ) dlmContainer.appendChild( me );
    }
    
    // (Optional) set up download link onclick event to start the download
    if ( linkId ) {
        var clickLink = document.getElementById( linkId );
        if ( clickLink ) clickLink.onclick = function () {
            me.beginDownload();
            return false;
        }
    }

    // Return our modified div 'me'.
    return me;
}

// ####################################################################################################################
// ####################################################################################################################
// New BundledDLM object for bundled downloads. Takes the same arguments as DLM, except that 'url' is replaced with
// 'urls', which is now an array.
// ####################################################################################################################
// ####################################################################################################################
function BundledDLM(cid, urls, dlmParams, containerId, linkId)
{
    // Warn if we didn't get an array of URLs. This probably means we should be making a DLM instead of a
    // BundledDLM.
    if ( !urls || typeof( urls ) != "object" || !(urls instanceof Array)) {
        DLMHelper.warn("BundledDLM created with non-array urls parameter.");
    }

    // Initialize myself via our base class.
    var me = new DLM(cid, "", dlmParams, containerId, linkId); 

    // We no longer use these parameters.
    me.file = null;

    // We add some extra parameters.
    me.waitingToStart = true; // Turn this off once all our files are PAUSED or COMPLETE.
    me.skipFailedUrls = false;
    me.urls = urls;
    me.unregisteredURLs = [];   // We remove files from this list as they are added to the bundle.
    me.incompleteURLs = [];   // We remove files from this list as they complete.
    me.files = {};
    me.url = null; // the url of the file in the bundle currently being downloaded.
    me.fileToOpen = null;

    // Per url auth parameters
    me.cookieStringPerUrl = {};
    me.queryAuthPerUrl = {};
    me.basicAuthUsernamePerUrl = {};
    me.basicAuthPasswordPerUrl = {};

    // Initialize our URLs.
    for(var ii = 0; ii < me.urls.length; ii++) me.unregisteredURLs.push(me.urls[ii]);
    for(var ii = 0; ii < me.urls.length; ii++) me.incompleteURLs.push(me.urls[ii]);

    // Initialize all our files.
    for(var ii = 0; ii < me.urls.length; ii++){
        var file        = new Object();
        file.dlrate     = 0;
        file.path       = "";
        file.size       = 0;
        file.dlStatus   = "WAITING";
        file.uniquerecv = 0;
        me.files[me.urls[ii]] = file;
    }

    // We require this to be set to *something*, as automatically setting it to the URL is no longer practical.
    if ( !me.downloadName ) {
      me.downloadName = "bundle";
    }

    // setUIState extends but doesn't really replace the parent class' function.
    me.parentSetUIState = me.setUIState;
    me.setUIState = function(state){
        var extraElements = {
            "downloading": [me._progressBarDiv2, me._statusDiv2],
            "cancelled": [me._cancelledTitle, me._cancelledMsg]
        }
        me.parentSetUIState(state, extraElements);
    }
    // The parent class has initialized some UI State, so we need to reinitialize it with our updated function.
    /* Is this really necesary? Doesn't it get called anywhere else?
    // If the client is installed, default to the downloading state.
    if ( DLMHelper.installed ) {
        me.setUIState( "DOWNLOADING" );
        me._pauseImg.className = "DLMresume";
    }
    // Otherwise, default to the waiting state.
    else {
        me.setUIState( "WAITING" );
    }
    */

    // ################################################################################################################
    me.unpause = function() {
      me.shouldWait = false;
      if ( me.waitingToStart ) {
        me.intendedState = "DOWNLOADING";
        me._pauseImg.className = "DLMpause";
      } else if (me.intendedState == "PAUSED") {
        me.pauseResume();
      }
    }
    // ################################################################################################################
    // Like with setUIState, we need to add a small amount of functionality here without replacing everything.
    me.parentSetLanguage = me.setLanguage;
    me.setLanguage = function(){
        me.parentSetLanguage();
        me._statusDiv2.innerHTML = me.localize("defaultStatus2");
    }

    // ################################################################################################################
    me.setCookieAuthForUrl = function( url, cookieString ) {
      me.cookieStringPerUrl[url] = cookieString;
      if ( !cookieString) {
        delete me.cookieStringPerUrl[url];
      }
    }

    // ################################################################################################################
    me.setQueryAuthForUrl = function( url, queryAuth ) {
      me.queryAuthPerUrl[url] = queryAuth;
      if ( !queryAuth) {
        delete me.queryAuthPerUrl[url];
      }
    }

    // ################################################################################################################
    me.setBasicAuthForUrl = function( url, basicAuthUsername, basicAuthPassword ) {
      me.basicAuthUsernamePerUrl[url] = basicAuthUsername;
      me.basicAuthPasswordPerUrl[url] = basicAuthPassword;
      if ( !basicAuthUsername && !basicAuthPassword ) 
      {
        delete me.basicAuthUsernamePerUrl[url];
        delete me.basicAuthPasswordPerUrl[url];
      }
    }

    // ################################################################################################################
    me.appendAuth = function( url ) {
      var cookieString = "";
      var queryAuth = "";
      var basicAuth = "";
      if ( me.cookiestring ) cookieString = "&cookiestring=" + encodeURIComponent( me.cookiestring );
      if ( me.queryauth ) queryAuth = "&queryauth=" + encodeURIComponent( me.queryauth );
      if ( me.basicauth_username && me.basicauth_password ) {
        basicAuth = "&basicauth=" + encodeURIComponent( me.authString( me.basicauth_username, 
                                                                       me.basicauth_password ) );
      }
      if ( url != null )
      {
        if ( me.cookieStringPerUrl[url] ) {
          cookieString = "&cookiestring=" + encodeURIComponent( me.cookieStringPerUrl[url] );
        }
        if ( me.queryAuthPerUrl[url] ) {
          queryAuth = "&queryauth=" + encodeURIComponent( me.queryAuthPerUrl[url] );
        }
        if ( me.basicAuthUsernamePerUrl[url] && me.basicAuthPasswordPerUrl[url] ) {
          basicAuth = "&basicauth=" + encodeURIComponent( me.authString( me.basicAuthUsernamePerUrl[url], 
                                                                  me.basicAuthPasswordPerUrl[url] ) );
        }
      }
      return cookieString + queryAuth + basicAuth;
    }

    // ################################################################################################################
    me.isFinished = function( dlStatus ) {
      if ((dlStatus == "COMPLETE") ||
          (me.skipFailedUrls && 
           ((dlStatus == "NOTFOUND") || 
            (dlStatus == "INSUFFICIENTDISKSPACE") || 
            (dlStatus == "FORBIDDEN")))) {
        return true;
      } else {
        return false;
      }
    }

    // ################################################################################################################
    me.predictedURL = null;
    me.download = function(predictive){
        // Copy from DLM() object. Needs to act on multiple files!
        if ( !DLMHelper.installed ) return;
        
        var dlURL  = "";
        // Get a url set id
        if ( !me.urlSetId ) {
          dlURL = "http://127.0.0.1:9421/api?function=createUrlSet&cid=" + me.cid;
          DLMHelper.sendRequest( me.dlmId, "CREATE_URL_SET", dlURL );
          return;
        }

        var dlPath = "";
        var iqs    = "";
        var ts     = "";
        var saveAs = "";
        var oo     = "";
        var res    = "";
        var resurl = "";
        var resfilename = "";
        var autopause = "";
        var wait = "";

        // This should work, right?
        // var dlPath, iqs, ts, cs, qa, ba, saveAs, oo, res, resurl = "";

        if ( me.ignoreQueryString ) {
            iqs = "&originurl=" + encodeURIComponent( me.url );
            url = url.replace( /\?.*$/, "" );
        }
        if ( me.originOnly               ) oo     = "&originonly";
        if ( me.targetSpeed              ) ts     = "&targetspeed=" + me.targetSpeed;
        if ( me.downloadPath == "prompt" ) saveAs = "&saveas=true";

        if ( me.resumable && me.resumeURL ) {
          res    = "&resumable=true";
          resurl = "&resumeurl=" + encodeURIComponent( me.resumeURL );          
          if ( me.resumeAddUrlSetId )          
          {            
            resurl += encodeURIComponent( ( ( me.resumeURL.indexOf( "?" ) == -1 ) ? "?" : "&" ) + me.resumeAddUrlSetId 
              + "=" + me.urlSetId );
          }
          if ( me.downloadName )
          {
            resfilename = "&resumefilename=" + encodeURIComponent( me.downloadName );
          }
        }
        if ( me.autopause             ) autopause = "&autopause=30";
        if ( me.shouldWait || !me.initialized ) wait = "&wait=true"; 

        dlURL = "http://127.0.0.1:9421/api?function=downloadFile" + autopause + "&cid=" + me.cid + ts + iqs +
          saveAs + dlPath + oo + res + resurl + resfilename + wait + "&urlSetId=" + me.urlSetId; 

        // Set the pause blackout, otherwise we may move from one 'complete' file to the next, see it's paused, and
        // assume it was caused by an outside influence.
        me.pauseBlackout = true;
        setTimeout(function(){me.pauseBlackout = false}, 3000);

        // The first time, we don't actually start any downloads.
        if(!me.initialized){
          if (me.unregisteredURLs.length > 0) 
          {
            dlURL += "&url=" + encodeURIComponent(me.unregisteredURLs[0]);
            dlURL += me.appendAuth( me.unregisteredURLs[0] );
            DLMHelper.sendRequest( me.dlmId, "REGISTER", dlURL );
            return; 
          }
          else
          {
            dlURL = "http://127.0.0.1:9421/api?function=closeUrlSet" + wait + "&cid=" + me.cid + 
              "&urlSetId=" + me.urlSetId;
            if ( me.downloadPath == "prompt" ) {
              dlURL += "&saveas=true";
            }
            DLMHelper.sendRequest( me.dlmId, "CLOSE_URL_SET", dlURL );
            return;
          }
        }
        else{
            // If we were called with the 'predictive' flag, we try to start the next file from the incompleteURLs
            // list. This will fire again in a couple seconds, but that's ok.
            if(predictive && me.incompleteURLs.length > 1 && me.predictedURL != me.incompleteURLs[1]){
                dlURL += "&url=" + encodeURIComponent(me.incompleteURLs[1]);
                dlURL += me.appendAuth(me.incompleteURLs[1]);
                me.predictedURL = me.incompleteURLs[1];
            }
            else if(predictive){
                return;
            }
            // If there's a current file and it's not complete, try starting it.
            else if(me.url && !(me.isFinished(me.files[me.url].dlStatus))) {
                dlURL += "&url=" + encodeURIComponent(me.url);
                dlURL += me.appendAuth(me.url);
            }
            // Otherwise, there's no url, or it's COMPLETE, so start the next file, if we've got one.
            else if(me.incompleteURLs.length){
                dlURL += "&url=" + encodeURIComponent(me.incompleteURLs[0]);
                dlURL += me.appendAuth(me.incompleteURLs[0]);
                me.url = me.incompleteURLs[0];
            }
            me.predictedURL = null;
            DLMHelper.sendRequest( me.dlmId, "DOWNLOAD", dlURL );
        }
    }

    // ################################################################################################################
    me.getETA = function( speed, size, progress ){
        // This is an unknowable value with the current implementation, since we don't know the size of all our
        // files until we begin the last one.
        return -1;
    }

    // ################################################################################################################
    me.handleUpdate = function( json ) {
        // Update the status of all our files.
        for (var i in json) {
            if(json[i] == "File not found."){
                me.waitingToStart = true;
                me.initialized = false;
                me.intendedState = "CANCELLED";
                me.setUIState( "CANCELLED" );
                if (me.onCancel) {
                  me.onCancel();
                }
                return;
            }
            var oldStatus = me.files[i].dlStatus;

            me.files[i].size       = json[i]["size"        ];
            me.files[i].dlStatus   = json[i]["status"      ];
            me.files[i].dlrate     = json[i]["downloadrate"];
            me.files[i].uniquerecv = json[i]["uniquerecv"  ];
            me.files[i].path       = json[i]["path"        ];

            if (me.onStatusUpdate) {
              me.onStatusUpdate(i, me.files[i].dlStatus);
            }

            // If we just completed a file, then we remove it from our update list.
            if(me.isFinished(json[i]["status"]) && (json[i]["status"] != oldStatus)) {
                for(var ii = 0; ii < me.incompleteURLs.length; ii++){
                    if(me.incompleteURLs[ii] == i){
                        me.incompleteURLs.splice(ii, 1); // Remove completed files from the incomplete list.
                        // If the file finished, but not because it reached COMPLETE, there's an error we should notify
                        // users of.
                        if ((json[i]["status"] != "COMPLETE") &&
                            (me.onError)) {
                          me.onError(json[i]["status"]);
                        }
                        if(!me.waitingToStart){
                            // Start another file downloading.
                            if(me.intendedState == "DOWNLOADING") {
                                me.download();
                            }
                        }
                        break;
                    }
                }
            }
        }

        // File completion prediction to avoid downtime between files.
        // Causes some odd behavior (specifically with pausing downloads), so not currently enabled
        /*
        var cf = me.files[me.url];
        if(cf && ((cf.size - cf.uniquerecv) / cf.dlrate) < 2 ){
            me.download(true); // start a predictive download.
        }
        */

        if(me.waitingToStart){
            // Check and see if everything's PAUSED or COMPLETE.
            var allArePausedorComplete = true;
            for(var ii = 0; ii < me.incompleteURLs.length; ii++){
                if(me.files[me.incompleteURLs[ii]].dlStatus != "PAUSED"){
                    if(me.files[me.incompleteURLs[ii]].dlStatus == "DOWNLOADING"){
                        // Files shouldn't be downloading. Pause them.
                        // This can happen if the DLM page is reloaded.
                        DLMHelper.sendRequest(
                            me.dlmId,
                            "PAUSE",
                            "http://127.0.0.1:9421/api?function=pauseFile&cid=" + me.cid + "&url=" + 
                                encodeURIComponent( me.incompleteURLs[ii] )
                        );
                    }
                    allArePausedorComplete = false;
                    break;
                }
            }
            if(allArePausedorComplete){
                me.download();
                me.waitingToStart = false;
            }
        }

        // Check if we are not downloading the file at all (This can happen if the saveas 
        // dialog is canceled or cache was cleared out or any other event occured and we have 
        // simply deleted the download.)
        /* Not sure how important this is. May leave out for now.
        if ( typeof( me.file.dlStatus ) == "undefined" ) {
            // Reinitialize the download and hide the DLM
            me.polling = false;
            me.file.dlrate     = 0;
            me.file.path       = "";
            me.file.size       = 0;
            me.file.dlStatus   = "WAITING";
            me.file.uniquerecv = 0;
            me.intendedState = "STOPPED";
            me.setUIState( "WAITING" );
            me._pauseImg.className = "DLMpause";
            me.style.display  = "none";
            return;
        }
        */

        // If we're complete, just mark everything as complete and return.
        if(me.incompleteURLs.length == 0 && me.intendedState != "COMPLETE"){
            me.intendedState = "COMPLETE";
            DLMHelper.log( "downloadCompleted" );
            me.setUIState( "COMPLETE" );
            if ( me.onComplete ) me.onComplete(); // run the onComplete callback if defined
            if ( me.openOnComplete ) me.openFile(); // open the file if requested
            return;
        }

        // Error states
        me.pausedStatusReason = ""; // Clear the error description        
        for(var ii = 0; ii < me.incompleteURLs.length; ii++){
            var s = me.files[me.incompleteURLs[ii]].dlStatus;
            if ( s == "NOTFOUND" || s == "INSUFFICIENTDISKSPACE" || s == "FORBIDDEN" ) {
                me._pauseImg.className = "DLMresume";
                var strings = { "NOTFOUND": "pausedNotFound", "INSUFFICIENTDISKSPACE": "pausedInsufficientDiskSpace",
                                "FORBIDDEN": "pausedForbidden" };
                me.pausedStatusReason = me.localize(strings[s]);
                if ( me.intendedState != "PAUSED" ) 
                {
                  me.intendedState = "PAUSED";
                  if ( me.onError ) me.onError( s );          
                }
            }
        }

        // Setting of DLM state based on only the current file.
        if(me.url){
            var dlStatus = me.files[me.url].dlStatus;
            switch(dlStatus)
            {
                case "PAUSED":
                case "INITIALIZING":
                case "WAITING":
                case "DOWNLOADING":
                {
                    if(!me.pauseBlackout)
                    {
                        if(dlStatus == "PAUSED")
                        {
                            me.intendedState = "PAUSED";
                            me._pauseImg.className = "DLMresume";
                        }
                        else
                        {
                            me.intendedState = "DOWNLOADING";
                            me._pauseImg.className = "DLMpause";
                        }
                    }
                    break;
                }
                case "DISCONNECTED":
                {
                    me.pausedStatusReason = me.localize("pausedDisconnected");
                    break;
                }
                // Other cases handled outside this switch block.
            }
        }

        // intendedState-specific actions.
        switch ( me.intendedState ) {
            // If we're downloading, we need to update the progress bars.
            // Actually, do this in a "PAUSED" state, too, since it can change for a second after pausing.
            case "DOWNLOADING":
            case "PAUSED":
                var filePercent = 0;
                var bundlePercent = 0;
                // Per-file progress bar.
                if(me.url){
                    var f = me.files[me.url];
                    if(f.size > 0) filePercent = ( f.uniquerecv / f.size ) * 100;
                }
                me._progressDiv.lastPercent = me._progressDiv.measuredPercent;
                me._progressDiv.measuredPercent = filePercent;

                // Overall progress bar.
                bundlePercent = ((me.urls.length - me.incompleteURLs.length) / me.urls.length) * 100;
                bundlePercent += me._progressDiv.measuredPercent / me.urls.length;

                me._progressDiv2.lastPercent = me._progressDiv2.measuredPercent;
                me._progressDiv2.measuredPercent = bundlePercent;

                // Hack to make sure bundle progress bar never runs too far ahead. Sure with Tyler wasn't on vacation
                // and could review this.
                if ((me._progressDiv2.measuredPercent - me._progressDiv2.lastPercent) > 5) {
                  me._progressDiv2.lastPercent = me._progressDiv2.measuredPercent - 5;
                }

                me.updateProgressBarCounter = 0;
                me.updateProgressBarsSmooth();

                if (me.onProgress) {
                  me.onProgress(me.url, filePercent, bundlePercent);
                }

                break;
            default:
                // do nothing.
        }

        // Update the status text message.
        me.writeStatusText();
    }

    // ################################################################################################################
    me.handleRegister = function( json ) {
      for (var i in json) {
        for(var ii = 0; ii < me.unregisteredURLs.length; ii++) {
          if (me.unregisteredURLs[ii] == i) {
            me.unregisteredURLs.splice(ii, 1); // Remove completed files from the unregistered list.
          }
        }
      }
      me.download();
    }

    // ################################################################################################################
    me.updateProgressBarTimer = null;
    me.updateProgressBarCounter = 0;
    me.progressLastFileChecked = null;
    me.updateProgressBarsSmooth = function(){

        // If we've got a count of 0, then we reset. Also, if we've gone a full second, then we reset.
        if(me.updateProgressBarCounter == 0 || me.updateProgressBarCounter >= 20){
            if(me.updateProgressBarTimer){
                clearInterval(me.updateProgressBarTimer);
                me.updateProgressBarTimer = null;
            }
        }

        var done = 0; // Number of progress bars done updating.
        var bars = [me._progressDiv, me._progressDiv2];

        // If our counter is zero, we update our progress bars to indicate actual progress.
        // Otherwise, we estimate based on the time.
        for(var ii = 0; ii < bars.length; ii++){
            var percent = 0;
            if(me.updateProgressBarCounter >= 20){
                var offset = bars[ii].measuredPercent - bars[ii].lastPercent;
                var percent = bars[ii].lastPercent + offset;
                done++;
            }
            else if(bars[ii].lastPercent == 0){
                percent = bars[ii].measuredPercent;
            }
            else{
                var offset = ((bars[ii].measuredPercent - bars[ii].lastPercent) / 20) * me.updateProgressBarCounter;
                percent = bars[ii].measuredPercent + offset;
            }
            if(me.progressLastFileChecked == me.url){
                var old = parseFloat(bars[ii].style.width.replace(/%$/, ""));
                if(old > percent) percent = old;
            }
            if(percent > 100) percent = 100;
            bars[ii].style.width = (Math.round( percent * 100 ) / 100) + "%";
        }

        // If there are unfinished progress bars, and our interval isn't already set, and we're on our zeroth
        // iteration, then set a timer.
        if(done < bars.length && me.updateProgressBarTimer == null && me.updateProgressBarCounter == 0){
            me.updateProgressBarTimer = setInterval(me.updateProgressBarsSmooth, 50);
        }
        // Update for the next run through.
        me.progressLastFileChecked = me.url;
        me.updateProgressBarCounter++;
    }

    // ################################################################################################################
    me.setFileToOpen = function( name ){
        me.fileToOpen = name;
        me.setLanguage();
    }

    // ################################################################################################################
    me.parentOpenFile = me.openFile;
    me.openFile = function( evt ){
        if(!me.fileToOpen){
            DLMHelper.warn("Called openFile, but no fileToOpen has been set!");
        }
        else if(!me.files[me.fileToOpen]){
            DLMHelper.warn("Called openFile, but fileToOpen set to invalid URL.");
        }
        else{
            DLMHelper.sendRequest(
                me.dlmId,
                "OPEN",
                "http://127.0.0.1:9421/api?function=openFile&cid=" + me.cid + "&url=" +
                encodeURIComponent( me.fileToOpen )
            );
        }

        // Prevent following links in the case that this function was called via an onclick handler.
        if ( evt && evt.preventDefault ) evt.preventDefault();
        else if ( window.event ) window.event.returnValue = false;
    }

    // ################################################################################################################
    me.poll = function() {
        if (!me.polling)
        {
            me.polling = true;
            setTimeout(me.poll, 1000);
            return;
        }
        if(me.incompleteURLs.length == 0 || me.intendedState == "CANCELLED"){
            me.polling = false;
            return;
        }
        var urlString = "";
        // If we've got a url, we only check on that file. This implies we've completed all initialization.
        if(me.url){
            urlString += "&url=" + encodeURIComponent(me.url);
        }
        // Otherwise, we have to check on everything, so we can tell when we're ready to actually start downloading.
        else if (me.unregisteredURLs.length == 0) {
            for(var ii = 0; ii < me.incompleteURLs.length; ii++){
                urlString = "&url=" + encodeURIComponent(me.incompleteURLs[ii]);
                DLMHelper.sendRequest(
                    me.dlmId,
                    "UPDATE",
                    "http://127.0.0.1:9421/api?cid=" + me.cid + "&function=getFileAttributes&complete" + urlString
                );
            }
            setTimeout(me.poll, 1000);
            return;
        }
        DLMHelper.sendRequest(
            me.dlmId,
            "UPDATE",
            "http://127.0.0.1:9421/api?cid=" + me.cid + "&function=getFileAttributes&complete" + urlString
        );
        setTimeout(me.poll, 1000);
    }

    // ################################################################################################################
    me.writeStatusText = function() {
        var statusText = me.localize("waitStatus");
        var percent = me.localize("percentage", (Math.round(me._progressDiv.measuredPercent * 100) / 100));
        var totalPercent = me.localize("percentage", (Math.round(me._progressDiv2.measuredPercent * 100) / 100));
        var titleText = me.localize("titleTextProgress", totalPercent);
        var fileNum = me.urls.length - me.incompleteURLs.length + 1;
        var fileOf = me.urls.length;
        switch ( me.intendedState ){
            case "STOPPED":
                break;
            case "PAUSED":
                if(me.url)
                    statusText = me.localize("statusProgress", me.url.replace(/^.*[\\\/]/, ""),
                        fileNum, fileOf, percent);
                titleText = me.localize("titleTextPaused", totalPercent);
                if ( me.pausedStatusReason )
                {
                    statusText += " " + me.pausedStatusReason;  
                }
                break;
            case "DOWNLOADING":
                if( me.pausedStatusReason )
                {
                    statusText = me.pausedStatusReason;
                }
                else if(me.url)
                {
                    statusText = me.localize("statusProgress", me.url.replace(/^.*[\\\/]/, ""),
                        fileNum, fileOf, percent);
                }
                break;
            case "COMPLETE":
                statusText = "&nbsp;";
                break;
            case "EULAPROMPT":
                statusText = "&nbsp;";
                break;
            default:
                DLMHelper.warn( "Couldn't write status text for state " + me.intendedState );
                break;
        }
        me._statusDiv.innerHTML = statusText;
        me._statusDiv2.innerHTML = titleText;
    }

    // New UI elements.
    me._progressBarDiv2 = me.createElement("div", "progressBar2");
    me._progressDiv2 = me.createElement("div", "progress2");
    me._progressBarDiv2.appendChild(me._progressDiv2);
    me._progressBarDiv.parentNode.insertBefore(me._progressBarDiv2, me._progressBarDiv);
    me._statusDiv2 = me.createElement("div", "statusDiv2");
    me._progressBarDiv2.parentNode.insertBefore(me._statusDiv2, me._progressBarDiv2);

    // TODO: Defaults for these are not currently set in the single-file DLM, but they *should* be.
    me._cancelledMsg.href = "#";
    me._cancelledMsg.onclick = function(){
        DLMHelper.getUrlSetId( function(urlSetId) {
            me.urlSetId = urlSetId ;
            for(var ii = 0; ii < me.urls.length; ii++) me.unregisteredURLs.push(me.urls[ii]);
            if( "function" == typeof me.onResume ) me.onResume( ) ;
            me.beginDownload( ) ;
        } ) ;
        return false;
    }

    me._titleDiv.parentNode.insertBefore(me._cancelledTitle, me._titleDiv.nextSibling);
    me._titleDiv.parentNode.insertBefore(me._cancelledMsg, me._cancelledTitle.nextSibling);

    // Moved UI elements.
    me._progressBarDiv.parentNode.insertBefore(me._statusDiv.parentNode.removeChild(me._statusDiv), me._progressBarDiv);

    // TODO: This is a hack and should be set somewhere else.
    me._statusDiv.style.marginTop = "0.5em";
    me._statusDiv2.style.marginTop = "0.5em";

    // Initialization for drawing smooth progress bars.
    me._progressDiv.lastPercent = 0;
    me._progressDiv.measuredPercent = 0;
    me._progressDiv2.lastPercent = 0;
    me._progressDiv2.measuredPercent = 0;

    // ################################################################################################################
    // Re-attach event handlers that have changed. This needs to be done because of how scoping works in javascript.
    // We also need to remove the exiting event handlers.
    if (window.attachEvent){
        me._completeLink.detachEvent("onclick", me.parentOpenFile);
        me._completeLink.attachEvent("onclick", me.openFile);
    }
    else if (window.addEventListener){
        me._completeLink.removeEventListener("click", me.parentOpenFile, false);
        me._completeLink.addEventListener("click", me.openFile, false);
    }

    // Done initializing this object.
    return me;
}

// ####################################################################################################################
// pseudoDLM class, used for using DLMHelper without a DLM
// ####################################################################################################################
function pseudoDLM( request, callback)
{
    // Internal state variables.
    var me                = document.createElement( "div" );
    me.request            = request;
    me.callback           = callback;
    me.style.display      = "none";
    // We put ourself in the global list of DLMs and keep track of where we are in that list.
    me.dlmId = DLMHelper.register( me );
    // ################################################################################################################
    // This function gets called by DLMHelper's response handler, it passes a request type as sent to
    // DLMHelper.sendRequest, as well as the json response from the client.
    me.handleResponse = function( type, json ) {
      callback( json );
    }

    // ################################################################################################################
    // This is a pseudo-event-handler that lets the DLMHelper object send us messages that we can
    // act on. Notably, the DLMHelper can let us know as soon as the client has been installed so
    // we can proceed with our download.
    me.notify = function( message ){
      switch ( message ) {
            case "INSTALLED":
                DLMHelper.sendRequest( me.dlmId, "PSEUDO", me.request );
                break;
            case "EULAACCEPTED":
                break;
            default:
                DLMHelper.warn( "'notify()' called with unsupported message: " + message );
        }
    }

    if ( DLMHelper.installed ) {
      me.notify("INSTALLED");
    } else {
      DLMHelper.startInstall( );
    }

    // Return our modified div 'me'.
    return me;
}

// ####################################################################################################################
// DLMHelper is an Object, rather than a 'Class'. It's a singleton and can not be instantiated. #######################
// ####################################################################################################################
var DLMHelper = new Object();

// Configuration
DLMHelper.enableQueryLog = false;

// Global state variables.
DLMHelper.DLMs             = new Array();
DLMHelper.installed        = false;
DLMHelper.lookingForClient = false;
DLMHelper.lookedForClient  = false;
DLMHelper.installClientOnceLookedFor = false;
// Default EXE name, if one wasn't specified.
DLMHelper.exeName          = "installer";
DLMHelper.supportedBrowser = false;
DLMHelper.acceptedEULA     = false;
DLMHelper.logEvents        = {};
DLMHelper.onClientInstall  = null;

// ####################################################################################################################
// Helper functions from here on down. ################################################################################
// ####################################################################################################################

// ####################################################################################################################
// Auxiliary functions to support multiple downloads:

// Starts download of all DLMs in the group.
// Parameter group is optional. If not provided, all DLMs registered with DLMHelper are started. 
DLMHelper.downloadAll = function( group ) {
    var dlms = DLMHelper.DLMs; 
    if ( group ) dlms = group;
    for ( var i = 0; i < dlms.length; i++ )
        dlms[ i ].beginDownload();
    return false; // prevents standard event handler when invoked by click on anchor
}

// Starts download of all DLMs in the group having their checkboxes checked. 
// If they don't have a checkbox they are started too.
// Parameter group is optional. If not provided, all DLMs registered with DLMHelper are started. 
DLMHelper.downloadSelected = function( group ) {
    var dlms = DLMHelper.DLMs; 
    if ( group ) dlms = group;
    for ( var i = 0; i < dlms.length; i++ ) {
        if ( dlms[ i ].checkbox ) {
            var checkbox = document.getElementById( dlms[ i ].checkbox );
            if ( checkbox && !checkbox.checked ) continue;
        }
        dlms[i].beginDownload();
    }
    return false; // prevents standard event handler when invoked by click on anchor
}

// Pauses or resumes (depending on current state) all the DLMs in a group 
// or if group not specified pauses/resumes all DLMs registered with the DLMHelper. 
DLMHelper.pauseResumeAll = function( group ) {
    var dlms = DLMHelper.DLMs; 
    if ( group ) dlms = group;
    for ( var i = 0; i < dlms.length; i++ )
        dlms[ i ].pauseResume();
    return false; // prevents standard event handler when invoked by click on anchor
}

// Checks/unchecks all checkboxes for DLMs in a group. Param checked is true (to check) or false (to uncheck).
// Parameter group is optional. If not provided, all DLMs registered with DLMHelper and having checkboxes are
// (un)checked.
DLMHelper.checkAll = function( checked, group ) {
    var dlms = DLMHelper.DLMs; 
    if ( group ) dlms = group;
    for ( var i = 0; i < dlms.length; i++ ) {
        if ( dlms[ i ].checkbox ) {
            var checkbox = document.getElementById( dlms[ i ].checkbox );
            if ( checkbox ) checkbox.checked = checked;
        }
    }
    return false; // prevents standard event handler when invoked by click on anchor
}

// ####################################################################################################################
// Creates a new script tag with the provided source url. A random number is appended to avoid caching.
// The script tag is removed after 10 seconds.
DLMHelper.scriptRequest = function( url ) {
    var s = document.createElement( "script" );
    s.type = "text/javascript";
    s.src = url + "&r=" + Math.random();
    document.getElementsByTagName( "head" )[ 0 ].appendChild( s );
    setTimeout( function(){ s.parentNode.removeChild( s ) }, 10000 );
}

// ####################################################################################################################
// When we get responses from the client, we send the response back to the same DLM that made the request in the first
// place.
DLMHelper.dispatchResponse = function( dlmId, type, json ) {
    try        { DLMHelper.DLMs[ dlmId ].handleResponse( type, json ); }
    catch( e ) {
        DLMHelper.warn("Couldn't call 'handleResponse()' for DLM " + dlmId + ", Error: " + e);
        throw( e );
    }
}

// ####################################################################################################################
// This is used to locate the Akamai client. Optionally runs repeatedly until the client is found.
DLMHelper.findClient = function( delay ) {
    if ( DLMHelper.installed ) return;
    var cid = 1;
    try{
        eval("cid = DLMCID");
    }
    catch(e){
        // Whatever, I guess they didn't define DLMCID, use 1.
    }
    if(cid == 1 && DLMHelper.DLMs[0]) cid = DLMHelper.DLMs[0].cid;
    DLMHelper.scriptRequest( "http://127.0.0.1:9421/api?function=getClientAttributes&cid=" + cid +
        "&complete&wrapper=DLMHelper.setInstalled(*);" );
    if ( delay ) setTimeout( function(){ DLMHelper.findClient( delay ) }, delay );
}

// ####################################################################################################################
// Initialize everything that's required for this library to function.
DLMHelper.init = function(){

    var osOK      = false;
    var browserOK = false;

    // Regexes to check for supported OSes (Windows, OS X).
    var sOSes = [
        "OS X",
        "Windows"
    ];

    // Regexes to check for supported browsers:
    // Firefox 2/3, IE6/7/8, Safari 3, Google Chrome
    var sBrowsers = [
        "Gecko/[0-9.]+ Firefox/(2|3)[0-9.]+",
        "MSIE (6|7|8)",
        "AppleWebKit/[0-9.]+ \\(KHTML, like Gecko\\) (Version|Chrome)/[0-9.]+ Safari/[0-9.]+"
    ];

    for ( var i = 0; i < sOSes.length; i++ ) {
        var matcher = new RegExp( sOSes[ i ] );
        if ( matcher.exec( window.navigator.userAgent ) ) osOK = true;
    }

    for ( var i = 0; i < sBrowsers.length; i++ ) {
        var matcher = new RegExp( sBrowsers[ i ] );
        if ( matcher.exec( window.navigator.userAgent ) ) browserOK = true;
    }

    if ( osOK && browserOK ) {
        DLMHelper.supportedBrowser = true;
        DLMHelper.findClient( 0 );
    }

    window.onbeforeunload = function() {
        for ( var i = 0; i < DLMHelper.DLMs.length; i++ )
            if ( DLMHelper.DLMs[ i ].intendedState == "DOWNLOADING" )
                return DLMHelper.DLMs[ i ].localize( "unloadMsg" );
    }

    // We want to log that this page was loaded, but we want to know if the client was already installed.
    setTimeout( function(){
        DLMHelper.lookedForClient = true;
        if( DLMHelper.installed ) {
          if ( DLMHelper.onClientInstall && "function" == typeof DLMHelper.onClientInstall ) {
            DLMHelper.onClientInstall( /*newInstall=*/false ) ;
          }
          DLMHelper.log( "loadAlreadyInstalled" );
        } else {
          DLMHelper.log( "loadNotInstalled" );
          if (DLMHelper.installClientOnceLookedFor)
          {
            DLMHelper.startInstall( );
          }
        }
    }, 1000 );
}

// ####################################################################################################################
DLMHelper.open = function( a, b, c, d ) {
    if ( window.attachEvent ) { // should be IE.
        DLMHelper.startInstall( d );
    }
    return window.open( a, b, c );
}

// ####################################################################################################################
DLMHelper.register = function( dlm ){
    DLMHelper.DLMs.push( dlm );
    return DLMHelper.DLMs.length - 1;
}

// ####################################################################################################################
// Sends requests to the client in a format that guarantees we'll be able to give the response back to the correct DLM
// object.
DLMHelper.sendRequest = function( dlmId, type, url ) {
    DLMHelper.scriptRequest( url + "&wrapper=DLMHelper.dispatchResponse(" + dlmId + ", '" + type + "',*);" );
}

// ####################################################################################################################
// Used as the callback via the 'findClient' function, simply sets the installed flag to true on any response from the
// client.
DLMHelper.setInstalled = function( json ) {
    if(DLMHelper.installed) return;
    DLMHelper.installed = true;
    if (DLMHelper.logEvents["loadNotInstalled"]) {// Keeps from logging before we've find out we were already there.
        DLMHelper.log("installCompleted");
        if ( DLMHelper.onClientInstall && "function" == typeof DLMHelper.onClientInstall ) {
            DLMHelper.onClientInstall( /*newInstall=*/true ) ;
        }
    }

    // If the EULA had already been accepted before we even figured out the client had been installed, then a 
    // user must have accepted it to start the installation. This means we'll have to notify the client that
    // the EULA's been installed.
    var alreadyAcceptedEULA = DLMHelper.acceptedEULA;

    // See if a EULA's been accepted.
    if( json[ "acceptedeula" ] && json[ "acceptedeula" ] == true ) {
        DLMHelper.acceptedEULA = true;
    }
    
    // Notify any existing DLMs that the client's been installed.
    for ( var i = 0; i < DLMHelper.DLMs.length; i++ ) {
        if ( DLMHelper.DLMs[ i ] ){
            DLMHelper.DLMs[ i ].notify( "INSTALLED" );
            if ( DLMHelper.acceptedEULA )
                DLMHelper.DLMs[ i ].notify( "EULAACCEPTED" );
        }
    }

    // If we've got a cached EULA acceptance to send, we send it now that we've verified a connection to the client.
    if( DLMHelper.acceptEULA.cachedAcceptance ){
        DLMHelper.acceptEULA.cachedAcceptance();
        DLMHelper.acceptEULA.cachedAcceptance = null; // Don't run this twice.
    }
}

// ####################################################################################################################
DLMHelper.acceptEULA = function( cid, eulaVersion ){
    if ( DLMHelper.acceptedEULA ) return;
    DLMHelper.acceptedEULA = true;

    DLMHelper.acceptEULA.cachedAcceptance = function(){
        //  The client was already installed, so we need to notify it of the newly accepted EULA.
        var url = "http://127.0.0.1:9421/api?cid=" + cid + "&function=acceptEULA&version=" + eulaVersion +
            "&wrapper=function ignore(){var ig = *;return false;}";
        DLMHelper.scriptRequest( url );  
    }

    if( DLMHelper.installed ) {
        DLMHelper.acceptEULA.cachedAcceptance();
        DLMHelper.acceptEULA.cachedAcceptance = null; // Don't run this twice.

        // Notify any existing DLMs that the EULA's been accepted.
        for ( var i = 0; i < DLMHelper.DLMs.length; i++ ) {
            if ( DLMHelper.DLMs[ i ] ) DLMHelper.DLMs[ i ].notify( "EULAACCEPTED" );
        }
    }
}

// ####################################################################################################################
// This pops up the dialog box to download and run the installer.
DLMHelper.startInstall = function( exeName ) {

    if ( exeName ) {
      DLMHelper.exeName = exeName;
    }

    if ( !DLMHelper.lookedForClient ) {
      DLMHelper.installClientOnceLookedFor = true;
      return;
    }
    
    // Once we've had someone start an install, we begin checking for the client every second until it's found.
    if ( !DLMHelper.lookingForClient ) {
        DLMHelper.LookingForClient = true;
        DLMHelper.findClient( 1000 );
    }

    // For Internet Explorer, we only want to run this if we're running as part of an onclick event handler.
    // If we're called from any other context, we'll be blocked by the pop-up blocker anyway, so we just return now to
    // avoid causing a yellow bar at the top of the window.
    if ( window.attachEvent ) { // should be IE.
        if ( !window.event || window.event.type != "click" ) return;
    }

    if ( DLMHelper.installed ) return;
    var platform = window.navigator.userAgent.match( /OS X/ ) ? "mac" : "win";

    var iframe           = document.createElement( "iframe" );
    iframe.style.width   = "0";
    iframe.style.height  = "0";
    iframe.style.display = "none";
    if(window.navigator.userAgent.match(
        /Windows.*AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/[0-9.]+ Safari\/[0-9.]+/
    ))
    {
        // Safari on Windows doesn't seem to listen to Content-Disposition headers correctly when naming downloads,
        // so we don't allow renaming of the binary in that case, and instead go straight to the original.
        iframe.src = "https://client.akamai.com/install/bin/setup_2009-07-21.exe";
    }
    else
        iframe.src = "https://client.akamai.com/conf/install_" + 
                     platform + ".html?file=" + encodeURIComponent( DLMHelper.exeName.replace( / /g, "_" ) );
    document.body.appendChild( iframe );
}

// ####################################################################################################################
// Determines whether the Browser+OS combination is supported or not
DLMHelper.isPlatformSupported = function( ) {
    return DLMHelper.supportedBrowser ;
}

// ####################################################################################################################
// Determines whether the Netsession client is installed or not
DLMHelper.isClientInstalled = function( ) {
    return DLMHelper.installed ;
}

// ####################################################################################################################
// Display warnings as alerts. This may be replaced with a logging mechanism.
DLMHelper.warn = function( warning ) {
     // alert( warning ); // temporarily disabled
}

// ####################################################################################################################
DLMHelper.queryLog = function( colName ) {
    if ( !DLMHelper.enableQueryLog ) 
        return;
    var sSrc = "http://qg.redswoosh.akadns.net/query?t=dlmstats&c=" + colName + "&o=inc&w=count";
    DLMHelper.scriptRequest( sSrc );
}

// ####################################################################################################################
DLMHelper.log = function( eventKey ) {
    if( DLMHelper.logEvents["loadAlreadyInstalled"] )
        return; // If the client was installed when we got here, then we never log anything besides that.
    if( DLMHelper.logEvents[eventKey] )
        return; // We don't log the same event more than once.
    DLMHelper.logEvents[eventKey] = true;
    DLMHelper.queryLog( eventKey );
}

// ####################################################################################################################
DLMHelper.getUrlSetId = function( urlSetIdCallback ) {
  new pseudoDLM("http://127.0.0.1:9421/api?function=createUrlSet&cid=" + DLMCID, 
                function( json ) { 
                  for ( var i in json ) {
                    if ( i == "urlSetId" ) {
                      urlSetIdCallback(json[i]);
                      return;
                    }
                  }
                });
}

// ####################################################################################################################
  DLMHelper.getUrlSet = function( urlSetId, urlSetCallback ) {
  new pseudoDLM("http://127.0.0.1:9421/api?function=getUrlSet&cid=" + DLMCID + "&urlSetId=" + urlSetId, 
                function( json ) { 
                  for ( var i in json ) {
                    if ( i == "urls" ) {
                      urlSetCallback(eval(json[i]));
                    }
                  }
                });
}

// Create the default stylesheet for DLM objects.
DLMHelper.css = "http://client.akamai.com/dlm/dlm-1.2.css";
try{
    DLMHelper.css = DLMCSS;
}
catch(e){
    // We don't actually care about this error, we're just trying to trap 'DLMCSS' being undefined.
}

if(DLMHelper.css){
    // For already loaded DOMs.
    if(document.getElementsByTagName("head").length){
        var style = document.createElement("link");
        style.type = "text/css";
        style.rel = "stylesheet";
        style.href = DLMHelper.css;
        document.getElementsByTagName("head")[0].appendChild(style);
    }
    // For DOMs currently loading. (Not sure if this is ever called).
    else document.write( "<link rel='stylesheet' href='" + DLMHelper.css + "' type='text/css' />" );
}

// Set all the strings used for all of our supported languages.
DLMHelper.languages = {
    cs: {
        "startTitle": "Klikněte na možnost Spustit nebo Otevřít, tím spustíte instalační program.",
        "relaunchMsgStart": "Nezobrazil se instalační program? ",
        "relaunchLink": "Zkuste jej znovu otevřít.",
        "relaunchMsgEnd": "",
        "title": "Stahování souboru %s",
        "autoStart": " Automaticky otevřít po dokončení.",
        "completeTitle": "Stahování dokončeno!",
        "completeText": "Otevřít soubor %s",
        "timeLabel": "%s do konce.",
        "waiting": "Čekám.",
        "paused": "Pozastaveno.",
        "pausedNotFound": "Soubor nenalezen!",
        "pausedInsufficientDiskSpace": "Nedostatečné místo na disku!",
        "pausedForbidden": "Přístup odepřen!",
        "pausedDisconnected": "Odpojeno od serveru, zkouším znovu...",
        "unloadMsg": "Momentálně probíhá stahování. Pokud nyní odejdete, stahování bude brzy pozastaveno.",
        "minute": "minuta",
        "minutes": "minut(y)",
        "second": "sekunda",
        "seconds": "sekund(y)",
        "download": "Stáhnout",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Výpočet zbývající doby.",
        "acceptEULA": "Přijmout",
        "rejectEULA": "Zrušit",
        "EULADeniedText": "Je nám líto, ale odmítli jste licenci EULA. Níže uvedený odkaz můžete použít pro přímé stahování ze zdroje bez potřeby správce stahování Akamai Download Manager.",
        "EULADeniedLink": "Stáhnout přímo",
        "EULA1": "<span class='DLMeulaTitle'>Pro stažení tohoto souboru je nutný správce stahování <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, který využívá v omezené míře Vašeho připojení a zdrojů počítače pro připojení k síti vzájemně propojených počítačů, což zvyšuje rychlost a spolehlivost stahování jak pro Vás, tak pro ostatní uživatele správce Akamai Download Manager.</span>",
        "EULA2": "Kliknutím na tlačítko „Přijmout“ souhlasíte s <a href='http://www.akamai.com/eula'>licenční smlouvou společnosti Akamai</a>.",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Čekám...",
        "defaultStatus2": "Inicializace...",
        "titleTextProgress": "Celkový průběh – %s",
        "titleTextPaused": "Celkový průběh – %s – POZASTAVENO",
        "statusProgress": "%s (%s ze %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Zrušeno – %s",
        "cancelledMsg": "Spustit stahování znovu."
    },
    da : {
        "startTitle": "Klik på \"kør\" eller \"åbn\" for at starte installationsprogrammet.",
        "relaunchMsgStart": "Kan du ikke se installationsprogrammet? ",
        "relaunchLink": "Prøv at åbne det igen.",
        "relaunchMsgEnd": "",
        "title": "Overfører %s",
        "autoStart": " Åbn automatisk, når udført.",
        "completeTitle": "Overførslen udført!",
        "completeText": "Åbn %s",
        "timeLabel": "%s tilbage.",
        "waiting": "Venter.",
        "paused": "Stoppet midlertidigt.",
        "pausedNotFound": "Fil ikke fundet!",
        "pausedInsufficientDiskSpace": "Utilstrækkelig plads på disken!",
        "pausedForbidden": "Adgang nægtet!",
        "pausedDisconnected": "Forbindelse til serveren afbrudt, prøver igen...",
        "unloadMsg": "Der er en overførsel i gang. Hvis du afslutter nu, vil overførslen blive sat på pause.",
        "minute": "minut",
        "minutes": "minutter",
        "second": "sekund",
        "seconds": "sekunder",
        "download": "Overfør",
        "hourAbbr": "t",
        "minAbbr": "m",
        "calcTime": "Beregner tiden tilbage.",
        "acceptEULA": "Accepter",
        "rejectEULA": "Annuller",
        "EULADeniedText": "Vi beklager, at du afviste EULA'en. Du kan bruge linket herunder til at overføre direkte fra kilden uden Akamai Download Manager.",
        "EULADeniedLink": "Overfør direkte",
        "EULA1": "<span class='DLMeulaTitle'>Denne overførsel kræver <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, som bruger en begrænset del af din overførselsbåndbredde og pc-ressourcer til at tilslutte dig til et peered-netværk, hvilket forbedrer overførselshastigheden og pålideligheden for dig og andre slutbrugere af Akamai Download Manager.</span>",
        "EULA2": "Ved at klikke på \"Accepter\" accepterer du <a href='http://www.akamai.com/eula'>Akamai-licensaftalen.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Venter...",
        "defaultStatus2": "Initialiserer...",
        "titleTextProgress": "Samlet status %s",
        "titleTextPaused": "Samlet status %s STOPPET MIDLERTIDIGT",
        "statusProgress": "%s (%s af %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Annulleret %s",
        "cancelledMsg": "Genstart overførslen."
    },
    de: {
        "startTitle": "Klicken Sie auf \„Ausführen\“ oder \„Öffnen\“, um das Installationsprogramm zu öffnen.",
        "relaunchMsgStart": "Das Installationsprogramm wird nicht angezeigt? ",
        "relaunchLink": "Öffnen Sie das Programm erneut.",
        "relaunchMsgEnd": "",
        "title":  "Wird heruntergeladen: %s",
        "autoStart": " Nach Beenden Datei automatisch öffnen.",
        "completeTitle": "Download beendet!",
        "completeText": " öffnen",
        "timeLabel": "Noch %s.",
        "waiting": "Warten.",
        "paused": "Angehalten.",
        "pausedNotFound": "Datei nicht gefunden.",
        "pausedInsufficientDiskSpace": "Festplattenspeicher nicht ausreichend.",
        "pausedForbidden": "Zugriff verweigert.",
        "pausedDisconnected": "Verbindung unterbrochen.",
        "unloadMsg": "Es wird derzeit ein Download durchgeführt. Wenn Sie diese Seite jetzt verlassen, wird der Download in Kürze angehalten.",
        "minute": "Minute",
        "minutes": "Minuten",
        "second": "Sekunde",
        "seconds": "Sekunden",
        "download": "Download",
        "hourAbbr": "Std",
        "minAbbr": "Min",
        "calcTime": "Dauer wird berechnet.",
        "acceptEULA": "Akzeptieren", 
        "rejectEULA": "Abbrechen", 
        "EULADeniedText": "Wir bedauern, dass Sie die Endnutzer-Lizenzvereinbarung abgelehnt haben. Sie können den folgenden Link verwenden und den Download direkt vom Ursprung durchführen, ohne den Akamai Download Manager zu verwenden.",
        "EULADeniedLink": "Direkter Download",
        "EULA1": "<span class='DLMeulaTitle'>Für diesen Download wird der <a href='http://www.akamai.com/client/'>Akamai Download Manager</a> benötigt, der eine begrenzte Menge Ihrer Upload-Bandbreite und PC-Ressourcen verwendet, um eine Verbindung zu einem Peer-Netzwerk herzustellen, das die Download-Geschwindigkeit und -Zuverlässigkeit für Sie und andere Endnutzer des Akamai Download Manager verbessert.</span>",
        "EULA2": "Durch Klicken auf \„Akzeptieren\“ akzeptieren Sie die <a href='http://www.akamai.com/eula'>Lizenzvereinbarung von Akamai</a>.", 

        "waitStatus": "Warten ...",
        "defaultStatus2": "Initialisieren ...",
        "titleTextProgress": "Gesamtfortschritt %s",
        "titleTextPaused": "Gesamtfortschritt %s PAUSIERT",
        "statusProgress": "%s (%s von %s): %s",
        "percentage": "%s %",
        "cancelledTitle": "%s abgebrochen",
        "cancelledMsg": "Starten Sie den Download erneut."
    },
    en: {
        "startTitle": "Click \"run\" or \"open\" to start the installer.",
        "relaunchMsgStart": "Don't see the installer? ",
        "relaunchLink": "Try reopening it.",
        "relaunchMsgEnd": "",
        "title": "Downloading %s",
        "autoStart": " Automatically open when complete.",
        "completeTitle": "Download Complete!",
        "completeText": "Open %s",
        "timeLabel": "%s remaining.",
        "waiting": "Waiting.",
        "paused": "Paused.",
        "pausedNotFound": "File not found!",
        "pausedInsufficientDiskSpace": "Insufficient disk space!",
        "pausedForbidden": "Access denied!",
        "pausedDisconnected": "Disconnected from server, retrying...",
        "unloadMsg": "There is currently a download in progress. If you leave now, the download will pause shortly.",
        "minute": "minute",
        "minutes": "minutes",
        "second": "second",
        "seconds": "seconds",
        "download": "Download",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Calculating time remaining.",
        "acceptEULA": "Accept",
        "rejectEULA": "Cancel",
        "EULADeniedText": "We are sorry you denied the EULA. You may use the link below to download direct from the origin without the Akamai Download Manager.",
        "EULADeniedLink": "Download Direct",
        "EULA1": "<span class='DLMeulaTitle'>This download requires the <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, which utilizes a limited amount of your upload bandwidth and PC resources to connect you to a peered network, which improves download speed and reliability for you and other end users of the Akamai Download Manager.</span>",
        "EULA2": "By clicking \"Accept\" you accept the <a href='http://www.akamai.com/eula'>Akamai License Agreement.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Waiting...",
        "defaultStatus2": "Initializing...",
        "titleTextProgress": "Total Progress %s",
        "titleTextPaused": "Total Progress %s PAUSED",
        "statusProgress": "%s (%s of %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Cancelled %s",
        "cancelledMsg": "Restart the download."
    },
    es: {
        "startTitle": "Haga clic en \"ejecutar\" o \"abrir\" para iniciar el instalador",
        "relaunchMsgStart": "¿No ve el instalador? ",
        "relaunchLink": "Pruebe a abrirlo de nuevo",
        "relaunchMsgEnd": "",
        "title": "Descargando %s",
        "autoStart": " Abrir el archivo automáticamente una vez finalizada la descarga",
        "completeTitle": "¡Descarga completa!",
        "completeText": "Abrir ",
        "timeLabel": "%s restante",
        "waiting": "Esperando",
        "paused": "Pausado",
        "pausedNotFound": "¡Archivo no encontrado!",
        "pausedInsufficientDiskSpace": "¡No hay suficiente espacio en el disco!",
        "pausedForbidden": "¡Acceso denegado!",
        "pausedDisconnected": "Desconectado",
        "unloadMsg": "Actualmente hay una descarga en proceso. Si abandona ahora, la descarga se detendrá en breve.",
        "minute": "minuto",
        "minutes": "minutos",
        "second": "segundo",
        "seconds": "segundos",
        "download": "Descarga",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Calculando tiempo restante",
        "acceptEULA": "Aceptar",
        "rejectEULA": "Cancelar",
        "EULADeniedText": "Lo sentimos, usted ha rechazado el Contrato de Licencia. Puede utilizar el enlace a continuación para descargar directamente desde el origen sin utilizar el Akamai Download Manager",
        "EULADeniedLink": "Descarga Directa",
        "EULA1": "<span class='DLMeulaTitle'>Esta descarga requiere el <a href='http://www.akamai.com/client/'>Gestor de Descargas de Akamai</a>, que utiliza una cantidad limitada de su ancho de banda de carga y de recursos de su PC para conectarle a una red interconectada, que mejora la velocidad de descarga y la fiabilidad tanto para usted como para los demás usuarios del Gestor de Descargas de Akamai.</span>",
        "EULA2": "Haciendo clic en \"Aceptar\", usted acepta el <a href='http://www.akamai.com/eula'>Acuerdo de Licencia de Akamai.</a>", 

        "waitStatus": "Esperando...",
        "defaultStatus2": "Inicializando...",
        "titleTextProgress": "Progreso Total  %s",
        "titleTextPaused": "Progreso Total PAUSADO %s",
        "statusProgress": "%s (%s de %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Cancelado %s",
        "cancelledMsg": "Reiniciar la descarga."
    },
    fi: {
        "startTitle": "Käynnistä asennusohjelma valitsemalla suorita tai avaa.",
        "relaunchMsgStart": "Etkö näe asennusohjelmaa? ",
        "relaunchLink": "Yritä avata se uudelleen.",
        "relaunchMsgEnd": "",
        "title": "Ladataan kohdetta %s",
        "autoStart": " Avaa automaattisesti, kun tiedosto on ladattu.",
        "completeTitle": "Tiedosto on ladattu!",
        "completeText": "Avaa %s",
        "timeLabel": "%s jäljellä.",
        "waiting": "Odotetaan.",
        "paused": "Keskeytetty.",
        "pausedNotFound": "Tiedostoa ei löydy.",
        "pausedInsufficientDiskSpace": "Levytila ei riitä.",
        "pausedForbidden": "Käyttö on estetty.",
        "pausedDisconnected": "Yhteys palvelimeen on katkennut, yritetään uudelleen...",
        "unloadMsg": "Lataaminen on käynnissä. Jos lopetat nyt, lataaminen keskeytetään.",
        "minute": "minuutti",
        "minutes": "minuuttia",
        "second": "sekunti",
        "seconds": "sekuntia",
        "download": "Lataa",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Lasketaan kestoa jäljellä.",
        "acceptEULA": "Hyväksy",
        "rejectEULA": "Peruuta",
        "EULADeniedText": "Valitettavasti et hyväksynyt käyttöoikeussopimusta. Voit ladata kohteen suoraan alkuperäisestä lähteestä alla olevan linkin kautta ilman Akamai-lataustenhallintasovellusta.",
        "EULADeniedLink": "Lataa suoraan",
        "EULA1": "<span class='DLMeulaTitle'>Lataamiseen tarvitaan <a href='http://www.akamai.com/client/'> Akamai-lataustenhallintasovellus</a>, joka muodostaa yhteyden vertaisverkkoon ja käyttää rajoitetusti kaistanleveyttä ja tietokoneen suorituskykyä, mikä parantaa latausnopeutta ja luotettavuutta niin sinun kuin muidenkin Akamai-lataustenhallintasovelluksen käyttäjien kohdalla.</span>",
        "EULA2": "Valitsemalla Hyväksy ilmaiset hyväksyväsi <a href='http://www.akamai.com/eula'>Akamai-käyttöoikeussopimuksen.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Odotetaan...",
        "defaultStatus2": "Alustetaan...",
        "titleTextProgress": "Kokonaisedistyminen: %s",
        "titleTextPaused": "Kokonaisedistyminen: %s. KESKEYTETTY",
        "statusProgress": "%s (%s / %s): %s",
        "percentage": "%s %",
        "cancelledTitle": "Peruutettu: %s",
        "cancelledMsg": "Käynnistä lataaminen uudelleen."
    },
    fr: {
        "startTitle": "Cliquez sur \"exécuter\" ou \"ouvrir\" pour démarrer l’utilitaire d’installation.",
        "relaunchMsgStart": "L’utilitaire d’installation ne s’affiche pas ? ",
        "relaunchLink": "Essayez de l’ouvrir à nouveau.",
        "relaunchMsgEnd": "",
        "title": "Téléchargement %s",
        "autoStart": " Ouvrir le fichier automatiquement à la fin.",
        "completeTitle": "Téléchargement terminé.",
        "completeText": "Ouvrir ",
        "timeLabel": "%s de temps restant.",
        "waiting": "En attente.",
        "paused": "En suspens.",
        "pausedNotFound": "Fichier non trouvé !",
        "pausedInsufficientDiskSpace": "Espace de stockage insuffisant !",
        "pausedForbidden": "Accès refusé !",
        "pausedDisconnected": "Déconnecté.",
        "unloadMsg": "Téléchargement en cours. Si vous quittez la page maintenant, le téléchargement sera interrompu.",
        "minute": "minute",
        "minutes": "minutes",
        "second": "seconde",
        "seconds": "secondes",
        "download": "Téléchargement",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Calcul du temps requis de temps restant.",
        "acceptEULA": "Accepter",
        "rejectEULA": "Annuler",
        "EULADeniedText": "Nous regrettons que vous ayez refusé le CLUF. Vous pouvez utiliser le lien ci-dessous pour télécharger directement à l’origine, sans le gestionnaire de téléchargement Download Manager d’Akamai.",
        "EULADeniedLink": "Télécharger directement",
        "EULA1": "<span class='DLMeulaTitle'>Ce téléchargement requiert <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, utilisant une quantité limitée de votre bande passante de chargement et de vos ressources PC pour vous connecter à un réseau d’appairage, qui améliore la vitesse et la fiabilité des téléchargements pour vous et d’autres utilisateurs finaux de Akamai Download Manager.</span>",
        "EULA2": "En cliquant sur \"Accepter\" vous acceptez <a href='http://www.akamai.com/eula'>l’accord de licence d’Akamai.</a>",

        // Nouvelles chaînes DLM groupées. Inclut aussi le format de pourcentage localisable.
        "waitStatus": "En attente...",
        "defaultStatus2": "Initialisation...",
        "titleTextProgress": "Progrès total %s",
        "titleTextPaused": "Progrès total %s EN ATTENTE",
        "statusProgress": "%s (%s de %s) : %s",
        "percentage": "%s%",
        "cancelledTitle": "%s d’annulation",
        "cancelledMsg": "Réinitialiser le téléchargement."
    },
    it: {
        "startTitle": "Per avviare l'installazione, fate clic su Esegui o Apri.",
        "relaunchMsgStart": "Il modulo di installazione non viene visualizzato? ",
        "relaunchLink": "Provate a riaprirlo.",
        "relaunchMsgEnd": "",
        "title": "Scaricamento in corso di %s",
        "autoStart": " Al termine, apri automaticamente.",
        "completeTitle": "Download completato.",
        "completeText": "Apri %s",
        "timeLabel": "%s rimanente.",
        "waiting": "In attesa.",
        "paused": "In pausa.",
        "pausedNotFound": "File non trovato.",
        "pausedInsufficientDiskSpace": "Spazio su disco insufficiente.",
        "pausedForbidden": "Accesso negato.",
        "pausedDisconnected": "Disconnesso dal server, nuovo tentativo...",
        "unloadMsg": "È in corso un download. Se uscite adesso, il download verrà messo in pausa.",
        "minute": "minuto",
        "minutes": "minuti",
        "second": "secondo",
        "seconds": "secondi",
        "download": "Download",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Calcolo del tempo necessario rimanente.",
        "acceptEULA": "Accetta",
        "rejectEULA": "Annulla",
        "EULADeniedText": "Ci dispiace che non abbiate accettato il Contratto di licenza per l'utente finale. Per scaricare direttamente dalla sorgente senza ricorrere ad Akamai Download Manager, potete usare il collegamento seguente.",
        "EULADeniedLink": "Download diretto",
        "EULA1": "<span class='DLMeulaTitle'>Questo download richiede <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, che utilizza una quantità limitata di ampiezza di banda in upload e di risorse PC per la connessione a una rete peer-to-peer, al fine di migliorare la velocità e l'affidabilità del download per voi e gli altri utenti di Akamai Download Manager.</span>",
        "EULA2": "Facendo clic sul pulsante Accetta confermate di accettare il <a href='http://www.akamai.com/eula'>Contratto di licenza per Akamai.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "In attesa...",
        "defaultStatus2": "Inizializzazione in corso...",
        "titleTextProgress": "Avanzamento totale %s",
        "titleTextPaused": "Avanzamento totale %s IN PAUSA",
        "statusProgress": "%s (%s di %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "%s annullato",
        "cancelledMsg": "Riavviate il download."
    },
    ja: {
        "startTitle": "実行\"または\"開く\"をクリックして\"インストーラーを起動",
        "relaunchMsgStart": "インストーラーが見えない場合",
        "relaunchLink": "もう一度開く",
        "relaunchMsgEnd": "",
        "title": "ダウンロード中 %s",
        "autoStart": " 終了後、自動的にファイルを開きます。",
        "completeTitle": "ダウンロードが完了しました！",
        "completeText": "開く",
        "timeLabel": "%s残り",
        "waiting": "待機中",
        "paused": "停止",
        "pausedNotFound": "ファイルが見つかりません！",
        "pausedInsufficientDiskSpace": "ディスクスペースが不十分です！",
        "pausedForbidden": "アクセスが拒否されました！",
        "pausedDisconnected": "切断されました。",
        "unloadMsg": "現在ダウンロード中です。このページを閉じますと、ダウンロードは中断されます",
        "minute": "分", 
        "minutes": "分", 
        "second": "秒", 
        "seconds": "秒", 
        "download": "ダウンロード",
        "hourAbbr": "時間",
        "minAbbr": "分",
        "calcTime": "時間を計算中残り",
        "acceptEULA": "同意",
        "rejectEULA": "キャンセル",
        "EULADeniedText": "お客様は EULA の使用を拒否されました。下記のリンクでも、Akamai Download Manager を使わずにオリジンから直接ダウンロードしていただけます。", 
        "EULADeniedLink": "直接ダウンロード", 
        "EULA1":"<span class='DLMeulaTitle'>このダウンロードには <a href='http://www.akamai.com/client/'>Akamai Download Manager</a> が必要です。Akamai Download Manager は、限られたアップロードの帯域幅や PC　のリソースを活用して、ピアネットワークに接続し、お客様とその他のユーザーのダウンロード速度と信頼性を向上します。</span>",
        "EULA2":" \"同意する\" をクリックすると <a href='http://www.akamai.com/eula'>アカマイ ライセンス契約</a> に同意したことになります。",

        "waitStatus": "待機中…",
        "defaultStatus2": "初期化処理中…",
        "titleTextProgress": "全体の進行状況 %s",
        "titleTextPaused": "全体の進行状況 %s 停止中",
        "statusProgress": "%s (%s 中 %s) : %s",
        "percentage": "%s%",
        "cancelledTitle": "キャンセル済み %s",
        "cancelledMsg": "ダウンロードを再開"
    },
    ko: {
        "startTitle": "설치 프로그램를 시작하려면 \"실행\" 또는 \"열기\"를 클릭하십시오.",
        "relaunchMsgStart": "설치 프로그램이 보이지 않으십니까? ",
        "relaunchLink": "설치 프로그램 다시 열기",
        "relaunchMsgEnd": "",
        "title": "%s를 다운로드 중",
        "autoStart": " 다운로드가 완료되면 자동으로 열기.",
        "completeTitle": "다운로드 완료!",
        "completeText": "%s 열기",
        "timeLabel": "%s 남음.",
        "waiting": "대기 중.",
        "paused": "일시 중지됨.",
        "pausedNotFound": "파일을 찾을 수 없습니다!",
        "pausedInsufficientDiskSpace": "디스크 공간이 부족합니다!",
        "pausedForbidden": "액세스가 거부되었습니다!",
        "pausedDisconnected": "서버 연결이 끊겼습니다. 다시 시도하는 중...",
        "unloadMsg": "다운로드가 현재 진행 중입니다. 이 페이지를 벗어나면 다운로드가 일시 중지됩니다.",
        "minute": "분",
        "minutes": "분",
        "second": "초",
        "seconds": "초",
        "download": "다운로드",
        "hourAbbr": "시간",
        "minAbbr": "분",
        "calcTime": "시간 계산 중 남음",
        "acceptEULA": "동의",
        "rejectEULA": "취소",
        "EULADeniedText": "최종 사용자 사용권 계약에 동의하지 않으셨습니다. Akamai Download Manager 없이 아래 링크를 클릭하여 바로 다운로드할 수 있습니다.",
        "EULADeniedLink": "바로 다운로드하기",
        "EULA1": "<span class='DLMeulaTitle'>이 다운로드를 수행하려면 제한된 업로드 대역폭과 PC 리소스를 활용하여 피어 네트워크에 연결함으로써 <a href='http://www.akamai.com/client/'>의 사용자에게 빠른 다운로드 속도와 개선된 안정성을 제공하는 Akamai Download Manager가 필요합니다. </span>",
        "EULA2": "\"동의\" 버튼을 클릭하면 <a href='http://www.akamai.com/eula'>Akamai 사용권 계약에 동의하는 것입니다.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "대기 중...",
        "defaultStatus2": "초기화하는 중...",
        "titleTextProgress": "전체 진행률 %s",
        "titleTextPaused": "전체 진행률 %s 일시 중지",
        "statusProgress": "%s(%s/%s): %s",
        "percentage": "%s%",
        "cancelledTitle": "%s 취소",
        "cancelledMsg": "다운로드 재시작."
    },
    nl: {
        "startTitle": "Klik op \"Uitvoeren\" of \"Openen\" om het installatieprogramma te starten.",
        "relaunchMsgStart": "Als het installatieprogramma niet wordt weergegeven, ",
        "relaunchLink": "probeer het dan opnieuw te openen.",
        "relaunchMsgEnd": "",
        "title": "Bezig met downloaden van %s",
        "autoStart": "  Automatisch openen nadat het downloaden is voltooid.",
        "completeTitle": "Het downloaden is voltooid.",
        "completeText": "%s openen",
        "timeLabel": "%s resterend.",
        "waiting": "Een ogenblik geduld.",
        "paused": "Onderbroken.",
        "pausedNotFound": "Bestand niet gevonden.",
        "pausedInsufficientDiskSpace": "Onvoldoende schijfruimte.",
        "pausedForbidden": "Toegang geweigerd.",
        "pausedDisconnected": "Verbinding met server verbroken. Bezig met opnieuw verbinding maken...",
        "unloadMsg": "Momenteel wordt er een bestand gedownload. Als u deze pagina sluit, wordt het downloaden onderbroken.",
        "minute": "minuut",
        "minutes": "minuten",
        "second": "seconde",
        "seconds": "seconden",
        "download": "Downloaden",
        "hourAbbr": "u",
        "minAbbr": "m",
        "calcTime": "Bezig met berekenen tijdsduur resterend.",
        "acceptEULA": "Ik ga akkoord",
        "rejectEULA": "Annuleren",
        "EULADeniedText": "Het spijt ons dat u niet akkoord gaat met de EULA. U kunt de onderstaande koppeling gebruiken om het oorspronkelijke bestand rechtstreeks te downloaden zonder Akamai Download Manager.",
        "EULADeniedLink": "Rechtstreeks downloaden",
        "EULA1": "<span class='DLMeulaTitle'>Voor deze download is <a href='http://www.akamai.com/client/'>Akamai Download Manager</a> vereist. Deze software maakt gebruik van een klein deel van uw uploadbandbreedte en pc-middelen om u te verbinden met een peer-to-peer-netwerk, waardoor de downloadsnelheid wordt verhoogd en de betrouwbaarheid voor u en andere eindgebruikers van Akamai Download Manager verbetert.</span>",
        "EULA2": "Door te klikken op \"Ik ga akkoord\" gaat u akkoord met de <a href='http://www.akamai.com/eula'>licentieovereenkomst van Akamai.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Een ogenblik geduld…",
        "defaultStatus2": "Bezig met initialiseren….",
        "titleTextProgress": "Voortgang van %s",
        "titleTextPaused": "Voortgang van %s ONDERBROKEN",
        "statusProgress": "%s (%s van %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "%s geannuleerd",
        "cancelledMsg": "Start het downloaden opnieuw."
    },
    // Note: nb & no are both treated as Norwegian, as it is unclear which is 'right' (microsoft doc says no, 
    // mac testing shows nb)
    nb: {
        "startTitle": "Klikk på \"kjør\" eller \"åpne\" for å starte installeringsprogrammet.",
        "relaunchMsgStart": "Ser du ikke installeringsprogrammet? ",
        "relaunchLink": "Prøv å åpne det på nytt.",
        "relaunchMsgEnd": "",
        "title": "Laster ned %s",
        "autoStart": " Åpne automatisk når fullført.",
        "completeTitle": "Nedlasting fullført.",
        "completeText": "Åpne %s",
        "timeLabel": "%s gjenstår.",
        "waiting": "Venter.",
        "paused": "Stanset midlertidig.",
        "pausedNotFound": "Finner ikke filen.",
        "pausedInsufficientDiskSpace": "Ikke nok diskplass.",
        "pausedForbidden": "Ikke tilgang.",
        "pausedDisconnected": "Koblet fra server, prøver på nytt...",
        "unloadMsg": "En nedlasting pågår for øyeblikket. Hvis du går ut nå, stanses nedlastingen midlertidig.",
        "minute": "minutt",
        "minutes": "minutter",
        "second": "sekund",
        "seconds": "sekunder",
        "download": "Last ned",
        "hourAbbr": "t",
        "minAbbr": "m",
        "calcTime": "Beregner tid gjenstår.",
        "acceptEULA": "Godta",
        "rejectEULA": "Avbryt",
        "EULADeniedText": "Vi beklager at du ikke godtok lisensavtalen for sluttbrukere. Du kan bruke koblingen nedenfor til å laste ned direkte fra startpunktet uten Akamai Download Manager.",
        "EULADeniedLink": "Last ned direkte",
        "EULA1": "<span class='DLMeulaTitle'>Denne nedlastingen krever <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, som bruker en begrenset mengde opplastingsbåndbredde og PC-ressurser for å koble deg til et nodet nettverk, noe som forbedrer nedlastingshastigheten og påliteligheten for deg og andre sluttbrukere av Akamai Download Manager.</span>",
        "EULA2": "Når du klikker på Godta, godtar du <a href='http://www.akamai.com/eula'>Akamai-lisensavtalen.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Venter...",
        "defaultStatus2": "Initialiserer...",
        "titleTextProgress": "Total fremdrift: %s",
        "titleTextPaused": "Total fremdrift: %s STANSET MIDLERTIDIG",
        "statusProgress": "%s (%s av %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Avbrøt %s",
        "cancelledMsg": "Start nedlastingen på nytt."
    },
    no: {
        "startTitle": "Klikk på \"kjør\" eller \"åpne\" for å starte installeringsprogrammet.",
        "relaunchMsgStart": "Ser du ikke installeringsprogrammet? ",
        "relaunchLink": "Prøv å åpne det på nytt.",
        "relaunchMsgEnd": "",
        "title": "Laster ned %s",
        "autoStart": " Åpne automatisk når fullført.",
        "completeTitle": "Nedlasting fullført.",
        "completeText": "Åpne %s",
        "timeLabel": "%s gjenstår.",
        "waiting": "Venter.",
        "paused": "Stanset midlertidig.",
        "pausedNotFound": "Finner ikke filen.",
        "pausedInsufficientDiskSpace": "Ikke nok diskplass.",
        "pausedForbidden": "Ikke tilgang.",
        "pausedDisconnected": "Koblet fra server, prøver på nytt...",
        "unloadMsg": "En nedlasting pågår for øyeblikket. Hvis du går ut nå, stanses nedlastingen midlertidig.",
        "minute": "minutt",
        "minutes": "minutter",
        "second": "sekund",
        "seconds": "sekunder",
        "download": "Last ned",
        "hourAbbr": "t",
        "minAbbr": "m",
        "calcTime": "Beregner tid gjenstår.",
        "acceptEULA": "Godta",
        "rejectEULA": "Avbryt",
        "EULADeniedText": "Vi beklager at du ikke godtok lisensavtalen for sluttbrukere. Du kan bruke koblingen nedenfor til å laste ned direkte fra startpunktet uten Akamai Download Manager.",
        "EULADeniedLink": "Last ned direkte",
        "EULA1": "<span class='DLMeulaTitle'>Denne nedlastingen krever <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, som bruker en begrenset mengde opplastingsbåndbredde og PC-ressurser for å koble deg til et nodet nettverk, noe som forbedrer nedlastingshastigheten og påliteligheten for deg og andre sluttbrukere av Akamai Download Manager.</span>",
        "EULA2": "Når du klikker på Godta, godtar du <a href='http://www.akamai.com/eula'>Akamai-lisensavtalen.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Venter...",
        "defaultStatus2": "Initialiserer...",
        "titleTextProgress": "Total fremdrift: %s",
        "titleTextPaused": "Total fremdrift: %s STANSET MIDLERTIDIG",
        "statusProgress": "%s (%s av %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Avbrøt %s",
        "cancelledMsg": "Start nedlastingen på nytt."
    },
    pl: {
        "startTitle": "Kliknij przycisk „Run” (Uruchom) lub „Open” (Otwórz), aby uruchomić instalator.",
        "relaunchMsgStart": "Nie widzisz okna instalatora? ",
        "relaunchLink": "Otwórz instalator ponownie.",
        "relaunchMsgEnd": "",
        "title": "Pobieranie %s",
        "autoStart": " Otwórz automatycznie po zakończeniu pobierania.",
        "completeTitle": "Pobieranie zakończone!",
        "completeText": "Otwórz %s",
        "timeLabel": "%s pozostało.",
        "waiting": "Oczekiwanie.",
        "paused": "Wstrzymano.",
        "pausedNotFound": "Nie znaleziono pliku!",
        "pausedInsufficientDiskSpace": "Brak miejsca na dysku!",
        "pausedForbidden": "Odmowa dostępu!",
        "pausedDisconnected": "Rozłączono z serwerem. Trwa ponawianie...",
        "unloadMsg": "Trwa pobieranie pliku. Jeśli zakończysz teraz, pobieranie zostanie wstrzymane.",
        "minute": "min",
        "minutes": "min",
        "second": "s",
        "seconds": "s",
        "download": "Pobierz",
        "hourAbbr": "godz.",
        "minAbbr": "min.",
        "calcTime": "Obliczanie czasu pozostało.",
        "acceptEULA": "Akceptuj",
        "rejectEULA": "Anuluj",
        "EULADeniedText": "Przepraszamy. Odrzuciłeś umowę licencyjną EULA. Skorzystaj z poniższego łącza, aby pobrać plik bezpośrednio z lokalizacji źródłowej bez użycia programu Akamai Download Manager.",
        "EULADeniedLink": "Pobierz bezpośrednio",
        "EULA1": "<span class='DLMeulaTitle'>Do pobrania tego pliku potrzebny jest program <a href='http://www.akamai.com/client/'>, który w minimalnym stopniu wykorzystuje zarówno pasmo wysyłania, jak i zasoby komputera, w celu połączenia z siecią użytkowników równorzędnych, co pozwala zwiększyć prędkość pobierania oraz zapewnić stabilność połączenia z innymi użytkownikami programu Akamai Download Manager.</span>",
        "EULA2": "Klikając przycisk „Accept” (Akceptuję) akceptujesz warunki umowy <a href='http://www.akamai.com/eula'>licencyjnej Akamai.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Oczekiwanie...",
        "defaultStatus2": "Inicjalizacja...",
        "titleTextProgress": "Postęp całkowity %s",
        "titleTextPaused": "Postęp całkowity %s WSTRZYMANO",
        "statusProgress": "%s (%s z %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Anulowano %s",
        "cancelledMsg": "Rozpocznij pobieranie ponownie."
    },
    pt: {
        "startTitle": "Clique em “executar” ou “abrir” para iniciar o installer.",
        "relaunchMsgStart": "Não vê o installer? ",
        "relaunchLink": "Tentar abrir novamente.",
        "relaunchMsgEnd": "",
        "title": "Fazendo o download de %s",
        "autoStart": " Abrir automaticamente quando concluído.",
        "completeTitle": "Download Concluído!",
        "completeText": "Abrir %s",
        "timeLabel": "Faltam %s.",
        "waiting": "Aguardando.",
        "paused": "Pausa.",
        "pausedNotFound": "Arquivo não encontrado!",
        "pausedInsufficientDiskSpace": "Espaço insuficiente no disco!",
        "pausedForbidden": "Acesso negado!",
        "pausedDisconnected": "Desconectado do servidor; tentando novamente",
        "unloadMsg": "No momento há um download em progresso. Se você sair agora, o download será interrompido imediatamente.",

        "minute": "minuto",
        "minutes": "minutos",
        "second": "segundo",
        "seconds": "segundos",
        "download": "Download",
        "hourAbbr": "h",
        "minAbbr": "min",
        "calcTime": "Calculando tempo.",
        "acceptEULA": "Aceitar",
        "rejectEULA": "Cancelar",
        "EULADeniedText": "Sentimos muito que você não esteja de acordo com o EULA. Você pode usar o link abaixo para fazer o download diretamente da origem sem o Akamai Download Manager.",
        "EULADeniedLink": "Fazer o Download Direto",
        "EULA1": "<span class='DLMeulaTitle'>Este download requer o <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, que utiliza uma quantidade limitada da sua largura de banda para upload e recursos de PC para conectá-lo a uma rede paralela, o que melhora a velocidade do download e a segurança para você e outros usuários do Akamai Download Manager.</span>",
        "EULA2": "Ao clicar em “Aceitar” você estará aceitando o <a href='http://www.akamai.com/eula'>Acordo de Licença da Akamai.</a>",

        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Aguardando…",
        "defaultStatus2": "Iniciando…",
        "titleTextProgress": "Progresso total do %s",
        "titleTextPaused": "Progresso total do %s INTERROMPIDO",
        "statusProgress": "%s (%s de %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "%s cancelado",
        "cancelledMsg": "Reiniciar o download."
    },
    "pt-br": {
        "startTitle": "Clique em \"executar\" ou \"abrir\" para iniciar o instalador.",
        "relaunchMsgStart": "Não encontra o instalador? ",
        "relaunchLink": "Tente abri-lo novamente.",
        "relaunchMsgEnd": "",
        "title": "Fazendo download %s",
        "autoStart": " Abre automaticamente quando concluído.",
        "completeTitle": "Download concluído!",
        "completeText": "Abrir %s",
        "timeLabel": "%s estimado.",
        "waiting": "Aguardando.",
        "paused": "Pausado.",
        "pausedNotFound": "Arquivo não encontrado!",
        "pausedInsufficientDiskSpace": "Espaço em disco insuficiente!",
        "pausedForbidden": "Acesso negado!",
        "pausedDisconnected": "Desconectado do servidor, tentando novamente...",
        "unloadMsg": "Já há um download em andamento. Se sair agora, o download será pausado.",
        "minute": "minuto",
        "minutes": "minutos",
        "second": "segundo",
        "seconds": "segundos",
        "download": "Download",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Calculando tempo estimado.",
        "acceptEULA": "Aceitar",
        "rejectEULA": "Cancelar",
        "EULADeniedText": "Lamentamos que você tenha recusado o EULA. Use o link abaixo para fazer o download direto da origem, sem usar o Akamai Download Manager.",
        "EULADeniedLink": "Download direto",
        "EULA1": "<span class='DLMeulaTitle'>Para fazer download é necessário o <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, que utiliza uma porcentagem limitada da sua banda larga para upload e recursos do PC para conectá-lo a uma rede peer-to-peer. A rede melhorará a velocidade do download e a sua confiabilidade e de outros usuários no Akamai Download Manager.</span>",
        "EULA2": "Clique em \"Aceitar\" para aceitar o <a href='http://www.akamai.com/eula'>Acordo de licença do Akamai.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Aguardando...",
        "defaultStatus2": "Inicializando...",
        "titleTextProgress": "Andamento total %s",
        "titleTextPaused": "Andamento total %s PAUSADO",
        "statusProgress": "%s (%s de %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Cancelado %s",
        "cancelledMsg": "Reiniciar o download."
    },
    ru: {
        "startTitle": "Нажмите \"run\" или \"open\" для запуска программы установки.",
        "relaunchMsgStart": "Не можете найти каталог, в который загрузили программу установки? ",
        "relaunchLink": "Нажмите эту ссылку.",
        "relaunchMsgEnd": "",
        "title": "Загрузка %s",
        "autoStart": " Открыть после окончания загрузки",
        "completeTitle": "Загрузка завершена!",
        "completeText": "Открыть %s",
        "timeLabel": "%s до окончания загрузки.",
        "waiting": "Ожидание.",
        "paused": "Приостановлено.",
        "pausedNotFound": "Файл не найден!",
        "pausedInsufficientDiskSpace": "Недостаточно свободного пространства на диске!",
        "pausedForbidden": "Доступ запрещен!",
        "pausedDisconnected": "Соединение с сервером прервано, выполняется попытка восстановить подключение...",
        "unloadMsg": "Выполняется загрузка. Закрытие страницы приведет к приостановке загрузки.",
        "minute": "мин.",
        "minutes": "мин.",
        "second": "сек.",
        "seconds": "сек.",
        "download": "Загрузить",
        "hourAbbr": "ч.",
        "minAbbr": "мин.",
        "calcTime": "Расчетное время до окончания загрузки.",
        "acceptEULA": "Принять",
        "rejectEULA": "Отмена",
        "EULADeniedText": "К сожалению, вы не приняли условия лицензионного соглашения. Вы можете использовать ссылку, указанную ниже, для прямой загрузки файлов без использования утилиты Akamai Download Manager.",
        "EULADeniedLink": "Прямая загрузка",
        "EULA1": "<span class='DLMeulaTitle'>Для загрузки используется <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>r. Эта утилита потребляет ограниченный объем пропускной способности и ресурсов ПК для подключения к одноранговой сети, что улучшает скорость загрузки и надежность передачи данных для пользователей Akamai Download Manager.</span>",
        "EULA2": "Нажатие кнопки \"Принять\" означает согласие с условиями лицензионного соглашения Akamai.<a href='http://www.akamai.com/eula'>Akamai.</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "Ожидание...",
        "defaultStatus2": "Инициализация...",
        "titleTextProgress": "Загрузка %s",
        "titleTextPaused": "Загрузка %s: приостановлено",
        "statusProgress": "%s (%s из %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Загрузка %s: отменено",
        "cancelledMsg": "Перезапустить загрузку."
    },
    sv: {
        "startTitle": "Klicka på \"kör\" eller  \"öppna\" för att starta installationsprogrammet.",
        "relaunchMsgStart": "Ser du inte installationsprogrammet? ",
        "relaunchLink": "Försök att öppna det igen.",
        "relaunchMsgEnd": "",
        "title": "Laddar ned  %s",
        "autoStart": "Öppna fil automatiskt efter installation.",
        "completeTitle": "Installation avslutad!",
        "completeText": "Öppna ",
        "timeLabel": "%s återstående.",
        "waiting": "Väntar.",
        "paused": "Pausad.",
        "pausedNotFound": "Fil kunde inte hittas!",
        "pausedInsufficientDiskSpace": "Otillräckligt med plats på hårddisken!",
        "pausedForbidden": "Åtkomst nekad!",
        "pausedDisconnected": "Frånkopplad.",
        "unloadMsg": "Det pågår en nedladdning. Om du går nu kommer nedladdningen att avbrytas tillfälligt. ",
        "minute": "minut",
        "minutes": "minuter",
        "second": "sekund",
        "seconds": "sekunder",
        "download": "Nedladdning",
        "hourAbbr": "h",
        "minAbbr": "m",
        "calcTime": "Beräknar tid återstående.",
        "acceptEULA": "Acceptera",
        "rejectEULA": "Avbryt",
        "EULADeniedText": "Tyvärr nekades du EULA. Du kan använda länken nedan för att ladda ned direkt utan Akamai Download Manager.",
        "EULADeniedLink": "Ladda ned direkt",
        "EULA1": "<span class='DLMeulaTitle'>Denna nedladdning kräver <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>, som använder en begränsad del av din bandbredd och din dators kapacitet för att ansluta dig till ett samtrafikerat nätverk som gör nedladdningen snabbare och pålitligare för dig och andra slutanvändare av Akamai Download Manager.</span>",
        "EULA2": "Genom att klicka på \"Acceptera\" accepterar du <a href='http://www.akamai.com/eula'>Akamai licensavtal.</a>", 

        "waitStatus": "Väntar...",
        "defaultStatus2": "Initierar...",
        "titleTextProgress": "Totalt förlopp %s",
        "titleTextPaused": "Totalt förlopp %s PAUSAD",
        "statusProgress": "%s (%s av %s): %s",
        "percentage": "%s%",
        "cancelledTitle": "Avbruten %s",
        "cancelledMsg": "Starta om nedladdningen."
    },
    tr:{
       "startTitle": "Kurulumu başlatmak için \"run (başlat)\" ya da \"open(aç)\"a tıklayın.",
       "relaunchMsgStart": "Kurulum programını görmüyor musunuz? ",
       "relaunchLink": "Tekrar açmayı deneyin.",
       "relaunchMsgEnd": "",
       "title": "%s indiriliyor",
       "autoStart": "Tamamlandığında otomatik olarak aç.",
       "completeTitle": "İndirme işlemi tamamlanmıştır!",
       "completeText": "%s aç",
       "timeLabel": "%skalan süredir.",
       "waiting": "Bekliyor.",
       "paused": "Duraklatıldı.",
       "pausedNotFound": "Dosya bulunamadı!",
       "pausedInsufficientDiskSpace": "Yetersiz disk alanı!",
       "pausedForbidden": "Erişim reddedildi!",
       "pausedDisconnected": "Bağlantı kesildi.",
       "unloadMsg": "Şu an indirme işlemi mevcut. Eğer kapatırsanız, indirme işlemi duraklayacaktır.",
       "minute": "dakika",
       "minutes": "dakika",
       "second": "saniye",
       "seconds": "saniye",
       "download": "İndir",
       "hourAbbr": "saat",
       "minAbbr": "san.",
       "calcTime": "Zamanı hesaplıyor skalan süredir.",
       "acceptEULA": "Kabul",
       "rejectEULA": "İptal",
       "EULADeniedText": "EULA’yı reddettiğiniz için üzgünüz.  İstemciyi Akamai Download Manager kullanmadan direkt olarak kaynaktan indirmek için aşağıdaki linki kullanabilirsiniz.",
       "EULADeniedLink": "Direkt indir", 
       "EULA1": "<span class='DLMeulaTitle'>Bu indirme işlemi için<a href='http://www.akamai.com/client/'>Akamai Download Manager</a> gerekmektedir, bu sayede yükleme bant genişliğinizin limitli bir kısmını ve eş bir ağa bağlandığınız PC’nin kaynaklarını kullanarak Akamai Download Manager kullanan diğer kullanıcıların güvenilirliğini, kendi emniyetinizi ve indirme hızınızı arttırabilirsiniz.”</span>",
       "EULA2": " \"Kabul\" linkine tıklayarak<a href='http://www.akamai.com/eula'>Akamai Lisans Anlaşmasını.</a> kabul ediyorsunuz.",

       "waitStatus": "Bekliyor...",
       "defaultStatus2": "Başlatılıyor...",
       "titleTextProgress": "Toplam işlem durumu %s",
       "titleTextPaused": "Toplam işlem durumu %s DURAKLATILDI",
       "statusProgress": "%s (%s’den %s): %s",
       "percentage": "%s%",
       "cancelledTitle": "%s iptal edildi",
       "cancelledMsg": "İndirme işlemini tekrar başlatın."
    },
    "zh-cn": {
        "startTitle": "单击“运行”或“打开”以启动安装程序。",
        "relaunchMsgStart": "看不到安装程序？ ",
        "relaunchLink": "请尝试重新打开它。",
        "relaunchMsgEnd": "",
        "title": "正在下载 %s",
        "autoStart": " 完成时自动打开。",
        "completeTitle": "下载完成！",
        "completeText": "打开 %s",
        "timeLabel": "%s 剩余。",
        "waiting": "正在等待。",
        "paused": "已暂停。",
        "pausedNotFound": "未找到文件！",
        "pausedInsufficientDiskSpace": "磁盘空间不足！",
        "pausedForbidden": "访问被拒绝！",
        "pausedDisconnected": "已从服务器断开连接，正在重试...",
        "unloadMsg": "当前正在下载。 如果现在离开，下载将暂停。",
        "minute": "分钟",
        "minutes": "分钟",
        "second": "秒",
        "seconds": "秒",
        "download": "下载",
        "hourAbbr": "h",
        "minAbbr": "M",
        "calcTime": "正在计算时间 剩余。",
        "acceptEULA": "接受",
        "rejectEULA": "取消",
        "EULADeniedText": "很遗憾，您拒绝接受 EULA。 您可以使用下面的链接，在不使用 Akamai Download Manager 的情况下从原位置直接下载",
        "EULADeniedLink": "直接下载",
        "EULA1": "<span class='DLMeulaTitle'>要执行下载，需要使用 <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>，此程序会利用您的有限上载带宽和计算机资源以连接到对等网络，进而改进您以及 Akamai Download Manager 的其他最终用户的下载速度和可靠性。</span>",
        "EULA2": "请单击“接受”，以接受 <a href='http://www.akamai.com/eula'>Akamai 许可协议。</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "正在等待...",
        "defaultStatus2": "正在初始化...",
        "titleTextProgress": "总进度 %s",
        "titleTextPaused": "总进度 %s 已暂停",
        "statusProgress": "%s（%s，共 %s）：%s",
        "percentage": "%s%",
        "cancelledTitle": "已取消 %s",
        "cancelledMsg": "重新启动下载。"
    },
    "zh-tw": {
        "startTitle": "按一下「執行」或「開啟」以啟動安裝程式。",
        "relaunchMsgStart": "找不到安裝程式？ ",
        "relaunchLink": "請嘗試重新開啟。",
        "relaunchMsgEnd": "",
        "title": "正在下載 %s",
        "autoStart": "  完成時自動開啟。",
        "completeTitle": "下載完成！",
        "completeText": "開啟 %s",
        "timeLabel": "%s 未完成。",
        "waiting": "正在等待。",
        "paused": "已暫停。",
        "pausedNotFound": "找不到檔案！",
        "pausedInsufficientDiskSpace": "磁碟空間不足！",
        "pausedForbidden": "拒絕存取！",
        "pausedDisconnected": "與伺服器的連線中斷，正在重試...",
        "unloadMsg": "目前有下載正在進行中。 如果您現在離開，下載將會暫停。",
        "minute": "分鐘",
        "minutes": "分鐘",
        "second": "秒鐘",
        "seconds": "秒鐘",
        "download": "下載",
        "hourAbbr": "時",
        "minAbbr": "分",
        "calcTime": "正在計算時間 未完成。",
        "acceptEULA": "接受",
        "rejectEULA": "取消",
        "EULADeniedText": "很遺憾，您已拒絕 EULA。 您可以此用以下連結，直接從原始來源下載，而不透過 Akamai Download Manager。",
        "EULADeniedLink": "直接下載",
        "EULA1": "<span class='DLMeulaTitle'>此下載需要 <a href='http://www.akamai.com/client/'>Akamai Download Manager</a>，該程式會佔用您有限的上載頻寬與電腦資源以連線至對等網路，該網路能為您與 Akamai Download Manager 的其他使用者改善下載速度與可靠性。</span>",
        "EULA2": "按一下「接受」即表示，您接受 <a href='http://www.akamai.com/eula'>Akamai 授權合約。</a>",
        // New Bundled DLM strings. Also adds localizable percentage format.
        "waitStatus": "正在等待...",
        "defaultStatus2": "正在初始化...",
        "titleTextProgress": "總體進度 %s",
        "titleTextPaused": "總體進度 %s 已暫停",
        "statusProgress": "%s (%s/%s)：%s",
        "percentage": "%s%",
        "cancelledTitle": "已取消 %s",
        "cancelledMsg": "重新啟動下載。"
    }
};

// Run the init() function to get everything started.
DLMHelper.init();
