<commit_before>setRefLocalStorage = function(newVal) {
  localStorage.setItem('signup_referral', newVal);
}
getRefLocalStorage = function(){
  return localStorage.getItem('signup_referral');
}

checkReferrer = (function() {
  return {
    addTestParam: function (val) {
      if (location.href.indexOf("?") === -1) {
          window.location = location.href += "?" + val + "=testParam";
      }
    },
    getParam: function(val) {
      // http://stackoverflow.com/questions/5448545/how-to-retrieve-get-parameters-from-javascript
      var result = undefined
      var tmp = []
      location.search
          //.replace ( "?", "" )
          // this is better, there might be a question mark inside
          .substr(1)
          .split("&")
          .forEach(function (item) {
              tmp = item.split("=");
              if (tmp[0] === val) result = decodeURIComponent(tmp[1]);
          });
      return result;
    }
  }
}());

fluxAnnounce = (function() {
  return {
    closeModal: function () {
      $('#js-modal').fadeOut('fast');
    },
    showModal: function() {
      $('#js-modal').fadeIn('fast');
    },
    showSection: function() {
      $('#js-announcement-home').removeClass('hide');
    },
    removeCounter: function() {
      $("#countdown-wrapper").addClass('hide');
    },
    showModalContent: function() {
      $('#js-modal-content').removeClass('hide');
      $('#js-modal-loading').addClass('hide');
    },
    showAnnouncementContent: function() {
      $('#js-announcement-content').removeClass('hide');
      $('#js-announcement-loading').addClass('hide');
    },
    getAnnouncement: function() {
      var $modal = {
        wrapper: $("#js-modal"),
        heading: $("#js-modal-heading"),
        body: $("#js-modal-body"),
        link: $("#js-modal-link")
      };
      var $announcement = {
        wrapper: $("#js-announcement-home"),
        heading: $("#js-callout-heading"),
        body: $("#js-callout-body"),
        link: $("#js-callout-link")
      }
      $.ajax({
        // url: "http://flux-api-dev.herokuapp.com/api/v0/announcement",
        url: "https://api.voteflux.org/api/v0/announcement",
        type: 'GET',
        error: function() {
          console.log('error');
          setTimeout( function() {
            this.getAnnouncement();
          }, 1000);
        },
        success: function(response) {

          if (Boolean($modal.wrapper)) {
            $modal.heading.html(response.heading);
            $modal.body.html(response.body);
            $modal.link.prop("href", response.link)
          }
          if (Boolean($announcement.wrapper)) {
            $announcement.heading.html(response.heading);
            $announcement.body.html(response.body);
            $announcement.link.prop("href", response.link)
          }
          fluxAnnounce.showModalContent();
          fluxAnnounce.showAnnouncementContent();
        }
      });
    }
  }
}());

$(document).ready(function() {

  // close ANNOUNCEMENT modal
  $('#js-modal-close').on('click', function() {
    fluxAnnounce.closeModal();
  })

  //referrer
  if(window.location.hostname === 'localhost') {
    // checkReferrer.addTestParam('r')
  }
  var referrer = checkReferrer.getParam('r');
  if(referrer){
    setRefLocalStorage(referrer);
  }
  var isWAPage = location.pathname.indexOf('/flux-wa') !== -1;
  if(isWAPage && referrer === undefined){
    console.log('On WA page');
    setRefLocalStorage('wa-landing-page + maybe r:' + document.referrer);
  }
  console.log("Local storage ref: " + getRefLocalStorage());

  // if(referrer === undefined){
  //     utmSource = checkReferrer.getParam('utm_source');
  //     utmCampaign = checkReferrer.getParam('utm_campaign');
  //     if(utmSource != undefined && utmCampaign != undefined){
  //         referrer = utmSource + "-" + utmCampaign;
  //     }
  // }

  //
  // // countdown
  // if( $('#clock').length ) {
  //   var countdownTo = new Date((1465948800) * 1000);  // June 15th 10am
  //   var now = new Date();
  //
  //   var countdownOver = function (event) {
  //     fluxAnnounce.getAnnouncement();
  //     fluxAnnounce.showSection();
  //     fluxAnnounce.removeCounter();
  //   };
  //   var countdownFinished = function(event){
  //     countdownOver(event);
  //     fluxAnnounce.showModal();
  //   };
  //
  //   if (countdownTo > now) {
  //     $('#clock').countdown(countdownTo, function (event) {
  //       $(this).html(event.strftime(
  //         '

%d

Day%!D

'
  //         + '

%H

Hour%!H

'
  //         + '

%M

Minute%!M

'
  //         + '

%S

Second%!S

' + '
'));
  //     })
  //       .on('finish.countdown', countdownFinished);
  //   } else {
  //     countdownOver();
  //   }
  //
  //   var countDownHeight = $("#countdown-wrapper").outerHeight(true);
  //   $('footer').css({'margin-bottom': countDownHeight + 'px'})
  // }

  // candidates slider
  if ( $('#js-candidates').length != 0 ) {
    // init slick carousel
    $('#js-candidates').slick({
      autoplay: false,
      accessibility: true,
      pauseOnHover: true,
      speed: 700,
      arrows: true,
      focusOnSelect: false,
      cssEase: 'ease',
      dots: true,
      responsive: [
        {
          breakpoint: 2000,
          settings: {
            autoplay: true,
            autoplaySpeed: 4000,
            speed: 1000,
            slidesToShow: 3,
            slidesToScroll: 3
          }
        },
        {
          breakpoint: 1024,
          settings: {
            autoplay: true,
            autoplaySpeed: 4000,
            speed: 1000,
            slidesToShow: 2,
            slidesToScroll: 2
          }
        },
        {
          breakpoint: 768,
          settings: {
            autoplay: true,
            autoplaySpeed: 4000,
            speed: 1000,
            slidesToShow: 1,
            slidesToScroll: 2
          }
        },
        {
          breakpoint: 480,
          settings: {
            slidesToShow: 1,
            slidesToScroll: 1,
            centerMode: false
          }
        }
        // You can unslick at a given breakpoint now by adding:
        // settings: "unslick"
        // instead of a settings object
      ]
    })
  };

  var $root = $('html, body');

// animate scroll behaviour on side menu
  $("a[href^='#']").on('click', function(e) {
    e.preventDefault();
      console.log("link-clicked")
    var hash = this.hash;
    // animate
    $('body').animate({
      scrollTop: $(hash).offset().top
    }, 500, 'swing', function() {
      window.location.hash = hash;
    });
  });

  //  offset hash location when arriving from external link
  //
  // grab target from URL hash (i.e. www.mysite.com/page-a.html#target-name)
  var target = window.location.hash;

  // only try to scroll to offset if target has been set in location hash
  if ( target != '' ){
    var $target = $(target);

    $root.stop().animate({
      'scrollTop': $target.length && $target.offset().top
    }, 500,'swing', function () {
      // when done, add hash to url
      window.location.hash = target ;
    });
  };

  // Returns number of days until a given date. Used for election countdowns
  function getDaysTo(endDate) {
    var today = new Date();
    var distance = endDate - today;
    if (distance < 0)
      return 0;
    return Math.ceil(distance / 86400000); // 86400000 ms in 1 day
  }

  // get member and volenteer info ajax request
  var getMembers = function() {
    $.ajax({
      url: "https://api.voteflux.org/api/v0/getinfo",
      data: {
        format: 'json'
      },
      error: function() {
        console.log('error')
      },
      success: function(response) {
        var data = JSON.parse(response);
        var classValueMap = {
          "js-member-count": data.n_members,
          "js-wamember-count": data.n_members_state.wa,
          "js-volunteer-count": data.n_volunteers,
          // TS: No need to differentiate between mobile and non-mobile here for now
          // "js-member-count-mobile": data.n_members,
          // "js-volunteer-count-mobile": data.n_volunteers
          // WA State Election Countdown - Remove After 11 March 2017
          "js-waelection-countdown": getDaysTo(new Date('03/11/2017')), // Use US Date Format MM/DD/YYYY
        };

        var set_contents = function(e, to_set){
          if(Boolean(e)) {
            e.innerHTML = to_set;
            console.log("Setting", e, "to", to_set);
          }
        };

        _.map(classValueMap, function(val, className){
          _.map(document.getElementsByClassName(className), function(elem){
            set_contents(elem, val);
          });
        });
        //for (var key in classValueMap) {
        //  var value = classValueMap[key];
        //  var ref = document.getElementsByClassName(key);
        //  // Some pages have more than one member counter
        //  for (var i = 0, len = ref.length; i < len; i++) {
        //    var element = ref[i];
        //    set_contents(element, value);
        //  }
        //}

      },
      type: 'GET'
    });
  }
  var mins = 1
  var interval = 1000 * 60 * mins
  getMembers(); //init
  setInterval(getMembers, interval);

  // footer date
	var dteNow = new Date();
	var intYear = dteNow.getFullYear();
  var elemYear = document.getElementById("js-footer-year");
	elemYear.innerHTML = intYear

  // nav menu
  var isOpen = true;
  var transitionTime = 150;

  $("#js-menu-button").on('click', function() {
    toggleMenu();
  });
  $("#js-menu").on('click', function() {
    toggleMenu();
  });

  function toggleMenu() {
    isOpen = !isOpen;
    if (!isOpen) {
      $("#js-menu").addClass('opacity-1 will-change-opacity').removeClass('hide').removeClass('opacity-0');
      $(".js-menu-hide").addClass('opacity-0 will-change-opacity').removeClass('opacity-1').addClass('hide');
      $('#js-fading').addClass('all-transparent')
    } else {
      $('#js-fading').removeClass('all-transparent')
      $("#js-menu").addClass('opacity-0').removeClass('opacity-1');
      $(".js-menu-hide").addClass('opacity-1').removeClass('opacity-0, hide');
      setTimeout(function() {
        $("#js-menu")
          .addClass('hide')
          .removeClass('will-change-opacity');
      }, transitionTime);
    }
    // for hamburger animation
    $("#js-menu-button").toggleClass('is-active');
  };

  var fadeStart = 0;
  var fadeUntil = 150;
  var $fading = $('#js-fading');
  var $document = $(document);
  var faded = false;
  // var contactHeight = $('#contact').outerHeight()
  // var contactPos = $('#contact').offset().top
    //  console.log(contactPos, contactHeight)
  $(window).bind('scroll', function(){
      var offset = $document.scrollTop()
      var opacity = 0
      faded = false
      if ( offset >= fadeStart && offset <= fadeUntil ) {
          opacity = 0.001 + offset/fadeUntil;

      } else if ( offset >= fadeUntil ) {
          opacity = 1
          faded = true
      }

      // for logo text on dark background
      if (opacity >= 0.1) {
        $('.js-flux-text-darktheme').css({ fill: "#222" });
        $("#js-nav-links").removeClass('white');
      } else {
        $('.js-flux-text-darktheme').css({ fill: "#fff" });
        $("#js-nav-links").addClass('white');
      }
      $fading.css('opacity',opacity);
  });

});
<commit_msg>Fix scroll bug<commit_after>setRefLocalStorage = function(newVal) {
  localStorage.setItem('signup_referral', newVal);
}
getRefLocalStorage = function(){
  return localStorage.getItem('signup_referral');
}

checkReferrer = (function() {
  return {
    addTestParam: function (val) {
      if (location.href.indexOf("?") === -1) {
          window.location = location.href += "?" + val + "=testParam";
      }
    },
    getParam: function(val) {
      // http://stackoverflow.com/questions/5448545/how-to-retrieve-get-parameters-from-javascript
      var result = undefined
      var tmp = []
      location.search
          //.replace ( "?", "" )
          // this is better, there might be a question mark inside
          .substr(1)
          .split("&")
          .forEach(function (item) {
              tmp = item.split("=");
              if (tmp[0] === val) result = decodeURIComponent(tmp[1]);
          });
      return result;
    }
  }
}());

fluxAnnounce = (function() {
  return {
    closeModal: function () {
      $('#js-modal').fadeOut('fast');
    },
    showModal: function() {
      $('#js-modal').fadeIn('fast');
    },
    showSection: function() {
      $('#js-announcement-home').removeClass('hide');
    },
    removeCounter: function() {
      $("#countdown-wrapper").addClass('hide');
    },
    showModalContent: function() {
      $('#js-modal-content').removeClass('hide');
      $('#js-modal-loading').addClass('hide');
    },
    showAnnouncementContent: function() {
      $('#js-announcement-content').removeClass('hide');
      $('#js-announcement-loading').addClass('hide');
    },
    getAnnouncement: function() {
      var $modal = {
        wrapper: $("#js-modal"),
        heading: $("#js-modal-heading"),
        body: $("#js-modal-body"),
        link: $("#js-modal-link")
      };
      var $announcement = {
        wrapper: $("#js-announcement-home"),
        heading: $("#js-callout-heading"),
        body: $("#js-callout-body"),
        link: $("#js-callout-link")
      }
      $.ajax({
        // url: "http://flux-api-dev.herokuapp.com/api/v0/announcement",
        url: "https://api.voteflux.org/api/v0/announcement",
        type: 'GET',
        error: function() {
          console.log('error');
          setTimeout( function() {
            this.getAnnouncement();
          }, 1000);
        },
        success: function(response) {

          if (Boolean($modal.wrapper)) {
            $modal.heading.html(response.heading);
            $modal.body.html(response.body);
            $modal.link.prop("href", response.link)
          }
          if (Boolean($announcement.wrapper)) {
            $announcement.heading.html(response.heading);
            $announcement.body.html(response.body);
            $announcement.link.prop("href", response.link)
          }
          fluxAnnounce.showModalContent();
          fluxAnnounce.showAnnouncementContent();
        }
      });
    }
  }
}());

$(document).ready(function() {

  // close ANNOUNCEMENT modal
  $('#js-modal-close').on('click', function() {
    fluxAnnounce.closeModal();
  })

  //referrer
  if(window.location.hostname === 'localhost') {
    // checkReferrer.addTestParam('r')
  }
  var referrer = checkReferrer.getParam('r');
  if(referrer){
    setRefLocalStorage(referrer);
  }
  var isWAPage = location.pathname.indexOf('/flux-wa') !== -1;
  if(isWAPage && referrer === undefined){
    console.log('On WA page');
    setRefLocalStorage('wa-landing-page + maybe r:' + document.referrer);
  }
  console.log("Local storage ref: " + getRefLocalStorage());

  // if(referrer === undefined){
  //     utmSource = checkReferrer.getParam('utm_source');
  //     utmCampaign = checkReferrer.getParam('utm_campaign');
  //     if(utmSource != undefined && utmCampaign != undefined){
  //         referrer = utmSource + "-" + utmCampaign;
  //     }
  // }

  //
  // // countdown
  // if( $('#clock').length ) {
  //   var countdownTo = new Date((1465948800) * 1000);  // June 15th 10am
  //   var now = new Date();
  //
  //   var countdownOver = function (event) {
  //     fluxAnnounce.getAnnouncement();
  //     fluxAnnounce.showSection();
  //     fluxAnnounce.removeCounter();
  //   };
  //   var countdownFinished = function(event){
  //     countdownOver(event);
  //     fluxAnnounce.showModal();
  //   };
  //
  //   if (countdownTo > now) {
  //     $('#clock').countdown(countdownTo, function (event) {
  //       $(this).html(event.strftime(
  //         '

%d

Day%!D

'
  //         + '

%H

Hour%!H

'
  //         + '

%M

Minute%!M

'
  //         + '

%S

Second%!S

' + '
'));
  //     })
  //       .on('finish.countdown', countdownFinished);
  //   } else {
  //     countdownOver();
  //   }
  //
  //   var countDownHeight = $("#countdown-wrapper").outerHeight(true);
  //   $('footer').css({'margin-bottom': countDownHeight + 'px'})
  // }

  // candidates slider
  if ( $('#js-candidates').length != 0 ) {
    // init slick carousel
    $('#js-candidates').slick({
      autoplay: false,
      accessibility: true,
      pauseOnHover: true,
      speed: 700,
      arrows: true,
      focusOnSelect: false,
      cssEase: 'ease',
      dots: true,
      responsive: [
        {
          breakpoint: 2000,
          settings: {
            autoplay: true,
            autoplaySpeed: 4000,
            speed: 1000,
            slidesToShow: 3,
            slidesToScroll: 3
          }
        },
        {
          breakpoint: 1024,
          settings: {
            autoplay: true,
            autoplaySpeed: 4000,
            speed: 1000,
            slidesToShow: 2,
            slidesToScroll: 2
          }
        },
        {
          breakpoint: 768,
          settings: {
            autoplay: true,
            autoplaySpeed: 4000,
            speed: 1000,
            slidesToShow: 1,
            slidesToScroll: 2
          }
        },
        {
          breakpoint: 480,
          settings: {
            slidesToShow: 1,
            slidesToScroll: 1,
            centerMode: false
          }
        }
        // You can unslick at a given breakpoint now by adding:
        // settings: "unslick"
        // instead of a settings object
      ]
    })
  };

  var $root = $('html, body');

// animate scroll behaviour on side menu
  $("a[href^='#']").on('click', function(e) {
    e.preventDefault();
      console.log("link-clicked")
    var hash = this.hash;
    // animate
    $('body').animate({
      scrollTop: $(hash).offset().top
    }, 500, 'swing', function() {
      window.location.hash = hash;
    });
  });

  //  offset hash location when arriving from external link
  //
  // grab target from URL hash (i.e. www.mysite.com/page-a.html#target-name)
  var target = window.location.hash;

  // only try to scroll to offset if target has been set in location hash
  if ( target != '' ){
    var $target = $(target);

    $root.stop().animate({
      'scrollTop': $target.length && $target.offset().top
    }, 500,'swing', function () {
      // when done, add hash to url
      window.location.hash = target ;
    });
  };

  // Returns number of days until a given date. Used for election countdowns
  function getDaysTo(endDate) {
    var today = new Date();
    var distance = endDate - today;
    if (distance < 0)
      return 0;
    return Math.ceil(distance / 86400000); // 86400000 ms in 1 day
  }

  // get member and volenteer info ajax request
  var getMembers = function() {
    $.ajax({
      url: "https://api.voteflux.org/api/v0/getinfo",
      data: {
        format: 'json'
      },
      error: function() {
        console.log('error')
      },
      success: function(response) {
        var data = JSON.parse(response);
        var classValueMap = {
          "js-member-count": data.n_members,
          "js-wamember-count": data.n_members_state.wa,
          "js-volunteer-count": data.n_volunteers,
          // TS: No need to differentiate between mobile and non-mobile here for now
          // "js-member-count-mobile": data.n_members,
          // "js-volunteer-count-mobile": data.n_volunteers
          // WA State Election Countdown - Remove After 11 March 2017
          "js-waelection-countdown": getDaysTo(new Date('03/11/2017')), // Use US Date Format MM/DD/YYYY
        };

        var set_contents = function(e, to_set){
          if(Boolean(e)) {
            e.innerHTML = to_set;
            console.log("Setting", e, "to", to_set);
          }
        };

        _.map(classValueMap, function(val, className){
          _.map(document.getElementsByClassName(className), function(elem){
            set_contents(elem, val);
          });
        });
        //for (var key in classValueMap) {
        //  var value = classValueMap[key];
        //  var ref = document.getElementsByClassName(key);
        //  // Some pages have more than one member counter
        //  for (var i = 0, len = ref.length; i < len; i++) {
        //    var element = ref[i];
        //    set_contents(element, value);
        //  }
        //}

      },
      type: 'GET'
    });
  }
  var mins = 1
  var interval = 1000 * 60 * mins
  getMembers(); //init
  setInterval(getMembers, interval);

  // footer date
	var dteNow = new Date();
	var intYear = dteNow.getFullYear();
  var elemYear = document.getElementById("js-footer-year");
	elemYear.innerHTML = intYear

  // nav menu
  var isOpen = true;
  var transitionTime = 150;

  $("#js-menu-button").on('click', function() {
    toggleMenu();
  });
  $("#js-menu").on('click', function() {
    toggleMenu();
  });

  function toggleMenu() {
    isOpen = !isOpen;
    if (!isOpen) {
      $("#js-menu").addClass('opacity-1 will-change-opacity').removeClass('hide').removeClass('opacity-0');
      $(".js-menu-hide").addClass('opacity-0 will-change-opacity').removeClass('opacity-1').addClass('hide');
      $('#js-fading').addClass('all-transparent')
    } else {
      $('#js-fading').removeClass('all-transparent')
      $("#js-menu").addClass('opacity-0').removeClass('opacity-1');
      $(".js-menu-hide").addClass('opacity-1').removeClass('opacity-0, hide');
      setTimeout(function() {
        $("#js-menu")
          .addClass('hide')
          .removeClass('will-change-opacity');
      }, transitionTime);
    }
    // for hamburger animation
    $("#js-menu-button").toggleClass('is-active');
  };

  var fadeStart = 0;
  var fadeUntil = 150;
  var $fading = $('#js-fading');
  var $document = $(document);
  var faded = false;
  // var contactHeight = $('#contact').outerHeight()
  // var contactPos = $('#contact').offset().top
    //  console.log(contactPos, contactHeight)
  var onScrollUpdateMenu = function(){
    var offset = $document.scrollTop()
    var opacity = 0
    faded = false
    if ( offset >= fadeStart && offset <= fadeUntil ) {
      opacity = 0.001 + offset/fadeUntil;

    } else if ( offset >= fadeUntil ) {
      opacity = 1
      faded = true
    }

    // for logo text on dark background
    if (opacity >= 0.1) {
      $('.js-flux-text-darktheme').css({ fill: "#222" });
      $("#js-nav-links").removeClass('white');
    } else {
      $('.js-flux-text-darktheme').css({ fill: "#fff" });
      $("#js-nav-links").addClass('white');
    }
    $fading.css('opacity',opacity);
  }

  $(window).bind('scroll', onScrollUpdateMenu);

  // also do the scroll thing on load in case we're reloading halfway down the page
  onScrollUpdateMenu();

});
<|endoftext|>


<commit_before>/*global document*/
'use strict';

var fs = require('fs');
var hyperglue = require('hyperglue');
var locationTracker = require('./location-tracker');
var animate = require('./animate');
var color = require('./color');
var message = require('./message');

var html = fs.readFileSync(__dirname + '/screen-navigate.html', 'utf8');

exports.create = function (parent, shape, opts, next) {
  var doc = hyperglue(html, {});
  if (opts.compass === false) {
    doc.querySelector('.compass').style.display = 'none';
  }
  if (opts.distance === false) {
    doc.querySelector('.distance').style.display = 'none';
    doc.querySelector('.accuracy').style.display = 'none';
  }
  parent.appendChild(doc);

  var sx = shape.center.latitude;
  var sy = shape.center.longitude;
  var mx, my, deg;
  var lastPos;
  var visible = false;
  var animating = false;
  var arrow = doc.querySelector('.arrow');

  function updateArrow() {
    // http://www.movable-type.co.uk/scripts/latlong.html
    mx = lastPos.latitude;
    my = lastPos.longitude;
    var wy = sy - my;
    var x = Math.cos(mx) * Math.sin(sx)
      - Math.sin(mx) * Math.cos(sx) * Math.cos(wy);
    var y = Math.sin(wy) * Math.cos(sx);
    var d = Math.atan2(x, y) * 180 / Math.PI;
    var transform = 'rotate(' + Math.round(d - deg + 180) + 'deg)';
    arrow.style.transform = transform;
    arrow.style.webkitTransform = transform;
    if (!visible) {
      visible = true;
      animating = true;
      arrow.style.visibility = 'visible';
      animate(arrow, 'zoomIn', function () {
        animating = false;
        updateArrow();
      });
    }
  }

  var tracker = locationTracker.create();
  var makeColor = opts.colorSteps ? color(opts.colorSteps) : null;

  function updatePosition() {
    var distance = shape.distance(lastPos);
    if (opts.distance !== false) {
      hyperglue(doc, {
        '.distance': distance + ' m',
        '.accuracy': Math.round(lastPos.accuracy) + ' m'
      });
    }
    if (deg !== undefined) {
      updateArrow();
    }
    if (makeColor) {
      document.documentElement.style.backgroundColor = makeColor(distance);
    }
    if (shape.within(lastPos)) {
      tracker.destroy();
      next();
    }
  }

  var msg;

  tracker.on('position', function (pos) {
    lastPos = pos;
    if (animating) {
      return;
    }
    if (pos.accuracy > 20) {
      if (!msg) {
        visible = false;
        arrow.style.visibility = 'hidden';
        document.documentElement.style.backgroundColor = 'transparent';
        animating = true;
        msg = message.create(doc, 'Signal', function () {
          animating = false;
        });
      }
      return;
    }
    if (msg) {
      animating = true;
      msg.destroy(function () {
        animating = false;
        msg = null;
        updatePosition();
      });
    } else {
      updatePosition();
    }
  });

  if (opts.compass !== false) {
    tracker.on('heading', function (heading) {
      if (!heading) {
        return;
      }
      deg = heading;
      if (lastPos && !msg && !animating) {
        updateArrow();
      }
    });
  }
};
<commit_msg>Handle geo location errors<commit_after>/*global document*/
'use strict';

var fs = require('fs');
var hyperglue = require('hyperglue');
var locationTracker = require('./location-tracker');
var animate = require('./animate');
var color = require('./color');
var message = require('./message');

var html = fs.readFileSync(__dirname + '/screen-navigate.html', 'utf8');

var POSITION_ERRORS = {
  '1': 'Permission Denied',
  '2': 'Position Unavailable',
  '3': 'Position Timeout'
};

exports.create = function (parent, shape, opts, next) {
  var screen = hyperglue(html, {});
  if (opts.compass === false) {
    screen.querySelector('.compass').style.display = 'none';
  }
  if (opts.distance === false) {
    screen.querySelector('.distance').style.display = 'none';
    screen.querySelector('.accuracy').style.display = 'none';
  }
  parent.appendChild(screen);

  var sx = shape.center.latitude;
  var sy = shape.center.longitude;
  var mx, my, deg;
  var lastPos;
  var visible = false;
  var animating = false;
  var arrow = screen.querySelector('.arrow');

  function updateArrow() {
    // http://www.movable-type.co.uk/scripts/latlong.html
    mx = lastPos.latitude;
    my = lastPos.longitude;
    var wy = sy - my;
    var x = Math.cos(mx) * Math.sin(sx)
      - Math.sin(mx) * Math.cos(sx) * Math.cos(wy);
    var y = Math.sin(wy) * Math.cos(sx);
    var d = Math.atan2(x, y) * 180 / Math.PI;
    var transform = 'rotate(' + Math.round(d - deg + 180) + 'deg)';
    arrow.style.transform = transform;
    arrow.style.webkitTransform = transform;
    if (!visible) {
      visible = true;
      animating = true;
      arrow.style.visibility = 'visible';
      animate(arrow, 'zoomIn', function () {
        animating = false;
        updateArrow();
      });
    }
  }

  var tracker = locationTracker.create();
  var makeColor = opts.colorSteps ? color(opts.colorSteps) : null;

  function updatePosition() {
    var distance = shape.distance(lastPos);
    if (opts.distance !== false) {
      hyperglue(screen, {
        '.distance': distance + ' m',
        '.accuracy': Math.round(lastPos.accuracy) + ' m'
      });
    }
    if (deg !== undefined) {
      updateArrow();
    }
    if (makeColor) {
      document.documentElement.style.backgroundColor = makeColor(distance);
    }
    if (shape.within(lastPos)) {
      tracker.destroy();
      animate(screen, 'flash', { iterationCount: 3 }, next);
    }
  }

  var msg;

  function showMessage(text) {
    visible = false;
    arrow.style.visibility = 'hidden';
    document.documentElement.style.backgroundColor = 'transparent';
    animating = true;
    msg = message.create(screen, text, function () {
      animating = false;
    });
  }

  tracker.on('error', function (err) {
    var text = POSITION_ERRORS[err.code] || 'Position Error';
    animating = true;
    if (msg) {
      msg.destroy(function () {
        showMessage(text);
      });
    } else {
      showMessage(text);
    }
  });

  tracker.on('position', function (pos) {
    lastPos = pos;
    if (animating) {
      return;
    }
    if (pos.accuracy > 20) {
      if (!msg) {
        showMessage('Signal');
      }
      return;
    }
    if (msg) {
      animating = true;
      msg.destroy(function () {
        animating = false;
        msg = null;
        updatePosition();
      });
    } else {
      updatePosition();
    }
  });

  if (opts.compass !== false) {
    tracker.on('heading', function (heading) {
      if (!heading) {
        return;
      }
      deg = heading;
      if (lastPos && !msg && !animating) {
        updateArrow();
      }
    });
  }
};
<|endoftext|>


<commit_before>// Requires
const _ = require('lodash')
const q = require('q')
const async = require('async')
const mathjs = require('mathjs')

/**
 * Checks if the expression is an equation or a simple math
 * expression. Checks if there is an = sign and/or variables
 * to decide.
 * @type {Function}
 * @param {String} expressions Math expressions
 * @return {Promise} promise
 */
var getExpType = (expression) => {
  var dfd = q.defer()

  var paramError = {message: 'Please provide a parameter'}
  var typeError = {message: 'Parameter must be a string'}

  var funcArray = [
    (callback) => {
      if (!expression) return callback(paramError)
      if (typeof expression !== 'string') return callback(typeError)

      var isEquation = expression.indexOf('=') > -1 // Needs to be improved

      if (isEquation) {
        var equation = {}
        var expressions = expression.split('=')
        equation.leftHandSide = mathjs.parse(expressions[0]).toString()
        equation.leftHandSide = mathjs.simplify(equation.leftHandSide).toString()
        equation.rightHandSide = mathjs.parse(expressions[1]).toString()
        equation.rightHandSide = mathjs.simplify(equation.rightHandSide).toString()
        callback(null, equation, isEquation)
      } else {
        expression = mathjs.parse(expression).toString()
        callback(null, expression, isEquation)
      }
    },
    (en, isEq, callback) => {
      var err = null
      var result = {
        equation: isEq
      }
      if (isEq) {
        result.expression = en.leftHandSide + ' = ' + en.rightHandSide
      } else {
        result.expression = en
      }
      callback(err, result)
    }
  ]

  async.waterfall(
    funcArray,
    (err, result) => err ? dfd.reject(err) : dfd.resolve(result)
  )

  return dfd.promise
}

/**
 * Solves mathematical expression
 * @type {Function}
 * @param {Array} expressions Math expressions
 * @return {Promise} promise
 */
var mathJsSolve = (expressions) => {
  var dfd = q.defer()

  var paramError = {message: 'Please provide a parameter'}
  var typeError = {message: 'Parameter must be an array'}
  var expressionError = {message: 'Expression must be a string'}

  var funcArray = [
    (callback) => {
      var hasError = false
      var solvedExpressions = _.map(expressions, (expression) => {
        var simplified, result, error
        try {
          simplified = mathjs.simplify(expression).toString()
          result = {
            simplified: simplified,
            expression: expression,
            error: null,
            solution: mathjs.eval(simplified)
          }
        } catch (error) {
          hasError = true
          result = {
            expression: expression,
            error: error
          }
        }
        return result
      })

      if (hasError) {
        callback(solvedExpressions)
      } else {
        callback(null, solvedExpressions)
      }
    }
  ]

  async.waterfall(
    funcArray,
    (err, result) => err ? dfd.reject(err) : dfd.resolve(result)
  )

  return dfd.promise
}

/**
 * Wraps promise over Wolfram Module.
 * needs input object to be validated
 * before hand. This also saves the Wolfram
 * result to the database.
 * @type {Function}
 * @param {Object} input Input information
 * @return {Promise} promise
 */
var wolframCall = (input) => {
  var dfd = q.defer()

  wolfram.query(input.query, (err, result) => {
    if (err) return dfd.reject(err)

    var hist = new History({{
      user: input.user,
      query: input.query,
      equation: input.equation,
      result: result
    })

    hist.save( err => {
      if (err) return dfd.reject(err)
      dfd.resolve(err)
    })
  })

  return dfd.promise
}

/**
 * Gets wolfram result from Wolfram API
 * 1 - Checks if input is saved on database
 * 2 - if not, call wolfram
 * 3 - Save wolfram result to database
 * 4 - Resolves data-base entry
 * @type {Function}
 * @param {Array} expressions Math expressions
 * @return {Promise} promise
 */
var wolframSolve = (input) => {
  var dfd = q.defer()

  var paramError = {message: 'Please provide a parameter'}
  var typeError = {message: 'Parameter must be an array'}
  var expressionError = {message: 'Expression must be a string'}

  var funcArray = [
    ( callback ) => { // 1
      //INPUT ASSERTS HERE
      History
        .findOne({query: input.query})
        .where('active': true)
        .exec((err, doc) => {
          callback(err, doc, input)
        })
    },
    ( doc, input, callback ) => {
      if ( !doc ) { // 2
        wolframCall( input ) // 3
        .then( res => callback( null, res ) ) // 4
        .catch( err => callback( err ) )
      } else {
        callback( null, doc ) // 4
      }
    }
  ]

  async.waterfall(
    funcArray,
    (err, result) => err ? dfd.reject(err) : dfd.resolve(result)
  )

  return dfd.promise
}

module.exports = {
  getExpType: getExpType,
  mathJsSolve: mathJsSolve
}
<commit_msg>Added a few function as finished mathJsSolve<commit_after>// Requires
const config = require('./private.config.js')
const xml2js = require('xml2js').parseString
const _ = require('lodash')
const q = require('q')
const async = require('async')
const unirest = require('unirest')
const mathjs = require('mathjs')
const mongoose = require('mongoose')
mongoose.connect(config.mongo)

/**
 * Checks if the expression is an equation or a simple math
 * expression. Checks if there is an = sign and/or variables
 * to decide.
 * @type {Function}
 * @param {String} expressions Math expressions
 * @return {Promise} promise
 */
var getExpType = (expression) => {
  var dfd = q.defer()

  var paramError = {message: 'Please provide a parameter'}
  var typeError = {message: 'Parameter must be a string'}

  var funcArray = [
    (callback) => {
      if (!expression) return callback(paramError)
      if (typeof expression !== 'string') return callback(typeError)

      var isEquation = expression.indexOf('=') > -1 // Needs to be improved

      if (isEquation) {
        var equation = {}
        var expressions = expression.split('=')
        equation.leftHandSide = mathjs.parse(expressions[0]).toString()
        equation.leftHandSide = mathjs.simplify(equation.leftHandSide).toString()
        equation.rightHandSide = mathjs.parse(expressions[1]).toString()
        equation.rightHandSide = mathjs.simplify(equation.rightHandSide).toString()
        callback(null, equation, isEquation)
      } else {
        expression = mathjs.parse(expression).toString()
        callback(null, expression, isEquation)
      }
    },
    (en, isEq, callback) => {
      var err = null
      var result = {
        equation: isEq
      }
      if (isEq) {
        result.expression = en.leftHandSide + ' = ' + en.rightHandSide
      } else {
        result.expression = en
      }
      callback(err, result)
    }
  ]

  async.waterfall(
    funcArray,
    (err, result) => err ? dfd.reject(err) : dfd.resolve(result)
  )

  return dfd.promise
}

/**
 * Solves mathematical expression
 * @type {Function}
 * @param {Array} expressions Math expressions
 * @return {Promise} promise
 */
var mathJsSolve = (expressions) => {
  var dfd = q.defer()

  var paramErrorMessage = 'Please provide a parameter'
  var arrayErrorMessage = 'Expression array is empty!'
  var typeErrorMessage = 'Parameter must be an array'
  var expressionErrorMessage = 'Expression must be a string'

  var funcArray = [
    (callback) => {

      var paramError = {
        status: false,
        message: null
      }

      if ( !expressions ) {
        paramError.status = true
        paramError.message = paramErrorMessage
      }

      if ( !_.isArray(expressions) && !!expressions ) {
        paramError.status = true
        paramError.message = typeErrorMessage
      }

      if ( _.isArray(expressions) && _.isEmpty(expressions) ) {
        paramError.status = true
        paramError.message = arrayErrorMessage
      }

      var hasError = paramError.status

      if (!hasError) {
        solvedExpressions = _.map(expressions, (expression) => {
          var simplified, result, error
          try {
            if (typeof expression !== 'string') throw new Error(expressionErrorMessage)
            simplified = mathjs.simplify(expression).toString()
            result = {
              simplified: simplified,
              expression: expression,
              error: null,
              solution: mathjs.eval(simplified)
            }
          } catch (error) {
            paramError.status = true
            result = {
              expression: expression,
              error: error
            }
          }
          return result
        })
        callback(null, solvedExpressions)
      } else {
        callback(paramError)
      }
    }
  ]

  async.waterfall(
    funcArray,
    (err, result) => err ? dfd.reject(err) : dfd.resolve(result)
  )

  return dfd.promise
}

/**
 * Wraps promise over Wolfram Module.
 * It needs input object to be validated
 * before hand. This also saves the Wolfram
 * result to the database.
 * @type {Function}
 * @param {Object} input Input information
 * @return {Promise} promise
 */
var wolframCall = (input) => {
  var dfd = q.defer()

  unirest
    .get('http://api.wolframalpha.com/v2/')
    .query('input' + input)
    .query('primary=true')
    .query('appid=' + config.app_id)
    .end(res => {
      if (res.statusCode == 200) { // A OK
        xml2js(res.body, (err, result) => {
          if (err) return dfd.reject(err)
          dfd.resolve(result)
        })
      } else {
        dfd.reject(response)
      }
    })
  return dfd.promise
}

/**
 * Evaluate expression function.
 * 1 - Get Expression type
 * 2 - Send to solve
 * 3 - build and return result object
 * @type {Function} evaluate
 * @param {Object} input input data
 * @return {Promise} promise
 */
var evaluate = (input) => {
  var dfd = q.defer()

  var funcArray = [
    ( callback ) => {
      getExpType(input.query)
        .then(result => {
          var endRes = {
            user: result.user,
            query: input.query
          }
          if (result.isEq) { // WolframSolve
            wolframCall(input.query)
              .then(solution => {
                endRes.solveType = ['wolfram']
                endRes.result = solution
                callback(null, endRes)
              })
              .catch(err => callback(err))
          } else { // MathJS Solve
            mathJsSolve([input.query])
              .then(solution => {
                endRes.solveType = ['mathjs']
                endRes.result = solution
                callback(null, endRes)
              })
              .catch(err => callback(err))
          }
        })
        .catch(err => callback(err))
    }
  ]

  async.waterfall(
    funcArray,
    (err, result) => err ? dfd.reject(err) : dfd.resolve(result)
  )

  return dfd.promise
}

/**
 * Main Solve function, check if exists in the database,
 * if not, evaluates the input and saves the result at the end
 * @type {Function} solve
 * @param {Object} input input data
 * @return {Promise} promise
 */
var solve = (input) => {
  var dfd = q.defer()

  var funcArray = [
    ( callback ) => { // 1
      //VALIDATE INPUT HERE
      History
        .findOne({query: input.query})
        .where('active', true)
        .exec((err, doc) => {
          callback(err, doc, input)
        })
    },
    (doc, input, callback) => { // 2
      if (doc) return callback(null, null, doc)
      evaluate(input)
        .then(result => callback(null, result, null))
        .catch(err=> callback(err))
    },
    (result, doc, callback) => { // 3
      if (result && !doc) {
        var model = new History({
          user: result.user,
          solveType: result.solveType,
          query: result.query,
          result: result.res
        })
        model.save(err => err? callback(err) : callback(null, model))
      } else {
        callback(null, doc)
      }
    }
  ]

  async.waterfall(
    funcArray,
    (err, result) => err ? dfd.reject(err) : dfd.resolve(result)
  )

  return dfd.promise
}

module.exports = {
  db: mongoose,
  getExpType: getExpType,
  mathJsSolve: mathJsSolve
}
<|endoftext|>


<commit_before>import {expect} from 'chai';
import {Map, List, fromJS} from 'immutable';

import {INITIAL_STATE, DEFAULT_LABEL} from '../src/constants';
import {select, product} from '../src/core';
import {getLabel} from '../src/label';

describe('label', () => {

	describe('defaults', () => {

    it('should have default label by default', () => {
      expect(getLabel(INITIAL_STATE)).to.eq('Map of The United States of America');
    });

    it('should return null if given no state', () => {
      expect(getLabel(null, '000000')).to.be.null;
    });

  });

  describe('when have a region', () => {

    it('should set a state-related label', () => {
      var
        stateFIPS = '41000',
        stateName = 'Oregon',
        newState  = select(INITIAL_STATE, stateFIPS)
      ;
      expect(getLabel(newState)).to.eq(`Map of ${stateName}`);
    });

    it('should set a county-related label', () => {
      var
        countyFIPS = '41029',
        countyName = 'Jackson County, OR',
        newState   = select(INITIAL_STATE, countyFIPS)
      ;
      expect(getLabel(newState)).to.eq(`Map of ${countyName}`);
    });

  });

});
<commit_msg>dispatch -- testing label for both product and region<commit_after>import {expect} from 'chai';
import {Map, List, fromJS} from 'immutable';

import {INITIAL_STATE, DEFAULT_LABEL} from '../src/constants';
import {select, product} from '../src/core';
import {getLabel} from '../src/label';

describe('label', () => {

	describe('defaults', () => {

    it('should have default label by default', () => {
      expect(getLabel(INITIAL_STATE)).to.eq('Map of The United States of America');
    });

    it('should return null if given no state', () => {
      expect(getLabel(null, '000000')).to.be.null;
    });

  });

  describe('when have a region', () => {

    it('should set a state-related label', () => {
      var
        stateFIPS = '41000',
        stateName = 'Oregon',
        newState  = select(INITIAL_STATE, stateFIPS)
      ;
      expect(getLabel(newState)).to.eq(`Map of ${stateName}`);
    });

    it('should set a county-related label', () => {
      var
        countyFIPS = '41029',
        countyName = 'Jackson County, OR',
        newState   = select(INITIAL_STATE, countyFIPS)
      ;
      expect(getLabel(newState)).to.eq(`Map of ${countyName}`);
    });

  });

  describe('when have a product', () => {

    it('should set the product name in the label', () => {
      var
      productKey    = 'corn',
        productName = 'Corn',
        newState    = product(INITIAL_STATE, 'corn')
      ;
      expect(getLabel(newState)).to.eq(`Map of ${productName} production in ${DEFAULT_LABEL}`);
    });

  });

  describe('when have both a product and a region', () => {

    it('should include both product and region', () => {
      var
        productKey  = 'corn',
        productName = 'Corn',
        regionFIPS  = '41029',
        regionName  = 'Jackson County, OR',
        newState    = product(INITIAL_STATE, productKey),
        newState    = select(newState, regionFIPS)
      ;
      expect(getLabel(newState)).to.eq(`Map of ${productName} production in ${regionName}`);
    });

  });

});
<|endoftext|>


<commit_before>var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure();
var useSSL = process.env['USE_SSL'] != null ? true : false;

var testCase = require('../deps/nodeunit').testCase,
  debug = require('util').debug,
  inspect = require('util').inspect,
  nodeunit = require('../deps/nodeunit'),
  gleak = require('../tools/gleak'),
  Db = mongodb.Db,
  Cursor = mongodb.Cursor,
  Collection = mongodb.Collection,
  ServerManager = require('../test/tools/server_manager').ServerManager,
  Server = mongodb.Server;

var MONGODB = 'integration_tests';
var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4, ssl:useSSL}), {native_parser: (process.env['TEST_NATIVE'] != null)});

// Define the tests, we want them to run as a nested test so we only clean up the
// db connection once
var tests = testCase({
  setUp: function(callback) {
    client.open(function(err, db_p) {
      if(numberOfTestsRun == Object.keys(tests).length) {
        // If first test drop the db
        client.dropDatabase(function(err, done) {
          callback();
        });
      } else {
        return callback();
      }
    });
  },

  tearDown: function(callback) {
    numberOfTestsRun = numberOfTestsRun - 1;
    // Drop the database and close it
    if(numberOfTestsRun <= 0) {
      // client.dropDatabase(function(err, done) {
        client.close();
        callback();
      // });
    } else {
      client.close();
      callback();
    }
  },

  // Test the auto connect functionality of the db
  shouldCorrectlyUseSameConnectionsForTwoDifferentDbs : function(test) {
    var second_test_database = new Db(MONGODB + "_2", new Server("127.0.0.1", 27017, {auto_reconnect: true, ssl:useSSL}), {native_parser: (process.env['TEST_NATIVE'] != null), retryMiliSeconds:50});
    second_test_database.bson_deserializer = client.bson_deserializer;
    second_test_database.bson_serializer = client.bson_serializer;
    second_test_database.pkFactory = client.pkFactory;

    // Just create second database
    second_test_database.open(function(err, second_test_database) {
      // Close second database
      second_test_database.close();
      // Let's grab a connection to the different db resusing our connection pools
      var secondDb = client.db(MONGODB + "_2");
      secondDb.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
        // Insert a dummy document
        collection.insert({a:20}, {safe: true}, function(err, r) {
          test.equal(null, err);

          // Query it
          collection.findOne({}, function(err, item) {
            test.equal(20, item.a);

            // Use the other db
            client.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
              // Insert a dummy document
              collection.insert({b:20}, {safe: true}, function(err, r) {
                test.equal(null, err);

                // Query it
                collection.findOne({}, function(err, item) {
                  test.equal(20, item.b);

                  // Drop the second db
                  secondDb.dropDatabase(function(err, item) {
                    test.equal(null, err);
                    test.done();
                  })
                })
              });
            });
          })
        });
      });
    });
  },

  // Test the auto connect functionality of the db
  shouldCorrectlyUseSameConnectionsForTwoDifferentDbs : function(test) {
    var second_test_database = new Db(MONGODB + "_2", new Server("127.0.0.1", 27017, {auto_reconnect: true, ssl:useSSL}), {native_parser: (process.env['TEST_NATIVE'] != null), retryMiliSeconds:50});
    second_test_database.bson_deserializer = client.bson_deserializer;
    second_test_database.bson_serializer = client.bson_serializer;
    second_test_database.pkFactory = client.pkFactory;

    // Just create second database
    second_test_database.open(function(err, second_test_database) {
      // Close second database
      second_test_database.close();
      // Let's grab a connection to the different db resusing our connection pools
      var secondDb = client.db(MONGODB + "_2");
      secondDb.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
        // Insert a dummy document
        collection.insert({a:20}, {safe: true}, function(err, r) {
          test.equal(null, err);

          // Query it
          collection.findOne({}, function(err, item) {
            test.equal(20, item.a);

            // Use the other db
            client.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
              // Insert a dummy document
              collection.insert({b:20}, {safe: true}, function(err, r) {
                test.equal(null, err);

                // Query it
                collection.findOne({}, function(err, item) {
                  test.equal(20, item.b);

                  // Drop the second db
                  secondDb.dropDatabase(function(err, item) {
                    test.equal(null, err);
                    test.done();
                  })
                })
              });
            });
          })
        });
      });
    });
  },

  shouldCorrectlyEmitErrorOnAllDbsOnPoolClose : function(test) {
    var db = new Db('tests', new Server("127.0.0.1", 27027, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)});
    // All inserted docs
    var docs = [];
    var errs = [];
    var insertDocs = [];
    var numberOfCloses = 0;

    // Start server
    var serverManager = new ServerManager({auth:false, purgedirectories:true, journal:true, start_port:27027})
    serverManager.start(false, function() {
      db.on("close", function(err) {
        numberOfCloses = numberOfCloses + 1;
      })

      db.open(function(err, db) {
        db.createCollection('shouldCorrectlyErrorOnAllDbs', function(err, collection) {
          test.equal(null, err);

          collection.insert({a:1}, {safe:true}, function(err, result) {
            test.equal(null, err);

            // Open a second db
            var db2 = db.db('tests_2');
            // Add a close handler
            db2.on("close", function(err) {
              numberOfCloses = numberOfCloses + 1;
            });

            db.serverConfig.connectionPool.openConnections[0].connection.destroy();

            // Kill server and end test
            serverManager.stop(9, function() {
              test.equal(2, numberOfCloses)
              test.done();
            });
          });
        });
      });
    });
  },

  // run this last
  noGlobalsLeaked: function(test) {
    var leaks = gleak.detectNew();
    test.equal(0, leaks.length, "global var leak detected: " + leaks.join(', '));
    test.done();
  }
})

// Stupid freaking workaround due to there being no way to run setup once for each suite
var numberOfTestsRun = Object.keys(tests).length;
// Assign out tests
module.exports = tests;
<commit_msg>Made a test not run under linux which seems to be related to make test<commit_after>var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure();
var useSSL = process.env['USE_SSL'] != null ? true : false;

var testCase = require('../deps/nodeunit').testCase,
  debug = require('util').debug,
  inspect = require('util').inspect,
  nodeunit = require('../deps/nodeunit'),
  gleak = require('../tools/gleak'),
  Db = mongodb.Db,
  Cursor = mongodb.Cursor,
  Collection = mongodb.Collection,
  ServerManager = require('../test/tools/server_manager').ServerManager,
  Server = mongodb.Server;

var MONGODB = 'integration_tests';
var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4, ssl:useSSL}), {native_parser: (process.env['TEST_NATIVE'] != null)});

// Define the tests, we want them to run as a nested test so we only clean up the
// db connection once
var tests = testCase({
  setUp: function(callback) {
    client.open(function(err, db_p) {
      if(numberOfTestsRun == Object.keys(tests).length) {
        // If first test drop the db
        client.dropDatabase(function(err, done) {
          callback();
        });
      } else {
        return callback();
      }
    });
  },

  tearDown: function(callback) {
    numberOfTestsRun = numberOfTestsRun - 1;
    // Drop the database and close it
    if(numberOfTestsRun <= 0) {
      // client.dropDatabase(function(err, done) {
        client.close();
        callback();
      // });
    } else {
      client.close();
      callback();
    }
  },

  shouldCorrectlyEmitErrorOnAllDbsOnPoolClose : function(test) {
    if(process.platform !== 'linux') {
      var db = new Db('tests', new Server("127.0.0.1", 27027, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)});
      // All inserted docs
      var docs = [];
      var errs = [];
      var insertDocs = [];
      var numberOfCloses = 0;

      // Start server
      var serverManager = new ServerManager({auth:false, purgedirectories:true, journal:false, start_port:27027})
      serverManager.start(false, function() {
        db.on("close", function(err) {
          numberOfCloses = numberOfCloses + 1;
        })

        db.open(function(err, db) {
          console.dir(err)

          db.createCollection('shouldCorrectlyErrorOnAllDbs', function(err, collection) {
            test.equal(null, err);

            collection.insert({a:1}, {safe:true}, function(err, result) {
              test.equal(null, err);

              // Open a second db
              var db2 = db.db('tests_2');
              // Add a close handler
              db2.on("close", function(err) {
                numberOfCloses = numberOfCloses + 1;
              });

              db.serverConfig.connectionPool.openConnections[0].connection.destroy();

              // Kill server and end test
              serverManager.stop(9, function() {
                test.equal(2, numberOfCloses)
                test.done();
              });
            });
          });
        });
      });
    } else {
      test.done();
    }
  },

  // Test the auto connect functionality of the db
  shouldCorrectlyUseSameConnectionsForTwoDifferentDbs : function(test) {
    var second_test_database = new Db(MONGODB + "_2", new Server("127.0.0.1", 27017, {auto_reconnect: true, ssl:useSSL}), {native_parser: (process.env['TEST_NATIVE'] != null), retryMiliSeconds:50});
    second_test_database.bson_deserializer = client.bson_deserializer;
    second_test_database.bson_serializer = client.bson_serializer;
    second_test_database.pkFactory = client.pkFactory;

    // Just create second database
    second_test_database.open(function(err, second_test_database) {
      // Close second database
      second_test_database.close();
      // Let's grab a connection to the different db resusing our connection pools
      var secondDb = client.db(MONGODB + "_2");
      secondDb.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
        // Insert a dummy document
        collection.insert({a:20}, {safe: true}, function(err, r) {
          test.equal(null, err);

          // Query it
          collection.findOne({}, function(err, item) {
            test.equal(20, item.a);

            // Use the other db
            client.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
              // Insert a dummy document
              collection.insert({b:20}, {safe: true}, function(err, r) {
                test.equal(null, err);

                // Query it
                collection.findOne({}, function(err, item) {
                  test.equal(20, item.b);

                  // Drop the second db
                  secondDb.dropDatabase(function(err, item) {
                    test.equal(null, err);
                    test.done();
                  })
                })
              });
            });
          })
        });
      });
    });
  },

  // Test the auto connect functionality of the db
  shouldCorrectlyUseSameConnectionsForTwoDifferentDbs : function(test) {
    var second_test_database = new Db(MONGODB + "_2", new Server("127.0.0.1", 27017, {auto_reconnect: true, ssl:useSSL}), {native_parser: (process.env['TEST_NATIVE'] != null), retryMiliSeconds:50});
    second_test_database.bson_deserializer = client.bson_deserializer;
    second_test_database.bson_serializer = client.bson_serializer;
    second_test_database.pkFactory = client.pkFactory;

    // Just create second database
    second_test_database.open(function(err, second_test_database) {
      // Close second database
      second_test_database.close();
      // Let's grab a connection to the different db resusing our connection pools
      var secondDb = client.db(MONGODB + "_2");
      secondDb.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
        // Insert a dummy document
        collection.insert({a:20}, {safe: true}, function(err, r) {
          test.equal(null, err);

          // Query it
          collection.findOne({}, function(err, item) {
            test.equal(20, item.a);

            // Use the other db
            client.createCollection('shouldCorrectlyUseSameConnectionsForTwoDifferentDbs', function(err, collection) {
              // Insert a dummy document
              collection.insert({b:20}, {safe: true}, function(err, r) {
                test.equal(null, err);

                // Query it
                collection.findOne({}, function(err, item) {
                  test.equal(20, item.b);

                  // Drop the second db
                  secondDb.dropDatabase(function(err, item) {
                    test.equal(null, err);
                    test.done();
                  })
                })
              });
            });
          })
        });
      });
    });
  },

  // run this last
  noGlobalsLeaked: function(test) {
    var leaks = gleak.detectNew();
    test.equal(0, leaks.length, "global var leak detected: " + leaks.join(', '));
    test.done();
  }
})

// Stupid freaking workaround due to there being no way to run setup once for each suite
var numberOfTestsRun = Object.keys(tests).length;
// Assign out tests
module.exports = tests;
<|endoftext|>


<commit_before>var Tethys = (function () {

    document.querySelector('#tree').addEventListener('click', function (event) {
        if (event.target.className.indexOf('file') !== -1) {
            var fileId = event.target.dataset.fileid;
            if (fileId === 'new') {
                var parentId = event.target.dataset.parent;
                Modal.onsubmit["createFile"] = function (button, input) {
                    var newName = input[0];
                    if (newName.length <= 0) newName = "New " + button;
                    if (button === 'file') {
                        FileSystem.mkfile(parentId, newName);
                    } else if (button === 'folder'){
                        FileSystem.mkdir(parentId, newName);
                    }
                    Modal.close();
                }
                Modal.open('createFile');
                document.querySelector("#fileUpload").addEventListener('change', function(event){
                    var files = event.target.files;
                    for (var i=0; i<files.length; i++){
                        FileSystem.loadFile(files[i], parentId);
                    }
                    Modal.close();
                });
            } else if (fileId === 'delete'){
                var parentId = event.target.dataset.parent;
                Modal.onsubmit["confirmFolderDelete"] = function (button, input) {
                    if (button === 'yes') {
                        FileSystem.del(parentId);
                    }
                    Modal.close();
                }
                Modal.open('confirmFolderDelete');
            }else {
                FileSystem.open(fileId);
            }

        }
    });

    document.querySelector('#delete').addEventListener('click', function (event) {
        Modal.onsubmit["confirmDelete"] = function (button, input) {
            if (button === 'yes') {
                FileSystem.delCurrent();
            }
            Modal.close();
        }
        Modal.open('confirmDelete', FileSystem.workingFile);
    });

    var toolbarCollapsed=false;
    document.querySelector('#collapsetoolbar').addEventListener('click', function (event) {
        toolbarCollapsed=!toolbarCollapsed;
        if (toolbarCollapsed){
            document.querySelector('.toolbar').style.height='30px';
            document.querySelector('.workspace').style.bottom='30px';
            document.querySelector('.sidebar').style.bottom='30px';
            document.querySelector('.roomlist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist').style.border = '0';
        }else{
            document.querySelector('.toolbar').style.height='';
            document.querySelector('.workspace').style.bottom='';
            document.querySelector('.sidebar').style.bottom='';
            document.querySelector('.roomlist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist').style.border = '';
        }
    });

    var sidebarCollapsed=false;
    document.querySelector('#collapsesidebar').addEventListener('click', function (event) {
        sidebarCollapsed=!sidebarCollapsed;
        if (sidebarCollapsed){
            document.querySelector('.sidebar').style.width='30px';
            document.querySelector('.workspace').style.left='30px';
            document.querySelector('#tree').style.display='none';
            document.querySelector('.sidebar .panel-topbar').style.display='none';
        }else{
            document.querySelector('.sidebar').style.width='';
            document.querySelector('.workspace').style.left='';
            document.querySelector('#tree').style.display='';
            document.querySelector('.sidebar .panel-topbar').style.display='';
        }
    });

    document.querySelector('#savezip').addEventListener('click', function (event) {
        FileSystem.saveAsZip();
    });

    document.querySelector('#settings').addEventListener('click', function (event) {
        Modal.onsubmit['themes'] = function(button, input){
            switch(button){
                case 'material':
                    FileSystem.setTheme('material');
                    break;
                case 'atom':
                    FileSystem.setTheme('atom');
                    break;
                case 'codepen':
                    FileSystem.setTheme('codepen');
                    break;
                default:
                    FileSystem.setTheme('material');
            }
            Modal.close();
        }
        Modal.open("themes");
    });

    document.querySelector('#roomlist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me" || !SocketAPI.isMyRoom) return;
            Modal.onsubmit["confirmKick"] = function () {
                SocketAPI.kick(userID);
                Modal.close();
            };
            Modal.open('confirmKick', {
                name: name
            });
        }
    });

    document.querySelector('#onlinelist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me") return;
            Modal.onsubmit["requestInvite"] = function () {
                SocketAPI.requestRoom(userID);
                Modal.close();
            };
            Modal.open('requestInvite', {
                name: name
            });
        }
    });

    var me;
    var username;
    var hash;
    Modal.onsubmit['intro'] = function (button, input) {
        if (!input[0] || input[0].length <= 1) {
            input[0]="Guest";
        }
        username = input[0];
        var pic = Math.floor(Math.random() * 15);
        hash = Math.random();
        SocketAPI.joinOnline(username, pic, hash);

        me = {
            id: "me",
            name: "You",
            pic: pic,
            hash : hash
        }
        makeUser(me, "room", true);

        Modal.open('welcome');
    }

    var roomlistElement = document.querySelector("#roomlist > .panel");
    var onlinelistElement = document.querySelector("#onlinelist > .panel");

    var roomElements = {};
    var onlineElements = {};
    var userTemplate = `<img class="user-img" data-name="{{name}}" data-userid="{{id}}" src="img/avatars/avatar-{{pic}}.png"><label>{{name}}</label>`;

    function makeUser(user, group, isMe){
        if (user.hash == hash && !isMe) return; //Don't make self
        var div = document.createElement('div');
        div.className = "square";
        div.innerHTML = MicroMustache.template(userTemplate, user);

        if (group === "online"){
            onlinelistElement.appendChild(div);
            onlineElements[user.id] = div;
        }
        if (group === 'room'){
            roomlistElement.appendChild(div);
            roomElements[user.id] = div;
        }
    }
    function removeUser(user, group){
        var re = roomElements[user.id];
        var we = onlineElements[user.id]
        if (re && re.parentNode == roomlistElement){
            roomlistElement.removeChild(roomElements[user.id]);
        }
        if (we && we.parentNode == onlinelistElement){
            onlinelistElement.removeChild(onlineElements[user.id]);
        }
    }
    function clearRoom(){
        while (roomlistElement.firstChild){
            roomlistElement.removeChild(roomlistElement.firstChild);
        }
        makeUser(me, 'room', true);
    }

    SocketAPI.onOtherJoinOnline = function (user) {
        removeUser(user);
        makeUser(user,'online');
    }
    SocketAPI.onOtherLeftOnline = function (user) {
        removeUser(user);
    }
    SocketAPI.onOtherJoinRoom = function (user) {
        removeUser(user);
        makeUser(user, 'room');
    }
    SocketAPI.onOtherLeftRoom = function (user) {
        removeUser(user, 'room');
    }
    SocketAPI.onWho = function(onlineList){
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
    }
    SocketAPI.onRequestRoom = function(user, orignalId){
        Modal.onsubmit["request-join"]=function(button){
            if (button==="accept"){
                SocketAPI.respondToRoomRequest(user.id, orignalId);
            }
            Modal.close();
        }
        Modal.open('request-join', user);
    }
    SocketAPI.onRoomRespond = function(roomOwner, who){
        Modal.onsubmit['join-response'] = function(){};
        Modal.open('join-response', {name:roomOwner.name});
        clearRoom();
        for (var i=0; i<who.length; i++){
            removeUser(who[i]);
            makeUser(who[i], 'room');
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = roomOwner.name+"'s Room";
    }
    SocketAPI.onKick = function(onlineList){
        clearRoom();
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = "Your Room";
        Modal.onsubmit['kick-alert'] = function(){};
        Modal.open('kick-alert');
    }

    FileSystem.init();
    FileSystem.open("welcome");
    Modal.open('intro');

    var code = Util.getParameterByName("code");
    var ext= Util.getParameterByName("ext");
    FileSystem.openString(code,ext);

    console.log("%c Rock that console! If you're after the source: https://github.com/RationalCoding/TETHYS", "color:#263238; font-size: 15px;");

}())<commit_msg>Add theming parameter to url<commit_after>var Tethys = (function () {

    document.querySelector('#tree').addEventListener('click', function (event) {
        if (event.target.className.indexOf('file') !== -1) {
            var fileId = event.target.dataset.fileid;
            if (fileId === 'new') {
                var parentId = event.target.dataset.parent;
                Modal.onsubmit["createFile"] = function (button, input) {
                    var newName = input[0];
                    if (newName.length <= 0) newName = "New " + button;
                    if (button === 'file') {
                        FileSystem.mkfile(parentId, newName);
                    } else if (button === 'folder'){
                        FileSystem.mkdir(parentId, newName);
                    }
                    Modal.close();
                }
                Modal.open('createFile');
                document.querySelector("#fileUpload").addEventListener('change', function(event){
                    var files = event.target.files;
                    for (var i=0; i<files.length; i++){
                        FileSystem.loadFile(files[i], parentId);
                    }
                    Modal.close();
                });
            } else if (fileId === 'delete'){
                var parentId = event.target.dataset.parent;
                Modal.onsubmit["confirmFolderDelete"] = function (button, input) {
                    if (button === 'yes') {
                        FileSystem.del(parentId);
                    }
                    Modal.close();
                }
                Modal.open('confirmFolderDelete');
            }else {
                FileSystem.open(fileId);
            }

        }
    });

    document.querySelector('#delete').addEventListener('click', function (event) {
        Modal.onsubmit["confirmDelete"] = function (button, input) {
            if (button === 'yes') {
                FileSystem.delCurrent();
            }
            Modal.close();
        }
        Modal.open('confirmDelete', FileSystem.workingFile);
    });

    var toolbarCollapsed=false;
    document.querySelector('#collapsetoolbar').addEventListener('click', function (event) {
        toolbarCollapsed=!toolbarCollapsed;
        if (toolbarCollapsed){
            document.querySelector('.toolbar').style.height='30px';
            document.querySelector('.workspace').style.bottom='30px';
            document.querySelector('.sidebar').style.bottom='30px';
            document.querySelector('.roomlist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist').style.border = '0';
        }else{
            document.querySelector('.toolbar').style.height='';
            document.querySelector('.workspace').style.bottom='';
            document.querySelector('.sidebar').style.bottom='';
            document.querySelector('.roomlist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist').style.border = '';
        }
    });

    var sidebarCollapsed=false;
    document.querySelector('#collapsesidebar').addEventListener('click', function (event) {
        sidebarCollapsed=!sidebarCollapsed;
        if (sidebarCollapsed){
            document.querySelector('.sidebar').style.width='30px';
            document.querySelector('.workspace').style.left='30px';
            document.querySelector('#tree').style.display='none';
            document.querySelector('.sidebar .panel-topbar').style.display='none';
        }else{
            document.querySelector('.sidebar').style.width='';
            document.querySelector('.workspace').style.left='';
            document.querySelector('#tree').style.display='';
            document.querySelector('.sidebar .panel-topbar').style.display='';
        }
    });

    document.querySelector('#savezip').addEventListener('click', function (event) {
        FileSystem.saveAsZip();
    });

    document.querySelector('#settings').addEventListener('click', function (event) {
        Modal.onsubmit['themes'] = function(button, input){
            switch(button){
                case 'material':
                    FileSystem.setTheme('material');
                    break;
                case 'atom':
                    FileSystem.setTheme('atom');
                    break;
                case 'codepen':
                    FileSystem.setTheme('codepen');
                    break;
                default:
                    FileSystem.setTheme('material');
            }
            Modal.close();
        }
        Modal.open("themes");
    });

    document.querySelector('#roomlist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me" || !SocketAPI.isMyRoom) return;
            Modal.onsubmit["confirmKick"] = function () {
                SocketAPI.kick(userID);
                Modal.close();
            };
            Modal.open('confirmKick', {
                name: name
            });
        }
    });

    document.querySelector('#onlinelist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me") return;
            Modal.onsubmit["requestInvite"] = function () {
                SocketAPI.requestRoom(userID);
                Modal.close();
            };
            Modal.open('requestInvite', {
                name: name
            });
        }
    });

    var me;
    var username;
    var hash;
    Modal.onsubmit['intro'] = function (button, input) {
        if (!input[0] || input[0].length <= 1) {
            input[0]="Guest";
        }
        username = input[0];
        var pic = Math.floor(Math.random() * 15);
        hash = Math.random();
        SocketAPI.joinOnline(username, pic, hash);

        me = {
            id: "me",
            name: "You",
            pic: pic,
            hash : hash
        }
        makeUser(me, "room", true);

        Modal.open('welcome');
    }

    var roomlistElement = document.querySelector("#roomlist > .panel");
    var onlinelistElement = document.querySelector("#onlinelist > .panel");

    var roomElements = {};
    var onlineElements = {};
    var userTemplate = `<img class="user-img" data-name="{{name}}" data-userid="{{id}}" src="img/avatars/avatar-{{pic}}.png"><label>{{name}}</label>`;

    function makeUser(user, group, isMe){
        if (user.hash == hash && !isMe) return; //Don't make self
        var div = document.createElement('div');
        div.className = "square";
        div.innerHTML = MicroMustache.template(userTemplate, user);

        if (group === "online"){
            onlinelistElement.appendChild(div);
            onlineElements[user.id] = div;
        }
        if (group === 'room'){
            roomlistElement.appendChild(div);
            roomElements[user.id] = div;
        }
    }
    function removeUser(user, group){
        var re = roomElements[user.id];
        var we = onlineElements[user.id]
        if (re && re.parentNode == roomlistElement){
            roomlistElement.removeChild(roomElements[user.id]);
        }
        if (we && we.parentNode == onlinelistElement){
            onlinelistElement.removeChild(onlineElements[user.id]);
        }
    }
    function clearRoom(){
        while (roomlistElement.firstChild){
            roomlistElement.removeChild(roomlistElement.firstChild);
        }
        makeUser(me, 'room', true);
    }

    SocketAPI.onOtherJoinOnline = function (user) {
        removeUser(user);
        makeUser(user,'online');
    }
    SocketAPI.onOtherLeftOnline = function (user) {
        removeUser(user);
    }
    SocketAPI.onOtherJoinRoom = function (user) {
        removeUser(user);
        makeUser(user, 'room');
    }
    SocketAPI.onOtherLeftRoom = function (user) {
        removeUser(user, 'room');
    }
    SocketAPI.onWho = function(onlineList){
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
    }
    SocketAPI.onRequestRoom = function(user, orignalId){
        Modal.onsubmit["request-join"]=function(button){
            if (button==="accept"){
                SocketAPI.respondToRoomRequest(user.id, orignalId);
            }
            Modal.close();
        }
        Modal.open('request-join', user);
    }
    SocketAPI.onRoomRespond = function(roomOwner, who){
        Modal.onsubmit['join-response'] = function(){};
        Modal.open('join-response', {name:roomOwner.name});
        clearRoom();
        for (var i=0; i<who.length; i++){
            removeUser(who[i]);
            makeUser(who[i], 'room');
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = roomOwner.name+"'s Room";
    }
    SocketAPI.onKick = function(onlineList){
        clearRoom();
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = "Your Room";
        Modal.onsubmit['kick-alert'] = function(){};
        Modal.open('kick-alert');
    }

    FileSystem.init();
    FileSystem.open("welcome");
    Modal.open('intro');

    var code = Util.getParameterByName("code");
    var ext= Util.getParameterByName("ext");
    var theme = Util.getParameterByName("theme");
    FileSystem.openString(code,ext);
    switch(theme){
        case 'material':
            FileSystem.setTheme('material');
            break;
        case 'atom':
            FileSystem.setTheme('atom');
            break;
        case 'codepen':
            FileSystem.setTheme('codepen');
            break;
    }

    console.log("%c Rock that console! If you're after the source: https://github.com/RationalCoding/TETHYS", "color:#263238; font-size: 15px;");

}())<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 by Greg Reimer <gregreimer@gmail.com>
 * MIT License. See mit-license.txt for more info.
 */

/* eslint-env mocha */

import assert from 'assert';
import munge from '../src/munge';

describe('munge', () => {

  it('should mutate top-level items of an array', () => {
    const obj = ['a','b','c'];
    munge(obj, [{ select: ['$index'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, ['A','B','C']);
  });

  it('should mutate top-level props of an object', () => {
    const obj = {a:'a',b:'b'};
    munge(obj, [{ select: ['$key'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'A',b:'B'});
  });

  it('should selectively mutate top-level props of an object', () => {
    const obj = {a:'a',b:'b'};
    munge(obj, [{ select: ['b'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'a',b:'B'});
  });

  it('should mutate second-level props of an object', () => {
    const obj = {a:'a',b:['b','c']};
    munge(obj, [{ select: ['b','$index'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'a',b:['B','C']});
  });

  it('should selectively mutate second-level props of an object', () => {
    const obj = {a:'a',b:['b','c']};
    munge(obj, [{ select: ['b',0], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'a',b:['B','c']});
  });

  it('should delete props from an object', () => {
    const obj = {a:'a',b:{c:2}};
    munge(obj, [{ select: ['b','c'], edit: () => undefined }]);
    assert.deepEqual(obj, {a:'a',b:{}});
  });

  it('should not delete props from an array', () => {
    const obj = {a:'a',b:[1,2]};
    munge(obj, [{ select: ['b','$index'], edit: () => undefined }]);
    assert.deepEqual(obj, {a:'a',b:[undefined,undefined]});
  });

  it('should munge its own munges', () => {
    const obj = { a: 'a', b: null };
    munge(obj, [{
      select: ['b'],
      edit: () => ({ c: true })
    }, {
      select: ['b','c'],
      edit: val => !val
    }]);
    assert.deepEqual(obj, { a: 'a', b: { c: false } });
  });

  it('should mutate the root item', () => {
    const obj = ['a','b','c'];
    munge(obj, [{ select: [], edit: root => root.push('d') }]);
    assert.deepEqual(obj, ['a','b','c','d']);
  });

  it('should pass parent', () => {
    const obj = ['a','b','c'];
    function edit(val, parent) {
      assert.deepEqual(parent, ['a','b','c']);
      return val.toUpperCase();
    }
    munge(obj, [{ select: [0], edit }]);
    assert.deepEqual(obj, ['A','b','c']);
  });
});
<commit_msg>test for parent prop<commit_after>/*
 * Copyright (c) 2015 by Greg Reimer <gregreimer@gmail.com>
 * MIT License. See mit-license.txt for more info.
 */

/* eslint-env mocha */

import assert from 'assert';
import munge from '../src/munge';

describe('munge', () => {

  it('should mutate top-level items of an array', () => {
    const obj = ['a','b','c'];
    munge(obj, [{ select: ['$index'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, ['A','B','C']);
  });

  it('should mutate top-level props of an object', () => {
    const obj = {a:'a',b:'b'};
    munge(obj, [{ select: ['$key'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'A',b:'B'});
  });

  it('should selectively mutate top-level props of an object', () => {
    const obj = {a:'a',b:'b'};
    munge(obj, [{ select: ['b'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'a',b:'B'});
  });

  it('should mutate second-level props of an object', () => {
    const obj = {a:'a',b:['b','c']};
    munge(obj, [{ select: ['b','$index'], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'a',b:['B','C']});
  });

  it('should selectively mutate second-level props of an object', () => {
    const obj = {a:'a',b:['b','c']};
    munge(obj, [{ select: ['b',0], edit: val => val.toUpperCase() }]);
    assert.deepEqual(obj, {a:'a',b:['B','c']});
  });

  it('should delete props from an object', () => {
    const obj = {a:'a',b:{c:2}};
    munge(obj, [{ select: ['b','c'], edit: () => undefined }]);
    assert.deepEqual(obj, {a:'a',b:{}});
  });

  it('should not delete props from an array', () => {
    const obj = {a:'a',b:[1,2]};
    munge(obj, [{ select: ['b','$index'], edit: () => undefined }]);
    assert.deepEqual(obj, {a:'a',b:[undefined,undefined]});
  });

  it('should munge its own munges', () => {
    const obj = { a: 'a', b: null };
    munge(obj, [{
      select: ['b'],
      edit: () => ({ c: true })
    }, {
      select: ['b','c'],
      edit: val => !val
    }]);
    assert.deepEqual(obj, { a: 'a', b: { c: false } });
  });

  it('should mutate the root item', () => {
    const obj = ['a','b','c'];
    munge(obj, [{ select: [], edit: root => root.push('d') }]);
    assert.deepEqual(obj, ['a','b','c','d']);
  });

  it('should pass parent', () => {
    const obj = ['a','b','c'];
    function edit(val, parent) {
      assert.deepEqual(parent, ['a','b','c']);
      return val.toUpperCase();
    }
    munge(obj, [{ select: [0], edit }]);
    assert.deepEqual(obj, ['A','b','c']);
  });

  it('should pass parent prop', () => {
    const obj = ['a','b','c'];
    function edit(val, parent, prop) {
      assert.strictEqual(parent[prop], val);
      return val.toUpperCase();
    }
    munge(obj, [{ select: [0], edit }]);
    assert.deepEqual(obj, ['A','b','c']);
  });
});
<|endoftext|>