
//<!--
//*****************************************************************************************************
//      The Truveo Video Search AJAX API version 3.
//      Copyright (c) 2007, AOL LLC.
//      All rights reserved.
//*****************************************************************************************************

// The TruveoVideoSearch object.  This object is the top-level object for the Truveo Video Search AJAX API.
var TruveoVideoSearch = function(appid) {

        // PRIVATE CONSTANTS:
        // Production URLS:
        var xmlhttpUrl = 'http://xml.truveo.com/libs/xmlhttp';           // The URL for the xmlhttp server; this must have the same domain as the serviceUrl.
        var serviceUrl = "http://xml.truveo.com/apiv3";                       // The service URL for the REST API;  this must have the same domain as the xmlhttpUrl.
        var sessionCookie = new Cookie(document, "aolvs_session_token", 720);   // The user session cookie, which stores the user token and will persist for 30 days.
        var stateCookie = new Cookie(document, "aolvs_api_state");                              // The api state cookie, which stores the api state; persists only for the current browser session.

        // PRIVATE ATTRIBUTES:
        var urlParams = null;                                           // An associative array for any parameters passed in the original document URL.
        var onUpdateHandlerArray = new Array();         // The array containing the list of methods to be called when the onupdate event is fired.
        var onLoadHandlerArray = new Array();           // The array containing the list of methods to be called when the onLoad event is fired.
        var onErrorHandlerArray = new Array();          // The array containing the list of methods to be called when the onerror event is fired.
        var errorMessages = { '501': 'Error connecting to XMLHTTP AJAX service',
                                                  '502': 'Invalid AJAX method call: The wrong number of arguments was provided to this method.',
                                                  '503': 'Method not available: You must be logged in to use this method.'};

        // PUBLIC ATTRIBUTES:
        // Request attributes:
        this.appid = appid;                     // Application ID for this application.
        this.showAdult = 0;                     // Flag to indicate if adult video should be included in results.
        this.showRelatedItems = 0;      // Flag to indicate if related tags, channels, categories and users should be returned with each VideoSet.
        this.start = 0;                         // The position of the first video of the current VideoSet in the total result set.
        this.results = 10;                      // The number of videos to return in each page of video results.
        this.tagResults = 10;           // The number of tags to return in each TagSet.
        this.channelResults = 10;       // The number of channels to return in each ChannelSet.
        this.categoryResults = 10;      // The number of categories to return in each CategorySet.
        this.userResults = 10;          // The number of users to return in each UserSet.
        this.mode = 'ajax';                     // The mode can be set to either 'ajax' or 'rest'.

        // Response attributes:
        this.method = "";                       // A string containing the method associated with the most recently received API response.
        this.query = "";                        // A string containing the query associated with the current TruveoVideoSearch data objects.
        this.querySuggestion = "";                      // A string containing the query associated with the current TruveoVideoSearch data objects.
        this.previousQuery = "";        // A string containing the query that was executed immediately previous to the current query.
        this.VideoSet = null;           // A data object containing the current VideoSet, as derived from the JSON string in the API response.
        this.TagSet = null;                     // A data object containing the current TagSet, as derived from the JSON string in the API response.                   
        this.ChannelSet = null;         // A data object containing the current ChannelSet, as derived from the JSON string in the API response.
        this.CategorySet = null;        // A data object containing the current CategorySet, as derived from the JSON string in the API response.               
        this.UserSet = null;            // A data object containing the current UserSet, as derived from the JSON string in the API response.
        this.WatchlistSet = null;       // A data object containing the current WatchlistSet, as derived from the JSON string in the API response.
        this.Result = null;                     // A data object containing generic information, typically a status message, associated with an API response.

        // PUBLIC METHODS:
        // Function getVideos() can be used to submit a query to the Truveo video search service. This method returns the set of video results
        // that match the submitted query.  The matching videos will be returned in the VideoSet object.
        this.getVideos = function(query, start) {
                if (arguments.length < 1) { var query = ''; }
                if (arguments.length < 2) { var start = 0; }
                var urlParams = { 'method': 'truveo.videos.getVideos',
                                                  'query': query,
                                                  'results': this.results,
                                                  'start': start,
                                                  'showRelatedItems': this.showRelatedItems,
                                                  'tagResults': this.tagResults,
                                                  'channelResults': this.channelResults,
                                                  'categoryResults': this.categoryResults,
                                                  'userResults': this.userResults,
                                                  'showAdult': this.showAdult };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }
       
        // Function getRelatedTags() returns the set of tags that are associated with the videos that match the submitted query.   
        // The resulting tags will be returned in the TagSet object.
        this.getRelatedTags = function(query, start, results) {
                if (arguments.length < 1) { var query = ''; }
                if (arguments.length < 2) { var start = 0; }
                if (arguments.length < 3) { var results = this.tagResults; }
                var urlParams = { 'method': 'truveo.videos.getRelatedTags',
                                                  'query': query,
                                                  'results': results,
                                                  'start': start };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }

        // Function getRelatedChannels() returns the set of channels that are associated with the videos that match the submitted query.   
        // The resulting channels will be returned in the ChannelSet object.
        this.getRelatedChannels = function(query, start, results) {
                if (arguments.length < 1) { var query = ''; }
                if (arguments.length < 2) { var start = 0; }
                if (arguments.length < 3) { var results = this.channelResults; }
                var urlParams = { 'method': 'truveo.videos.getRelatedChannels',
                                                  'query': query,
                                                  'results': results,
                                                  'start': start };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }

        // Function getRelatedCategories() returns the set of categories that are associated with the videos that match the submitted query.   
        // The resulting categories will be returned in the CategorySet object.
        this.getRelatedCategories = function(query, start, results) {
                if (arguments.length < 1) { var query = ''; }
                if (arguments.length < 2) { var start = 0; }
                if (arguments.length < 3) { var results = this.categoryResults; }
                var urlParams = { 'method': 'truveo.videos.getRelatedCategories',
                                                  'query': query,
                                                  'results': results,
                                                  'start': start };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }

        // Function getRelatedUsers() returns the set of users that are associated with the videos that match the submitted query.   
        // The resulting users will be returned in the UserSet object.
        this.getRelatedUsers = function(query, start, results) {
                if (arguments.length < 1) { var query = ''; }
                if (arguments.length < 2) { var start = 0; }
                if (arguments.length < 3) { var results = this.userResults; }
                var urlParams = { 'method': 'truveo.videos.getRelatedUsers',
                                                  'query': query,
                                                  'results': results,
                                                  'start': start };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }

        // Function submitRating() submits the specified rating for the video with the specified id.
        this.submitRating = function(videoId, rating) {
                if (arguments.length < 2) {
                        this.onerror(502, errorMessages['502']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.videos.submitRating',
                                                  'id': videoId,
                                                  'rating': rating };
                this.submitRestQuery(urlParams, 'ajax');
                return(true);
        }

        // Function login() logs a user into the Truveo video search service.  This function takes one argument: the callbackUrl which will
        // be loaded into the browser when the page returns from the login screen.
        this.login = function(callbackUrl) {
                this.saveAPIState();
                var cleanCallbackUrl = this.removeUrlParameters(callbackUrl, ["auth", "token", "loginCancel", "errorCode", "errorMessage", "logout"]);
                var urlParams = { 'method': 'truveo.users.login',
                                                  'callback_url': cleanCallbackUrl };
                window.location.href = this.getRestUrl(urlParams);
        }
       
        // Function logout() logs the users out of the Truveo video search service and deletes any sessionCookie.  This function takes one
        // argument: the callbackUrl which will be loaded into the browser when the page returns from the login screen.  When the browser
        // is redirected to the callbackUrl, the URL will have one additional parameter, 'login', set to 'true'.
        this.logout = function(callbackUrl) {
                sessionCookie.remove();
                //this.saveAPIState();
                var cleanCallbackUrl = this.removeUrlParameters(callbackUrl, ["auth", "token", "loginCancel", "errorCode", "errorMessage", "logout"]);
                if (cleanCallbackUrl.indexOf("?") == -1) { cleanCallbackUrl = cleanCallbackUrl + "?logout=true"; }
                else { cleanCallbackUrl = cleanCallbackUrl + "&logout=true"; }
                var urlParams = { 'method': 'truveo.users.logout',
                                                  'logout_callback_url': cleanCallbackUrl };
                window.location.href = this.getRestUrl(urlParams);
        }

        // Function isLoggedIn() checks the login state of the Truveo video search API and returns true is the user is currently
        // logged in, or false otherwise.
        this.isLoggedIn = function() {
                if (sessionCookie.load() && sessionCookie.token) { return(true); }
                else { return(false); }
        }
       
        // Function getPublicName() retrieves the public name of the user from the session cookie.
        this.getPublicName = function() {
                if (sessionCookie.load() && sessionCookie.publicName) { return(sessionCookie.publicName); }
                else { return(false); }
        }

        // Function getFavoriteVideos() retrieves the VideoSet containing the user's favorite videos.  If the user is not
        // logged in, this function returns false.
        this.getFavoriteVideos = function(start) {
                if (!this.isLoggedIn() && (this.mode == 'ajax')) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                if (arguments.length < 1) { var start = 0; }
                var urlParams = { 'method': 'truveo.users.getFavoriteVideos',
                                                  'token': sessionCookie.token,
                                                  'start': start,
                                                  'results': this.results,
                                                  'showRelatedItems': this.showRelatedItems };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }
       
        // Function addFavorite() takes a video id and submits it to the user's favorites list.
        this.addFavorite = function(id) {
                if (!this.isLoggedIn()) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                if (arguments.length < 1) {
                        this.onerror(502, errorMessages['502']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.users.addFavorite',
                                                  'id': id,
                                                  'token': sessionCookie.token };
                this.submitRestQuery(urlParams, 'ajax');
                return(true);
        }
       
        // Function removeFavorite() removes the video with the specified id from the user's favorites list.  This method returns false
        // if the user is not logged in.
        this.removeFavorite = function(id) {
                if (!this.isLoggedIn()) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                if (arguments.length < 1) {
                        this.onerror(502, errorMessages['502']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.users.removeFavorite',
                                                  'id': id,
                                                  'token': sessionCookie.token };
                this.submitRestQuery(urlParams, 'ajax');
                return(true);
        }

        // Function getRecentVideos() retrieves the VideoSet containing the user's recent videos.  If the user is not
        // logged in, this function returns false.
        this.getRecentVideos = function(start) {
                if (!this.isLoggedIn() && (this.mode == 'ajax')) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                if (arguments.length < 1) { var start = 0; }
                var urlParams = { 'method': 'truveo.users.getRecentVideos',
                                                  'token': sessionCookie.token,
                                                  'start': start,
                                                  'results': this.results,
                                                  'showRelatedItems': this.showRelatedItems };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }

        // Function addRecentVideo() takes a video id and submits it to the user's recent videos list.  This method returns false
        // if the user is not logged in.
        this.addRecentVideo = function(id) {
                if (!this.isLoggedIn()) {
                        return(false);
                }
                if (arguments.length < 1) {
                        this.onerror(502, errorMessages['502']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.users.addRecentVideo',
                                                  'id': id,
                                                  'token': sessionCookie.token };
                this.submitRestQuery(urlParams, 'ajax');
                return(true);
        }

        // Function clearRecentVideos() removes all videos from the user's recent videos list.  This method returns false
        // if the user is not logged in.
        this.clearRecentVideos = function() {
                if (!this.isLoggedIn()) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.users.clearRecentVideos',
                                                  'token': sessionCookie.token };
                this.submitRestQuery(urlParams, 'ajax');
                return(true);
        }

        // Function getWatchlists() retrieves the WatchlistSet containing the user's watchlists.  If the user is not
        // logged in, this function returns false.
        this.getWatchlists = function() {
                if (!this.isLoggedIn() && (this.mode == 'ajax')) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.users.getWatchlists',
                                                  'token': sessionCookie.token };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }
       
        // Function addWatchlist() takes a query string and submits it to the user's watchlists.
        this.addWatchlist = function(query) {
                if (!this.isLoggedIn()) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                if (arguments.length < 1) {
                        this.onerror(502, errorMessages['502']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.users.addWatchlist',
                                                  'query': query,
                                                  'token': sessionCookie.token };
                this.submitRestQuery(urlParams, 'ajax');
                return(true);
        }
       
        // Function removeWatchlist() removes the specified query from the user's watchlists.  This method returns false
        // if the user is not logged in.
        this.removeWatchlist = function(query) {
                if (!this.isLoggedIn()) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                if (arguments.length < 1) {
                        this.onerror(502, errorMessages['502']);
                        return(false);
                }
                var urlParams = { 'method': 'truveo.users.removeWatchlist',
                                                  'query': query,
                                                  'token': sessionCookie.token };
                this.submitRestQuery(urlParams, 'ajax');
                return(true);
        }

        // Function getRecommendedVideos() retrieves a VideoSet containing the user's recommended videos.  If the user is not
        // logged in, this function returns false.
        this.getRecommendedVideos = function(start) {
                if (!this.isLoggedIn() && (this.mode == 'ajax')) {
                        this.onerror(503, errorMessages['503']);
                        return(false);
                }
                if (arguments.length < 1) { var start = 0; }
                var urlParams = { 'method': 'truveo.users.getRecommendedVideos',
                                                  'token': sessionCookie.token,
                                                  'start': start,
                                                  'results': this.results,
                                                  'showRelatedItems': this.showRelatedItems };
                this.submitRestQuery(urlParams, this.mode);
                return(true);
        }

        // Function hasNextPage() returns true if another page of video search results is available; otherwise it returns false.
        this.hasNextPage = function() { return(parseInt(this.VideoSet.firstResultPosition) + parseInt(this.VideoSet.totalResultsReturned) < parseInt(this.VideoSet.totalResultsAvailable)); }

        // Function hasPreviousPage() returns true if a previous page of video search results is available; otherwise it returns false.
        this.hasPreviousPage = function() { return(parseInt(this.VideoSet.firstResultPosition) > 0); }
       
        // Function nextPage() retrives the VideoSet containing the next page of video search results.
        this.nextPage = function() {
                var startPosition = parseInt(this.VideoSet.firstResultPosition) + parseInt(this.VideoSet.totalResultsReturned);
                if (this.method.indexOf("getRecentVideos") >= 0) { this.getRecentVideos(startPosition); }
                else if (this.method.indexOf("getFavoriteVideos") >= 0) { this.getFavoriteVideos(startPosition); }
                else if (this.method.indexOf("getRecommendedVideos") >= 0) { this.getRecommendedVideos(startPosition); }
                else { this.getVideos(this.query, startPosition); }
                return(true);
        }

        // Function previousPage() retrives the VideoSet containing the previous page of video search results.
        this.previousPage = function() {
                var startPosition = parseInt(this.VideoSet.firstResultPosition) - this.results;
                startPosition = (startPosition<0 ? 0 : startPosition);
                if (this.method.indexOf("getRecentVideos") >= 0) { this.getRecentVideos(startPosition); }
                else if (this.method.indexOf("getFavoriteVideos") >= 0) { this.getFavoriteVideos(startPosition); }
                else if (this.method.indexOf("getRecommendedVideos") >= 0) { this.getRecommendedVideos(startPosition); }
                else { this.getVideos(this.query, startPosition); }
                return(true);
        }
       
        // Function goToPage() retrieves the VideoSet containing page of video search results specified by the give pageNum.
        this.goToPage = function(pageNum) {
                var startPosition = (pageNum - 1) * this.results;
                startPosition = (startPosition<0 ? 0 : startPosition);
                if (this.method.indexOf("getRecentVideos") >= 0) { this.getRecentVideos(startPosition); }
                else if (this.method.indexOf("getFavoriteVideos") >= 0) { this.getFavoriteVideos(startPosition); }
                else if (this.method.indexOf("getRecommendedVideos") >= 0) { this.getRecommendedVideos(startPosition); }
                else { this.getVideos(this.query, startPosition); }
                return(true);
        }

        // Function attachEvent() attaches the handler function specified by 'handler' to the specified event. The value provided
        // in the argument handler will be eval'ed when the event with the specified eventName is fired.  Note that the handler
        // argument can be a string or a pointer to a method.  Also, the handler will always be eval'ed in the global
        // context.
        this.attachEvent = function(eventName, handler) {
                switch(eventName) {
                        case 'onupdate':
                                var index = onUpdateHandlerArray.length;
                                onUpdateHandlerArray[index] = handler;
                                break;
                        case 'onerror':
                                var index = onErrorHandlerArray.length;
                                onErrorHandlerArray[index] = handler;
                                break;
                        case 'onload':
                                var index = onLoadHandlerArray.length;
                                onLoadHandlerArray[index] = handler;
                                break;
                }
                return(true);
        }

        // PRIVATE METHODS:
        // Function onupdate() fires the onupdate event for this TruveoVideoSearch object.  It calls all of the handlers that have
        // been attached to this event using the attachEvent() method.  All the currently attached onupdate handlers are stored
        // in the array onUpdateHandlerArray[].
        this.onupdate = function(methodName) {
                for (var i=0; i < onUpdateHandlerArray.length; i++) { eval(onUpdateHandlerArray[i]); }
        }

        // Function onerror() fires the onerror event for the TruveoVideoSearchobject.  It calls all of the handlers that have
        // been attached to this event using the attachEvent() method.  All the currently attached onerror handlers are stored
        // in the array onErrorHandlerArray[].
        this.onerror = function(errorCode, errorMessage) {
                for (var i=0; i < onErrorHandlerArray.length; i++) { eval(onErrorHandlerArray[i]); }
        }

        // Function onload() fires the onload event for the TruveoVideoSearchobject.  It calls all of the handlers that have
        // been attached to this event using the attachEvent() method.  All the currently attached onload handlers are stored
        // in the array onLoadHandlerArray[].
        this.onload = function(reloadStateFlag) {
                if (arguments.length < 1) reloadStateFlag = false;
                if (reloadStateFlag == true) { this.loadAPIState(); }
                for (var i=0; i < onLoadHandlerArray.length; i++) { eval(onLoadHandlerArray[i]); }
        }

        // Function saveAPIState() saves the current state of the API to a cookie.  Note this function does not save any
        // of the API response data objects.
        this.saveAPIState = function() {
                stateCookie.showAdult = this.showAdult;
                stateCookie.showRelatedItems = this.showRelatedItems;
                stateCookie.start = this.start;
                stateCookie.results = this.results;
                stateCookie.tagResults = this.tagResults;
                stateCookie.channelResults = this.channelResults;
                stateCookie.categoryResults = this.categoryResults;
                stateCookie.userResults = this.userResults;
                stateCookie.mode = this.mode;
                stateCookie.method = this.method;
                stateCookie.query = this.query;
                stateCookie.previousQuery = this.previousQuery;
                stateCookie.store();
        }

        // Function loadAPIState() loads the past state of the API from a cookie.
        this.loadAPIState = function() {
                if (stateCookie.load()) {
                        this.showAdult = stateCookie.showAdult;
                        this.showRelatedItems = stateCookie.showRelatedItems;
                        this.start = stateCookie.start;
                        this.results = stateCookie.results;
                        this.tagResults = stateCookie.tagResults;
                        this.channelResults = stateCookie.channelResults;
                        this.categoryResults = stateCookie.categoryResults;
                        this.userResults = stateCookie.userResults;
                        this.mode = stateCookie.mode;
                        this.method = stateCookie.method;
                        this.query = stateCookie.query;
                        this.previousQuery = stateCookie.previousQuery;
                        stateCookie.remove();
                }
        }

        // Function update() updates the state of the TruveoVideoSearch object using the XML text string, xmlText.  This function
        // is typically called when a search engine response has been received and new data needs to be handled.  This function
        // takes the xmlText string, transforms it into a JSON string and then a Javascript object, and stores the resulting
        // object components in the attributes of the TruveoVideoSearch object.  When the update is complete, this method will fire
        // the onupdate event which will trigger any handlers attached to this object.  The XML to JSON conversion is performed
        // using the XML JSON object tree class xotree.
        this.update = function(xmlText) {
               
                // Initialize the ObjTree object.  Specify the XML tags should always be converted to a JSON array.
                var xotree = new XML.ObjTree();
                xotree.force_array = ["Video", "Tag", "Channel", "Category", "User", "Watchlist"];

                // Now parse the xml response message.
                var tree = xotree.parseXML(xmlText);
                if (tree && ("Response" in tree)) {
                        var response = tree.Response; 
                       
                        // If the response is an error message, then fire an onerror event.
                        if ("Error" in response) { this.onerror(response.Error["-Code"], response.Error["#text"]); }
                       
                        // If the response is from the 'checkToken' method then set the session state depending on the result.  If the token
                        // is good, then fire the onload event.  If not, then delete the sessionCookie before firing the onload event.
                        else if (("method" in response) && (response.method.indexOf("checkToken") >= 0) && response.Result && response.Result.code) {
                                if (response.Result.code == 1) { this.onload(); }
                                else {
                                        sessionCookie.remove();
                                        this.onload();
                                }
                        }
                       
                        // If the response is an authentication response, then save the user login info, and refresh the application state.
                        else if (("method" in response) && (response.method.indexOf("getToken") >= 0) && response.Result && response.Result.token) {
                                sessionCookie.token = response.Result.token;
                                if (response.Result.publicName) { sessionCookie.publicName = response.Result.publicName; }
                                sessionCookie.store();
                                this.onload(true);
                        }
                       
                        // For all other responses, save the response data in the appropriate attributes and then fire the onupdate event.
                        else {
                                var methodName = '';
                                if ("method" in response) {
                                        this.method = response.method;
                                        methodName = response.method.slice(response.method.lastIndexOf('.') + 1);
                                }
                                if ("query" in response) {
                                        this.previousQuery = this.query;
                                        this.query = response.query;
                                }
                                if ("querySuggestion" in response) {
                                        this.querySuggestion = response.querySuggestion;
                                }
                                if ("VideoSet" in response) {
                                        this.VideoSet = response.VideoSet;
                                        if ("firstResultPosition" in response.VideoSet) { this.start = response.VideoSet.firstResultPosition; }
                                }
                                if ("TagSet" in response) { this.TagSet = response.TagSet; }
                                if ("ChannelSet" in response) { this.ChannelSet = response.ChannelSet; }
                                if ("CategorySet" in response) { this.CategorySet = response.CategorySet; }
                                if ("UserSet" in response) { this.UserSet = response.UserSet; }
                                if ("WatchlistSet" in response) {  this.WatchlistSet = response.WatchlistSet; }
                                if ("Result" in response) {  this.Result = response.Result; }
                                this.onupdate(methodName);
                        }
                }
        }

        // Function onXMLHTTPLoad() is the handler called by the XMLHTTP object when a query returns.  Before this handler can be
        // called, the TruveoVideoSearch object must first be registered with the XMLHTTP object using its registerCallback()
        // method.
        this.onXMLHTTPLoad = function(xmlhttp) {
                this.update(xmlhttp.responseText);
        }

        // Function onXMLHTTPError() is the handler called by the XMLHTTP object when an error is thrown.  Before this handler can be
        // called, the TruveoVideoSearch object must first be registered with the XMLHTTP object using its registerCallback() method.
        this.onXMLHTTPError = function(message) {
                this.onerror(501, errorMessages['501'] + "; " + message);
        }

        // Function submitRestQuery() takes the submitted urlParameters and sends an HTTP GET request to the Truveo video search API.
        // Note that if the TruveoVideoSearch object is set to 'rest' mode, this function will load a new webpage into the browser
        // window rather than sending an AJAX request.
        this.submitRestQuery = function(urlParams, mode) {
                if (mode == 'rest') {
                        var restUrl = window.location.protocol + '//' + window.location.host + window.location.pathname + '?';
                        for (name in urlParams) {
                                if ((name != 'token') && (name != 'showAdult')) { restUrl += name + '=' + encodeURIComponent(urlParams[name]) + '&'; }
                        }
                        window.location.href = restUrl.slice(0, -1);
                }
                else {
                       
                        // Initialize the XMLHTTP object, which allows for cross-domain ajax requests.  Specify the server url, register
                        // this object as the callback object, and attach an error handler.  When the response to this request returns,
                        // it will call the onXMLHTTPLoad() method of the callback object.  The onXMLHTTPLoad() method will be called with one argument
                        // specifying this xmlhttp object which will contain the response data.
                        var xmlhttp = new XMLHTTP();
                        xmlhttp.setXMLHTTPURL(xmlhttpUrl);
                        xmlhttp.registerCallback(this);
                        xmlhttp.open("GET", this.getRestUrl(urlParams), true);
                        xmlhttp.send(null);
                }
        }
       
        // Function getRestUrl() returns a string containing a properly formated REST URL that can be submitted to the
        // Truveo Video Search REST API.  This URL will include all of the URL parameters specified in the provided associative
        // array, urlParameters.
        this.getRestUrl = function(urlParameters) {
                var urlString = serviceUrl + '?appid=' + encodeURIComponent(this.appid);
                for (name in urlParameters) { urlString += '&' + name + '=' + encodeURIComponent(urlParameters[name]); }
                return(urlString);
        }
       
        // Function getUrlParameters() takes an URL and returns an associative array containing name-value pairs for all
        // arguments in the URL.
        this.getUrlParameters = function(url) {
                var args = new Object();
                if (url.lastIndexOf('?') == -1) { return(args); }
                else { var urlQueryString = url.slice(url.lastIndexOf('?') + 1); }
                if (urlQueryString.length == 0) { return(args); }
                var pairs = urlQueryString.split('&');
                for (var i=0; i < pairs.length; i++) {
                        var pos = pairs[i].indexOf('=');
                        if (pos == -1) {
                                var argname = pairs[i];
                                var value = '';
                        }
                        else {
                                var argname = pairs[i].substring(0, pos);
                                var value = pairs[i].substring(pos+1);
                        }
                        args[argname] = decodeURIComponent(value);
                }
                return(args);
        }

        // Function removeUrlParameters() takes an URL and removes any both the name and value associated with any of the
        // specified parameters from the URL query string.  All other parameters are left intact.  The first argument supplied
        // to this function should be the URL string.  The second argument should be an array containing the names of each
        // parameter to be removed from the URL.  This function returns the modified url with the parameters removed.
        this.removeUrlParameters = function(url, paramArray) {
                if (url.lastIndexOf('?') == -1) { var baseUrl = url; }
                else { var baseUrl = url.slice(0, url.lastIndexOf('?')); }
                var urlParameters = this.getUrlParameters(url);
                for (var i=0; i < paramArray.length; i++) {
                        if (paramArray[i] in urlParameters) { urlParameters[paramArray[i]] = null; }
                }
                var j = 0;
                var paramString = '';
                for (name in urlParameters) {
                        if (urlParameters[name] != null) {
                                if (j==0) { paramString += name + '=' + encodeURIComponent(urlParameters[name]); }
                                else { paramString += '&' + name + '=' + encodeURIComponent(urlParameters[name]); }
                        }
                        j++;
                }
                if (paramString == '') { return(baseUrl); }
                else { return(baseUrl + "?" + paramString); }
        }

        // Function initialize() is called when the TruveoVideoSearch object is first instantiated.  This function checks
        // and sets the login state of this object based on the session cookie or URL parameters.
        this.initialize = function() {
               
                // First, check the user session cookie to see if it is valid.  If the cookie exists and contains
                // the user token, then call the API method checkToken to check the token's validity.
                if (this.isLoggedIn() && (this.mode == 'ajax')) {
                        var newUrlParams = { 'method': 'truveo.users.checkToken',
                                                                 'token': sessionCookie.token };
                        this.submitRestQuery(newUrlParams);
                }
               
                // If no session cookie is present then, get any arguments in the URL of the document that loaded this class
                // If the token is in the current URL parameters, then the user is already logged in - so store the
                // token in the sessionCookie.  If the auth is in the URL parameters, then attempt to retrive a
                // session token using the auth key.
                else {
                        urlParams = this.getUrlParameters(window.location.href);
                        if ('token' in urlParams) {
                                sessionCookie.token = urlParams.token;
                                sessionCookie.store();
                                this.onload(true);
                        }
                        else if ('auth' in urlParams) {
                                var newUrlParams = { 'method': 'truveo.users.getToken',
                                                                         'auth': urlParams.auth };
                                this.submitRestQuery(newUrlParams);
                        }
                        else if ('loginCancel' in urlParams) { this.onload(true); }
                        else if ('logout' in urlParams) { this.onload(); }
                        else if ('errorCode' in urlParams) { this.onerror(urlParams.errorCode, urlParams.errorMessage); }
                        else { this.onload(); }
                }
        }
}


//*****************************************************************************************************
//      XMLHTTP JS class is is developed by Alex Serebryakov (#0.9.1)
//      For more information, consult www.ajaxextended.com
//*****************************************************************************************************

XMLHTTP = function() {

  // The following two options are configurable
  // you don't need to change the rest. Plug & play!
  var _maximumRequestLength = 1500

  // This URL must point to the same server where the REST API is located.
  var _apiURL = null;
  this.status = null
  this.statusText = null
  this.responseText = null
  this.responseXML = null
  this.synchronous = false
  this.readyState = 0
  this.callbackContext = null;          // Truveo Mods 7.15.06: The object to use as context when calling the callback functions.
  this.onreadystatechange =  function() { }
  this.onXMLHTTPError = function() { }
  this.onXMLHTTPLoad = function() { }

  // Truveo Mods 7.15.06:
  this.registerCallback = function(obj) {
        this.callbackContext = obj;
  }

  // Truveo Mods 7.15.06:
  this.setXMLHTTPURL = function(url) {
        _apiURL = url;
  }

  this.abort = function() {
    _stop = true
    _destroyScripts()
  }

  this.getAllResponseHeaders = function() {
    // Returns all response headers as a string
    var result = ''
    for (property in _responseHeaders)
      result += property + ': ' + _responseHeaders[property] + '\r\n'
    return result
  }

  this.getResponseHeader = function(name) {
    // Returns a response header value
    // Note, that the search is case-insensitive
    for(property in _responseHeaders) {
      if(property.toLowerCase() == name.toLowerCase())
        return _responseHeaders[property]
    }
    return null
  }

  this.overrideMimeType = function(type) {
    _overrideMime = type
  }

  this.open = function(method, url, sync, userName, password) {
    // Setting the internal values
    if (!_checkParameters(method, url)) return
    _method = (method) ? method : ''
    _url = (url) ? url : ''
    _userName = (userName) ? userName : ''
    _password = (password) ? password : ''
    _setReadyState(1)
  }

  this.openRequest = function(method, url, sync, userName, password) {
    // This method is inserted for compatibility purposes only
    return this.open(method, url, sync, userName, password)
  }

  this.send = function(data) {
    if (_stop) return
    var src = _createQuery(data)
    _createScript(src)
//    _setReadyState(2)
  }

  this.setRequestHeader = function(name, value) {
    // Set the request header. If the defined header
    // already exists (search is case-insensitive), rewrite it
    if (_stop) return
    for(property in _requestHeaders) {
      if(property.toLowerCase() == name.toLowerCase()) {
        _requestHeaders[property] = value; return
      }
    }
    _requestHeaders[name] = value
  }

  var _method = ''
  var _url = ''
  var _userName = ''
  var _password = ''
  var _requestHeaders = {
    "HTTP-Referer": document.location,
    "Content-Type": "application/x-www-form-urlencoded"
  }
  var _responseHeaders = { }
  var _overrideMime = ""
  var self = this
  var _id = ''
  var _scripts = []
  var _stop = false

  // Truveo Mods 7.15.06
  var _throwError = function(description, mythis) {
         
        // mythis is used to store the context for the current XMLHTTP object.
        if (arguments.length < 2) { mythis = self; }

    // Stop script execution and run
    // the user-defined error handler
        if ((mythis.callbackContext != null) && mythis.callbackContext.onXMLHTTPError) { mythis.callbackContext.onXMLHTTPError(description); }
        else { self.onXMLHTTPError(description); }
    self.abort()
    return false
  }

  var _createQuery = function(data) {
    if(!data) data = ''
    var headers = ''
    // Truveo mod 9.19.07: encode all request headers
    for (property in _requestHeaders)
      headers += encodeURIComponent(property) + '=' + encodeURIComponent(_requestHeaders[property]) + '&'
    var originalsrc = _method
    + '$' + _id
    + '$' + _userName
    + "$" + _password
    + "$" + headers
    + '$' + _escape(data)
    + '$' + _url
    var src = originalsrc
    var max =  _maximumRequestLength, request = []
    var total = Math.floor(src.length / max), current = 0
    while(src.length > 0) {
      var query = _apiURL + '?'
      + 'multipart'
      + '$' + _id
      + '$' + current++
      + '$' + total
      + '$' + src.substr(0, max)
      request.push(query)
      src = src.substr(max)
    }
    if(request.length == 1)
      src = _apiURL + '?' + originalsrc
    else
      src = request
    return src
  }

  var _checkParameters = function(method, url) {
    // Check the method value (GET, POST, HEAD)
    // and the prefix of the url (http://)
    if(!method)
      return _throwError('Please, specify the query method (GET, POST or HEAD)')
    if(!url)
      return _throwError('Please, specify the URL')
    if(method.toLowerCase() != 'get' &&
      method.toLowerCase() != 'post' &&
      method.toLowerCase() != 'head')
      return _throwError('Please, specify either a GET, POST or a HEAD method')
    if(url.toLowerCase().substr(0,7) != 'http://')
      return _throwError('Only HTTP protocol is supported (http://)')
    return true
  }

  var _createScript = function(src) {
    if ('object' == typeof src) {
      for(var i = 0; i < src.length; i++)
        _createScript(src[i])
      return
    }
    // Create the SCRIPT tag
    var script = document.createElement('script')
    script.src = src
    script.type = 'text/javascript'
    if (navigator.userAgent.indexOf('Safari'))
      script.charset = 'utf-8' // Safari bug
    script = document.getElementsByTagName('head')[0].appendChild(script)
    _scripts.push(script)
    return script
  }

  var _escape = function(string) {
    // Native escape() function doesn't quote the plus sign +
    string = escape(string)
    string = string.replace('+', '%2B')
    return string
  }

  var _destroyScripts = function() {
    // Removes the SCRIPT nodes used by the class
    for(var i = 0; i < _scripts.length; i++)
      if(_scripts[i].parentNode)
        _scripts[i].parentNode.removeChild(_scripts[i])
  }

  var _registerCallback = function() {
    // Register a callback variable (in global scope)
    // that points to current instance of the class
    _id = 'v' + Math.random().toString().substr(2)
    window[_id] = self
  }

  // Truveo Mods 7.15.06
  var _setReadyState = function(number, mythis) {       

        // mythis is used to store the context for the current XMLHTTP object.
        if (arguments.length < 2) { mythis = self; }
       
    // Set the ready state property of the class
    self.readyState = number
       
        // If the callbackContext has been defined and the handler in the context object has been defined, then call
        // the onreadystatechange or onXMLHTTPLoad handler in the context object.  If not, then call the handlers in this xmlhttp object.
        if ((mythis.callbackContext != null) && mythis.callbackContext.onreadystatechange) { mythis.callbackContext.onreadystatechange(); }
        else { self.onreadystatechange(); }
    if(number == 4) {
                if ((mythis.callbackContext != null) && mythis.callbackContext.onXMLHTTPLoad) { mythis.callbackContext.onXMLHTTPLoad(mythis); }
                else { self.onXMLHTTPLoad(); }
        }
  }

  var _parseXML = function() { 
      var type = self.getResponseHeader('Content-type') + _overrideMime
      if(!(type.indexOf('html') > -1 || type.indexOf('xml') > -1)) return
      if(document.implementation &&
              document.implementation.createDocument &&
              navigator.userAgent.indexOf('Opera') == -1) {
        var parser = new DOMParser()
        var xml = parser.parseFromString(self.responseText, "text/xml")
        self.responseXML = xml
      } else if (window.ActiveXObject) {
        var xml = new ActiveXObject('MSXML2.DOMDocument.3.0')
        if (xml.loadXML(self.responseText))
                self.responseXML = xml
      } else {
        var xml = document.body.appendChild(document.createElement('div'))
        xml.style.display = 'none'
        xml.innerHTML = self.responseText
        _cleanWhitespace(xml, true)
        self.responseXML = xml.childNodes[0]
        document.body.removeChild(xml)
     }
  }

  var _cleanWhitespace = function(element, deep) {
    var i = element.childNodes.length; if(i == 0) return
    do {
      var node = element.childNodes[--i]
      if (node.nodeType == 3 && !_cleanEmptySymbols(node.nodeValue))
        element.removeChild(node)
      if (node.nodeType == 1 && deep)
        _cleanWhitespace(node, true)
    } while(i > 0)
  }

  var _cleanEmptySymbols = function(string) {
    string = string.replace('\r', '')
    string = string.replace('\n', '')
    string = string.replace(' ', '')
        return (string.length == 0) ? false : true
  }

  this._parse = function(object) {
    // Parse the received data and set all
    // the appropriate properties of the class
    if(_stop) return
    if(object.multipart) return
    if(!object.success)
      return _throwError(object.description, this)
    _responseHeaders = object.responseHeaders
    this.status = object.status
    this.statusText = object.statusText
    this.responseText = object.responseText
    _parseXML()
    _destroyScripts()
    _setReadyState(4, this);  // Truveo Mods 7.15.06
  }
   
   _registerCallback()
}


//*****************************************************************************************************
//      XML.ObjTree -- XML source code from/to JavaScript object like E4X
//  See http://www.kawa.net/works/js/xml/objtree-e.html.
//      Copyright (c) 2005-2006 Yusuke Kawasaki. All rights reserved.
//*****************************************************************************************************

if ( typeof(XML) == 'undefined' ) XML = function() {};

//  constructor
XML.ObjTree = function () {
    return this;
};

//  class variables
XML.ObjTree.VERSION = "0.23";

//  object prototype
XML.ObjTree.prototype.xmlDecl = '<?xml version="1.0" encoding="UTF-8" ?>\n';
XML.ObjTree.prototype.attr_prefix = '-';

//  method: parseXML( xmlsource )
XML.ObjTree.prototype.parseXML = function ( xml ) {
    var root;
    if ( window.DOMParser ) {
        var xmldom = new DOMParser();
//      xmldom.async = false;           // DOMParser is always sync-mode
        var dom = xmldom.parseFromString( xml, "application/xml" );
        if ( ! dom ) return;
        root = dom.documentElement;
    } else if ( window.ActiveXObject ) {
        xmldom = new ActiveXObject('Microsoft.XMLDOM');
        xmldom.async = false;
        xmldom.loadXML( xml );
        root = xmldom.documentElement;
    }
    if ( ! root ) return;
    return this.parseDOM( root );
};

//  method: parseDOM( documentroot )
XML.ObjTree.prototype.parseDOM = function ( root ) {
    if ( ! root ) return;

    this.__force_array = {};
    if ( this.force_array ) {
        for( var i=0; i<this.force_array.length; i++ ) {
            this.__force_array[this.force_array[i]] = 1;
        }
    }

    var json = this.parseElement( root );       // parse root node
    if ( this.__force_array[root.nodeName] ) {
        json = [ json ];
    }
    if ( root.nodeType != 11 ) {            // DOCUMENT_FRAGMENT_NODE
        var tmp = {};
        tmp[root.nodeName] = json;          // root nodeName
        json = tmp;
    }
    return json;
};

//  method: parseElement( element )
XML.ObjTree.prototype.parseElement = function ( elem ) {
    //  COMMENT_NODE
    if ( elem.nodeType == 7 ) {
        return;
    }

    //  TEXT_NODE CDATA_SECTION_NODE
    if ( elem.nodeType == 3 || elem.nodeType == 4 ) {
        var bool = elem.nodeValue.match( /[^\x00-\x20]/ );
        if ( bool == null ) return;     // ignore white spaces
        return elem.nodeValue;
    }

    var retval;
    var cnt = {}; 

    //  parse attributes
    if ( elem.attributes && elem.attributes.length ) {
        retval = {};
        for ( var i=0; i<elem.attributes.length; i++ ) {
            var key = elem.attributes[i].nodeName;
            if ( typeof(key) != "string" ) continue;
            var val = elem.attributes[i].nodeValue;
            if ( ! val ) continue;
            key = this.attr_prefix + key;
            if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
            cnt[key] ++;
            this.addNode( retval, key, cnt[key], val );
        }
    }

    //  parse child nodes (recursive)  -- Truveo Mods 7.20.06 - changed condition below from elem.childNodes.length to (elem.childNode.length>=0)
    if ( elem.childNodes && (elem.childNodes.length>=0) ) {
        var textonly = true;
        if ( retval ) textonly = false;        // some attributes exists
        for ( var i=0; i<elem.childNodes.length && textonly; i++ ) {
            var ntype = elem.childNodes[i].nodeType;
            if ( ntype == 3 || ntype == 4 ) continue;
            textonly = false;
        }
        if ( textonly ) {
            if ( ! retval ) retval = new String();              // Truveo Mods: 7/20/06 - Changed from "" to 'new String()'
            for ( var i=0; i<elem.childNodes.length; i++ ) {
                retval += elem.childNodes[i].nodeValue;
            }
        } else {
            if ( ! retval ) retval = {};
            for ( var i=0; i<elem.childNodes.length; i++ ) {
                var key = elem.childNodes[i].nodeName;
                if ( typeof(key) != "string" ) continue;
                var val = this.parseElement( elem.childNodes[i] );
                if ( ! val ) continue;
                if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
                cnt[key] ++;
                this.addNode( retval, key, cnt[key], val );
            }
        }
    }
    return retval;
};

//  method: addNode( hash, key, count, value )
XML.ObjTree.prototype.addNode = function ( hash, key, cnts, val ) {
    if ( this.__force_array[key] ) {
        if ( cnts == 1 ) hash[key] = [];
        hash[key][hash[key].length] = val;      // push
    } else if ( cnts == 1 ) {                   // 1st sibling
        hash[key] = val;
    } else if ( cnts == 2 ) {                   // 2nd sibling
        hash[key] = [ hash[key], val ];
    } else {                                    // 3rd sibling and more
        hash[key][hash[key].length] = val;
    }
};

//  method: writeXML( tree )
XML.ObjTree.prototype.writeXML = function ( tree ) {
    var xml = this.hash_to_xml( null, tree );
    return this.xmlDecl + xml;
};

//  method: hash_to_xml( tagName, tree )
XML.ObjTree.prototype.hash_to_xml = function ( name, tree ) {
    var elem = [];
    var attr = [];
    for( var key in tree ) {
        if ( ! tree.hasOwnProperty(key) ) continue;
        var val = tree[key];
        if ( key.charAt(0) != this.attr_prefix ) {
            if ( typeof(val) == "undefined" || val == null ) {
                elem[elem.length] = "<"+key+" />";
            } else if ( typeof(val) == "object" && val.constructor == Array ) {
                elem[elem.length] = this.array_to_xml( key, val );
            } else if ( typeof(val) == "object" ) {
                elem[elem.length] = this.hash_to_xml( key, val );
            } else {
                elem[elem.length] = this.scalar_to_xml( key, val );
            }
        } else {
            attr[attr.length] = " "+(key.substring(1))+'="'+(this.xml_escape( val ))+'"';
        }
    }
    var jattr = attr.join("");
    var jelem = elem.join("");
    if ( typeof(name) == "undefined" || name == null ) {
        // no tag
    } else if ( elem.length > 0 ) {
        if ( jelem.match( /\n/ )) {
            jelem = "<"+name+jattr+">\n"+jelem+"</"+name+">\n";
        } else {
            jelem = "<"+name+jattr+">"  +jelem+"</"+name+">\n";
        }
    } else {
        jelem = "<"+name+jattr+" />\n";
    }
    return jelem;
};

//  method: array_to_xml( tagName, array )
XML.ObjTree.prototype.array_to_xml = function ( name, array ) {
    var out = [];
    for( var i=0; i<array.length; i++ ) {
        var val = array[i];
        if ( typeof(val) == "undefined" || val == null ) {
            out[out.length] = "<"+name+" />";
        } else if ( typeof(val) == "object" && val.constructor == Array ) {
            out[out.length] = this.array_to_xml( name, val );
        } else if ( typeof(val) == "object" ) {
            out[out.length] = this.hash_to_xml( name, val );
        } else {
            out[out.length] = this.scalar_to_xml( name, val );
        }
    }
    return out.join("");
};

//  method: scalar_to_xml( tagName, text )
XML.ObjTree.prototype.scalar_to_xml = function ( name, text ) {
    if ( name == "#text" ) {
        return this.xml_escape(text);
    } else {
        return "<"+name+">"+this.xml_escape(text)+"</"+name+">\n";
    }
};

//  method: xml_escape( text )
XML.ObjTree.prototype.xml_escape = function ( text ) {
    return text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
};


// The constructor function: creates a cookie object for the specified
// document, with a specified name and optional attributes.
// Arguments:
//   document: The Document object that the cookie is stored for. Required.
//   name:     A string that specifies a name for the cookie. Required.
//   hours:    An optional number that specifies the number of hours from now
//             that the cookie should expire.
//   path:     An optional string that specifies the cookie path attribute.
//   domain:   An optional string that specifies the cookie domain attribute.
//   secure:   An optional Boolean value that, if true, requests a secure cookie.
//
function Cookie(document, name, hours, path, domain, secure)
{
    // All the predefined properties of this object begin with '$'
    // to distinguish them from other properties which are the values to
    // be stored in the cookie.
    this.$document = document;
    this.$name = name;
    if (hours)
        this.$expiration = new Date((new Date()).getTime() + hours*3600000);
    else this.$expiration = null;
    if (path) this.$path = path; else this.$path = null;
    if (domain) this.$domain = domain; else this.$domain = null;
    if (secure) this.$secure = true; else this.$secure = false;
}

// This function is the store() method of the Cookie object.
Cookie.prototype.store = function () {
    // First, loop through the properties of the Cookie object and
    // put together the value of the cookie. Since cookies use the
    // equals sign and semicolons as separators, we'll use colons
    // and ampersands for the individual state variables we store
    // within a single cookie value. Note that we escape the value
    // of each state variable, in case it contains punctuation or other
    // illegal characters.
    var cookieval = "";
    for(var prop in this) {
        // Ignore properties with names that begin with '$' and also methods.
        if ((prop.charAt(0) == '$') || ((typeof this[prop]) == 'function'))
            continue;
        if (cookieval != "") cookieval += '&';
        cookieval += prop + ':' + escape(this[prop]);
    }

    // Now that we have the value of the cookie, put together the
    // complete cookie string, which includes the name and the various
    // attributes specified when the Cookie object was created.
    var cookie = this.$name + '=' + cookieval;
    if (this.$expiration)
        cookie += '; expires=' + this.$expiration.toGMTString();
    if (this.$path) cookie += '; path=' + this.$path;
    if (this.$domain) cookie += '; domain=' + this.$domain;
    if (this.$secure) cookie += '; secure';

    // Now store the cookie by setting the magic Document.cookie property.
    this.$document.cookie = cookie;
}

// This function is the load() method of the Cookie object.
Cookie.prototype.load = function() {
    // First, get a list of all cookies that pertain to this document.
    // We do this by reading the magic Document.cookie property.
    var allcookies = this.$document.cookie;
    if (allcookies == "") return false;

    // Now extract just the named cookie from that list.
    var start = allcookies.indexOf(this.$name + '=');
    if (start == -1) return false;   // Cookie not defined for this page.
    start += this.$name.length + 1;  // Skip name and equals sign.
    var end = allcookies.indexOf(';', start);
    if (end == -1) end = allcookies.length;
    var cookieval = allcookies.substring(start, end);

    // Now that we've extracted the value of the named cookie, we've
    // got to break that value down into individual state variable
    // names and values. The name/value pairs are separated from each
    // other by ampersands, and the individual names and values are
    // separated from each other by colons. We use the split method
    // to parse everything.
    var a = cookieval.split('&');    // Break it into array of name/value pairs.
    for(var i=0; i < a.length; i++)  // Break each pair into an array.
        a[i] = a[i].split(':');

    // Now that we've parsed the cookie value, set all the names and values
    // of the state variables in this Cookie object. Note that we unescape()
    // the property value, because we called escape() when we stored it.
    for(var i = 0; i < a.length; i++) {
        this[a[i][0]] = unescape(a[i][1]);
    }

    // We're done, so return the success code.
    return true;
}

// This function is the remove() method of the Cookie object.
Cookie.prototype.remove = function() {
    var cookie;
    cookie = this.$name + '=';
    if (this.$path) cookie += '; path=' + this.$path;
    if (this.$domain) cookie += '; domain=' + this.$domain;
    cookie += '; expires=Fri, 02-Jan-1970 00:00:00 GMT';

    this.$document.cookie = cookie;
}

//-->




