<commit_before>(function($) {
  $(document).ready(function() {
    /*-------------------- EXPANDABLE PANELS ----------------------*/
    var panelspeed = 500; //panel animate speed in milliseconds
    var totalpanels = 37; //total number of collapsible panels
    var defaultopenpanel = 0; //leave 0 for no panel open
    var accordian = true; //set panels to behave like an accordian, with one panel only ever open at once
    var panelheight = new Array();
    var currentpanel = defaultopenpanel;
    var iconheight = parseInt($('.icon-close-open').css('height'));
    var highlightopen = true;

    // Hash Step 1: On Page Load, read URL hash and parse it, checking boxes where available.
    var numStories = 263;
    var hashLen = Math.ceil(numStories / 5);
    // read hash string from URL
    var hash = (window.location.hash.slice(1) + "00000000000000000000000000000000000000000000000000000").substr(0, hashLen);

    // set the N-th character in a string (strings are zero-indexed)
    function setCharAt(str, index, chr) {
      if (index > str.length - 1) return str;
      return str.substr(0, index) + chr + str.substr(index + 1);
    }

    // Initialize checkbox states
    function checkboxInit() {
      var hashChar = '';
      var hashBin = '';
      var hashBit = '';
      var storyIndex = 0;
      var totalInit = 0;

      // loop through each character in the hash string
      for (i = 0; i < hashLen; i++) {
        hashChar = hash[i];
        hashBin = ('00000' + parseInt(hashChar, 36).toString(2)).substring(-5);
        // loop through each bit in the 5-bit hash letter
        for (j = 1; j <= 5; j++) {
          storyIndex = 5 * i + j;
          if (storyIndex >= numStories) {
            break;
          }
          hashBit = hashBin[hashBin.length - j];
          if (hashBit == '1') {
            document.getElementById('story' + storyIndex).checked = true;
            totalInit += 1;
          } else {
            document.getElementById('story' + storyIndex).checked = false;
          }
        }
      }

      document.getElementById('total').value = '' + Math.round(totalInit);
      document.getElementById('q').value = formatDecimal(totalInit / numStories);
    }

    // Initialise collapsible panels
    function panelinit() {
      for (var i = 1; i <= totalpanels; i++) {
        panelheight[i] = parseInt($('#cp-' + i).find('.expandable-panel-content').css('height'));
        $('#cp-' + i).find('.expandable-panel-content').css('margin-top', -panelheight[i]);
        if (defaultopenpanel == i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
          $('#cp-' + i).find('.expandable-panel-content').css('margin-top', 0);
        }
      }
    }

    $('.expandable-panel-heading').click(function() {
      var obj = $(this).next();
      var objid = parseInt($(this).parent().attr('ID').substr(3, 2));
      currentpanel = objid;
      if (accordian == true) {
        resetpanels();
      }

      if (parseInt(obj.css('margin-top')) <= (panelheight[objid] * -1)) {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
        obj.animate({
          'margin-top': 0
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').addClass('header-active');
        }
      } else {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px 0px');
        obj.animate({
          'margin-top': (panelheight[objid] * -1)
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').removeClass('header-active');
        }
      }
    });

    function resetpanels() {
      for (var i = 1; i <= totalpanels; i++) {
        if (currentpanel != i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px 0px');
          $('#cp-' + i).find('.expandable-panel-content').animate({
            'margin-top': -panelheight[i]
          }, panelspeed);
          if (highlightopen == true) {
            $('#cp-' + i + ' .expandable-panel-heading').removeClass('header-active');
          }
        }
      }
    }

    //Uncomment these lines if the expandable panels are not a fixed width and need to resize
    /* $( window ).resize(function() {
       panelinit();
     });*/

    $(window).load(function() {
      panelinit();
      checkboxInit();
    }); //END LOAD

    // call onload or in script segment below form
    function attachCheckboxHandlers() {
      // assign updateTotal function to onclick property of each checkbox
      for (var i = 1, len = numStories; i <= len; i++) {
        box = document.getElementById('story' + i);
        box.onclick = updateTotal;
      }
    }

    // called onclick of toppings checkboxes
    function updateTotal(e) {
      // 'this' is reference to checkbox clicked on
      var form = this.form;

      // get current value in total text box, using parseFloat since it is a string
      var total = parseFloat(form.elements['total'].value);

      // if check box is checked, add its value to val, otherwise subtract it
      if (this.checked) {
        total += 1.0;
      } else {
        total -= 1.0;
      }

      // format val with correct number of decimal places
      // and use it to update value of total text box
      form.elements['total'].value = '' + Math.round(total);
      form.elements['q'].value = formatDecimal(total / numStories);

      // Hash Step 2: On box (un)check, change hash value in URL.
      var storyNumber = parseInt(this.id.split("story")[1]);
      var hashPosition = Math.floor((storyNumber - 1) / 5);
      var thisBinary = ('00000' + parseInt(hash[hashPosition], 36).toString(2)).substr(-5);
      var binaryPosition = 5 - (storyNumber % 5);
      if (binaryPosition == 5) {
        binaryPosition = 0;
      }

      if (document.getElementById(this.id).checked) {
        thisBinary = setCharAt(thisBinary, binaryPosition, '1');
      } else {
        thisBinary = setCharAt(thisBinary, binaryPosition, '0');
      }
      hash = setCharAt(hash, hashPosition, parseInt(thisBinary, 2).toString(36));
      window.location.hash = hash;
    }

    // format val to n number of decimal places
    // modified version of Danny Goodman's (JS Bible)
    function formatDecimal(val, n) {
      n = n || 2;
      var str = "" + Math.round(parseFloat(val) * Math.pow(10, n));
      while (str.length <= n) {
        str = "0" + str;(function($) {
  $(document).ready(function() {
    /*-------------------- EXPANDABLE PANELS ----------------------*/
    var panelspeed = 500; //panel animate speed in milliseconds
    var totalpanels = 37; //total number of collapsible panels
    var defaultopenpanel = 0; //leave 0 for no panel open
    var accordian = true; //set panels to behave like an accordian, with one panel only ever open at once
    var panelheight = new Array();
    var currentpanel = defaultopenpanel;
    var iconheight = parseInt($('.icon-close-open').css('height'));
    var highlightopen = true;
    var panelCounts = [8, 9, 10, 9, 7, 7, 4, 5, 5, 5,
                       5, 5, 6, 6, 6, 6, 5, 7, 7, 7,
                       7, 6, 1, 4, 4, 4, 1, 10, 11, 10,
                       11, 4, 10, 12, 17, 11, 11]

    // Hash Step 1: On Page Load, read URL hash and parse it, checking boxes where available.
    var numStories = 263;
    var hashLen = Math.ceil(numStories / 5);
    // read hash string from URL
    var hash = (window.location.hash.slice(1) + "00000000000000000000000000000000000000000000000000000").substr(0, hashLen);

    // set the N-th character in a string (strings are zero-indexed)
    function setCharAt(str, index, chr) {
      if (index > str.length - 1) return str;
      return str.substr(0, index) + chr + str.substr(index + 1);
    }

    // Initialize checkbox states
    function checkboxInit() {
      var hashChar = '';
      var hashBin = '';
      var hashBit = '';
      var storyIndex = 0;
      var totalInit = 0;
      var userCountInit = 0;

      // loop through each character in the hash string
      for (i = 0; i < hashLen; i++) {
        hashChar = hash[i];
        hashBin = ('00000' + parseInt(hashChar, 36).toString(2)).substring(-5);
        // loop through each bit in the 5-bit hash letter
        for (j = 1; j <= 5; j++) {
          storyIndex = 5 * i + j;
          if (storyIndex > numStories) {
            break;
          }
          hashBit = hashBin[hashBin.length - j];
          if (hashBit == '1') {
            document.getElementById('story' + storyIndex).checked = true;
            userCountInit = document.getElementById(document.getElementById('story' + storyIndex).className + "-userCount");
            userCountInit.value = parseInt(userCountInit.value) + 1;
            totalInit += 1;
          } else {
            document.getElementById('story' + storyIndex).checked = false;
          }
        }
      }

      // init count and Q at top of page
      document.getElementById('total').value = '' + Math.round(totalInit);
      document.getElementById('q').value = formatDecimal(totalInit / numStories);

      // init counter labels
      var panUseCount = 0;
      var panTotal = 1;
      var panLabel = '';
      for (var k=1; k <= totalpanels; k++) {
        panUseCount = parseInt(document.getElementById("cp-" + k.toString() + "-panel-userCount").value);
        panTotal = parseInt(panelCounts[k - 1]);
        panLabel = document.getElementById("cp-" + k.toString() + "-panelLabel");
        if (panUseCount == 0) {
          panLabel.innerHTML = "";
        } else if (panUseCount == panTotal) {
          panLabel.innerHTML = "✔";
        } else {
          panLabel.innerHTML = "(" + panUseCount.toString() + "/" + panTotal.toString() + ")";
        }
      }
    }

    // Initialise collapsible panels
    function panelinit() {
      for (var i = 1; i <= totalpanels; i++) {
        panelheight[i] = parseInt($('#cp-' + i).find('.expandable-panel-content').css('height'));
        $('#cp-' + i).find('.expandable-panel-content').css('margin-top', -panelheight[i]);
        if (defaultopenpanel == i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
          $('#cp-' + i).find('.expandable-panel-content').css('margin-top', 0);
        }
      }

      // init user count value for each panel
      for (var k=1; k <= totalpanels; k++) {
          document.getElementById("cp-" + k.toString() + "-panel-userCount").value = 0;
      }
    }

    $('.expandable-panel-heading').click(function() {
      var obj = $(this).next();
      var objid = parseInt($(this).parent().attr('ID').substr(3, 2));
      currentpanel = objid;
      if (accordian == true) {
        resetpanels();
      }

      if (parseInt(obj.css('margin-top')) <= (panelheight[objid] * -1)) {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
        obj.animate({
          'margin-top': 0
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').addClass('header-active');
        }
      } else {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px 0px');
        obj.animate({
          'margin-top': (panelheight[objid] * -1)
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').removeClass('header-active');
        }
      }
    });

    function resetpanels() {
      for (var i = 1; i <= totalpanels; i++) {
        if (currentpanel != i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px 0px');
          $('#cp-' + i).find('.expandable-panel-content').animate({
            'margin-top': -panelheight[i]
          }, panelspeed);
          if (highlightopen == true) {
            $('#cp-' + i + ' .expandable-panel-heading').removeClass('header-active');
          }
        }
      }
    }

    //Uncomment these lines if the expandable panels are not a fixed width and need to resize
    /* $( window ).resize(function() {
       panelinit();
     });*/

    $(window).load(function() {
      panelinit();
      checkboxInit();
    }); //END LOAD

    // call onload or in script segment below form
    function attachCheckboxHandlers() {
      // assign updateTotal function to onclick property of each checkbox
      for (var i = 1, len = numStories; i <= len; i++) {
        box = document.getElementById('story' + i);
        box.onclick = updateTotal;
      }
    }

    // called onclick of toppings checkboxes
    function updateTotal(e) {
      // 'this' is reference to checkbox clicked on
      var form = this.form;

      // get current value in total text box, using parseFloat since it is a string
      var total = parseFloat(form.elements['total'].value);

      // if check box is checked, add its value to val, otherwise subtract it
      if (this.checked) {
        total += 1.0;
      } else {
        total -= 1.0;
      }

      // format val with correct number of decimal places
      // and use it to update value of total text box
      form.elements['total'].value = '' + Math.round(total);
      form.elements['q'].value = formatDecimal(total / numStories);

      // Hash Step 2: On box (un)check, change hash value in URL.
      var storyNumber = parseInt(this.id.split("story")[1]);
      var hashPosition = Math.floor((storyNumber - 1) / 5);
      var thisBinary = ('00000' + parseInt(hash[hashPosition], 36).toString(2)).substr(-5);
      var binaryPosition = 5 - (storyNumber % 5);
      if (binaryPosition == 5) {
        binaryPosition = 0;
      }

      if (document.getElementById(this.id).checked) {
        thisBinary = setCharAt(thisBinary, binaryPosition, '1');
      } else {
        thisBinary = setCharAt(thisBinary, binaryPosition, '0');
      }
      hash = setCharAt(hash, hashPosition, parseInt(thisBinary, 2).toString(36));
      window.location.hash = hash;

      // Update panel Count
      var panelName = this.className
      var panelLabel = document.getElementById(panelName + "Label");
      var panelUserCount = document.getElementById(panelName + "-userCount");
      var panelTotal = parseInt(panelCounts[panelName.split('-')[1] - 1]);
      if (document.getElementById(this.id).checked) {
        panelUserCount.value = parseInt(panelUserCount.value) + 1;
      } else {
        panelUserCount.value = parseInt(panelUserCount.value) - 1;
      }
      if (panelUserCount.value == 0) {
          panelLabel.innerHTML = "";
      } else if (panelUserCount.value == panelTotal) {
          panelLabel.innerHTML = "✔";
      } else {
          panelLabel.innerHTML = "(" + panelUserCount.value.toString() + "/" + panelTotal.toString() + ")";
      }
    }

    // format val to n number of decimal places
    // modified version of Danny Goodman's (JS Bible)
    function formatDecimal(val, n) {
      n = n || 2;
      var str = "" + Math.round(parseFloat(val) * Math.pow(10, n));
      while (str.length <= n) {
        str = "0" + str;
      }
      var pt = str.length - n;
      return str.slice(0, pt) + "." + str.slice(pt);
    }

    // in script segment below form
    attachCheckboxHandlers();
  }); //END READY
})(jQuery);

      }
      var pt = str.length - n;
      return str.slice(0, pt) + "." + str.slice(pt);
    }

    // in script segment below form
    attachCheckboxHandlers();
  }); //END READY
})(jQuery);
<commit_msg>Q fixing copy-paste error<commit_after>(function($) {
  $(document).ready(function() {
    /*-------------------- EXPANDABLE PANELS ----------------------*/
    var panelspeed = 500; //panel animate speed in milliseconds
    var totalpanels = 37; //total number of collapsible panels
    var defaultopenpanel = 0; //leave 0 for no panel open
    var accordian = true; //set panels to behave like an accordian, with one panel only ever open at once
    var panelheight = new Array();
    var currentpanel = defaultopenpanel;
    var iconheight = parseInt($('.icon-close-open').css('height'));
    var highlightopen = true;
    var panelCounts = [8, 9, 10, 9, 7, 7, 4, 5, 5, 5,
                       5, 5, 6, 6, 6, 6, 5, 7, 7, 7,
                       7, 6, 1, 4, 4, 4, 1, 10, 11, 10,
                       11, 4, 10, 12, 17, 11, 11]

    // Hash Step 1: On Page Load, read URL hash and parse it, checking boxes where available.
    var numStories = 263;
    var hashLen = Math.ceil(numStories / 5);
    // read hash string from URL
    var hash = (window.location.hash.slice(1) + "00000000000000000000000000000000000000000000000000000").substr(0, hashLen);

    // set the N-th character in a string (strings are zero-indexed)
    function setCharAt(str, index, chr) {
      if (index > str.length - 1) return str;
      return str.substr(0, index) + chr + str.substr(index + 1);
    }

    // Initialize checkbox states
    function checkboxInit() {
      var hashChar = '';
      var hashBin = '';
      var hashBit = '';
      var storyIndex = 0;
      var totalInit = 0;
      var userCountInit = 0;

      // loop through each character in the hash string
      for (i = 0; i < hashLen; i++) {
        hashChar = hash[i];
        hashBin = ('00000' + parseInt(hashChar, 36).toString(2)).substring(-5);
        // loop through each bit in the 5-bit hash letter
        for (j = 1; j <= 5; j++) {
          storyIndex = 5 * i + j;
          if (storyIndex > numStories) {
            break;
          }
          hashBit = hashBin[hashBin.length - j];
          if (hashBit == '1') {
            document.getElementById('story' + storyIndex).checked = true;
            userCountInit = document.getElementById(document.getElementById('story' + storyIndex).className + "-userCount");
            userCountInit.value = parseInt(userCountInit.value) + 1;
            totalInit += 1;
          } else {
            document.getElementById('story' + storyIndex).checked = false;
          }
        }
      }

      // init count and Q at top of page
      document.getElementById('total').value = '' + Math.round(totalInit);
      document.getElementById('q').value = formatDecimal(totalInit / numStories);

      // init counter labels
      var panUseCount = 0;
      var panTotal = 1;
      var panLabel = '';
      for (var k=1; k <= totalpanels; k++) {
        panUseCount = parseInt(document.getElementById("cp-" + k.toString() + "-panel-userCount").value);
        panTotal = parseInt(panelCounts[k - 1]);
        panLabel = document.getElementById("cp-" + k.toString() + "-panelLabel");
        if (panUseCount == 0) {
          panLabel.innerHTML = "";
        } else if (panUseCount == panTotal) {
          panLabel.innerHTML = "✔";
        } else {
          panLabel.innerHTML = "(" + panUseCount.toString() + "/" + panTotal.toString() + ")";
        }
      }
    }

    // Initialise collapsible panels
    function panelinit() {
      for (var i = 1; i <= totalpanels; i++) {
        panelheight[i] = parseInt($('#cp-' + i).find('.expandable-panel-content').css('height'));
        $('#cp-' + i).find('.expandable-panel-content').css('margin-top', -panelheight[i]);
        if (defaultopenpanel == i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
          $('#cp-' + i).find('.expandable-panel-content').css('margin-top', 0);
        }
      }

      // init user count value for each panel
      for (var k=1; k <= totalpanels; k++) {
          document.getElementById("cp-" + k.toString() + "-panel-userCount").value = 0;
      }
    }

    $('.expandable-panel-heading').click(function() {
      var obj = $(this).next();
      var objid = parseInt($(this).parent().attr('ID').substr(3, 2));
      currentpanel = objid;
      if (accordian == true) {
        resetpanels();
      }

      if (parseInt(obj.css('margin-top')) <= (panelheight[objid] * -1)) {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
        obj.animate({
          'margin-top': 0
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').addClass('header-active');
        }
      } else {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px 0px');
        obj.animate({
          'margin-top': (panelheight[objid] * -1)
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').removeClass('header-active');
        }
      }
    });

    function resetpanels() {
      for (var i = 1; i <= totalpanels; i++) {
        if (currentpanel != i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px 0px');
          $('#cp-' + i).find('.expandable-panel-content').animate({
            'margin-top': -panelheight[i]
          }, panelspeed);
          if (highlightopen == true) {
            $('#cp-' + i + ' .expandable-panel-heading').removeClass('header-active');
          }
        }
      }
    }

    //Uncomment these lines if the expandable panels are not a fixed width and need to resize
    /* $( window ).resize(function() {
       panelinit();
     });*/

    $(window).load(function() {
      panelinit();
      checkboxInit();
    }); //END LOAD

    // call onload or in script segment below form
    function attachCheckboxHandlers() {
      // assign updateTotal function to onclick property of each checkbox
      for (var i = 1, len = numStories; i <= len; i++) {
        box = document.getElementById('story' + i);
        box.onclick = updateTotal;
      }
    }

    // called onclick of toppings checkboxes
    function updateTotal(e) {
      // 'this' is reference to checkbox clicked on
      var form = this.form;

      // get current value in total text box, using parseFloat since it is a string
      var total = parseFloat(form.elements['total'].value);

      // if check box is checked, add its value to val, otherwise subtract it
      if (this.checked) {
        total += 1.0;
      } else {
        total -= 1.0;
      }

      // format val with correct number of decimal places
      // and use it to update value of total text box
      form.elements['total'].value = '' + Math.round(total);
      form.elements['q'].value = formatDecimal(total / numStories);

      // Hash Step 2: On box (un)check, change hash value in URL.
      var storyNumber = parseInt(this.id.split("story")[1]);
      var hashPosition = Math.floor((storyNumber - 1) / 5);
      var thisBinary = ('00000' + parseInt(hash[hashPosition], 36).toString(2)).substr(-5);
      var binaryPosition = 5 - (storyNumber % 5);
      if (binaryPosition == 5) {
        binaryPosition = 0;
      }

      if (document.getElementById(this.id).checked) {
        thisBinary = setCharAt(thisBinary, binaryPosition, '1');
      } else {
        thisBinary = setCharAt(thisBinary, binaryPosition, '0');
      }
      hash = setCharAt(hash, hashPosition, parseInt(thisBinary, 2).toString(36));
      window.location.hash = hash;

      // Update panel Count
      var panelName = this.className
      var panelLabel = document.getElementById(panelName + "Label");
      var panelUserCount = document.getElementById(panelName + "-userCount");
      var panelTotal = parseInt(panelCounts[panelName.split('-')[1] - 1]);
      if (document.getElementById(this.id).checked) {
        panelUserCount.value = parseInt(panelUserCount.value) + 1;
      } else {
        panelUserCount.value = parseInt(panelUserCount.value) - 1;
      }
      if (panelUserCount.value == 0) {
          panelLabel.innerHTML = "";
      } else if (panelUserCount.value == panelTotal) {
          panelLabel.innerHTML = "✔";
      } else {
          panelLabel.innerHTML = "(" + panelUserCount.value.toString() + "/" + panelTotal.toString() + ")";
      }
    }

    // format val to n number of decimal places
    // modified version of Danny Goodman's (JS Bible)
    function formatDecimal(val, n) {
      n = n || 2;
      var str = "" + Math.round(parseFloat(val) * Math.pow(10, n));
      while (str.length <= n) {
        str = "0" + str;
      }
      var pt = str.length - n;
      return str.slice(0, pt) + "." + str.slice(pt);
    }

    // in script segment below form
    attachCheckboxHandlers();
  }); //END READY
})(jQuery);
<|endoftext|>


<commit_before>(function($) {
  $(document).ready(function() {
    /*-------------------- EXPANDABLE PANELS ----------------------*/
    var panelspeed = 500; //panel animate speed in milliseconds
    var totalpanels = 37; //total number of collapsible panels
    var defaultopenpanel = 0; //leave 0 for no panel open
    var accordian = true; //set panels to behave like an accordian, with one panel only ever open at once
    var panelheight = new Array();
    var currentpanel = defaultopenpanel;
    var iconheight = parseInt($('.icon-close-open').css('height'));
    var highlightopen = true;
    var panelCounts = [8, 9, 10, 9, 7, 7, 4, 5, 5, 5,
                       5, 5, 6, 6, 6, 6, 5, 7, 7, 7,
                       7, 6, 1, 4, 4, 4, 1, 10, 11, 10,
                       11, 4, 10, 12, 17, 11, 11, 13]
    var storyLimits = [0, 8, 17, 27, 36, 43, 50, 54, 59,
                       64, 69, 74, 79, 85, 91, 97, 103,
                       108, 115, 122, 129, 136, 142,
                       143, 147, 151, 155, 156, 166,
                       177, 187, 198, 202, 212, 224,
                       241, 252, 263, 276]

    // Hash Step 1: On Page Load, read URL hash and parse it, checking boxes where available.
    var numStories = 263;
    var hashLen = Math.ceil(numStories / 5);
    // read hash string from URL
    var hash = (window.location.hash.slice(1) + "00000000000000000000000000000000000000000000000000000").substr(0, hashLen);

    // set the N-th character in a string (strings are zero-indexed)
    function setCharAt(str, index, chr) {
      if (index > str.length - 1) return str;
      return str.substr(0, index) + chr + str.substr(index + 1);
    }

    // Initialize checkbox states
    function checkboxInit() {
      var hashChar = '';
      var hashBin = '';
      var hashBit = '';
      var storyIndex = 0;
      var totalInit = 0;
      var userCountInit = 0;

      // loop through each character in the hash string
      for (i = 0; i < hashLen; i++) {
        hashChar = hash[i];
        hashBin = ('00000' + parseInt(hashChar, 36).toString(2)).substring(-5);
        // loop through each bit in the 5-bit hash letter
        for (j = 1; j <= 5; j++) {
          storyIndex = 5 * i + j;
          if (storyIndex > numStories) {
            break;
          }
          hashBit = hashBin[hashBin.length - j];
          if (hashBit == '1') {
            document.getElementById('story' + storyIndex).checked = true;
            userCountInit = document.getElementById(document.getElementById('story' + storyIndex).className + "-userCount");
            userCountInit.value = parseInt(userCountInit.value) + 1;
            totalInit += 1;
          } else {
            document.getElementById('story' + storyIndex).checked = false;
          }
        }
      }

      // init count and Q at top of page
      document.getElementById('total').value = '' + Math.round(totalInit);
      document.getElementById('q').value = formatDecimal(totalInit / numStories);

      // init counter labels
      var panUseCount = 0;
      var panTotal = 1;
      var panLabel = '';
      for (var k=1; k <= totalpanels; k++) {
        panUseCount = parseInt(document.getElementById("cp-" + k.toString() + "-panel-userCount").value);
        panTotal = parseInt(panelCounts[k - 1]);
        panLabel = document.getElementById("cp-" + k.toString() + "-panelLabel");
        if (panUseCount == 0) {
          panLabel.innerHTML = "";
        } else if (panUseCount == panTotal) {
          panLabel.innerHTML = "✔";
        } else {
          panLabel.innerHTML = "(" + panUseCount.toString() + "/" + panTotal.toString() + ")";
        }
      }
    }

    // Initialise collapsible panels
    function panelinit() {
      for (var i = 1; i <= totalpanels; i++) {
        panelheight[i] = parseInt($('#cp-' + i).find('.expandable-panel-content').css('height'));
        $('#cp-' + i).find('.expandable-panel-content').css('margin-top', -panelheight[i]);
        if (defaultopenpanel == i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
          $('#cp-' + i).find('.expandable-panel-content').css('margin-top', 0);
        }
      }

      // init user count value for each panel
      for (var k=1; k <= totalpanels; k++) {
          document.getElementById("cp-" + k.toString() + "-panel-userCount").value = 0;
      }
    }

    $('.expandable-panel-heading').click(function() {
      var obj = $(this).next();
      var objid = parseInt($(this).parent().attr('ID').substr(3, 2));
      currentpanel = objid;
      if (accordian == true) {
        resetpanels();
      }

      if (parseInt(obj.css('margin-top')) <= (panelheight[objid] * -1)) {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px -' + iconheight + 'px');
        obj.animate({
          'margin-top': 0
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').addClass('header-active');
        }
      } else {
        obj.clearQueue();
        obj.stop();
        obj.prev().find('.icon-close-open').css('background-position', '0px 0px');
        obj.animate({
          'margin-top': (panelheight[objid] * -1)
        }, panelspeed);
        if (highlightopen == true) {
          $('#cp-' + currentpanel + ' .expandable-panel-heading').removeClass('header-active');
        }
      }
    });

    function resetpanels() {
      for (var i = 1; i <= totalpanels; i++) {
        if (currentpanel != i) {
          $('#cp-' + i).find('.icon-close-open').css('background-position', '0px 0px');
          $('#cp-' + i).find('.expandable-panel-content').animate({
            'margin-top': -panelheight[i]
          }, panelspeed);
          if (highlightopen == true) {
            $('#cp-' + i + ' .expandable-panel-heading').removeClass('header-active');
          }
        }
      }
    }

    //Uncomment these lines if the expandable panels are not a fixed width and need to resize
    $( window ).resize(function() {
       panelinit();
     });

    $(window).load(function() {
      panelinit();
      checkboxInit();
    }); //END LOAD

    // call onload or in script segment below form
    function attachCheckboxHandlers() {
      // assign updateTotal function to onclick property of each checkbox
      for (var i = 1, len = numStories; i <= len; i++) {
        box = document.getElementById('story' + i);
        box.onclick = updateTotal;
      }

      // assign updateGroupTotal function to onclick for group checkbox
      for (var j = 1; j <= numStories; j++) {
        groupBox = document.getElementById('group' + j.toString());
        groupBox.onclick = updateGroupTotal;
      }
    }

    // call onclick for group checkboxes
    function updateGroupTotal(e) {
      ind = parseInt(this.id.substr(5));
      //alert(storyLimits[ind]);
      for (var k = storyLimits[ind - 1] + 1; k <= storyLimits[ind]; k++) {
        //alert(k);
        box = document.getElementById('story' + k.toString());
        // Is the box currently checked?
        if (this.checked == true) {
          if (box.checked == false) {
            box.click();
          }
        } else {
          if (box.checked == true) {
            box.click();
          }
        }
      }
    }

    // call onclick for story checkboxes
    function updateTotal(e) {
      // 'this' is reference to checkbox clicked on
      var form = this.form;

      // get current value in total text box, using parseFloat since it is a string
      var total = parseFloat(form.elements['total'].value);

      // if check box is checked, add its value to val, otherwise subtract it
      if (this.checked) {
        total += 1.0;
      } else {
        total -= 1.0;
      }

      // format val with correct number of decimal places
      // and use it to update value of total text box
      form.elements['total'].value = '' + Math.round(total);
      form.elements['q'].value = formatDecimal(total / numStories);

      // Hash Step 2: On box (un)check, change hash value in URL.
      var storyNumber = parseInt(this.id.split("story")[1]);
      var hashPosition = Math.floor((storyNumber - 1) / 5);
      var thisBinary = ('00000' + parseInt(hash[hashPosition], 36).toString(2)).substr(-5);
      var binaryPosition = 5 - (storyNumber % 5);
      if (binaryPosition == 5) {
        binaryPosition = 0;
      }

      if (document.getElementById(this.id).checked) {
        thisBinary = setCharAt(thisBinary, binaryPosition, '1');
      } else {
        thisBinary = setCharAt(thisBinary, binaryPosition, '0');
      }
      hash = setCharAt(hash, hashPosition, parseInt(thisBinary, 2).toString(36));
      window.location.hash = hash;

      // Update panel Count
      var panelName = this.className
      var panelLabel = document.getElementById(panelName + "Label");
      var panelUserCount = document.getElementById(panelName + "-userCount");
      var panelTotal = parseInt(panelCounts[panelName.split('-')[1] - 1]);
      if (document.getElementById(this.id).checked) {
        panelUserCount.value = parseInt(panelUserCount.value) + 1;
      } else {
        panelUserCount.value = parseInt(panelUserCount.value) - 1;
      }
      if (panelUserCount.value == 0) {
          panelLabel.innerHTML = "";
      } else if (panelUserCount.value == panelTotal) {
          panelLabel.innerHTML = "✔";
      } else {
          panelLabel.innerHTML = "(" + panelUserCount.value.toString() + "/" + panelTotal.toString() + ")";
      }
    }

    // format val to n number of decimal places
    // modified version of Danny Goodman's (JS Bible)
    function formatDecimal(val, n) {
      n = n || 2;
      var str = "" + Math.round(parseFloat(val) * Math.pow(10, n));
      while (str.length <= n) {
        str = "0" + str;
      }
      var pt = str.length - n;
      return str.slice(0, pt) + "." + str.slice(pt);
    }

    // in script segment below form
    attachCheckboxHandlers();
  }); //END READY
})(jQuery);
<commit_msg>#23 expandable panels fix<commit_after>(function($) {
	$(document).ready(function() {
		// Init variables
		var totalpanels = document.getElementById("number_of_panels").value;
		var panelCounts = [8, 9, 10, 9, 7, 7, 4, 5, 5, 5,
			5, 5, 6, 6, 6, 6, 5, 7, 7, 7,
			7, 6, 1, 4, 4, 4, 1, 10, 11, 10,
			11, 4, 10, 12, 17, 11, 11, 13]
		var storyLimits = [0, 8, 17, 27, 36, 43, 50, 54, 59,
			64, 69, 74, 79, 85, 91, 97, 103,
			108, 115, 122, 129, 136, 142,
			143, 147, 151, 155, 156, 166,
			177, 187, 198, 202, 212, 224,
			241, 252, 263, 276]
		// Page Load, read URL hash and parse it, checking boxes where available.
		var numStories = 263;
		var hashLen = Math.ceil(numStories / 5);

		// read hash string from URL
		var hash = (window.location.hash.slice(1) + "00000000000000000000000000000000000000000000000000000").substr(0, hashLen);

		// set the N-th character in a string (strings are zero-indexed)
		function setCharAt(str, index, chr) {
			if (index > str.length - 1) return str;
			return str.substr(0, index) + chr + str.substr(index + 1);
		}

		// Initialize checkbox states
		function checkboxInit() {
			var hashChar = '';
			var hashBin = '';
			var hashBit = '';
			var storyIndex = 0;
			var totalInit = 0;
			var userCountInit = 0;

			// loop through each character in the hash string
			for (i = 0; i < hashLen; i++) {
				hashChar = hash[i];
				hashBin = ('00000' + parseInt(hashChar, 36).toString(2)).substring(-5);
				// loop through each bit in the 5-bit hash letter
				for (j = 1; j <= 5; j++) {
					storyIndex = 5 * i + j;
					if (storyIndex > numStories) {
						break;
					}
					hashBit = hashBin[hashBin.length - j];
					if (hashBit == '1') {
						document.getElementById('story' + storyIndex).checked = true;
						userCountInit = document.getElementById(document.getElementById('story' + storyIndex).className + "-userCount");
						userCountInit.value = parseInt(userCountInit.value) + 1;
						totalInit += 1;
					} else {
						document.getElementById('story' + storyIndex).checked = false;
					}
				}
			}

			// init count and Q at top of page
			document.getElementById('total').value = '' + Math.round(totalInit);
			document.getElementById('q').value = formatDecimal(totalInit / numStories);

			// init counter labels
			var panUseCount = 0;
			var panTotal = 1;
			var panLabel = '';
			for (var k=1; k <= totalpanels; k++) {
				panUseCount = parseInt(document.getElementById("cp-" + k.toString() + "-panel-userCount").value);
				panTotal = parseInt(panelCounts[k - 1]);
				panLabel = document.getElementById("cp-" + k.toString() + "-panelLabel");
				if (panUseCount == 0) {
					panLabel.innerHTML = "";
				} else if (panUseCount == panTotal) {
					panLabel.innerHTML = "✔";
				} else {
					panLabel.innerHTML = "(" + panUseCount.toString() + "/" + panTotal.toString() + ")";
				}
			}
		}

		// on page load
		$(window).load(function() {
			checkboxInit();
		});

		// call onload or in script segment below form
		function attachCheckboxHandlers() {
			// assign updateTotal function to onclick property of each checkbox
			for (var i = 1, len = numStories; i <= len; i++) {
				box = document.getElementById('story' + i);
				box.onclick = updateTotal;
			}

			// assign updateGroupTotal function to onclick for group checkbox
			for (var j = 1; j <= numStories; j++) {
				groupBox = document.getElementById('group' + j.toString());
				groupBox.onclick = updateGroupTotal;
			}
		}

		// call onclick for group checkboxes
		function updateGroupTotal(e) {
			ind = parseInt(this.id.substr(5));
			for (var k = storyLimits[ind - 1] + 1; k <= storyLimits[ind]; k++) {
				box = document.getElementById('story' + k.toString());
				// Is the box currently checked?
				if (this.checked == true) {
					if (box.checked == false) {
						box.click();
					}
				} else {
					if (box.checked == true) {
						box.click();
					}
				}
			}
		}

		// call onclick for story checkboxes
		function updateTotal(e) {
			// 'this' is reference to checkbox clicked on
			var form = this.form;

			// get current value in total text box, using parseFloat since it is a string
			var total = parseFloat(form.elements['total'].value);

			// if check box is checked, add its value to val, otherwise subtract it
			if (this.checked) {
				total += 1.0;
			} else {
				total -= 1.0;
			}

			// format val with correct number of decimal places
			// and use it to update value of total text box
			form.elements['total'].value = '' + Math.round(total);
			form.elements['q'].value = formatDecimal(total / numStories);

			// Hash Step 2: On box (un)check, change hash value in URL.
			var storyNumber = parseInt(this.id.split("story")[1]);
			var hashPosition = Math.floor((storyNumber - 1) / 5);
			var thisBinary = ('00000' + parseInt(hash[hashPosition], 36).toString(2)).substr(-5);
			var binaryPosition = 5 - (storyNumber % 5);
			if (binaryPosition == 5) {
				binaryPosition = 0;
			}

			if (document.getElementById(this.id).checked) {
				thisBinary = setCharAt(thisBinary, binaryPosition, '1');
			} else {
				thisBinary = setCharAt(thisBinary, binaryPosition, '0');
			}
			hash = setCharAt(hash, hashPosition, parseInt(thisBinary, 2).toString(36));
			window.location.hash = hash;

			// Update panel Count
			var panelName = this.className
			var panelLabel = document.getElementById(panelName + "Label");
			var panelUserCount = document.getElementById(panelName + "-userCount");
			var panelTotal = parseInt(panelCounts[panelName.split('-')[1] - 1]);
			if (document.getElementById(this.id).checked) {
				panelUserCount.value = parseInt(panelUserCount.value) + 1;
			} else {
				panelUserCount.value = parseInt(panelUserCount.value) - 1;
			}
			if (panelUserCount.value == 0) {
				panelLabel.innerHTML = "";
			} else if (panelUserCount.value == panelTotal) {
				panelLabel.innerHTML = "✔";
			} else {
				panelLabel.innerHTML = "(" + panelUserCount.value.toString() + "/" + panelTotal.toString() + ")";
			}
		}

		// format val to n number of decimal places
		// modified version of Danny Goodman's (JS Bible)
		function formatDecimal(val, n) {
			n = n || 2;
			var str = "" + Math.round(parseFloat(val) * Math.pow(10, n));
			while (str.length <= n) {
				str = "0" + str;
			}
			var pt = str.length - n;
			return str.slice(0, pt) + "." + str.slice(pt);
		}

		// in script segment below form
		attachCheckboxHandlers();
	}); //END READY
})(jQuery);
<|endoftext|>


<commit_before>/*
#     CloudBoost - Core Engine that powers Bakend as a Service
#     (c) 2014 HackerBay, Inc.
#     CloudBoost may be freely distributed under the Apache 2 License
*/
var util = require('../helpers/util.js');

module.exports = {

    /* Gets the query connected to a socketId.
     * @socketId : Its a string.
     *
     * @callback : A query which is a string..
     */
    getData: function(socketId, eventType, callback) {
        try {
            global.redisClient.get('cb-socket-' + socketId + '-data' + eventType, function(err, reply) {
                callback(err, JSON.parse(reply));
            });

        } catch (err) {
            global.winston.log('error', {
                "error": String(err),
                "stack": new Error().stack
            });
        }
    },

    /*Attaches the socketId to the query of the user.
     */
    setData: function(socketId, data, callback) {
        try {
            global.redisClient.set('cb-socket-' + socketId + '-data' + data.eventType, JSON.stringify(data), function(err, reply) {
                if (callback)
                    callback(err, reply);
                }
            );
        } catch (err) {
            global.winston.log('error', {
                "error": String(err),
                "stack": new Error().stack
            });
        }

    },

    deleteData: function(socketId, eventType, callback) {
        try {
            global.redisClient.set('cb-socket-' + socketId + '-data' + eventType, null, function(err, reply) {
                if (callback)
                    callback(err, reply);
                }
            );
        } catch (err) {
            global.winston.log('error', {
                "error": String(err),
                "stack": new Error().stack
            });
        }
    },
    validateSocketQuery: function(cloudObject, query) {
        //validate query.
        for (var key in query) {

            if (query[key]) {
                var value = query[key];
                if (typeof value === 'object') {

                    if (key === '$or') {
                        if (query[key].length > 0) {
                            var isTrue = false;
                            for (var i = 0; i < query[key].length; i++) {
                                if (global.socketQueryHelper.validateSocketQuery(cloudObject, query[key][i])) {
                                    isTrue = true;
                                    break;
                                }
                            }

                            if (!isTrue) {
                                return false;
                            }
                        }
                    } else {

                        for (var objectKeys in value) {
                            //near query
                            if (objectKeys === '$near') {
                                var cbVal = cloudObject[key];
                                var qVal = query[key]['$near'];
                                var lat1 = cbVal.latitude,
                                    lon1 = cbVal.longitude,
                                    lat2 = qVal['$geometry'].coordinates[1],
                                    lon2 = qVal['$geometry'].coordinates[0];
                                var maxDistance = qVal['$maxDistance'],
                                    minDistance = qVal['$minDistance'];
                                var distance = util.getLatLongDistance(lat1, lon1, lat2, lon2)
                                if (!minDistance)
                                    minDistance = 0;
                                if (!maxDistance)
                                    maxDistance = 21036000; //maximum distance b/w 2 poits on earth
                                if (distance > maxDistance || distance < minDistance)
                                    return false;
                                }

                            //not equalTo query
                            if (objectKeys === '$ne') {
                                if (cloudObject[key] === query[key]['$ne']) {
                                    return false;
                                }
                            }

                            //greater than
                            if (objectKeys === '$gt') {
                                if (cloudObject[key] <= query[key]['$gt']) {
                                    return false;
                                }
                            }

                            //less than
                            if (objectKeys === '$lt') {
                                if (cloudObject[key] >= query[key]['$lt']) {
                                    return false;
                                }
                            }

                            //greater than and equalTo.
                            if (objectKeys === '$gte') {
                                if (cloudObject[key] < query[key]['$gte']) {
                                    return false;
                                }
                            }

                            //less than and equalTo.
                            if (objectKeys === '$lte') {
                                if (cloudObject[key] > query[key]['$lte']) {
                                    return false;
                                }
                            }

                            //exists
                            if (objectKeys === '$exists') {
                                if (query[key][objectKeys] && cloudObject[key]) {
                                    //do nothing.
                                } else if (query[key][objectKeys] !== false) {
                                    return false;
                                }
                            }

                            //doesNot exists.
                            if (objectKeys === '$exists') {
                                if (!query[key][objectKeys] && cloudObject[key]) {
                                    return false;
                                }
                            }

                            //startsWith.
                            if (objectKeys === '$regex') {

                                var reg = new RegExp(query[key][objectKeys]);

                                if (!query[key]['$options']) {
                                    if (!reg.test(cloudObject[key])) //test actial regex.
                                        return false;
                                    }
                                else {
                                    if (query[key]['$options'] === 'im') { //test starts with.
                                        //starts with.
                                        var value = trimStart('^', query[key][objectKeys]);
                                        if (cloudObject[key].indexOf(value) !== 0)
                                            return false;
                                        }
                                    }

                            }

                            //containedIn.
                            if (objectKeys === '$in') {

                                if (query[key][objectKeys]) {
                                    var arr = query[key][objectKeys];
                                    var value = null;
                                    if (key.indexOf('.') > -1) { //for CloudObjects
                                        var tempKey = key.substr(0, key.indexOf('.'));
                                        value = cloudObject[tempKey];
                                    } else {
                                        value = cloudObject[key];
                                    }

                                    if (Object.prototype.toString.call(value) === '[object Array]') {
                                        var exists = false;
                                        for (var i = 0; i < value.length; i++) {
                                            if (value[i]._type === 'custom') {
                                                if (arr.indexOf(value[i]._id) > -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            } else {
                                                if (arr.indexOf(value[i]) > -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            }

                                        }

                                        if (!exists) {
                                            return false;
                                        }

                                    } else {
                                        //if the element is not in the array then return false;
                                        if (arr.indexOf(value) === -1)
                                            return false;
                                        }

                                }
                            }

                            //doesNot containedIn.
                            if (objectKeys === '$nin') {
                                if (query[key][objectKeys]) {
                                    var arr = query[key][objectKeys];
                                    var value = null;
                                    if (key.indexOf('.') > -1) { //for CloudObjects
                                        var tempKey = key.substr(0, key.indexOf('.'))
                                        value = cloudObject[tempKey];
                                    } else {
                                        value = cloudObject[key];
                                    }

                                    if (Object.prototype.toString.call(value) === '[object Array]') {
                                        var exists = false;
                                        for (var i = 0; i < value.length; i++) {
                                            if (value[i]._type === 'custom') {
                                                if (arr.indexOf(value[i]._id) !== -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            } else {
                                                if (arr.indexOf(value[i]) !== -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            }

                                        }

                                        if (exists) {
                                            return false;
                                        }

                                    } else {
                                        //if the element is not in the array then return false;
                                        if (arr.indexOf(value) !== -1)
                                            return false;
                                        }

                                }
                            }

                            //containsAll.
                            if (objectKeys === '$all') {
                                if (query[key][objectKeys]) {
                                    var arr = query[key][objectKeys];
                                    var value = null;
                                    if (key.indexOf('.') > -1) { //for CloudObjects
                                        var tempKey = key.substr(0, key.indexOf('.'));
                                        value = cloudObject[tempKey];
                                    } else {
                                        value = cloudObject[key];
                                    }

                                    if (Object.prototype.toString.call(value) === '[object Array]') {
                                        for (var i = 0; i < value.length; i++) {
                                            if (value[i]._type === 'custom') {
                                                if (arr.indexOf(value[i]._id) === -1) {
                                                    return false;
                                                }
                                            } else {
                                                if (arr.indexOf(value[i]) === -1) {
                                                    return false;
                                                }
                                            }
                                        }
                                    } else {
                                        //if the element is not in the array then return false;
                                        if (arr.indexOf(value) === -1)
                                            return false;
                                        }

                                }
                            }
                        }

                    }
                } else {
                    //it might be a plain equalTo query.
                    if (key.indexOf('.') !== -1) { // for keys with "key._id" - This is for CloudObjects.
                        var temp = key.substring(0, key.indexOf('.'));
                        if (!cloudObject[temp]) {
                            return false;
                        }
                        var a = cloudObject[temp]._id;
                        var b = query[key];
                        if (cloudObject[temp]._id !== query[key]) {
                            return false;
                        }
                    } else {
                        if (cloudObject[key] !== query[key]) {
                            return false;
                        }
                    }

                }
            }

        }

        return true;
    }
};
<commit_msg>helpers/socketQuery.js<commit_after>/*
#     CloudBoost - Core Engine that powers Bakend as a Service
#     (c) 2014 HackerBay, Inc.
#     CloudBoost may be freely distributed under the Apache 2 License
*/
var util = require('../helpers/util.js');

module.exports = {

    /* Gets the query connected to a socketId.
     * @socketId : Its a string.
     *
     * @callback : A query which is a string..
     */
    getData: function(socketId, eventType, callback) {
        try {
            global.redisClient.get('cb-socket-' + socketId + '-data' + eventType, function(err, reply) {
                callback(err, JSON.parse(reply));
            });

        } catch (err) {
            global.winston.log('error', {
                "error": String(err),
                "stack": new Error().stack
            });
        }
    },

    /*Attaches the socketId to the query of the user.
     */
    setData: function(socketId, data, callback) {
        try {
            global.redisClient.set('cb-socket-' + socketId + '-data' + data.eventType, JSON.stringify(data), function(err, reply) {
                if (callback)
                    callback(err, reply);
                }
            );
        } catch (err) {
            global.winston.log('error', {
                "error": String(err),
                "stack": new Error().stack
            });
        }

    },

    deleteData: function(socketId, eventType, callback) {
        try {
            global.redisClient.set('cb-socket-' + socketId + '-data' + eventType, null, function(err, reply) {
                if (callback)
                    callback(err, reply);
                }
            );
        } catch (err) {
            global.winston.log('error', {
                "error": String(err),
                "stack": new Error().stack
            });
        }
    },
    validateSocketQuery: function(cloudObject, query) {
        //validate query.
        for (var key in query) {

            if (query[key]) {
                var value = query[key];
                if (typeof value === 'object') {

                    if (key === '$or') {
                        if (query[key].length > 0) {
                            var isTrue = false;
                            for (var i = 0; i < query[key].length; i++) {
                                if (global.socketQueryHelper.validateSocketQuery(cloudObject, query[key][i])) {
                                    isTrue = true;
                                    break;
                                }
                            }

                            if (!isTrue) {
                                return false;
                            }
                        }
                    } else {

                        for (var objectKeys in value) {
                            //near query
                            if (objectKeys === '$near') {
                                var cbVal = cloudObject[key];
                                var qVal = query[key]['$near'];
                                var lat1 = cbVal.latitude,
                                    lon1 = cbVal.longitude,
                                    lat2 = qVal['$geometry'].coordinates[1],
                                    lon2 = qVal['$geometry'].coordinates[0];
                                var maxDistance = qVal['$maxDistance'];
                                    minDistance = qVal['$minDistance'];
                                var distance = util.getLatLongDistance(lat1, lon1, lat2, lon2)
                                if (!minDistance)
                                    minDistance = 0;
                                if (!maxDistance)
                                    maxDistance = 21036000; //maximum distance b/w 2 poits on earth
                                if (distance > maxDistance || distance < minDistance)
                                    return false;
                                }

                            //not equalTo query
                            if (objectKeys === '$ne') {
                                if (cloudObject[key] === query[key]['$ne']) {
                                    return false;
                                }
                            }

                            //greater than
                            if (objectKeys === '$gt') {
                                if (cloudObject[key] <= query[key]['$gt']) {
                                    return false;
                                }
                            }

                            //less than
                            if (objectKeys === '$lt') {
                                if (cloudObject[key] >= query[key]['$lt']) {
                                    return false;
                                }
                            }

                            //greater than and equalTo.
                            if (objectKeys === '$gte') {
                                if (cloudObject[key] < query[key]['$gte']) {
                                    return false;
                                }
                            }

                            //less than and equalTo.
                            if (objectKeys === '$lte') {
                                if (cloudObject[key] > query[key]['$lte']) {
                                    return false;
                                }
                            }

                            //exists
                            if (objectKeys === '$exists') {
                                if (query[key][objectKeys] && cloudObject[key]) {
                                    //do nothing.
                                } else if (query[key][objectKeys] !== false) {
                                    return false;
                                }
                            }

                            //doesNot exists.
                            if (objectKeys === '$exists') {
                                if (!query[key][objectKeys] && cloudObject[key]) {
                                    return false;
                                }
                            }

                            //startsWith.
                            if (objectKeys === '$regex') {

                                var reg = new RegExp(query[key][objectKeys]);

                                if (!query[key]['$options']) {
                                    if (!reg.test(cloudObject[key])) //test actial regex.
                                        return false;
                                    }
                                else {
                                    if (query[key]['$options'] === 'im') { //test starts with.
                                        //starts with.
                                        var value = trimStart('^', query[key][objectKeys]);
                                        if (cloudObject[key].indexOf(value) !== 0)
                                            return false;
                                        }
                                    }

                            }

                            //containedIn.
                            if (objectKeys === '$in') {

                                if (query[key][objectKeys]) {
                                    var arr = query[key][objectKeys];
                                    var value = null;
                                    if (key.indexOf('.') > -1) { //for CloudObjects
                                        var tempKey = key.substr(0, key.indexOf('.'));
                                        value = cloudObject[tempKey];
                                    } else {
                                        value = cloudObject[key];
                                    }

                                    if (Object.prototype.toString.call(value) === '[object Array]') {
                                        var exists = false;
                                        for (var i = 0; i < value.length; i++) {
                                            if (value[i]._type === 'custom') {
                                                if (arr.indexOf(value[i]._id) > -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            } else {
                                                if (arr.indexOf(value[i]) > -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            }

                                        }

                                        if (!exists) {
                                            return false;
                                        }

                                    } else {
                                        //if the element is not in the array then return false;
                                        if (arr.indexOf(value) === -1)
                                            return false;
                                        }

                                }
                            }

                            //doesNot containedIn.
                            if (objectKeys === '$nin') {
                                if (query[key][objectKeys]) {
                                    var arr = query[key][objectKeys];
                                    var value = null;
                                    if (key.indexOf('.') > -1) { //for CloudObjects
                                        var tempKey = key.substr(0, key.indexOf('.'));
                                        value = cloudObject[tempKey];
                                    } else {
                                        value = cloudObject[key];
                                    }

                                    if (Object.prototype.toString.call(value) === '[object Array]') {
                                        var exists = false;
                                        for (var i = 0; i < value.length; i++) {
                                            if (value[i]._type === 'custom') {
                                                if (arr.indexOf(value[i]._id) !== -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            } else {
                                                if (arr.indexOf(value[i]) !== -1) {
                                                    exists = true;
                                                    break;
                                                }
                                            }

                                        }

                                        if (exists) {
                                            return false;
                                        }

                                    } else {
                                        //if the element is not in the array then return false;
                                        if (arr.indexOf(value) !== -1)
                                            return false;
                                        }

                                }
                            }

                            //containsAll.
                            if (objectKeys === '$all') {
                                if (query[key][objectKeys]) {
                                    var arr = query[key][objectKeys];
                                    var value = null;
                                    if (key.indexOf('.') > -1) { //for CloudObjects
                                        var tempKey = key.substr(0, key.indexOf('.'));
                                        value = cloudObject[tempKey];
                                    } else {
                                        value = cloudObject[key];
                                    }

                                    if (Object.prototype.toString.call(value) === '[object Array]') {
                                        for (var i = 0; i < value.length; i++) {
                                            if (value[i]._type === 'custom') {
                                                if (arr.indexOf(value[i]._id) === -1) {
                                                    return false;
                                                }
                                            } else {
                                                if (arr.indexOf(value[i]) === -1) {
                                                    return false;
                                                }
                                            }
                                        }
                                    } else {
                                        //if the element is not in the array then return false;
                                        if (arr.indexOf(value) === -1)
                                            return false;
                                        }

                                }
                            }
                        }

                    }
                } else {
                    //it might be a plain equalTo query.
                    if (key.indexOf('.') !== -1) { // for keys with "key._id" - This is for CloudObjects.
                        var temp = key.substring(0, key.indexOf('.'));
                        if (!cloudObject[temp]) {
                            return false;
                        }
                        var a = cloudObject[temp]._id;
                        var b = query[key];
                        if (cloudObject[temp]._id !== query[key]) {
                            return false;
                        }
                    } else {
                        if (cloudObject[key] !== query[key]) {
                            return false;
                        }
                    }

                }
            }

        }

        return true;
    }
};
<|endoftext|>


<commit_before>//import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
//import Search from '../utils/Search';
//import IdentityManager from 'service-framework/dist/IdentityManager';
//import { Discovery } from 'service-framework/dist/Discovery';
//import { ContextObserver } from 'service-framework/dist/ContextManager';

/**
 * The User Activity Hyperty provides an API to the Application to discover and connect to sources of user activity data.
 * These functions are only required to be used once.
 * By default, the Hyperty automatically connects and starts reading sources that were connected the last time.
 */
class UserActivityObserver {

  constructor(hypertyURL, bus, config, factory) {
//    super(hypertyURL, bus, config, ['availability_context'], factory);
    this._context = factory.createContextObserver(hypertyURL, bus, config,['availability_context']);

    let uri = new URI(hypertyURL);

    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
//    this.syncher = factory.createSyncher(hypertyURL, bus, config);
    this.identityManager = factory.createIdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = factory.createDiscovery(hypertyURL, config.runtimeURL, bus);
    this.search = factory.createSearch(this.discovery, this.identityManager);
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    bus.addListener(hypertyURL, (msg) => {
      console.log('[UserActivityObserver] new msg', msg);
    });
  }

  /**
   * This function discovers available user activity sources.
   * <Promise> Context.Context[] discover()
   *
   *  A list of Context objects is returned as a Promise. Each Context object contains:
      context.id : source id e.g. google fit api endpoint
      context.name : name of the source eg Google FIT
      context.description : additional information about the source (optional)
   */
  discover() {

    return new Promise((resolve, reject) => {
      let contexts = [];
      const context = {
        id: '1',
        name: 'Google FIT',
        description: 'no more additional info'
      };
      contexts.push(context);
      resolve(contexts);
    });

  }

  /**
  * This function connects to a certain previously discovered user activity source and starts reading it.
  * <Promise> Context connect( string id, options ?options )
  * - id source identity returned by the discover function ie context.id
  * - options is of type Options where measurement frequency is defined (is it required?).
  */
  connect(id, options) {

    return new Promise((resolve, reject) => {
      // returns as a promise the subscribed User Activity Context Data Object.
      resolve(true);
    });

  }

  start(callback, identity) {
    let _this = this;

    // get GFit access token (token received by protostub)

    _this.bus.postMessage({
      type: 'create',
      from: _this.hypertyURL,
      to: 'fitness://sharinglisboa@google.com',
      body: {

        value: {
          resources: ['user_activity_context']
        }
      }
    }, (reply) => {
      if (reply.body.code === 200) {
        console.log('[UserActivityObserver] GFit auth granted');
        callback(true);
      } else {
        console.log('[UserActivityObserver] GFit auth not granted');
        callback(false);
      }
    });

    // call runtimeUAstub authorise

    /*
        // send user profile
        debugger;
        const stubURL = 'runtime://fitness.google.com/user-activity';
        let createMessage = {
          type: 'forward', to: stubURL, from: _this.hypertyURL,
          identity: { userProfile: { userURL: identity.userURL } },
          body: {
            type: 'create',
            from: _this.hypertyURL
          }
        };
        _this.bus.postMessage(createMessage);*/
  }

  /*
    Stop GoogleProtoStub from querying sessions.
  */
  stop() {
    let _this = this;

    _this.bus.postMessage({
      type: 'delete',
      from: _this.hypertyURL,
      to: 'fitness://sharinglisboa@google.com',
      body: {
        value: {
          resources: ['user_activity_context']
        }
      }
    }, (reply) => {
      if (reply.body.code === 200) {
      } else {
      }
    });
  }

}
export default function activate(hypertyURL, bus, config, factory) {
  return {
    name: 'UserActivityObserver',
    instance: new UserActivityObserver(hypertyURL, bus, config, factory)
  };
}
<commit_msg>change on useractivity to get status change<commit_after>//import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
//import Search from '../utils/Search';
//import IdentityManager from 'service-framework/dist/IdentityManager';
//import { Discovery } from 'service-framework/dist/Discovery';
//import { ContextObserver } from 'service-framework/dist/ContextManager';

/**
 * The User Activity Hyperty provides an API to the Application to discover and connect to sources of user activity data.
 * These functions are only required to be used once.
 * By default, the Hyperty automatically connects and starts reading sources that were connected the last time.
 */
class UserActivityObserver {

  constructor(hypertyURL, bus, config, factory) {
//    super(hypertyURL, bus, config, ['availability_context'], factory);
    this._context = factory.createContextObserver(hypertyURL, bus, config,['availability_context']);

    let uri = new URI(hypertyURL);

    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
//    this.syncher = factory.createSyncher(hypertyURL, bus, config);
    this.identityManager = factory.createIdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = factory.createDiscovery(hypertyURL, config.runtimeURL, bus);
    this.search = factory.createSearch(this.discovery, this.identityManager);
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    bus.addListener(hypertyURL, (msg) => {
      console.log('[UserActivityObserver] new msg', msg);
    });
    this.callback = null;
  }

  /**
   * This function discovers available user activity sources.
   * <Promise> Context.Context[] discover()
   *
   *  A list of Context objects is returned as a Promise. Each Context object contains:
      context.id : source id e.g. google fit api endpoint
      context.name : name of the source eg Google FIT
      context.description : additional information about the source (optional)
   */
  discover() {

    return new Promise((resolve, reject) => {
      let contexts = [];
      const context = {
        id: '1',
        name: 'Google FIT',
        description: 'no more additional info'
      };
      contexts.push(context);
      resolve(contexts);
    });

  }

  /**
  * This function connects to a certain previously discovered user activity source and starts reading it.
  * <Promise> Context connect( string id, options ?options )
  * - id source identity returned by the discover function ie context.id
  * - options is of type Options where measurement frequency is defined (is it required?).
  */
  connect(id, options) {

    return new Promise((resolve, reject) => {
      // returns as a promise the subscribed User Activity Context Data Object.
      resolve(true);
    });

  }

  start(callback, identity) {
    let _this = this;
    _this.callback = callback;
    // get GFit access token (token received by protostub)
    _this.bus.postMessage({
      type: 'create',
      from: _this.hypertyURL,
      to: 'fitness://sharinglisboa@google.com',
      body: {

        value: {
          resources: ['user_activity_context']
        }
      }
    }, (reply) => {
      if (reply.body.code === 200) {
        console.log('[UserActivityObserver] GFit auth granted');
        console.log(_this);
        let googleStubUrlStatus = reply.body.runtimeURL + '/status'
        console.log('[UserActivityObserver] listener added on ', googleStubUrlStatus);
        _this.bus.addListener(googleStubUrlStatus, newMsg => {
          console.log('[UserActivityObserver] googleStatusChanged', newMsg);
          if (newMsg.hasOwnProperty('body') && newMsg.body.hasOwnProperty('desc') && newMsg.body.desc.hasOwnProperty('error') ){
            callback(newMsg.body.desc.error);
          }

        });
        callback(true);
      } else {
        console.log('[UserActivityObserver] GFit auth not granted');
        callback(false);
      }
    });

    // call runtimeUAstub authorise

    /*
        // send user profile
        debugger;
        const stubURL = 'runtime://fitness.google.com/user-activity';
        let createMessage = {
          type: 'forward', to: stubURL, from: _this.hypertyURL,
          identity: { userProfile: { userURL: identity.userURL } },
          body: {
            type: 'create',
            from: _this.hypertyURL
          }
        };
        _this.bus.postMessage(createMessage);*/
  }

  /*
    Stop GoogleProtoStub from querying sessions.
  */
  stop() {
    let _this = this;

    _this.bus.postMessage({
      type: 'delete',
      from: _this.hypertyURL,
      to: 'fitness://sharinglisboa@google.com',
      body: {
        value: {
          resources: ['user_activity_context']
        }
      }
    }, (reply) => {
      if (reply.body.code === 200) {
      } else {
      }
    });
  }

}
export default function activate(hypertyURL, bus, config, factory) {
  return {
    name: 'UserActivityObserver',
    instance: new UserActivityObserver(hypertyURL, bus, config, factory)
  };
}
<|endoftext|>


<commit_before>ZBase.registerView((function() {

  var kBasePath = "/a/logviewer/";

  var query_mgr;
  var logfiles;
  var default_end_time = (new Date()).getTime() * 1000;
  var next_page_time;
  var pagination_history = [];

  var init = function(params) {
    $.showLoader();
    query_mgr = EventSourceHandler();

    $.httpGet("/api/v1/logfiles", function(r) {
      render();

      if (r.status == 200) {
        logfiles = JSON.parse(r.response).logfile_definitions;
        updateQuery(params.path);
      } else {
        renderError("Server Error");
      }

      $.hideLoader();
    });
  };

  var destroy = function() {
    query_mgr.closeAll();
  };

  var updateQuery = function(url) {
    setQueryParams(url);
    executeQuery();
  }

  var executeQuery = function() {
    showLoadingBar(0);

    var params = getQueryParams();
    params.limit = 100;

    var url = "/api/v1/logfiles/scan?" + $.buildQueryString(params);
    var query = query_mgr.get("logfile_query", url);

    query.addEventListener("message", function(e) {
      var data = JSON.parse(e.data);
      var result = data.result;

      if (result.length > 0) {
        showLoadingBar(data.rows_scanned);
        renderResult(result);
      }

      if (data.status == "finished") {
        query_mgr.close("logfile_query");
        hideLoadingBar();

        next_page_time = result[result.length - 1].time;
      }
    });

    query.addEventListener("error", function(e) {
      query_mgr.close("logfile_query");
      hideLoadingBar();
    });
  };

  var getQueryParams = function() {
    var params = {};

    // param: logfile
    params.logfile = $(".zbase_logviewer z-dropdown.logfile_control").getValue();

    // param: time
    var time_control = $(".zbase_logviewer .time_control");
    var time = time_control.getAttribute("data-timestamp");
    if (time != default_end_time) {
      params.time = time;
    }

    // param: filter
    params.filter_type = $(".zbase_logviewer .filter_type_control").getValue();
    params.filter = $(".zbase_logviewer .filter_control").getValue();

    // param: columns
    params.columns = $(".zbase_logviewer .columns_control").getValue();

    return params;
  };

  var setQueryParams = function(url) {
    // param: logfile
    var logfile = UrlUtil.getPath(url).substr(kBasePath.length);
    setLogfileParam(logfile);
    setLogfileName(logfile);

    // param: end time
    var end_time = UrlUtil.getParamValue(url, "time");
    setTimeParam(end_time);

    // param: filter type
    var filter_type = UrlUtil.getParamValue(url, "filter_type");
    var filter = UrlUtil.getParamValue(url, "filter");
    setFilterParam(filter_type, filter);

    // param: columns
    var columns = UrlUtil.getParamValue(url, "columns");
    setColumnsParam(logfile, columns);

    // param: raw
    var raw = UrlUtil.getParamValue(url, "raw");

    //pagination
    setPagination();

    // "showing historic data" hint
    var is_historical = end_time && end_time != default_end_time;
    setHistoricalDataHint(is_historical);
  };

  var setLogfileParam = function(logfile) {
    var items = [];
    logfiles.forEach(function(logfile) {
      var item = document.createElement("z-dropdown-item");
      item.innerHTML = logfile.name;
      item.setAttribute("data-value", logfile.name);
      items.push(item);
    });

    var dropdown = $(".zbase_logviewer z-dropdown.logfile_control");
    dropdown.setDropdownItems(items);
    dropdown.setValue([logfile]);
  };

  var setTimeParam = function(end_time) {
    if (typeof end_time == "string") {
      end_time = parseInt(end_time, 10);
    }

    if (!end_time) {
      end_time = default_end_time;
    }

    var time_control = $(".zbase_logviewer .time_control");
    time_control.setAttribute("data-timestamp", end_time);
    time_control.value = DateUtil.printTimestamp(end_time);
  };

  var setFilterParam = function(filter_type, filter) {
    if (!filter_type) {
      filter_type = "sql";
    }

    $(".zbase_logviewer .filter_type_control").setValue([filter_type]);
    $(".zbase_logviewer .filter_control").setValue(filter);
  }

  var setColumnsParam = function(logfile, columns_str) {
    if (!columns_str) {
      columns_str = "__raw__";
    }

    var columns = listLogfileColumns(logfile);
    var items = [];

    {
      var item = document.createElement("z-dropdown-item");
      item.innerHTML = "<z-checkbox></z-checkbox> " + "Raw Logline";
      item.setAttribute("data-value", "__raw__");
      items.push(item);
    }

    columns.forEach(function(column) {
      var item = document.createElement("z-dropdown-item");
      item.innerHTML = "<z-checkbox></z-checkbox> " + column;
      item.setAttribute("data-value", column);
      items.push(item);
    });

    var dropdown = $(".zbase_logviewer .columns_control");
    dropdown.setDropdownItems(items);
    dropdown.setValue(columns_str.split(","));
  }

  var setLogfileName = function(logfile) {
    $(".zbase_logviewer .logfile_name_crumb").innerHTML = logfile;
  }

  var setPagination = function() {
    var prev_elem = $(".zbase_logviewer .z-pager .prev");

    if (pagination_history.length == 0) {
      prev_elem.setAttribute("data-disabled", true);
    } else {
      prev_elem.removeAttribute("data-disabled");
    }
  }

  var setHistoricalDataHint = function(is_historic) {
    var elem = $(".zbase_logviewer .go_to_recent");
    if (is_historic) {
      elem.classList.remove("hidden");
    } else {
      elem.classList.add("hidden");
    }
  }

  var getQueryURL = function(params) {
    var url = kBasePath + params.logfile;
    delete params.logfile;
    url += "?" + $.buildQueryString(params);
    return url;
  }

  var submitControls = function() {
    next_page_time = null;
    pagination_history = [];

    var url = getQueryURL(getQueryParams());
    $.navigateTo(url);
  }

  var goToMostRecentPage = function() {
    next_page_time = null;
    pagination_history = [];
    default_end_time = (new Date()).getTime() * 1000;
    setTimeParam(default_end_time);

    var params = getQueryParams();
    var url = getQueryURL(params);

    $.navigateTo(url);
  }

  var goToNextPage = function() {
    if (!next_page_time) {
      return;
    }

    var params = getQueryParams();
    params.time = next_page_time;
    var url = getQueryURL(params);

    pagination_history.push(url);
    $.navigateTo(url);
  };

  var goToPreviousPage = function() {
    var url = pagination_history.pop();

    if (url) {
      $.navigateTo(url);
    }
  };

  var findLogfileDefinition = function(logfile_name) {
    for (var i = 0; i < logfiles.length; ++i) {
      if (logfiles[i].name == logfile_name) {
        return logfiles[i];
      }
    }

    return null;
  }

  var listLogfileColumns = function(logfile_name) {
    var logfile_def = findLogfileDefinition(logfile_name);
    if (!logfile_def) {
      $.fatalError();
      return null;
    }

    var columns = [];
    for (var i = 0; i < logfile_def.source_fields.length; ++i) {
      columns.push(logfile_def.source_fields[i].name);
    }

    for (var i = 0; i < logfile_def.row_fields.length; ++i) {
      columns.push(logfile_def.row_fields[i].name);
    }

    return columns;
  }

  var render = function() {
    var page = $.getTemplate("views/logviewer", "zbase_logviewer_main_tpl");

    $(".logfile_control", page).addEventListener("change", submitControls);
    $(".filter_type_control", page).addEventListener("change", submitControls);
    $(".columns_control", page).addEventListener("change", submitControls);
    $(".time_control", page).addEventListener("change", submitControls);
    $(".z-pager .next", page).addEventListener("click", goToNextPage);
    $(".z-pager .prev", page).addEventListener("click", goToPreviousPage);
    $(".go_to_recent a", page).addEventListener("click", goToMostRecentPage);
    $(".filter_control", page).addEventListener("change", submitControls);
    $(".time_control", page).addEventListener(
      "z-datetimepicker-change", submitControls);
    $(".filter_control", page).addEventListener("keyup", function(e) {
      if (e.keyCode == 13) submitControls();
    });

    $.handleLinks(page);
    $.replaceViewport(page);
    initDatePicker();
  };

  var renderResult = function(result) {
    var logtable = LogfileTable(result);
    logtable.render($(".zbase_logviewer .table_container"));
  }

  var renderError = function(error) {
    var error_msg = $.getTemplate(
        "views/logviewer",
        "zbase_logviewer_error_msg_tpl");

    $(".error_text", error_msg).innerHTML = error;
    $.replaceContent($(".zbase_logviewer .table_container"), error_msg);
  }

  var showLoadingBar = function(num_rows) {
    $(".zbase_logviewer").classList.add("loading");
    var elem = $(".zbase_logviewer .loglines_loading_bar");
    elem.classList.remove("hidden");
    $(".loading_bar_info", elem).style.visibility =
        (num_rows > 0 ? "visible" : "hidden");
    $(".num_rows", elem).innerHTML = num_rows;
  };

  var hideLoadingBar = function() {
    $(".zbase_logviewer").classList.remove("loading");
    $(".zbase_logviewer .loglines_loading_bar").classList.add("hidden");
  };

  var initDatePicker = function() {
    var datepicker = new DateTimePicker($(".zbase_logviewer .time_control"));
  };

  return {
    name: "logviewer",
    loadView: init,
    unloadView: destroy,
    handleNavigationChange: updateQuery
  };

})());
<commit_msg>Update logviewer.js<commit_after>ZBase.registerView((function() {

  var kBasePath = "/a/logviewer/";

  var query_mgr;
  var logfiles;
  var default_end_time = (new Date()).getTime() * 1000;
  var next_page_time;
  var pagination_history = [];

  var init = function(params) {
    $.showLoader();
    query_mgr = EventSourceHandler();

    $.httpGet("/api/v1/logfiles", function(r) {
      render();

      if (r.status == 200) {
        logfiles = JSON.parse(r.response).logfile_definitions;
        updateQuery(params.path);
      } else {
        renderError("Server Error");
      }

      $.hideLoader();
    });
  };

  var destroy = function() {
    query_mgr.closeAll();
  };

  var updateQuery = function(url) {
    setQueryParams(url);
    executeQuery();
  }

  var executeQuery = function() {
    showLoadingBar(0);

    var params = getQueryParams();
    params.limit = 100;

    var url = "/api/v1/logfiles/scan?" + $.buildQueryString(params);
    var query = query_mgr.get("logfile_query", url);

    query.addEventListener("message", function(e) {
      var data = JSON.parse(e.data);
      var result = data.result;

      if (result.length > 0) {
        showLoadingBar(data.rows_scanned);
        renderResult(result);
      }

      if (data.status == "finished") {
        query_mgr.close("logfile_query");
        hideLoadingBar();

        next_page_time = result[result.length - 1].time;
      }
    });

    query.addEventListener("error", function(e) {
      query_mgr.close("logfile_query");
      hideLoadingBar();
    });
  };

  var getQueryParams = function() {
    var params = {};

    // param: logfile
    params.logfile = $(".zbase_logviewer z-dropdown.logfile_control").getValue();

    // param: time
    var time_control = $(".zbase_logviewer .time_control");
    var time = time_control.getAttribute("data-timestamp");
    if (time != default_end_time) {
      params.time = time;
    }

    // param: filter
    params.filter_type = $(".zbase_logviewer .filter_type_control").getValue();
    params.filter = $(".zbase_logviewer .filter_control").getValue();

    // param: columns
    params.columns = $(".zbase_logviewer .columns_control").getValue();

    return params;
  };

  var setQueryParams = function(url) {
    // param: logfile
    var logfile = UrlUtil.getPath(url).substr(kBasePath.length);
    setLogfileParam(logfile);
    setLogfileName(logfile);

    // param: end time
    var end_time = UrlUtil.getParamValue(url, "time");
    setTimeParam(end_time);

    // param: filter type
    var filter_type = UrlUtil.getParamValue(url, "filter_type");
    var filter = UrlUtil.getParamValue(url, "filter");
    setFilterParam(filter_type, filter);

    // param: columns
    var columns = UrlUtil.getParamValue(url, "columns");
    setColumnsParam(logfile, columns);

    // param: raw
    var raw = UrlUtil.getParamValue(url, "raw");

    //pagination
    setPagination();

    // "showing historic data" hint
    var is_historical = end_time && end_time != default_end_time;
    setHistoricalDataHint(is_historical);
  };

  var setLogfileParam = function(logfile) {
    var items = [];
    logfiles.forEach(function(logfile) {
      var item = document.createElement("z-dropdown-item");
      item.innerHTML = logfile.name;
      item.setAttribute("data-value", logfile.name);
      items.push(item);
    });

    var dropdown = $(".zbase_logviewer z-dropdown.logfile_control");
    dropdown.setDropdownItems(items);
    dropdown.setValue([logfile]);
  };

  var setTimeParam = function(end_time) {
    if (typeof end_time == "string") {
      end_time = parseInt(end_time, 10);
    }

    if (!end_time) {
      end_time = default_end_time;
    }

    var time_control = $(".zbase_logviewer .time_control");
    time_control.setAttribute("data-timestamp", end_time);
    time_control.value = DateUtil.printTimestamp(end_time);
  };

  var setFilterParam = function(filter_type, filter) {
    if (!filter_type) {
      filter_type = "sql";
    }

    $(".zbase_logviewer .filter_type_control").setValue([filter_type]);
    $(".zbase_logviewer .filter_control").setValue(filter);
  }

  var setColumnsParam = function(logfile, columns_str) {
    if (!columns_str) {
      columns_str = "__raw__";
    }

    var columns = listLogfileColumns(logfile);
    var items = [];

    {
      var item = document.createElement("z-dropdown-item");
      item.innerHTML = "<z-checkbox></z-checkbox> " + "Raw Logline";
      item.setAttribute("data-value", "__raw__");
      items.push(item);
    }

    columns.forEach(function(column) {
      var item = document.createElement("z-dropdown-item");
      item.innerHTML = "<z-checkbox></z-checkbox> " + column;
      item.setAttribute("data-value", column);
      items.push(item);
    });

    var dropdown = $(".zbase_logviewer .columns_control");
    dropdown.setDropdownItems(items);
    dropdown.setValue(columns_str.split(","));
  }

  var setLogfileName = function(logfile) {
    $(".zbase_logviewer .logfile_name_crumb").innerHTML = logfile;
  }

  var setPagination = function() {
    var prev_elem = $(".zbase_logviewer .z-pager .prev");

    if (pagination_history.length == 0) {
      prev_elem.setAttribute("data-disabled", true);
    } else {
      prev_elem.removeAttribute("data-disabled");
    }
  }

  var setHistoricalDataHint = function(is_historic) {
    var elem = $(".zbase_logviewer .go_to_recent");
    if (is_historic) {
      elem.classList.remove("hidden");
    } else {
      elem.classList.add("hidden");
    }
  }

  var getQueryURL = function(params) {
    var url = kBasePath + params.logfile;
    delete params.logfile;
    url += "?" + $.buildQueryString(params);
    return url;
  }

  var submitControls = function() {
    next_page_time = null;
    pagination_history = [];

    var url = getQueryURL(getQueryParams());
    $.navigateTo(url);
  }

  var goToMostRecentPage = function() {
    next_page_time = null;
    pagination_history = [];
    default_end_time = (new Date()).getTime() * 1000;
    setTimeParam(default_end_time);

    var params = getQueryParams();
    var url = getQueryURL(params);

    $.navigateTo(url);
  }

  var goToNextPage = function() {
    if (!next_page_time) {
      return;
    }

    var params = getQueryParams();
    params.time = next_page_time;
    var url = getQueryURL(params);

    pagination_history.push(url);
    $.navigateTo(url);
  };

  var goToPreviousPage = function() {
    var url = pagination_history.pop();

    if (url) {
      $.navigateTo(url);
    }
  };

  var findLogfileDefinition = function(logfile_name) {
    for (var i = 0; i < logfiles.length; ++i) {
      if (logfiles[i].name == logfile_name) {
        return logfiles[i];
      }
    }

    return null;
  }

  var listLogfileColumns = function(logfile_name) {
    var logfile_def = findLogfileDefinition(logfile_name);
    if (!logfile_def) {
      $.fatalError();
      return null;
    }

    var columns = [];
    for (var i = 0; i < logfile_def.source_fields.length; ++i) {
      columns.push(logfile_def.source_fields[i].name);
    }

    for (var i = 0; i < logfile_def.row_fields.length; ++i) {
      columns.push(logfile_def.row_fields[i].name);
    }

    return columns;
  }

  var render = function() {
    var page = $.getTemplate("views/logviewer", "zbase_logviewer_main_tpl");
    var datepicker = new DateTimePicker($(".time_control", page));

    $(".logfile_control", page).addEventListener("change", submitControls);
    $(".filter_type_control", page).addEventListener("change", submitControls);
    $(".columns_control", page).addEventListener("change", submitControls);
    $(".time_control", page).addEventListener("change", submitControls);
    $(".z-pager .next", page).addEventListener("click", goToNextPage);
    $(".z-pager .prev", page).addEventListener("click", goToPreviousPage);
    $(".go_to_recent a", page).addEventListener("click", goToMostRecentPage);
    $(".filter_control", page).addEventListener("change", submitControls);
    $(".time_control", page).addEventListener(
      "z-datetimepicker-change", submitControls);
    $(".filter_control", page).addEventListener("keyup", function(e) {
      if (e.keyCode == 13) submitControls();
    });

    $.handleLinks(page);
    $.replaceViewport(page);
    initDatePicker();
  };

  var renderResult = function(result) {
    var logtable = LogfileTable(result);
    logtable.render($(".zbase_logviewer .table_container"));
  }

  var renderError = function(error) {
    var error_msg = $.getTemplate(
        "views/logviewer",
        "zbase_logviewer_error_msg_tpl");

    $(".error_text", error_msg).innerHTML = error;
    $.replaceContent($(".zbase_logviewer .table_container"), error_msg);
  }

  var showLoadingBar = function(num_rows) {
    $(".zbase_logviewer").classList.add("loading");
    var elem = $(".zbase_logviewer .loglines_loading_bar");
    elem.classList.remove("hidden");
    $(".loading_bar_info", elem).style.visibility =
        (num_rows > 0 ? "visible" : "hidden");
    $(".num_rows", elem).innerHTML = num_rows;
  };

  var hideLoadingBar = function() {
    $(".zbase_logviewer").classList.remove("loading");
    $(".zbase_logviewer .loglines_loading_bar").classList.add("hidden");
  };

  return {
    name: "logviewer",
    loadView: init,
    unloadView: destroy,
    handleNavigationChange: updateQuery
  };

})());
<|endoftext|>