   var areq;
   var breq;

   var delay = 75; // 75 * 10 ms
   var clock = delay;

   var navigator_items         = new Array();
   var class_selector_items    = new Array();
   var property_items          = new Array();
   var property_selector_items = new Array();

   var current_uri       = '';
   var current_dataspace = '';
   var current_page      = 0;

   var progress_check_sent = false;
   var progress_404_count = 0;
   var progress_404_max_count = 12;

   function doEnterKey(e, field) {
      var key;

      if (window.event) {
         // IE
         key = window.event.keyCode;
      } else {
         // FF
         key = e.which;
      }

      if (key == 13) {
         if ((field.value.length > 0) && (field.value != "http://")) {
            var browser_query_url = document.getElementById('browser_query_url');
            var goto_url = browser_query_url.value + escape(field.value);
            // alert(goto_url);
            location.href = goto_url;
         }
         return false;
      } else {
         return true;
      }
   }

   function stopClock() {
      clock = "00";
   }

   function startClock() {
      if (clock != "00") {
         clock = clock - 1;
         if (clock <= 0) {
            clock = delay;
            get_analysis_progress();
         }
         timerID = setTimeout("startClock()", 10);
      }
   }

   function do_load_content(uri, dataspace, page, give_focus) {

      current_uri       = uri;
      current_dataspace = dataspace;
      current_page      = page;

      var url = browser_base_URL + '?';
      if (skin_num > 0) {
         url = url + 'skin=' + skin_num + "&";
      }
      if (do_load_from_js) {
          url = url + 'fromjs&';
      }
      url = url + 'page=' + page + '&';
      url = url + 'progress=' + progress_filename + '&';
      if (dataspace) {
         url = url + 'dataspace=' + escape(dataspace) + '&';
      }
      if (do_services) {
         url = url + 'services&';
      }
      url = url + 'uri=' + escape(uri);
      // if (do_load_from_js) { display_page_loading_progress('0', uri); }
      get_content_from_browser(url, uri, page, give_focus);
      clock = delay;
      startClock();
      startRequestClock();
   }

   function get_content_from_browser(url, uri, page, give_focus) {
      if (window.XMLHttpRequest) {
         // branch for native XMLHttpRequest object
         breq = new XMLHttpRequest();
      } else if (window.ActiveXObject) {
         // branch for IE/Windows ActiveX version
         breq = new ActiveXObject("Microsoft.XMLHTTP");
      }

      if (breq) {

         if (OAT.Browser.isIE || OAT.Browser.isGecko) {
            breq.onprogress = on_page_loading_progress;
         }
         breq.onreadystatechange = display_content;

         breq.uri = uri;
         breq.page = page;
         breq.give_focus = give_focus;

         breq.open("GET", url, true);
      }

      if (window.XMLHttpRequest) {
         // branch for native XMLHttpRequest object
         breq.send(null);
      } else if (window.ActiveXObject) {
         // branch for IE/Windows ActiveX version
         breq.send();
      }
   }

   function get_analysis_progress() {
      var url = browser_base_URL + 'data/' + progress_filename + '.xml';
      // alert(url);
      // branch for native XMLHttpRequest object

      // Make sure that we received an answer for the previous request.
      // This is to prevent when the server doesn't send back an answer for a progress request.
      if (!progress_check_sent) {
         if (window.XMLHttpRequest) {
            areq = new XMLHttpRequest();
            areq.onreadystatechange = display_analysis_progress;
            areq.open("GET", url, true);
            areq.send(null);

            progress_check_sent = true;
         // branch for IE/Windows ActiveX version
         } else if (window.ActiveXObject) {
            areq = new ActiveXObject("Microsoft.XMLHTTP");
            if (areq) {
               areq.onreadystatechange = display_analysis_progress;
               areq.open("GET", url, true);
               areq.send();

               progress_check_sent = true;
            }
         }
      }
   }

   function on_page_loading_progress(e) {
      var percentComplete = Math.round((e.position / e.totalSize)*100);
      var msg = msg_progress_loading_page + e.target.page;
      display_page_loading_progress(percentComplete, msg);
   }

   function display_analysis_progress() {
      window.status = '';

      if (areq) {
         if (areq.readyState == 4) {
            progress_check_sent = false;

            if (areq.status == 404) {
                progress_404_count++;
            } else {
                progress_404_count = 0;
            }

            if (progress_404_count > progress_404_max_count) {
                stopClock();
                progress_404_count = 0;
                // display_page_loading_progress(null, "Initialization timeout");
                display_page_loading_progress(null, msg_error_loading_timed_out);
            }

            if (areq.status == 200) {
               if (areq.responseXML) {
                  var response = areq.responseXML.documentElement;
                  if (response.getElementsByTagName('step').length > 0) {
                     if (response.getElementsByTagName('step')[0].hasChildNodes()) {
                        var step = response.getElementsByTagName('step')[0].firstChild.data;
                        if (response.getElementsByTagName('done').length > 0) {
                           if (response.getElementsByTagName('done')[0].hasChildNodes()) {
                              var done = response.getElementsByTagName('done')[0].firstChild.data;
                           }
                        }
                        if (response.getElementsByTagName('total').length > 0) {
                           if (response.getElementsByTagName('total')[0].hasChildNodes()) {
                              var total = response.getElementsByTagName('total')[0].firstChild.data;
                           }
                        }
                        var percentComplete = Math.round((done / total)*100);
                        display_page_loading_progress(percentComplete, step);
                     }
                  }
               }
            }
         }
      }
   }

   function display_page_loading_progress(percentComplete, msg) {
      var body = document.getElementById('body');

      if (percentComplete == null) {
         if (body) {
            html = '<div class="page_loading_progress_container">';
            html = html + msg + '<br />';
            html = html + '</div>';
            body.innerHTML = html;
         }
      } else {
          if (percentComplete == '0') {
             if (body) {
                html = '<div class="page_loading_progress_container">';
                html = html + msg + '<br />';
                html = html + '<div class="progress_container"><div class="progress_bar" style="background-image: url(); background-color: transparent; width: 100%;">0 %</div></div>';
                html = html + '</div>';
                body.innerHTML = html;
             }
         } else {
            if (body) {
               var displayPercent = percentComplete;
               if (skin_num > 0) {
                  var displayLimit = 15;
               } else {
                  var displayLimit = 7;
               }
               if (displayPercent < displayLimit) {
                  displayPercent = ''; // to avoid displaying a percentage that exceeds the div width
               } else {
                  displayPercent = displayPercent + ' %';
               }
               if (percentComplete == 100) { percentComplete = 99; } // to avoid exceeding the container
               html = '<div class="page_loading_progress_container">';
               html = html + msg + '<br />';
               html = html + '<div class="progress_container"><div class="progress_bar" style="width: ' + percentComplete + '%;">' + displayPercent + '</div></div>';
               html = html + '</div>';
               body.innerHTML = html;
            }
         }
      }
   }

   function display_content() {
      var allcontents = '';
      var give_focus  = '';

      if ((breq.readyState == 3) && (do_load_from_js)) {
         stopClock();
         /*
         if (!OAT.Browser.isIE7) {
            var totalBytes = breq.getResponseHeader("Content-Length");
         if (breq.responseStream) {
            var bytesLoaded = breq.responseStream.length;
         } else {
            if (breq.responseText) {
               var bytesLoaded = breq.responseText.length;
            }
         }
         }
         var msg = 'Loading page ' + breq.page;
         if (!OAT.Browser.isIE7) {
            var percentComplete = Math.round((bytesLoaded / totalBytes)*100);
         } else {
            var percentComplete = bytesLoaded ;
         }
         display_page_loading_progress(percentComplete, msg);
         */
         if (!OAT.Browser.isIE && !OAT.Browser.isGecko) {
            var totalBytes = breq.getResponseHeader("Content-Length");
            if (breq.responseStream) {
               var bytesLoaded = breq.responseStream.length;
            } else {
               if (breq.responseText) {
                  var bytesLoaded = breq.responseText.length;
               }
            }
            var msg = 'Loading page ' + breq.page;
            var percentComplete = Math.round((bytesLoaded / totalBytes)*100);
            display_page_loading_progress(percentComplete, msg);
         }
      }
      if (breq.readyState == 4) {
         stopClock();
         window.status = '';
         if (breq.status == 200) {
            if (breq.responseXML) {
               var response = breq.responseXML.documentElement;
               var result = 0;
               if (response) {
                  if (response.getElementsByTagName('result')) {
                     if (response.getElementsByTagName('result').length > 0) {
                        if (response.getElementsByTagName('result')[0].hasChildNodes()) {
                           var result = response.getElementsByTagName('result')[0].firstChild.data;
                        }
                     }
                  }

                  // contents must be broken in parts for this to works under FF
                  var contents = response.getElementsByTagName('contents');
                  for (var c=0;c<contents.length;c++) {
                     if (contents[c].hasChildNodes()) {
                        allcontents = allcontents + contents[c].firstChild.data;
                     }
                  }
               }

               var body = document.getElementById('body');
               if (body) {
                  if (result == '1') {
                     // add contents
                     body.innerHTML = allcontents;

                     // focus
                     if (breq.give_focus) {
                        location.href = '#' + breq.give_focus;
                        give_focus    = breq.give_focus;
                     }
                  } else {
                     body.innerHTML = display_error_msg_embedded(msg_error_dynamic_bad_xml_data);
                     // body.innerHTML = body.innerHTML + breq.statusText;
                     // body.innerHTML = body.innerHTML + breq.responseText;
                     // body.innerHTML = allcontents;
                  }
               }

               // maps
               if (result == '1') {
                  var maps = response.getElementsByTagName('map');
                  for (var k=0;k<maps.length;k++) {
                     loadMap(maps[k].firstChild.data);
                  }
               }

               // widgets
               if (result == '1') {
                  process_widgets(response);
               }

               // triggers
               if (result == '1') {
                  process_triggers(response, give_focus);
               }

               // services
               if (do_services && (result == '1')) {
                  var services = response.getElementsByTagName('service');
                  var serviceID;
                  var serviceValue;
                  for (var s=0;s<services.length;s++) {
                     serviceID    = services[s].getElementsByTagName('id')[0].firstChild.data;
                     serviceValue = services[s].getElementsByTagName('value')[0].firstChild.data;
                     load_webpage_url(serviceValue, serviceID);
                  }
               }

               // navigator + selector
               if (result == '1') {
                  process_navigator_items(response, true, false);
               }

               // resize images
               if (result == '1') {
                  resize_images();
               }

            } else {
               // no XML response
               // should we log this ? or send an email alert ?
               // alert(msg_error_dynamic_bad_xml_data);
            }
         } else {
            // status <> 200
         }
      }
   }

   function getElementsByClass(searchClass, tag) {
      var classElements = new Array();
      var els = document.getElementsByTagName(tag);
      var elsLen = els.length;
      var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
      for (i = 0, j = 0; i < elsLen; i++) {
         if ( pattern.test(els[i].className) ) {
            classElements[j] = els[i];
            j++;
         }
      }
      return classElements;
   }

   function doWaitSplashScreen() {
      // placeholder
   }

   function process_navigator_items(response, from_page, getIDOnly) {

      if (from_page == true) {
         // clear existing navigator items
         navigator_items = new Array();
         // clear existing selector anchors & pages
         for (var i=0;i<class_selector_items.length;i++) {
            class_selector_items[i].classAnchors = new Array();
            class_selector_items[i].classPages = new Array();
         }
         for (var i=0;i<property_selector_items.length;i++) {
            property_selector_items[i].propertyAnchors = new Array();
            property_selector_items[i].propertyPages = new Array();
         }
         for (var i=0;i<property_items.length;i++) {
            property_items[i].propertyAnchors = new Array();
            property_items[i].propertyPages = new Array();
         }
      }

      // alert(navigator_items.length);

      // read tab infos from response
      var tabs = response.getElementsByTagName('tab');
      for (var t=0;t<tabs.length;t++) {
         if (tabs[t].getElementsByTagName('type')[0].hasChildNodes()) {
            var tabType = tabs[t].getElementsByTagName('type')[0].firstChild.data;
         }
         if (tabs[t].getElementsByTagName('label')[0].hasChildNodes()) {
            var tabLabel = tabs[t].getElementsByTagName('label')[0].firstChild.data;
         }
         if (tabs[t].getElementsByTagName('page')[0].hasChildNodes()) {
            var tabPage = tabs[t].getElementsByTagName('page')[0].firstChild.data;
         } else {
            var tabPage = current_page;
         }
         if (tabs[t].getElementsByTagName('anchor')[0].hasChildNodes()) {
            var tabAnchor = tabs[t].getElementsByTagName('anchor')[0].firstChild.data;
         }
         tab = new tabInfo(tabType, tabLabel, tabPage, tabAnchor);
         if (!anchor_is_known(tabAnchor)) {
            navigator_items.push(tab);
         }
      }

      // read property infos from response
      var properties = response.getElementsByTagName('property');
      for (var p=0;p<properties.length;p++) {
         if (properties[p].getElementsByTagName('type')[0].hasChildNodes()) {
            var propertyType = properties[p].getElementsByTagName('type')[0].firstChild.data;
         }
         if (properties[p].getElementsByTagName('anchor')[0].hasChildNodes()) {
            var propertyAnchor = properties[p].getElementsByTagName('anchor')[0].firstChild.data;
         }
         if (properties[p].getElementsByTagName('page')[0].hasChildNodes()) {
            var propertyPage = properties[p].getElementsByTagName('page')[0].firstChild.data;
         }
         property = new propertyInfo(propertyType, true, propertyAnchor, propertyPage);
         property_items.push(property);
      }

      // update display
      // if (from_page == true) {
         update_navigator();
      // }
      if (getIDOnly == false) {
         update_selector();
      }
   }

   function process_widgets(response) {
      var widgets = response.getElementsByTagName('widget');
      var widgetID;
      var widgetType;
      for (var w=0;w<widgets.length;w++) {
         widgetID   = widgets[w].getElementsByTagName('id')[0].firstChild.data;
         widgetType = widgets[w].getElementsByTagName('type')[0].firstChild.data;

         // grids
         if (widgetType == 'grid') {
            var headers = new Array();
            var rows    = new Array();
            var cell;
            var widgetRows = widgets[w].getElementsByTagName('row');
            if (widgetRows) {
               for (var wr=0;wr<widgetRows.length;wr++) {
                  var widgetColumns = widgetRows[wr].getElementsByTagName('col');
                  var row           = new Array();
                  if (widgetColumns) {
                     for (var wc=0;wc<widgetColumns.length;wc++) {
                        cell = '';
                        if (widgetColumns[wc].firstChild) {
                           if (widgetColumns[wc].firstChild.data != '') {
                              cell = widgetColumns[wc].firstChild.data;
                           }
                        }
                        if (wr == 0) {
                           headers.push(cell);
                        } else {
                           row.push(cell);
                        }
                     }
                     if (wr > 0) { rows.push(row); }
                  }
               }
            }
            var widgetSortBy = widgets[w].getElementsByTagName('sortby')[0].firstChild.data;
            // var widgetSortBy = 0; // sort by track number
            make_grid(widgetID, headers, rows, widgetSortBy)
         }
      }
   }

   function process_triggers(response, give_focus) {
      var triggers = response.getElementsByTagName('trigger');
      var triggerID;
      var triggerValue;
      var triggerDataspace;
      var triggerEmbed;
      var triggerParent;
      var triggerElsewhere;
      for (var t=0;t<triggers.length;t++) {
         if (triggers[t].getElementsByTagName('id')[0].hasChildNodes()) {
            triggerID = triggers[t].getElementsByTagName('id')[0].firstChild.data;
         }
         if (triggers[t].getElementsByTagName('value')[0].hasChildNodes()) {
            triggerValue = triggers[t].getElementsByTagName('value')[0].firstChild.data;
         }
         if (triggers[t].getElementsByTagName('embed')[0].hasChildNodes()) {
            triggerEmbed = triggers[t].getElementsByTagName('embed')[0].firstChild.data;
         }
         if (triggers[t].getElementsByTagName('dataspace')[0].hasChildNodes()) {
            triggerDataspace = triggers[t].getElementsByTagName('dataspace')[0].firstChild.data;
         }
         if (triggers[t].getElementsByTagName('parent')[0].hasChildNodes()) {
            triggerParent = triggers[t].getElementsByTagName('parent')[0].firstChild.data;
         }
         if (triggers[t].getElementsByTagName('elsewhere')[0].hasChildNodes()) {
            triggerElsewhere = triggers[t].getElementsByTagName('elsewhere')[0].firstChild.data;
         }
         load_property_value(triggerValue, triggerID, triggerEmbed, triggerDataspace, triggerParent, give_focus, triggerElsewhere);
      }
   }

   function show_seemore_section(sectionID, give_focus) {
      // hide anchor
      var section = document.getElementById(sectionID);
      var anchorID = section.getAttribute('anchor');
      var anchor   = document.getElementById(anchorID);
      if (anchor) {
         // anchor.parentNode.removeChild(anchor);
         anchor.style.display = 'none';
      }

      // show section
      if (section) {
         section.style.display = 'block';
         // fade in
         var a1 = new OAT.AnimationOpacity(sectionID, {opacity:1, delay:50, speed: 0.2});
         a1.start();
      }

      // process triggers
      var triggers = getElementsByClass('seemore_trigger', 'div');
      if (triggers.length > 0) {
         var triggerID;
         var triggerValue;
         var triggerDataspace;
         var triggerEmbed;
         var triggerParent;
         var triggerParentID;
         var triggerElsewhere;
         for (var t=0;t<triggers.length;t++) {
            triggerID        = triggers[t].getAttribute('node_id');
            triggerValue     = triggers[t].getAttribute('node_value');
            triggerEmbed     = triggers[t].getAttribute('node_deep');
            triggerParentID  = triggers[t].getAttribute('parent_id');
            triggerDataspace = triggers[t].getAttribute('node_dataspace');
            triggerParent    = triggers[t].getAttribute('node_parent');
            triggerElsewhere = triggers[t].getAttribute('node_elsewhere');
            if (triggerParentID == sectionID) {
               load_property_value(triggerValue, triggerID, triggerEmbed, triggerDataspace, triggerParent, give_focus, triggerElsewhere);
               var trigger = triggers[t];
               trigger.parentNode.removeChild(trigger);
            }
         }
      }
   }

   function fade_out_seemore_section(sectionID) {
      OAT.Dom.hide($(sectionID));
      var section  = document.getElementById(sectionID);
      var anchorID = section.getAttribute('anchor');
      var anchor   = document.getElementById(anchorID);
      if (anchor) {
         anchor.style.display = 'block';
      }
   }

   function hide_seemore_section(sectionID) {
      // hide section
      var section = document.getElementById(sectionID);
      if (section) {
         // fade out
         var a = new OAT.AnimationOpacity(sectionID, {opacity:0, delay:50, speed: 0.2});
         OAT.MSG.attach(a.animation, OAT.MSG.ANIMATION_STOP, function() {fade_out_seemore_section(sectionID);} );
         a.start();
      }
   }

   function toggle_references_subsections(imgID, sectionID) {
      // toggle sections
      var section = document.getElementById(sectionID);
      var subsections = section.childNodes;
      for (var i=0;i<subsections.length;i++) {
          if (subsections[i].className == 'references_type_subsection') {
             if (subsections[i].style.display == 'block') {
                subsections[i].style.display = 'none';
             } else {
                subsections[i].style.display = 'block';
             }
          }
      }
      // toggle img
      var img = document.getElementById(imgID);
      var img_explode  = skinpath + 'references_explode.png';
      var img_collapse = skinpath + 'references_collapse.png';
      if (img.src == img_explode) {
          img.src   = img_collapse;
          img.alt   = msg_references_hide_subsections;
          img.title = msg_references_hide_subsections;
      } else {
          img.src   = img_explode;
          img.alt   = msg_references_show_subsections;
          img.title = msg_references_show_subsections;
      }
   }

   function toggle_references_items(imgID, typesectionID) {
      // toggle items
      var type_section = document.getElementById(typesectionID);
      var items = type_section.childNodes;
      for (var i=0;i<items.length;i++) {
          if (items[i].className == 'references_items') {
             if (items[i].style.display == 'block') {
                items[i].style.display = 'none';
             } else {
                items[i].style.display = 'block';
             }
          }
      }
      // toggle img
      var img = document.getElementById(imgID);
      var img_explode  = skinpath + 'references_explode.png';
      var img_collapse = skinpath + 'references_collapse.png';
      if (img.src == img_explode) {
          img.src   = img_collapse;
          img.alt   = msg_references_hide_type;
          img.title = msg_references_hide_type;
      } else {
          img.src   = img_explode;
          img.alt   = msg_references_show_type;
          img.title = msg_references_show_type;
      }
   }

   function tabInfo(tabType, tabLabel, tabPage, tabAnchor) {
      this.tabType   = tabType;
      this.tabLabel  = tabLabel;
      this.tabPage   = tabPage;
      this.tabAnchor = tabAnchor;
   }

   function anchor_is_known(anchor) {
      var result = false;
      if (anchor) {
         for (var i=0;i<navigator_items.length;i++) {
            if (navigator_items[i].tabAnchor == anchor) {
               result = true;
            }
         }
      }
      return result;
   }

   function sortTabs(a, b) {
      result = 1;
      if (a.tabType == b.tabType) {

         if (a.tabLabel == b.tabLabel) {
            result = 0;
         } else {

            // auto-numbered items
            var a_pos_hash = a.tabLabel.indexOf('#');
            if (a_pos_hash != -1) {
               var a_item_txt = a.tabLabel.slice(0, a_pos_hash);
               var a_item_num = Number(a.tabLabel.slice(a_pos_hash + 1));
            }
            var b_pos_hash = b.tabLabel.indexOf('#');
            if (b_pos_hash != -1) {
               var b_item_txt = b.tabLabel.slice(0, b_pos_hash);
               var b_item_num = Number(b.tabLabel.slice(b_pos_hash + 1));
            }

            if ((a_item_txt) && (b_item_txt)) {
               if (a_item_txt == b_item_txt) {
                   if (a_item_num <= b_item_num) { result = -1; }
               } else {
                   if (a.tabLabel <= b.tabLabel) { result = -1; }
               }
            } else {
               if (a.tabLabel <= b.tabLabel) { result = -1; }
            }
         }

      } else {
         if (a.tabType <= b.tabType) { result = -1; }
      }
      return result;
   }

   function update_navigator() {

      var navigator_panel_bar = new OAT.Panelbar($('pb_navigator'), 10);
      var navigator_panel_bar_div = document.getElementById('pb_navigator');

      // navigator_panel_bar_div : remove all children
      if (navigator_panel_bar_div.hasChildNodes()) {
         while (navigator_panel_bar_div.childNodes.length >= 1) {
            navigator_panel_bar_div.removeChild(navigator_panel_bar_div.firstChild);
         }
      }
      navigator_panel_bar_div.innerHTML = '';

      // sort items by type
      if (navigator_items.length > 0) {
         navigator_items.sort(sortTabs);
      }

      // add items
      var current_type = '';
      for (var i=0;i<navigator_items.length;i++) {

         if (navigator_items[i].tabType != current_type) {

            if (current_type != '') {
               content_div.appendChild(ul);
               navigator_panel_bar_div.appendChild(content_div);
               navigator_panel_bar.addPanel('pb_header_' + current_type, 'pb_content_' + current_type);
            }

            current_type = navigator_items[i].tabType;

            var h2 = document.createElement('h2');
            h2.setAttribute('id', 'pb_header_' + current_type);
            h2.innerHTML = navigator_items[i].tabType;
            navigator_panel_bar_div.appendChild(h2);

            var content_div = document.createElement('div');
            content_div.setAttribute('id', 'pb_content_' + current_type);

            var ul = document.createElement('ul');
         }

         var link = '<a ';
         if (navigator_items[i].tabPage == current_page) {
             link = link + 'href="#' + navigator_items[i].tabAnchor + '" >';
         } else {
             link = link + 'href="#" onclick="do_load_content(\'' + current_uri + '\', \'' + current_dataspace + '\', \'' + navigator_items[i].tabPage + '\', \'' + navigator_items[i].tabAnchor + '\'); " >';
         }
         link = link + navigator_items[i].tabLabel;
         link = link + '</a>';

         var li = document.createElement('li');
         li.innerHTML = link;
         ul.appendChild(li);
      }

      if (navigator_items.length > 0) {
         content_div.appendChild(ul);
         navigator_panel_bar_div.appendChild(content_div);
         navigator_panel_bar.addPanel('pb_header_' + current_type, 'pb_content_' + current_type);
      }

      navigator_panel_bar.go(0);
   }

   function classInfo(classType, classStatus, classAnchors, classPages) {
      this.classType    = classType;
      this.classStatus  = classStatus;
      this.classAnchors = classAnchors;
      this.classPages   = classPages;
   }

   function propertyInfo(propertyType, propertyStatus, propertyAnchors, propertyPages) {
      this.propertyType    = propertyType;
      this.propertyStatus  = propertyStatus;
      this.propertyAnchors = propertyAnchors;
      this.propertyPages   = propertyPages;
   }

   function sortClasses(a, b) {
      result = 1;
      if (a.classType <= b.classType) { result = -1; }
      return result;
   }

   function sortProperties(a, b) {
      result = 1;
      if (a.propertyType.toLowerCase() <= b.propertyType.toLowerCase()) { result = -1; }
      return result;
   }

   function get_class_index(classType) {
      var result = -1;
      if (classType) {
         for (var i=0;i<class_selector_items.length;i++) {
            if (class_selector_items[i].classType == classType) {
               result = i;
            }
         }
      }
      return result;
   }

   function get_property_index(propertyType) {
      var result = -1;
      if (propertyType) {
         for (var i=0;i<property_selector_items.length;i++) {
            if (property_selector_items[i].propertyType == propertyType) {
               result = i;
            }
         }
      }
      return result;
   }

   function get_class_status(classType) {
      var result = true;
      if (classType) {
         for (var i=0;i<class_selector_items.length;i++) {
            if (class_selector_items[i].classType == classType) {
               result = class_selector_items[i].classStatus;
            }
         }
      }
      return result;
   }

   function get_property_status(classType) {
      var result = true;
      if (propertyType) {
         for (var i=0;i<property_selector_items.length;i++) {
            if (property_selector_items[i].propertyType == propertyType) {
               result = property_selector_items[i].propertyStatus;
            }
         }
      }
      return result;
   }

   function add_class(classType, classAnchors, classPages) {

      if (classType) {
         var index = get_class_index(classType);
         if (index == -1) {
            // add class
            var new_class = new classInfo(classType, true, classAnchors, classPages);
            class_selector_items.push(new_class);
         } else {
            // class exists : add anchors & pages only
            for (var i=0;i<classAnchors.length;i++) {
               class_selector_items[index].classAnchors.push(classAnchors[i]);
            }
            for (var i=0;i<classPages.length;i++) {
               class_selector_items[index].classPages.push(classPages[i]);
            }
         }
      }
   }

   function add_property(propertyType, propertyAnchors, propertyPages) {

      if (propertyType) {
         var index = get_property_index(propertyType);
         if (index == -1) {
            // add property
            var new_property = new propertyInfo(propertyType, true, propertyAnchors, propertyPages);
            property_selector_items.push(new_property);
         } else {
            // property exists : add anchors & pages only
            for (var i=0;i<propertyAnchors.length;i++) {
               property_selector_items[index].propertyAnchors.push(propertyAnchors[i]);
            }
            for (var i=0;i<propertyPages.length;i++) {
               property_selector_items[index].propertyPages.push(propertyPages[i]);
            }
         }
      }
   }

   function update_selector() {

      var selector_panel_bar = new OAT.Panelbar($('pb_selector'), 10);
      var selector_panel_bar_div = document.getElementById('pb_selector');

      var classType;
      var propertyType;

      // selector_panel_bar_div : remove all children
      if (selector_panel_bar_div.hasChildNodes()) {
         while (selector_panel_bar_div.childNodes.length >= 1) {
            selector_panel_bar_div.removeChild(selector_panel_bar_div.firstChild);
         }
      }
      selector_panel_bar_div.innerHTML = '';

      // get classes from navigator items
      var current_type = '';
      for (var i=0;i<navigator_items.length;i++) {
         if (navigator_items[i].tabType != current_type) {
            if (current_type != '') {
               add_class(classType, classAnchors, classPages);
            }
            classType    = navigator_items[i].tabType;
            current_type = navigator_items[i].tabType;
            classAnchors = new Array();
            classAnchors.push(navigator_items[i].tabAnchor);
            classPages = new Array();
            classPages.push(navigator_items[i].tabPage);
         } else {
            classAnchors.push(navigator_items[i].tabAnchor);
            classPages.push(navigator_items[i].tabPage);
         }
      }
      if (navigator_items.length > 0) {
         add_class(classType, classAnchors, classPages);
      }

      // sort classes by type
      if (class_selector_items.length > 0) {
         class_selector_items.sort(sortClasses);
      }

      // prepare classes panel
      var h2 = document.createElement('h2');
      h2.setAttribute('id', 'pb_header_classes');
      h2.innerHTML = msg_selector_section_classes;
      selector_panel_bar_div.appendChild(h2);
      var content_div = document.createElement('div');
      content_div.setAttribute('id', 'pb_content_classes');

      // add all classes items
      var ul = document.createElement('ul');
      var link = '<a href="#" onclick="set_classes_status(true);" id="class_selector_item_show_all">' + msg_selector_show_all_classes + '</a>';
      link = link +  ' / <a href="#" onclick="set_classes_status(false);" id="class_selector_item_hide_all">' + msg_selector_hide_all_classes + '</a>';
      var li = document.createElement('li');
      li.innerHTML = link;
      ul.appendChild(li);

      // add class items
      for (var i=0;i<class_selector_items.length;i++) {

         var link = '<a onclick="toggle_class(\'' + i + '\');" id="class_selector_item_' + class_selector_items[i].classType + '">';

         var html = link + '<img class="selector_item_img" border="0" src="' + skinpath + 'selector_on.png" id="class_selector_item_' + class_selector_items[i].classType + '_img"></a>';
         html = html + link + class_selector_items[i].classType + '</a>';

         var li = document.createElement('li');
         li.innerHTML = html;
         ul.appendChild(li);
      }
      content_div.appendChild(ul);
      selector_panel_bar_div.appendChild(content_div);
      selector_panel_bar.addPanel('pb_header_classes', 'pb_content_classes');

      // get properties from property items
      current_type = '';
      for (var i=0;i<property_items.length;i++) {
         if (property_items[i].propertyType != current_type) {
            if (current_type != '') {
               add_property(propertyType, propertyAnchors, propertyPages);
            }
            propertyType = property_items[i].propertyType;
            current_type = property_items[i].propertyType;
            propertyAnchors = new Array();
            propertyAnchors.push(property_items[i].propertyAnchors);
            propertyPages = new Array();
            propertyPages.push(property_items[i].propertyPages);
         } else {
            propertyAnchors.push(property_items[i].propertyAnchors);
            propertyPages.push(property_items[i].propertyPages);
         }
      }
      if (property_items.length > 0) {
         add_property(propertyType, propertyAnchors, propertyPages);
      }

      // sort properties by type
      if (property_selector_items.length > 0) {
         property_selector_items.sort(sortProperties);
      }

      // prepare properties panel
      var h2 = document.createElement('h2');
      h2.setAttribute('id', 'pb_header_properties');
      h2.innerHTML = msg_selector_section_properties;
      selector_panel_bar_div.appendChild(h2);
      var content_div = document.createElement('div');
      content_div.setAttribute('id', 'pb_content_properties');

      // add all properties items
      var ul = document.createElement('ul');
      var link = '<a href="#" onclick="set_properties_status(true);" id="property_selector_item_show_all">' + msg_selector_show_all_properties + '</a>';
      link = link +  ' / <a href="#" onclick="set_properties_status(false);" id="property_selector_item_hide_all">' + msg_selector_hide_all_properties + '</a>';
      var li = document.createElement('li');
      li.innerHTML = link;
      ul.appendChild(li);

      // add property items
      for (var i=0;i<property_selector_items.length;i++) {

         var link = '<a onclick="toggle_property(\'' + i + '\');" id="property_selector_item_' + property_selector_items[i].propertyType + '">';

         var html = link + '<img class="selector_item_img" border="0" src="' + skinpath + 'selector_on.png" id="property_selector_item_' + property_selector_items[i].propertyType + '_img"></a>';
         html = html + link + property_selector_items[i].propertyType + '</a>';

         var li = document.createElement('li');
         li.innerHTML = html;
         ul.appendChild(li);
      }
      content_div.appendChild(ul);
      selector_panel_bar_div.appendChild(content_div);
      selector_panel_bar.addPanel('pb_header_properties', 'pb_content_properties');

      selector_panel_bar.go(0);

      refresh_class('all');
      refresh_property('all');
   }

   function toggle_class(i) {
      // toggle class status
      if (class_selector_items[i].classStatus == true) {
         class_selector_items[i].classStatus = false;
      } else {
         class_selector_items[i].classStatus = true;
      }

      refresh_class(i);
   }

   function set_classes_status(status) {
      for (var i=0;i<class_selector_items.length;i++) {
         class_selector_items[i].classStatus = status;
      }
      refresh_class('all');
   }

   function toggle_property(i) {
      // toggle property status
      if (property_selector_items[i].propertyStatus == true) {
         property_selector_items[i].propertyStatus = false;
      } else {
         property_selector_items[i].propertyStatus = true;
      }

      refresh_property(i);
   }

   function set_properties_status(status) {
      for (var i=0;i<property_selector_items.length;i++) {
         property_selector_items[i].propertyStatus = status;
      }
      refresh_property('all');
   }

   function hide_classes() {
      for (var i=0;i<class_selector_items.length;i++) {
         for (var j=0;j<class_selector_items[i].classAnchors.length;j++) {
            if (class_selector_items[i].classStatus == false) {
               OAT.Dom.hide($('class_' + class_selector_items[i].classAnchors[j]));
               OAT.Dom.show($('min_class_' + class_selector_items[i].classAnchors[j]));
               OAT.Dom.show($('max_img_' + class_selector_items[i].classAnchors[j]));
            }
         }
      }
   }

   function show_class(classTag, classPage) {
      if ((!classPage) || (classPage == current_page)) {
         OAT.Dom.show($('class_' + classTag));
         OAT.Dom.hide($('min_class_' + classTag));
         OAT.Dom.hide($('max_img_' + classTag));

         // fade in
         var a = new OAT.AnimationOpacity('class_body_' + classTag, {opacity:1, delay:50, speed: 0.2});
         a.start();
      }
   }

   function hide_class(classTag, classPage) {
      if ((!classPage) || (classPage == current_page)) {
         // fade out
         var a = new OAT.AnimationOpacity('class_body_' + classTag, {opacity:0, delay:50, speed: 0.2});
         OAT.MSG.attach(a.animation, OAT.MSG.ANIMATION_STOP, function() {OAT.Dom.hide($('class_' + classTag));OAT.Dom.show($('min_class_' + classTag));OAT.Dom.show($('max_img_' + classTag));} );
         a.start();
      }
   }

   function refresh_class(index) {

      if (index == 'all') {
         var from = 0;
         var to   = class_selector_items.length - 1;
      } else {
         var from = index;
         var to   = index;
      }

      // refresh
      for (var i=from;i<=to;i++) {
         var bullet = document.getElementById('class_selector_item_' + class_selector_items[i].classType + '_img');
         for (var j=0;j<class_selector_items[i].classAnchors.length;j++) {
            var classTag  = class_selector_items[i].classAnchors[j];
            var classPage = class_selector_items[i].classPages[j];
            if (class_selector_items[i].classStatus == false) {
               bullet.src = skinpath + 'selector_off.png';
               hide_class(classTag, classPage);
            } else {
               bullet.src = skinpath + 'selector_on.png';
               show_class(classTag, classPage);
            }
         }
      }
   }

   function hide_properties() {
      for (var i=0;i<property_selector_items.length;i++) {
         for (var j=0;j<property_selector_items[i].propertyAnchors.length;j++) {
            if ((property_selector_items[i].propertyStatus == false) && (property_selector_items[i].propertyPages[j] == current_page)) {
               var anchor = document.getElementById(property_selector_items[i].propertyAnchors[j]);
               OAT.Dom.hide(anchor);
            }
         }
      }
   }

   function refresh_property(index) {

      if (index == 'all') {
         var from = 0;
         var to   = property_selector_items.length - 1;
      } else {
         var from = index;
         var to   = index;
      }

      // refresh
      var a = new Array();
      for (var i=from;i<=to;i++) {
         var bullet = document.getElementById('property_selector_item_' + property_selector_items[i].propertyType + '_img');
         for (var j=0;j<property_selector_items[i].propertyAnchors.length;j++) {
            a[i] = new Array();
            if (property_selector_items[i].propertyStatus == false) {
               bullet.src = skinpath + 'selector_off.png';
               if (property_selector_items[i].propertyPages[j] == current_page) {
                  // fade out
                  a[i][j] = new OAT.AnimationOpacity(property_selector_items[i].propertyAnchors[j], {opacity:0, delay:50, speed: 0.2});
                  OAT.MSG.attach(a[i][j].animation, OAT.MSG.ANIMATION_STOP, hide_properties);
                  a[i][j].start();
               }
            } else {
               bullet.src = skinpath + 'selector_on.png';
               if (property_selector_items[i].propertyPages[j] == current_page) {
                  OAT.Dom.show($(property_selector_items[i].propertyAnchors[j]));
                  // fade in
                  a[i][j] = new OAT.AnimationOpacity(property_selector_items[i].propertyAnchors[j], {opacity:1, delay:50, speed: 0.2});
                  a[i][j].start();
               }
            }
         }
      }
   }

   function resize_images() {
      var height_resize = 200;

      // Special case handling for the small-dataviewer window. We have to resize images smaller than 200.
      if(skin_num == 1)
      {
        height_resize = 100;
      }

      var all_images = document.images;
      for (var i=0;i<all_images.length;i++) {
         var parent = all_images[i].parentNode;
         if ((parent.className == 'property_value_image') || (parent.className == 'property_hybrid_img')) {
            if ((all_images[i].height != height_resize) && ((all_images[i].width/all_images[i].height) <= 1.5)) {
            // if (all_images[i].height != 200) {
               // all_images[i].width  = all_images[i].width * 200 / all_images[i].height;
               all_images[i].height = height_resize;
               /*
               // image : force redraw
               original_display = all_images[i].style.display;
               all_images[i].style.display = 'none';
               all_images[i].style.display = original_display;
               // parent : force redraw
               original_display = parent.style.display;
               parent.style.display = 'none';
               parent.style.display = original_display;
               */
            }
         }
      }
   }

   function make_grid(gridID, columnHeaders, rowValues, sortBy) {

      // create grid
      var g = new OAT.Grid(gridID, 0, 0);

      // columns headers
      g.createHeader(columnHeaders);

      // populate grid
      for (var i=0;i<rowValues.length;i++) {
         // grid.createRow([\"<a href='$this->base_browser_url".displayLink($object, $this->graph)."'>$title</a>\", \"<a href='$this->base_browser_url".displayLink((strlen($creator) > 0 ? $creator : $this->creator), $this->graph)."'>". (strlen($creator_name) > 0 ? $creator_name : $this->creator_name) ."</a>\", \"$duration\", \"$track_number\"]);\n";
         g.createRow(rowValues[i]);
      }

      // sort
      g.sort(sortBy, OAT.GridData.SORT_ASC);

      // IE fix
      if (OAT.Browser.isIE) {
         g.ieFix();
      }
   }

   function toggle_browsing_tools(status, imgID, zLinksID) {
      if (status == true) {
         OAT.Dom.show(imgID);
         OAT.Dom.show(zLinksID);
      } else {
         OAT.Dom.hide(imgID);
         OAT.Dom.hide(zLinksID);
      }
   }

   function display_error_msg_embedded(msg) {
      // make sure that the output matches classRDFBrowser->displayErrorMessage()
      var result = '<div class="error_msg_embedded">';
      result = result + '<img src="' + skinpath + 'error_icon_embedded.png" class="error_msg_img_embedded">';
      result = result + '<span class="error_msg_embedded_text">' + msg + '</span>';
      result = result + '</div>';
      return result;
   }
