<commit_before>var contentGrid = {
    init : function () {
        var $contentGrid = $jQ('#main-column .content-grid'),
        $contentItems = $contentGrid.find('.content-item'),
        $quickviewLinks = $contentItems.find('.quick-view');
        $featuredHover = $contentItems.find('.featured-corner');
        $featuredReveal = $contentItems.find('.shop-this');
        $featuredHide = $contentItems.find('.back-to-story');
        $featuredReveal.click(contentGrid.featuredReveal);
        $featuredHide.click(contentGrid.featuredHide);
        $jQ('#load-more').click(MLS.ajax.lazyLoad.more);
        $jQ('#load-remaining').click(MLS.ajax.lazyLoad.remaining);
        contentGrid.sortHeader();
        contentGrid.mobileFilter.init();
        if (!isTouch) {
            MLS.ui.gridHover($contentItems, {
                topBar: $contentItems.find('.color-picker'),
                actions: $contentItems.find('.content-details')
            }, 10);
            //$contentItems.hover(contentGrid.productTileEnter, contentGrid.productTileLeave);
            $quickviewLinks.on('click', {'$contentGrid' : $contentGrid}, contentGrid.quickViewHandler);
            $featuredHover.hover(contentGrid.featuredHover, contentGrid.featuredHoverOff);
        }
    },
    sortHeader: function () {
        $jQ('li', '#sort-options').on('click', function (e) {
            e.preventDefault();
            var type = $jQ(this).attr('data-type');
            //Fire Ajax
            MLS.ajax.gridSort(type);
            $jQ('li', '#sort-options').removeClass('active');
            $jQ(this).addClass('active');
        });
    },
    mobileFilter : {
        init: function () {
            //Event handler for clicks !!!D.R.Y:-(
            $jQ('a.filter', '#mobile-sort-filter').on('click', function (e) {
                e.preventDefault();
                if ($jQ(this).hasClass('active')) {
                    $jQ(this).removeClass('active').css({height: '45px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideUp(200);

                } else {
                    $jQ('.dropdown-cta', '#mobile-sort-filter').not(this).removeClass('active').css({height: '45px'});
                    $jQ(this).addClass('active').css({height: '50px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideDown(200);
                    $jQ('.submenu-list', '#mobile-sort-filter').hide();
                    $jQ('.filter-options-list', '#mobile-sort-filter').show();
                }
            });
            $jQ('a.sort', '#mobile-sort-filter').on('click', function (e) {
                e.preventDefault();
                if ($jQ(this).hasClass('active')) {
                    $jQ(this).removeClass('active').css({height: '45px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideUp(200);

                } else {
                    $jQ('.dropdown-cta', '#mobile-sort-filter').not(this).removeClass('active').css({height: '45px'});
                    $jQ(this).addClass('active').css({height: '50px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideDown(200);
                    $jQ('.submenu-list', '#mobile-sort-filter').hide();
                    $jQ('.sort-options-list', '#mobile-sort-filter').show();
                }
            });
        }
    },
    productTileEnter : function () {
        $jQ(this).addClass('active');
    },
    productTileLeave : function () {
        $jQ(this).removeClass('active');
    },
    quickViewHandler : function (e) {
        var $quickView = $jQ('#quick-view-overlay'),
        $parentTile = $jQ(this).parent().parent(),
        $contentTile = $parentTile.hasClass('featured') ? $parentTile.next() : $parentTile,
        $cTposition = $contentTile.position(),
        $closeQv = $jQ('#close-quick-view').on('click', { qv : $quickView }, contentGrid.quickViewClose);

        if ($parentTile.hasClass('bundle')) {
            $quickView = $jQ('.quick-view-overlay.bundle');
        }

        $jQ('#quick-view-modal').fadeIn('fast');
        $quickView.css({
            'display' : 'block',
            'top' : $cTposition.top + ($parentTile.hasClass('featured') ? $parentTile.outerHeight() : 0) + 15,
            //'height' : $contentTile.outerHeight() * 2,
            'width' : (e.data.$contentGrid.outerWidth())
        });
        $jQ('html, body').animate({
            scrollTop : $cTposition.top + ($contentTile.outerHeight() / 2) + ($parentTile.hasClass('featured') ? $parentTile.outerHeight() : 0)
        }, 500, function () {
            contentGrid.initSlider();
            setTimeout(function () { // ensure scroll is fully complete before attaching these event handlers
                $jQ(window).on({
                    'resize.quickView' : contentGrid.quickViewClose,
                    'scroll.quickView' : contentGrid.quickViewClose,
                    'click.quickView' : function (e) {
                        if ($jQ(e.target).closest($quickView).length === 0) {
                            contentGrid.quickViewClose(e);
                        }
                    }
                }, { 'qv' : $quickView });
            }, 1);
        });
    },
    initSlider : function () {
        $jQ('#quick-view-slider').flexslider({
            animation: 'slide',
            controlNav: true,
            directionNav: false,
            controlsContainer: '#slider-controls',
            manualControls : '.flex-control-thumbs li',
            slideshow: false
        });

        var $sliderThumbs = $jQ('#slider-controls .flex-control-thumbs');
        $sliderThumbs.attr('style','');
        contentGrid.setThumbnailMargins($sliderThumbs, ($jQ(window).width() >= 1024 ? 'left' : 'top'));
    },
    setThumbnailMargins : function ($sT, pos) {
        var offset = pos === 'left' ? $sT.outerWidth() : $sT.outerHeight();
        $sT.css('margin-' + pos, '-' + (offset / 2) + 'px');
    },
    quickViewClose : function (e) {
        e.preventDefault();
        contentGrid.removeCloseListeners();
        var $qv = $jQ(e.data.qv);
        $qv.fadeOut('fast');
        $jQ('#quick-view-modal').fadeOut('fast');
    },
    removeCloseListeners : function () {
        $jQ(window).off('resize.quickView');
        $jQ(window).off('scroll.quickView');
        $jQ(window).off('click.quickView');
    },
    featuredHover : function () {
        var rThis = $jQ(this).parent().find('.featured-item-hover').stop(true, true).fadeIn('fast');
    },
    featuredHoverOff : function () {
        var rThis = $jQ(this).parent().find('.featured-item-hover').stop().fadeOut('fast');
    },
    featuredReveal : function (e) {
        e.preventDefault();
        var rThis = $jQ(this).parent().siblings('.featured-item');
        var rWd = rThis.width();
        var rHt = rThis.height();
        var wdIncr = (rWd) * -1;
        var htIncr = (rHt * .98) * -1;
		$jQ(rThis).css({
            'opacity' : 1,
            '-webkit-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            '-moz-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            '-ms-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            '-o-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            'transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) '

		}); // end css
    }, // end vznReveal
    featuredHide : function (e) {
        e.preventDefault();
        var hThis = $jQ(this).parents('.featured-item');
        $jQ(hThis).css({
            'opacity' : 0,
            '-webkit-transform' : ' translate3d(0 ,0 , 0) ',
            '-moz-transform' : ' translate3d(0 ,0 , 0) ',
            '-ms-transform' : ' translate3d(0 ,0 , 0) ',
            '-o-transform' : ' translate3d(0 ,0 , 0) ',
            'transform' : ' translate3d(0 ,0 , 0) '
		}); // end css
    }// end featuredHide
};

// ............. TEMP state toggle buttons in header .........

var stndrd = document.getElementById('state-standard');
var newProd = document.getElementById('state-new-products');
var featSale = document.getElementById('state-sale-featured');
var itemSale = document.getElementById('state-sale-item');

$jQ(stndrd).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(newProd).removeClass('on');
	$jQ(featSale).removeClass('on');
	$jQ(itemSale).removeClass('on');

	//turn off all special cases
	$jQ('.new-product').css('display', 'none');
	$jQ('.sale-featured').css('display', 'none');
	$jQ('.sale-item').css('display', 'none');

});

$jQ(newProd).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(stndrd).removeClass('on');

	// turn on new product elements
    $jQ('.new-product').css('display', 'block');

});

$jQ(featSale).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(stndrd).removeClass('on');

	//turn on featured sale elements & add class depending on screen width
	var pageWidth = document.body.clientWidth;
	if (pageWidth < 1281) {
		$jQ('.sale-featured.three-across').css('display', 'block').parent().addClass('sale-featured-block');
	} else if (pageWidth > 1280) {
		$jQ('.sale-featured.four-across').css('display', 'block').parent().addClass('sale-featured-block');
	}
});

$jQ(itemSale).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(stndrd).removeClass('on');

	//turn on item sale elements & turn off hover
	$jQ('.sale-item').css('display', 'block');

}); // end TEMP state buttons
<commit_msg>Adding events for mobile filter panels<commit_after>var contentGrid = {
    init : function () {
        var $contentGrid = $jQ('#main-column .content-grid'),
        $contentItems = $contentGrid.find('.content-item'),
        $quickviewLinks = $contentItems.find('.quick-view');
        $featuredHover = $contentItems.find('.featured-corner');
        $featuredReveal = $contentItems.find('.shop-this');
        $featuredHide = $contentItems.find('.back-to-story');
        $featuredReveal.click(contentGrid.featuredReveal);
        $featuredHide.click(contentGrid.featuredHide);
        $jQ('#load-more').click(MLS.ajax.lazyLoad.more);
        $jQ('#load-remaining').click(MLS.ajax.lazyLoad.remaining);
        contentGrid.sortHeader();
        contentGrid.mobileFilter.init();
        if (!isTouch) {
            MLS.ui.gridHover($contentItems, {
                topBar: $contentItems.find('.color-picker'),
                actions: $contentItems.find('.content-details')
            }, 10);
            //$contentItems.hover(contentGrid.productTileEnter, contentGrid.productTileLeave);
            $quickviewLinks.on('click', {'$contentGrid' : $contentGrid}, contentGrid.quickViewHandler);
            $featuredHover.hover(contentGrid.featuredHover, contentGrid.featuredHoverOff);
        }
    },
    sortHeader: function () {
        $jQ('li', '#sort-options').on('click', function (e) {
            e.preventDefault();
            var type = $jQ(this).attr('data-type');
            //Fire Ajax
            MLS.ajax.gridSort(type);
            $jQ('li', '#sort-options').removeClass('active');
            $jQ(this).addClass('active');
        });
    },
    mobileFilter : {
        init: function () {
            //Event handler for clicks !!!D.R.Y:-(
            $jQ('a.filter', '#mobile-sort-filter').on('click', function (e) {
                e.preventDefault();
                if ($jQ(this).hasClass('active')) {
                    $jQ(this).removeClass('active').css({height: '45px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideUp(200);
                } else {
                    $jQ('.dropdown-cta', '#mobile-sort-filter').not(this).removeClass('active').css({height: '45px'});
                    $jQ(this).addClass('active').css({height: '50px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideDown(200);
                    $jQ('.submenu-list', '#mobile-sort-filter').hide();
                    $jQ('.filter-options-list', '#mobile-sort-filter').show();
                }
            });
            $jQ('a.sort', '#mobile-sort-filter').on('click', function (e) {
                e.preventDefault();
                if ($jQ(this).hasClass('active')) {
                    $jQ(this).removeClass('active').css({height: '45px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideUp(200);
                } else {
                    $jQ('.dropdown-cta', '#mobile-sort-filter').not(this).removeClass('active').css({height: '45px'});
                    $jQ(this).addClass('active').css({height: '50px'});
                    $jQ('.dropdown-menu', '#mobile-sort-filter').slideDown(200);
                    $jQ('.submenu-list', '#mobile-sort-filter').hide();
                    $jQ('.sort-options-list', '#mobile-sort-filter').show();
                }
            });

            $jQ('li.filter-option', '.filter-options-list').on('click', function () {
                var dimension = $jQ(this).attr('data-type');
                contentGrid.mobileFilter.filterPanel(dimension);
            });

        },
        filterPanel: function (dimension) {
            var viewportHeight = Response.viewportH();
            $jQ('.filter-panels .panel').hide();
            $jQ('.filter-panel.' + dimension).show();
            $jQ('.filter-panels').show(function () {
                $jQ(this).animate({height: viewportHeight});
            });
            $jQ('.filter-panels .close').one('click', function () {
                $jQ('.filter-panels').animate({height: 0}, function () {
                    $jQ(this).hide();
                });
            });
            $jQ('.list-option').on('click', function () {
                $jQ(this).toggleClass('selected');
            });
        },
        updateFilters: function () {

        }
    },
    productTileEnter : function () {
        $jQ(this).addClass('active');
    },
    productTileLeave : function () {
        $jQ(this).removeClass('active');
    },
    quickViewHandler : function (e) {
        var $quickView = $jQ('#quick-view-overlay'),
        $parentTile = $jQ(this).parent().parent(),
        $contentTile = $parentTile.hasClass('featured') ? $parentTile.next() : $parentTile,
        $cTposition = $contentTile.position(),
        $closeQv = $jQ('#close-quick-view').on('click', { qv : $quickView }, contentGrid.quickViewClose);

        if ($parentTile.hasClass('bundle')) {
            $quickView = $jQ('.quick-view-overlay.bundle');
        }

        $jQ('#quick-view-modal').fadeIn('fast');
        $quickView.css({
            'display' : 'block',
            'top' : $cTposition.top + ($parentTile.hasClass('featured') ? $parentTile.outerHeight() : 0) + 15,
            //'height' : $contentTile.outerHeight() * 2,
            'width' : (e.data.$contentGrid.outerWidth())
        });
        $jQ('html, body').animate({
            scrollTop : $cTposition.top + ($contentTile.outerHeight() / 2) + ($parentTile.hasClass('featured') ? $parentTile.outerHeight() : 0)
        }, 500, function () {
            contentGrid.initSlider();
            setTimeout(function () { // ensure scroll is fully complete before attaching these event handlers
                $jQ(window).on({
                    'resize.quickView' : contentGrid.quickViewClose,
                    'scroll.quickView' : contentGrid.quickViewClose,
                    'click.quickView' : function (e) {
                        if ($jQ(e.target).closest($quickView).length === 0) {
                            contentGrid.quickViewClose(e);
                        }
                    }
                }, { 'qv' : $quickView });
            }, 1);
        });
    },
    initSlider : function () {
        $jQ('#quick-view-slider').flexslider({
            animation: 'slide',
            controlNav: true,
            directionNav: false,
            controlsContainer: '#slider-controls',
            manualControls : '.flex-control-thumbs li',
            slideshow: false
        });

        var $sliderThumbs = $jQ('#slider-controls .flex-control-thumbs');
        $sliderThumbs.attr('style','');
        contentGrid.setThumbnailMargins($sliderThumbs, ($jQ(window).width() >= 1024 ? 'left' : 'top'));
    },
    setThumbnailMargins : function ($sT, pos) {
        var offset = pos === 'left' ? $sT.outerWidth() : $sT.outerHeight();
        $sT.css('margin-' + pos, '-' + (offset / 2) + 'px');
    },
    quickViewClose : function (e) {
        e.preventDefault();
        contentGrid.removeCloseListeners();
        var $qv = $jQ(e.data.qv);
        $qv.fadeOut('fast');
        $jQ('#quick-view-modal').fadeOut('fast');
    },
    removeCloseListeners : function () {
        $jQ(window).off('resize.quickView');
        $jQ(window).off('scroll.quickView');
        $jQ(window).off('click.quickView');
    },
    featuredHover : function () {
        var rThis = $jQ(this).parent().find('.featured-item-hover').stop(true, true).fadeIn('fast');
    },
    featuredHoverOff : function () {
        var rThis = $jQ(this).parent().find('.featured-item-hover').stop().fadeOut('fast');
    },
    featuredReveal : function (e) {
        e.preventDefault();
        var rThis = $jQ(this).parent().siblings('.featured-item');
        var rWd = rThis.width();
        var rHt = rThis.height();
        var wdIncr = (rWd) * -1;
        var htIncr = (rHt * .98) * -1;
		$jQ(rThis).css({
            'opacity' : 1,
            '-webkit-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            '-moz-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            '-ms-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            '-o-transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) ',
            'transform' : ' translate3d(' + wdIncr + 'px,' + htIncr + 'px, 0) '

		}); // end css
    }, // end vznReveal
    featuredHide : function (e) {
        e.preventDefault();
        var hThis = $jQ(this).parents('.featured-item');
        $jQ(hThis).css({
            'opacity' : 0,
            '-webkit-transform' : ' translate3d(0 ,0 , 0) ',
            '-moz-transform' : ' translate3d(0 ,0 , 0) ',
            '-ms-transform' : ' translate3d(0 ,0 , 0) ',
            '-o-transform' : ' translate3d(0 ,0 , 0) ',
            'transform' : ' translate3d(0 ,0 , 0) '
		}); // end css
    }// end featuredHide
};

// ............. TEMP state toggle buttons in header .........

var stndrd = document.getElementById('state-standard');
var newProd = document.getElementById('state-new-products');
var featSale = document.getElementById('state-sale-featured');
var itemSale = document.getElementById('state-sale-item');

$jQ(stndrd).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(newProd).removeClass('on');
	$jQ(featSale).removeClass('on');
	$jQ(itemSale).removeClass('on');

	//turn off all special cases
	$jQ('.new-product').css('display', 'none');
	$jQ('.sale-featured').css('display', 'none');
	$jQ('.sale-item').css('display', 'none');

});

$jQ(newProd).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(stndrd).removeClass('on');

	// turn on new product elements
    $jQ('.new-product').css('display', 'block');

});

$jQ(featSale).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(stndrd).removeClass('on');

	//turn on featured sale elements & add class depending on screen width
	var pageWidth = document.body.clientWidth;
	if (pageWidth < 1281) {
		$jQ('.sale-featured.three-across').css('display', 'block').parent().addClass('sale-featured-block');
	} else if (pageWidth > 1280) {
		$jQ('.sale-featured.four-across').css('display', 'block').parent().addClass('sale-featured-block');
	}
});

$jQ(itemSale).click(function () {

	var stndrd = document.getElementById('state-standard');
	var newProd = document.getElementById('state-new-products');
	var featSale = document.getElementById('state-sale-featured');
	var itemSale = document.getElementById('state-sale-item');

	// change font colors for nav
	$jQ(this).addClass('on');
	$jQ(stndrd).removeClass('on');

	//turn on item sale elements & turn off hover
	$jQ('.sale-item').css('display', 'block');

}); // end TEMP state buttons
<|endoftext|>


<commit_before>'use strict';

// --- Configuration -----------------------------------------------------------
var CREDENTIALS = require('./conf/credentials.json');
var MESSAGES = require('./conf/messages.json');
var SKILL = require('./conf/skill.json');
var NETATMO = require('./conf/netatmo.json');
// -----------------------------------------------------------------------------

// --- Libraries ---------------------------------------------------------------
var ALEXA = require('alexa-sdk');
var HTTPS = require('https');
var JMESPATH = require('jmespath');
var QUERYSTRING = require('querystring');
var UTIL = require('util');
// -----------------------------------------------------------------------------

var NAMES = NETATMO.dataTypeToSpeech;
var SLOTS = NETATMO.slotToDataType;
var UNITS = NETATMO.dataTypeToUnit;

var ERRORS = {
  ACCESS_TOKEN_NA: '_ACCESS_TOKEN_NA',
  NETATMO_API_ERROR: '_NETATMO_API_ERROR'
};
var UNDEFINED = 'undefined';

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

var data;

exports.handler = function(event, context, callback) {

  // Fetch weather data right now since it's pretty much required for
  // all intents, then move on to 'Atmo'
  console.log("index.js - entry point.");
  getAllWeatherStationData(event, context, atmo);

};

// Main function
function atmo(event, context) {

  console.log("index.js - atmo");
  var alexa = ALEXA.handler(event, context);
  alexa.appId = CREDENTIALS.amazonApplicationId;
  alexa.registerHandlers(handlers);
  alexa.execute();

}

// Intent handlers
// TODO.
// - Move hasWeatherData = false to a common method
// - Check for a valid access token, otherwise, display a Link account card
var handlers = {
  'GetMeasurement': function() {
    console.log("index.js - handlers.GetMeasurement");
    if (!communicationWasSuccessful()) { this.emit(':tell', MESSAGES.voice.apiError); }
    else if (!accessTokenWasProvided()) { this.emit(':tellWithLinkAccountCard', UTIL.format(MESSAGES.voice.accountLinking, SKILL.title)); }
    else {
      this.emit(':tell',
        getTheWeatherStationData(
          getSpokenOrDefaultMeasurementName(this.event.request.intent),
          getSpokenOrDefaultSensorName(this.event.request.intent)
        )
      );
    }
  },
  'LaunchRequest': function() {
    console.log("index.js - handlers.LaunchRequest");
    // Launching the skill will read the temperature from the base station
    this.emit('GetMeasurement');
  },
  'ListSensors': function() {
    if (!communicationWasSuccessful()) { this.emit(':tell', MESSAGES.voice.apiError); }
    else if (!accessTokenWasProvided()) { this.emit(':tellWithLinkAccountCard', UTIL.format(MESSAGES.voice.accountLinking, SKILL.title)); }
    else {
      this.emit(':tell', getTheWeatherStationSensors());
    }
  },
  'Unhandled': function() {
    this.emit(':ask', MESSAGES.voice.help, MESSAGES.voice.help);
  }
};

// --- Helpers for intents -----------------------------------------------------

function getTheWeatherStationSensors() {

  if(hasWeatherData()) {
    // Find the name of the base station name & all the additional modules
    var pattern = "[ body.devices[].modules[].module_name, body.devices[].module_name ] | []";
    var result = JMESPATH.search(data, pattern);
    return UTIL.format(MESSAGES.voice.sensors, result.join(", "));
  } else {
    return MESSAGES.voice.weatherStationNotFound;
  }

}

function getTheWeatherStationData(measurement, sensor) {

  if(hasWeatherData()) {
    console.log("Data", JSON.stringify(data));

    var _data = JSON.parse(getSanitized(JSON.stringify(data)));
    var dataType = NETATMO.slotToDataType[getSanitized(measurement)];
    var _sensor = getSanitized(sensor);

    // console.log("Got '" + measurement + "' on '" + sensor + "'.");
    // console.log("Looking for '" + dataType + "' on '" + _sensor + "'.");

    // Exit if the sensor does not exist
    if(!sensorExists(_data, _sensor)) {
      return UTIL.format(MESSAGES.voice.sensorNotFound, sensor);
    }

    // Exit if the sensor cannot provide with the measurement
    if(!dataTypeProvidedBySensor(_data, dataType, _sensor)) {
      return UTIL.format(MESSAGES.voice.measurementNotFound, measurement, sensor);
    }

    // Get the value...
    var pattern = "[ body.devices[?module_name==`" + _sensor + "`].dashboard_data." + dataType + ", body.devices[].modules[?module_name==`" + _sensor + "`].dashboard_data." + dataType + " | [] ] | []";
    var value = JMESPATH.search(_data, pattern);
    // ... and the unit
    var unit = getUserUnits()[dataType];

    // All good, we've got something to tell the user
    return UTIL.format(MESSAGES.voice.measurement, NAMES[dataType], value, unit, sensor);

  } else {
    return MESSAGES.voice.weatherStationNotFound;
  }

}

function getSpokenOrDefaultSensorName(intent) {
    if(intent && intent.slots && intent.slots.SensorName && intent.slots.SensorName.value) {
      return intent.slots.SensorName.value;
    } else {
      return JMESPATH.search(data, "body.devices[0].module_name");
    }
}

function getSpokenOrDefaultMeasurementName(intent) {
  if(intent && intent.slots && intent.slots.MeasurementName && intent.slots.MeasurementName.value) {
    return intent.slots.MeasurementName.value
  } else {
    return 'temperature';
  }
}

function getUserUnits() {

    // Intent custom slot to unit
    return {
        "co2": UNITS.co2,
        "humidity": UNITS.humidity,
        "noise": UNITS.noise,
        "pressure": UNITS.pressure[JMESPATH.search(data, "body.user.administrative.pressureunit")],
        "temperature": "degrees " + UNITS.temperature[JMESPATH.search(data, "body.user.administrative.unit")]
    };

}

// --- Helpers that check the existence of things ------------------------------

function sensorExists(data, sensor) {

  var pattern = "[ body.devices[?module_name==`" + sensor + "`], body.devices[].modules[?module_name==`" + sensor + "`] | [] ] | []";
  var result = JMESPATH.search(data, pattern);
  return result.length > 0;

}

function dataTypeProvidedBySensor(data, dataType, sensor) {

    var pattern = "[ body.devices[?module_name==`" + sensor + "`].dashboard_data." + dataType + ", body.devices[].modules[?module_name==`" + sensor + "`].dashboard_data." + dataType + " | [] ] | []";
    var result = JMESPATH.search(data, pattern);
    return result.length > 0;

}

// --- Other helpers -----------------------------------------------------------

function getSanitized(text) {

  return text.replace(/[']/g, "").toLocaleLowerCase();

}

// Checks whether the data contains the bare minimum needed to answer the most
// basic intents
function hasWeatherData() {

  return data.body
    && data.body.user && data.body.user.administrative
    && data.body.devices && (data.body.devices.length > 0);

}

// Returns true if the API call to Netatmo was a success
function communicationWasSuccessful() {
  return data != ERRORS.NETATMO_API_ERROR;
}

// Returns true if the access token to the Netatmo API was provided
function accessTokenWasProvided() {
  return data != ERRORS.ACCESS_TOKEN_NA;
}

// Retrieves weather data from the Netatmo API
function getAllWeatherStationData(event, context, callback) {

  console.log("index.js - getAllWeatherStationData");
  // Access token is required
  if(!(event && event.session && event.session.user && event.session.user.accessToken)) {
    data = ERRORS.ACCESS_TOKEN_NA;
    callback(event, context);
  }

  var requestData = QUERYSTRING.stringify(
    { 'access_token': event.session.user.accessToken }
  );
  var requestOptions = {
    host: 'api.netatmo.com',
    path: '/api/getstationsdata',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': Buffer.byteLength(requestData)
    }
  };

  var request = HTTPS.request(
    requestOptions,
    function(response) {
      response.setEncoding('utf8');
      // On error
      response.on('error', function(error) {
        data = ERRORS.NETATMO_API_ERROR;
        callback(event, context);
      });
      // Incoming response
      var incoming = '';
      response.on('data', function(chunk) {
        incoming += chunk;
      });
      // Response received
      response.on('end', function() {
        data = JSON.parse(incoming);
        callback(event, context)
      });
    });
    request.write(requestData);
    request.end();

}
<commit_msg>Added handler for the built-in AMAZON.HelpIntent intent.<commit_after>'use strict';

// --- Configuration -----------------------------------------------------------
var CREDENTIALS = require('./conf/credentials.json');
var MESSAGES = require('./conf/messages.json');
var SKILL = require('./conf/skill.json');
var NETATMO = require('./conf/netatmo.json');
// -----------------------------------------------------------------------------

// --- Libraries ---------------------------------------------------------------
var ALEXA = require('alexa-sdk');
var HTTPS = require('https');
var JMESPATH = require('jmespath');
var QUERYSTRING = require('querystring');
var UTIL = require('util');
// -----------------------------------------------------------------------------

var NAMES = NETATMO.dataTypeToSpeech;
var SLOTS = NETATMO.slotToDataType;
var UNITS = NETATMO.dataTypeToUnit;

var ERRORS = {
  ACCESS_TOKEN_NA: '_ACCESS_TOKEN_NA',
  NETATMO_API_ERROR: '_NETATMO_API_ERROR'
};
var UNDEFINED = 'undefined';

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

var data;

exports.handler = function(event, context, callback) {

  // Fetch weather data right now since it's pretty much required for
  // all intents, then move on to 'Atmo'
  console.log("index.js - entry point.");
  getAllWeatherStationData(event, context, atmo);

};

// Main function
function atmo(event, context) {

  console.log("index.js - atmo");
  var alexa = ALEXA.handler(event, context);
  alexa.appId = CREDENTIALS.amazonApplicationId;
  alexa.registerHandlers(handlers);
  alexa.execute();

}

// Intent handlers
// TODO.
// - Move hasWeatherData = false to a common method
// - Check for a valid access token, otherwise, display a Link account card
var handlers = {
  'GetMeasurement': function() {
    console.log("index.js - handlers.GetMeasurement");
    if (!communicationWasSuccessful()) { this.emit(':tell', MESSAGES.voice.apiError); }
    else if (!accessTokenWasProvided()) { this.emit(':tellWithLinkAccountCard', UTIL.format(MESSAGES.voice.accountLinking, SKILL.title)); }
    else {
      this.emit(':tell',
        getTheWeatherStationData(
          getSpokenOrDefaultMeasurementName(this.event.request.intent),
          getSpokenOrDefaultSensorName(this.event.request.intent)
        )
      );
    }
  },
  'LaunchRequest': function() {
    console.log("index.js - handlers.LaunchRequest");
    // Launching the skill will read the temperature from the base station
    this.emit('GetMeasurement');
  },
  'ListSensors': function() {
    if (!communicationWasSuccessful()) { this.emit(':tell', MESSAGES.voice.apiError); }
    else if (!accessTokenWasProvided()) { this.emit(':tellWithLinkAccountCard', UTIL.format(MESSAGES.voice.accountLinking, SKILL.title)); }
    else {
      this.emit(':tell', getTheWeatherStationSensors());
    }
  },
  'AMAZON.HelpIntent': function() {
    this.emit(':ask', MESSAGES.voice.help, MESSAGES.voice.help);
  },
  'Unhandled': function() {
    this.emit('AMAZON.HelpIntent');
  }
};

// --- Helpers for intents -----------------------------------------------------

function getTheWeatherStationSensors() {

  if(hasWeatherData()) {
    // Find the name of the base station name & all the additional modules
    var pattern = "[ body.devices[].modules[].module_name, body.devices[].module_name ] | []";
    var result = JMESPATH.search(data, pattern);
    return UTIL.format(MESSAGES.voice.sensors, result.join(", "));
  } else {
    return MESSAGES.voice.weatherStationNotFound;
  }

}

function getTheWeatherStationData(measurement, sensor) {

  if(hasWeatherData()) {
    console.log("Data", JSON.stringify(data));

    var _data = JSON.parse(getSanitized(JSON.stringify(data)));
    var dataType = NETATMO.slotToDataType[getSanitized(measurement)];
    var _sensor = getSanitized(sensor);

    // console.log("Got '" + measurement + "' on '" + sensor + "'.");
    // console.log("Looking for '" + dataType + "' on '" + _sensor + "'.");

    // Exit if the sensor does not exist
    if(!sensorExists(_data, _sensor)) {
      return UTIL.format(MESSAGES.voice.sensorNotFound, sensor);
    }

    // Exit if the sensor cannot provide with the measurement
    if(!dataTypeProvidedBySensor(_data, dataType, _sensor)) {
      return UTIL.format(MESSAGES.voice.measurementNotFound, measurement, sensor);
    }

    // Get the value...
    var pattern = "[ body.devices[?module_name==`" + _sensor + "`].dashboard_data." + dataType + ", body.devices[].modules[?module_name==`" + _sensor + "`].dashboard_data." + dataType + " | [] ] | []";
    var value = JMESPATH.search(_data, pattern);
    // ... and the unit
    var unit = getUserUnits()[dataType];

    // All good, we've got something to tell the user
    return UTIL.format(MESSAGES.voice.measurement, NAMES[dataType], value, unit, sensor);

  } else {
    return MESSAGES.voice.weatherStationNotFound;
  }

}

function getSpokenOrDefaultSensorName(intent) {
    if(intent && intent.slots && intent.slots.SensorName && intent.slots.SensorName.value) {
      return intent.slots.SensorName.value;
    } else {
      return JMESPATH.search(data, "body.devices[0].module_name");
    }
}

function getSpokenOrDefaultMeasurementName(intent) {
  if(intent && intent.slots && intent.slots.MeasurementName && intent.slots.MeasurementName.value) {
    return intent.slots.MeasurementName.value
  } else {
    return 'temperature';
  }
}

function getUserUnits() {

    // Intent custom slot to unit
    return {
        "co2": UNITS.co2,
        "humidity": UNITS.humidity,
        "noise": UNITS.noise,
        "pressure": UNITS.pressure[JMESPATH.search(data, "body.user.administrative.pressureunit")],
        "temperature": "degrees " + UNITS.temperature[JMESPATH.search(data, "body.user.administrative.unit")]
    };

}

// --- Helpers that check the existence of things ------------------------------

function sensorExists(data, sensor) {

  var pattern = "[ body.devices[?module_name==`" + sensor + "`], body.devices[].modules[?module_name==`" + sensor + "`] | [] ] | []";
  var result = JMESPATH.search(data, pattern);
  return result.length > 0;

}

function dataTypeProvidedBySensor(data, dataType, sensor) {

    var pattern = "[ body.devices[?module_name==`" + sensor + "`].dashboard_data." + dataType + ", body.devices[].modules[?module_name==`" + sensor + "`].dashboard_data." + dataType + " | [] ] | []";
    var result = JMESPATH.search(data, pattern);
    return result.length > 0;

}

// --- Other helpers -----------------------------------------------------------

function getSanitized(text) {

  return text.replace(/[']/g, "").toLocaleLowerCase();

}

// Checks whether the data contains the bare minimum needed to answer the most
// basic intents
function hasWeatherData() {

  return data.body
    && data.body.user && data.body.user.administrative
    && data.body.devices && (data.body.devices.length > 0);

}

// Returns true if the API call to Netatmo was a success
function communicationWasSuccessful() {
  return data != ERRORS.NETATMO_API_ERROR;
}

// Returns true if the access token to the Netatmo API was provided
function accessTokenWasProvided() {
  return data != ERRORS.ACCESS_TOKEN_NA;
}

// Retrieves weather data from the Netatmo API
function getAllWeatherStationData(event, context, callback) {

  console.log("index.js - getAllWeatherStationData");
  // Access token is required
  if(!(event && event.session && event.session.user && event.session.user.accessToken)) {
    data = ERRORS.ACCESS_TOKEN_NA;
    callback(event, context);
  }

  var requestData = QUERYSTRING.stringify(
    { 'access_token': event.session.user.accessToken }
  );
  var requestOptions = {
    host: 'api.netatmo.com',
    path: '/api/getstationsdata',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': Buffer.byteLength(requestData)
    }
  };

  var request = HTTPS.request(
    requestOptions,
    function(response) {
      response.setEncoding('utf8');
      // On error
      response.on('error', function(error) {
        data = ERRORS.NETATMO_API_ERROR;
        callback(event, context);
      });
      // Incoming response
      var incoming = '';
      response.on('data', function(chunk) {
        incoming += chunk;
      });
      // Response received
      response.on('end', function() {
        data = JSON.parse(incoming);
        callback(event, context)
      });
    });
    request.write(requestData);
    request.end();

}
<|endoftext|>


<commit_before>define(["js/core/Bindable", "underscore", "js/core/BindingCreator"], function (Bindable, _, BindingCreator) {

        var undefined;
        var bindingCreator = new BindingCreator();

        function stringToPrimitive(str) {
            // if it's not a string
            if (_.isString(str)) {

                var num = Number(str);
                if (!isNaN(num)) {
                    return num;
                }

                if (str === "true") {
                    return true;
                } else if (str === "false") {
                    return false;
                }
            }
            return str;
        }

        var Element = Bindable.inherit("js.core.Element", {
            ctor: function (attributes, descriptor, stage, parentScope, rootScope) {
                attributes = attributes || {};

                if (!descriptor) {
                    // created from node
                    if (!rootScope) {
                        rootScope = this;
                    }
                }
                this.$stage = stage;
                this.$descriptor = descriptor;
                this.$parentScope = parentScope || null;
                this.$rootScope = rootScope || null;
                this.$attributesNamespace = this.$attributesNamespace || {};
                this.$bindingCreator = bindingCreator;

                this.callBase(attributes);

                this._initializeAttributes(this.$);

                // manually constructed
                if (descriptor === undefined || descriptor === null) {
                    this._initialize(this.$creationPolicy);
                }

            },

            _getAttributesFromDescriptor: function (descriptor) {

                this.$attributesNamespace = this.$attributesNamespace || {};

                var attributes = {};

                if (descriptor && descriptor.attributes) {
                    var node, localName;

                    for (var a = 0; a < descriptor.attributes.length; a++) {
                        node = descriptor.attributes[a];
                        // don't add xmlns attributes
                        if(node.nodeName.indexOf("xmlns") !== 0){
                            localName = this._getLocalNameFromNode(node);
                            attributes[localName] = stringToPrimitive(node.value);

                            if (node.namespaceURI) {
                                this.$attributesNamespace[localName] = node.namespaceURI;
                            }

                        }

                    }
                }

                return attributes;
            },
            _getLocalNameFromNode: function(node){
                return node.localName ? node.localName : node.name.split(":").pop();
            },
            defaults: {
                creationPolicy: "auto"
            },
            _initializeEventAttributes: function(attribute){

            },
            _initializeAttributes: function (attributes) {
            },

            _initializeDescriptors: function () {
            },

            /**
             *
             * @param creationPolicy
             *          auto - do not overwrite (default),
             *          all - create all children
             *          TODO none?
             */
            _initialize: function (creationPolicy, withBindings) {
                if (this.$initialized) {
                    return;
                }

                this._preinitialize();

                this.initialize();

                this._initializeDescriptors();

                this._initializeEventAttributes(this.$);

                if (this == this.$rootScope || (this.$parentScope && this.$parentScope.$initialized) || this.$descriptor === false) {
                    this._initializeBindings();
                }

            },

            _initializeBindings: function () {
                this._initializationComplete();
            },
            initialize: function () {

            },
            find: function (key) {
                var scope = this.getScopeForKey(key);
                if (this === scope) {
                    return this.get(key);
                } else if (scope != null) {
                    return scope.get(key);
                } else {
                    return null;
                }
            },
            getScopeForKey: function (key) {
                // if value was found
                if (this.$.hasOwnProperty(key)) {
                    return this;
                } else if (this.$parentScope) {
                    return this.$parentScope.getScopeForKey(key);
                } else {
                    return null;
                }
            },
            getScopeForFncName: function (fncName) {
                var fnc = this[fncName];
                if (!_.isUndefined(fnc) && _.isFunction(fnc)) {
                    return this;
                } else if (this.$parentScope) {
                    return this.$parentScope.getScopeForFncName(fncName);
                } else {
                    return null;
                }
            },
            _preinitialize: function () {

            },
            _initializationComplete: function () {

                // call commitChangedAttributes for all attributes
                this.set(this.$, {
                    force: true,
                    silent: true
                });

                this.$initialized = true;
            },
            _getTextContentFromDescriptor: function (desc) {
                var textContent = desc.textContent || desc.text || desc.data;
                if (!textContent) {
                    textContent = "";
                    for (var i = 0; i < desc.childNodes.length; i++) {
                        var node = desc.childNodes[i];
                        // element or cdata node
                        if (node.nodeType == 1 || node.nodeType == 4) {
                            textContent += this._getTextContentFromDescriptor(node);
                        }
                    }
                }
                return textContent;
            },
            /**
             * Binding helper to negate a Boolean value
             * @param value
             * @return {Boolean}
             */
            not: function(value){
                return !value;
            }
        });

        Element.xmlStringToDom = function(xmlString) {

            if (window && window.DOMParser) {
                return (new DOMParser()).parseFromString(xmlString, "text/xml").documentElement;
            } else if (typeof(ActiveXObject) !== "undefined") {
                var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
                xmlDoc.async = false;
                xmlDoc.loadXML(xmlString);
                return xmlDoc.documentElement;
            } else {
                throw "Couldn't parse xml string";
            }

        };

        return Element;
    }
);<commit_msg>added null support for strToPrimitive<commit_after>define(["js/core/Bindable", "underscore", "js/core/BindingCreator"], function (Bindable, _, BindingCreator) {

        var undefined;
        var bindingCreator = new BindingCreator();

        function stringToPrimitive(str) {
            // if it's not a string
            if (_.isString(str)) {

                var num = Number(str);
                if (!isNaN(num)) {
                    return num;
                }

                if (str === "true") {
                    return true;
                } else if (str === "false") {
                    return false;
                }

                if (str === "null") {
                    return null;
                }
            }
            return str;
        }

        var Element = Bindable.inherit("js.core.Element", {
            ctor: function (attributes, descriptor, stage, parentScope, rootScope) {
                attributes = attributes || {};

                if (!descriptor) {
                    // created from node
                    if (!rootScope) {
                        rootScope = this;
                    }
                }
                this.$stage = stage;
                this.$descriptor = descriptor;
                this.$parentScope = parentScope || null;
                this.$rootScope = rootScope || null;
                this.$attributesNamespace = this.$attributesNamespace || {};
                this.$bindingCreator = bindingCreator;

                this.callBase(attributes);

                this._initializeAttributes(this.$);

                // manually constructed
                if (descriptor === undefined || descriptor === null) {
                    this._initialize(this.$creationPolicy);
                }

            },

            _getAttributesFromDescriptor: function (descriptor) {

                this.$attributesNamespace = this.$attributesNamespace || {};

                var attributes = {};

                if (descriptor && descriptor.attributes) {
                    var node, localName;

                    for (var a = 0; a < descriptor.attributes.length; a++) {
                        node = descriptor.attributes[a];
                        // don't add xmlns attributes
                        if(node.nodeName.indexOf("xmlns") !== 0){
                            localName = this._getLocalNameFromNode(node);
                            attributes[localName] = stringToPrimitive(node.value);

                            if (node.namespaceURI) {
                                this.$attributesNamespace[localName] = node.namespaceURI;
                            }

                        }

                    }
                }

                return attributes;
            },
            _getLocalNameFromNode: function(node){
                return node.localName ? node.localName : node.name.split(":").pop();
            },
            defaults: {
                creationPolicy: "auto"
            },
            _initializeEventAttributes: function(attribute){

            },
            _initializeAttributes: function (attributes) {
            },

            _initializeDescriptors: function () {
            },

            /**
             *
             * @param creationPolicy
             *          auto - do not overwrite (default),
             *          all - create all children
             *          TODO none?
             */
            _initialize: function (creationPolicy, withBindings) {
                if (this.$initialized) {
                    return;
                }

                this._preinitialize();

                this.initialize();

                this._initializeDescriptors();

                this._initializeEventAttributes(this.$);

                if (this == this.$rootScope || (this.$parentScope && this.$parentScope.$initialized) || this.$descriptor === false) {
                    this._initializeBindings();
                }

            },

            _initializeBindings: function () {
                this._initializationComplete();
            },
            initialize: function () {

            },
            find: function (key) {
                var scope = this.getScopeForKey(key);
                if (this === scope) {
                    return this.get(key);
                } else if (scope != null) {
                    return scope.get(key);
                } else {
                    return null;
                }
            },
            getScopeForKey: function (key) {
                // if value was found
                if (this.$.hasOwnProperty(key)) {
                    return this;
                } else if (this.$parentScope) {
                    return this.$parentScope.getScopeForKey(key);
                } else {
                    return null;
                }
            },
            getScopeForFncName: function (fncName) {
                var fnc = this[fncName];
                if (!_.isUndefined(fnc) && _.isFunction(fnc)) {
                    return this;
                } else if (this.$parentScope) {
                    return this.$parentScope.getScopeForFncName(fncName);
                } else {
                    return null;
                }
            },
            _preinitialize: function () {

            },
            _initializationComplete: function () {

                // call commitChangedAttributes for all attributes
                this.set(this.$, {
                    force: true,
                    silent: true
                });

                this.$initialized = true;
            },
            _getTextContentFromDescriptor: function (desc) {
                var textContent = desc.textContent || desc.text || desc.data;
                if (!textContent) {
                    textContent = "";
                    for (var i = 0; i < desc.childNodes.length; i++) {
                        var node = desc.childNodes[i];
                        // element or cdata node
                        if (node.nodeType == 1 || node.nodeType == 4) {
                            textContent += this._getTextContentFromDescriptor(node);
                        }
                    }
                }
                return textContent;
            },
            /**
             * Binding helper to negate a Boolean value
             * @param value
             * @return {Boolean}
             */
            not: function(value){
                return !value;
            }
        });

        Element.xmlStringToDom = function(xmlString) {

            if (window && window.DOMParser) {
                return (new DOMParser()).parseFromString(xmlString, "text/xml").documentElement;
            } else if (typeof(ActiveXObject) !== "undefined") {
                var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
                xmlDoc.async = false;
                xmlDoc.loadXML(xmlString);
                return xmlDoc.documentElement;
            } else {
                throw "Couldn't parse xml string";
            }

        };

        return Element;
    }
);<|endoftext|>


<commit_before>define(["js/core/Bindable", "flow"], function (Bindable, flow) {

    var routeStripper = /^#?!?\/?/,
        undefined,
        emptyCallback = function () {
        };

    /***
     * @summary The History listens to the browsers history and calls the routers when the fragment has changed
     * It also allows to navigate to a given fragment.
     *
     */
    var History = Bindable.inherit("js.core.History", {

        ctor: function () {
            this.callBase();
            this.$routers = [];
            this.$processUrl = true;

            this.$history = [];

            if (this.$.useState === null) {
                this.set("useState", (this.runsInBrowser() && ("onpopstate" in window)));
            }
        },

        defaults: {
            /**
             * The polling interval for the URL hash if onhashchange is not supported
             * @type Number
             */
            interval: 50,

            /***
             * should the push and pop state api be used
             */
            useState: false,

            baseUrl: "/"
        },

        // TODO: make this bindable so that i can call this.fragment.triggerChange()

        /***
         * @Bindable
         * @return {String}
         */
        fragment: function() {
            return this.$fragment;
        }.on('change:fragment'),

        /***
         * determinate the current fragment
         * @return {String} the current fragment without the starting #/
         * @private
         */
        _getFragment: function () {
            var fragment;

            if (this.runsInBrowser()) {

                if (this.$.useState) {
                    fragment = (window.history.state || {}).fragment || "";
                } else {
                    fragment = decodeURI(window.location.hash);
                }

            } else {
                fragment = this.$history[this.$history.length - 1] || "";
            }

            return fragment.replace(routeStripper, '');
        },
        /***
         * This method is called to start the history
         * @param {Function} callback - get's called after the navigation is completed
         * @param {String} initialHash
         */
        start: function (callback, initialHash) {

            var self = this,
                fragment;

            this.$checkUrlFn = function () {
                self.checkUrl.apply(self, arguments);
            };

            if (this.runsInBrowser()) {
                // we're in a browser

                if (this.$.useState) {

                    fragment = window.location.pathname;
                    fragment = fragment.replace(new RegExp("^" + (this.$.baseUrl || "")), "");

                    if (window.addEventListener) {
                        window.addEventListener('popstate', this.$checkUrlFn, false);
                    } else {
                        window.attachEvent('onpopstate', this.$checkUrlFn);
                    }

                } else {

                    if ("onhashchange" in window) {
                        if (window.addEventListener) {
                            window.addEventListener('hashchange', this.$checkUrlFn, false);
                        } else {
                            window.attachEvent('onhashchange', this.$checkUrlFn);
                        }
                    } else {
                        // polling
                        this.$checkUrlInterval = setInterval(this.$checkUrlFn, this.$.interval);
                    }
                }

            } else {
                // rendering on node
                this.$history.push(initialHash || "");
            }

            fragment = fragment || this._getFragment();

            this.navigate(fragment, true, true, true, callback);
            this.$processUrl = true;
        },
        /***
         * Removes all onhaschange listeners or clears polling interval for hash check
         */
        stop: function () {
            if (typeof window !== "undefined") {

                if (this.$.useState) {
                    if (window.removeEventListener) {
                        window.removeEventListener('popstate', this.$checkUrlFn, false);
                    } else {
                        window.detachEvent('onpopstate', this.$checkUrlFn);
                    }
                } else {
                    if ("onhashchange" in window) {
                        if (window.removeEventListener) {
                            window.removeEventListener('hashchange', this.$checkUrlFn, false);
                        } else {
                            window.detachEvent('onhashchange', this.$checkUrlFn);
                        }
                    } else {
                        // polling
                        clearInterval(this.$checkUrlInterval);
                    }
                }
            }
        },

        /**
         * Adds a router to the history instance
         *
         * @param router
         */
        addRouter: function (router) {
            this.$routers.push(router);
        },

        /**
         * Checks if the current fragment has changed and calls navigate in case it did
         *
         */
        checkUrl: function () {

            if (this.$processUrl) {
                var currentFragment = this._getFragment();
                if (currentFragment == this.$fragment) {
                    return false;
                }

                this.navigate(currentFragment, !this.$.useState, true, true, emptyCallback);
            }

            this.$processUrl = true;

        },
        /**
         * Triggers a route
         *
         * @param {String} fragment - the fragment which should be triggered
         * @param {Function} callback - gets called after the route execution stack is done
         */
        triggerRoute: function (fragment, callback) {

            var routeExecutionStack = [];

            for (var i = 0; i < this.$routers.length; i++) {
                routeExecutionStack = routeExecutionStack.concat(this.$routers[i].generateRoutingStack(fragment));
            }

            if (routeExecutionStack.length === 0) {
                this.log("no route for '" + fragment + "' found.");
                // no route found but
                if (callback) {
                    // execute callback
                    callback();
                }
            } else {
                flow()
                    .seqEach(routeExecutionStack, function(routingFunction, cb){
                        routingFunction(cb);
                    })
                    .exec(callback);
            }
        },

        /***
         * Navigates to a fragment
         * @param {String} fragment
         * @param {Boolean} [createHistoryEntry] - default true
         * @param {Boolean} [triggerRoute] - default true
         * @param force
         * @param {Function} callback - navigate callback
         */
        navigate: function (fragment, createHistoryEntry, triggerRoute, force, callback) {

            var self = this;

            if (!callback && createHistoryEntry instanceof Function) {
                callback = createHistoryEntry;
                createHistoryEntry = null;
            }

            if (!callback && triggerRoute instanceof Function) {
                callback = triggerRoute;
                triggerRoute = null;
            }

            if (!callback && force instanceof Function) {
                callback = force;
                force = null;
            }

            if (createHistoryEntry == undefined || createHistoryEntry === null) {
                createHistoryEntry = true;
            }

            if (triggerRoute == undefined || triggerRoute === null) {
                triggerRoute = true;
            }

            var eventData = {
                fragment: fragment,
                createHistoryEntry: createHistoryEntry,
                triggerRoute: triggerRoute
            };

            var urlChange = this._getFragment() !== fragment;

            if (!urlChange && !force) {
                callback && callback();
                return;
            }

            this.trigger(History.EVENTS.NAVIGATION_START, eventData);
            this.$processUrl = urlChange;

            if (createHistoryEntry) {
                if (this.runsInBrowser()) {
                    if (this.$.useState) {

                        console.log("Pushing " + fragment + " to history");

                        window.history.pushState({
                            fragment: "/" + fragment
                        }, null, this.$.baseUrl + fragment);
                    } else {
                        window.location.hash = "/" + encodeURI(fragment);
                    }
                } else {
                    this.checkUrl(null);
                }
                this.$history.push(fragment);
            } else {
                if (this.runsInBrowser()) {

                    if (this.$.useState) {

                        console.log("Replacing " + fragment + " to history");

                        window.history.replaceState({
                            fragment: "/" + fragment
                        }, null, this.$.baseUrl + fragment);
                    } else {
                        // replace hash
                        window.location.replace("#/" + fragment);
                    }
                }
                this.$history[this.$history.length - 1] = fragment;
            }

            this.$processUrl = true;

            if(this.$fragment !== fragment){
                this.$fragment = fragment;
                this.trigger('change:fragment', this.$fragment);
            }

            if (triggerRoute) {
                this.triggerRoute(fragment, function() {
                    self.trigger(History.EVENTS.NAVIGATION_COMPLETE, eventData);
                    if (callback) {
                        callback.apply(self, arguments);
                    }
                });
            } else {
                this.trigger(History.EVENTS.NAVIGATION_COMPLETE, eventData);
            }
        }
    });

    History.EVENTS = {
        NAVIGATION_START: "navigationStart",
        NAVIGATION_COMPLETE: "navigationComplete"
    };

    return History;
});<commit_msg>fixed history start ... history entry is automatically when entering a new page ...<commit_after>define(["js/core/Bindable", "flow"], function (Bindable, flow) {

    var routeStripper = /^#?!?\/?/,
        undefined,
        emptyCallback = function () {
        };

    /***
     * @summary The History listens to the browsers history and calls the routers when the fragment has changed
     * It also allows to navigate to a given fragment.
     *
     */
    var History = Bindable.inherit("js.core.History", {

        ctor: function () {
            this.callBase();
            this.$routers = [];
            this.$processUrl = true;

            this.$history = [];

            if (this.$.useState === null) {
                this.set("useState", (this.runsInBrowser() && ("onpopstate" in window)));
            }
        },

        defaults: {
            /**
             * The polling interval for the URL hash if onhashchange is not supported
             * @type Number
             */
            interval: 50,

            /***
             * should the push and pop state api be used
             */
            useState: false,

            baseUrl: "/"
        },

        // TODO: make this bindable so that i can call this.fragment.triggerChange()

        /***
         * @Bindable
         * @return {String}
         */
        fragment: function() {
            return this.$fragment;
        }.on('change:fragment'),

        /***
         * determinate the current fragment
         * @return {String} the current fragment without the starting #/
         * @private
         */
        _getFragment: function () {
            var fragment;

            if (this.runsInBrowser()) {

                if (this.$.useState) {
                    fragment = (window.history.state || {}).fragment || "";
                } else {
                    fragment = decodeURI(window.location.hash);
                }

            } else {
                fragment = this.$history[this.$history.length - 1] || "";
            }

            return fragment.replace(routeStripper, '');
        },
        /***
         * This method is called to start the history
         * @param {Function} callback - get's called after the navigation is completed
         * @param {String} initialHash
         */
        start: function (callback, initialHash) {

            var self = this,
                fragment;

            this.$checkUrlFn = function () {
                self.checkUrl.apply(self, arguments);
            };

            if (this.runsInBrowser()) {
                // we're in a browser

                if (this.$.useState) {

                    fragment = window.location.pathname;
                    fragment = fragment.replace(new RegExp("^" + (this.$.baseUrl || "")), "");

                    if (window.addEventListener) {
                        window.addEventListener('popstate', this.$checkUrlFn, false);
                    } else {
                        window.attachEvent('onpopstate', this.$checkUrlFn);
                    }

                } else {

                    if ("onhashchange" in window) {
                        if (window.addEventListener) {
                            window.addEventListener('hashchange', this.$checkUrlFn, false);
                        } else {
                            window.attachEvent('onhashchange', this.$checkUrlFn);
                        }
                    } else {
                        // polling
                        this.$checkUrlInterval = setInterval(this.$checkUrlFn, this.$.interval);
                    }
                }

            } else {
                // rendering on node
                this.$history.push(initialHash || "");
            }

            fragment = fragment || this._getFragment();

            this.navigate(fragment, false, true, true, callback);
            this.$processUrl = true;
        },
        /***
         * Removes all onhaschange listeners or clears polling interval for hash check
         */
        stop: function () {
            if (typeof window !== "undefined") {

                if (this.$.useState) {
                    if (window.removeEventListener) {
                        window.removeEventListener('popstate', this.$checkUrlFn, false);
                    } else {
                        window.detachEvent('onpopstate', this.$checkUrlFn);
                    }
                } else {
                    if ("onhashchange" in window) {
                        if (window.removeEventListener) {
                            window.removeEventListener('hashchange', this.$checkUrlFn, false);
                        } else {
                            window.detachEvent('onhashchange', this.$checkUrlFn);
                        }
                    } else {
                        // polling
                        clearInterval(this.$checkUrlInterval);
                    }
                }
            }
        },

        /**
         * Adds a router to the history instance
         *
         * @param router
         */
        addRouter: function (router) {
            this.$routers.push(router);
        },

        /**
         * Checks if the current fragment has changed and calls navigate in case it did
         *
         */
        checkUrl: function () {

            if (this.$processUrl) {
                var currentFragment = this._getFragment();
                if (currentFragment == this.$fragment) {
                    return false;
                }

                this.navigate(currentFragment, !this.$.useState, true, true, emptyCallback);
            }

            this.$processUrl = true;

        },
        /**
         * Triggers a route
         *
         * @param {String} fragment - the fragment which should be triggered
         * @param {Function} callback - gets called after the route execution stack is done
         */
        triggerRoute: function (fragment, callback) {

            var routeExecutionStack = [];

            for (var i = 0; i < this.$routers.length; i++) {
                routeExecutionStack = routeExecutionStack.concat(this.$routers[i].generateRoutingStack(fragment));
            }

            if (routeExecutionStack.length === 0) {
                this.log("no route for '" + fragment + "' found.");
                // no route found but
                if (callback) {
                    // execute callback
                    callback();
                }
            } else {
                flow()
                    .seqEach(routeExecutionStack, function(routingFunction, cb){
                        routingFunction(cb);
                    })
                    .exec(callback);
            }
        },

        /***
         * Navigates to a fragment
         * @param {String} fragment
         * @param {Boolean} [createHistoryEntry] - default true
         * @param {Boolean} [triggerRoute] - default true
         * @param force
         * @param {Function} callback - navigate callback
         */
        navigate: function (fragment, createHistoryEntry, triggerRoute, force, callback) {

            var self = this;

            if (!callback && createHistoryEntry instanceof Function) {
                callback = createHistoryEntry;
                createHistoryEntry = null;
            }

            if (!callback && triggerRoute instanceof Function) {
                callback = triggerRoute;
                triggerRoute = null;
            }

            if (!callback && force instanceof Function) {
                callback = force;
                force = null;
            }

            if (createHistoryEntry == undefined || createHistoryEntry === null) {
                createHistoryEntry = true;
            }

            if (triggerRoute == undefined || triggerRoute === null) {
                triggerRoute = true;
            }

            var eventData = {
                fragment: fragment,
                createHistoryEntry: createHistoryEntry,
                triggerRoute: triggerRoute
            };

            var urlChange = this._getFragment() !== fragment;

            if (!urlChange && !force) {
                callback && callback();
                return;
            }

            this.trigger(History.EVENTS.NAVIGATION_START, eventData);
            this.$processUrl = urlChange;

            if (createHistoryEntry) {
                if (this.runsInBrowser()) {
                    if (this.$.useState) {

                        console.log("Pushing " + fragment + " to history");

                        window.history.pushState({
                            fragment: "/" + fragment
                        }, null, this.$.baseUrl + fragment);
                    } else {
                        window.location.hash = "/" + encodeURI(fragment);
                    }
                } else {
                    this.checkUrl(null);
                }
                this.$history.push(fragment);
            } else {
                if (this.runsInBrowser()) {

                    if (this.$.useState) {

                        console.log("Replacing " + fragment + " to history");

                        window.history.replaceState({
                            fragment: "/" + fragment
                        }, null, this.$.baseUrl + fragment);
                    } else {
                        // replace hash
                        window.location.replace("#/" + fragment);
                    }
                }
                this.$history[this.$history.length - 1] = fragment;
            }

            this.$processUrl = true;

            if(this.$fragment !== fragment){
                this.$fragment = fragment;
                this.trigger('change:fragment', this.$fragment);
            }

            if (triggerRoute) {
                this.triggerRoute(fragment, function() {
                    self.trigger(History.EVENTS.NAVIGATION_COMPLETE, eventData);
                    if (callback) {
                        callback.apply(self, arguments);
                    }
                });
            } else {
                this.trigger(History.EVENTS.NAVIGATION_COMPLETE, eventData);
            }
        }
    });

    History.EVENTS = {
        NAVIGATION_START: "navigationStart",
        NAVIGATION_COMPLETE: "navigationComplete"
    };

    return History;
});<|endoftext|>


<commit_before>(function($) {
  /**
   * An OpenSeadragon interface for the Djatoka tile server.  It is based
   * on Doug Reside's DjatokaSeadragon, but modified to work with the newer fork
   * of OpenSeadragon that's being developed by Chris Thatcher at LoC.
   *
   * https://github.com/dougreside/DjatokaSeadragon
   * https://github.com/thatcher/openseadragon
   *
   * @class
   * @extends Seadragon.TileSource
   * @param {string} imageID
   *   The UR{I,L} of the image.
   */
  $.DjatokaTileSource = function(imageID, settings) {
    var that = this;
    var djatoka_get_params = {
      'url_ver': 'Z39.88-2004',
      'rft_id': imageID,
      'svc_id': 'info:lanl-repo/svc/getMetadata'
    };
    this.baseURL = '/adore-djatoka/resolver';
    this.imageID = imageID;
    var djatoka_get_success = function(data, textStatus, jqXHR) {
      $.TileSource.call(
	that,
	parseInt(data.width),
	parseInt(data.height),
	parseInt(settings.tileSize),
	parseInt(settings.tileOverlap),
	1,
	parseInt(data.levels)
      );
      //XXX:  Kinda gross, but Seadragon.TileSource put the methods directly
      // on the object, not through "prototype"...
      that.getTileUrl = $.DjatokaTileSource.prototype.getTileUrl;
    };
    jQuery.ajaxSetup({async: false});
    jQuery.get(this.baseURL, djatoka_get_params, djatoka_get_success, 'json');
    jQuery.ajaxSetup({async:true});
  };
  jQuery.extend($.DjatokaTileSource.prototype, $.TileSource.prototype); // Inherit from TileSource.
  /**
   * Implement the abstract function.
   *
   * @function
   * @name Seadragon.DjatokaTileSource.prototype.getTileUrl
   *
   * @param {Number} level
   * @param {Number} x
   * @param {Number} y
   */
  $.DjatokaTileSource.prototype.getTileUrl = function(level, x, y) {
    /**
     *  XXX:  According to docs at http://sourceforge.net/apps/mediawiki/djatoka/index.php?title=Djatoka_OpenURL_Services#info:lanl-repo.2Fsvc.2FgetRegion,
     *  something like the following should work; however, seems that djatoka
     *  dies with a number format error while trying to parse as integers.
     *  (The bounds returned are "normalized" such that the width is between
     *  0 and 1, and the height is between 0 and the aspect ratio)
     *  var region = bounds.y + ',' + bounds.x +  ',' + bounds.height + ',' + bounds.width;
     */
    var bounds = this.getTileBounds(level, x, y);
    var scale = this.getLevelScale(level);
    // XXX:  Instead, we have to multiply and cast.
    var region = (bounds.y * this.dimensions.y * this.aspectRatio).toFixed() + ',' +
      (bounds.x * this.dimensions.x).toFixed() +  ',' +
      this.tileSize + ',' +
      this.tileSize;
    // Djatoka parameters
    var params = {
      'url_ver': 'Z39.88-2004',
      'rft_id': this.imageID,
      'svc_id': 'info:lanl-repo/svc/getRegion',
      'svc_val_fmt': 'info:ofi/fmt:kev:mtx:jpeg2000',
      'svc.region': region,
      'svc.level': level
    };
    return this.baseURL + '?' + jQuery.param(params);
  };
}(OpenSeadragon));
<commit_msg>LAADP-40: Review and debug the openseadragon.js TileSource interface and the default implementations and debug why the DjakotaTileSource implementation was not working. The problem is that looks that is using the API of old openseadragon version and with the last library version there are changes on how this should be implemented. I fixed it but still is needed a way to determine an image properties to correctly initialize the TileSource.<commit_after>(function($) {
  /**
  * An OpenSeadragon interface for the Djatoka tile server.  It is based
  * on Doug Reside's DjatokaSeadragon, but modified to work with the newer fork
  * of OpenSeadragon that's being developed by Chris Thatcher at LoC.
  *
  * https://github.com/dougreside/DjatokaSeadragon
  * https://github.com/thatcher/openseadragon
  *
  * @class
  * @extends Seadragon.TileSource
  * @param {string} imageID
  *   The UR{I,L} of the image.
  */
  $.DjatokaTileSource = function(imageID, settings) {
    var that = this;
    var djatoka_get_params = {
      'url_ver': 'Z39.88-2004',
      'rft_id': imageID,
      'svc_id': 'info:lanl-repo/svc/getMetadata'
    };
    this.baseURL = 'http://digital.library.ucla.edu/adore-djatoka/resolver';
    this.imageID = imageID;
    var options = {
      width: 6415,
      height: 8000,
      tileSize: settings.tileSize,
      tileOverlap: settings.tileOverlap,
      minLevel: 1,
      maxLevel: 5,
    };

    var djatoka_get_success = function(data, textStatus, jqXHR) {
    };

    jQuery.ajaxSetup({async: false});
    jQuery.get(this.baseURL, djatoka_get_params, djatoka_get_success, 'json');
    jQuery.ajaxSetup({async:true});

    $.TileSource.apply( this, [ options ] );
  };

  $.extend($.DjatokaTileSource.prototype, $.TileSource.prototype, {
    /**
    * @function
    * @name Seadragon.DjatokaTileSource.prototype.getTileUrl
    * @param {Number} level
    * @param {Number} x
    * @param {Number} y
    */
    getTileUrl: function(level, x, y) {
      var bounds = this.getTileBounds(level, x, y);
      var scale = this.getLevelScale(level);
      var region = (bounds.y * this.dimensions.y * this.aspectRatio).toFixed() + ',' +
        (bounds.x * this.dimensions.x).toFixed() +  ',' + this.tileSize + ',' + this.tileSize;
      // Djatoka parameters
      var params = {
        'url_ver': 'Z39.88-2004',
        'rft_id': this.imageID,
        'svc_id': 'info:lanl-repo/svc/getRegion',
        'svc_val_fmt': 'info:ofi/fmt:kev:mtx:jpeg2000',
        'svc.region': region,
        'svc.level': level
      };
      return this.baseURL + '?' + jQuery.param(params);
    }
  });
}(OpenSeadragon));
<|endoftext|>


<commit_before>(function () {

	var host = "meotrics.com";
	if(location.hostname == "client.meotrics.dev") host = "meotrics.dev";
	var encodeFunction = encodeURIComponent, i = 0, j = 0, isready, request_queue2 = [], doc = document;

	var T = 2000;
	var SESSIONGAP = 1200;
	var STARTANDLEAVE;
	var ISBLUR, lastcycle,totaltime,totalidle;
	var lefttime;

	function init()
	{
		totaltime = 0;
		totalidle = 0;
		STARTANDLEAVE = ISBLUR = lastcycle = lefttime = undefined;
	}

	function attach(event, fn)
	{
		if (window.addEventListener)
			window.addEventListener(event, fn, false);
		else if (window.attachEvent)
			window.attachEvent('on' + event, fn);
	}

	function interact(){
		totalidle = 0;
	}

	attach("beforeunload", function (e) {
		var delta = Math.round(new Date().getTime() / 1000) - lastcycle;
		stopsession(totaltime+delta);
	});

	attach('keydown', interact);
	attach('mousemove', interact);
	attach('mousedown', interact);
	attach('scroll', interact);
	attach('resize', interact);
	attach('pagehide', interact);
	attach('pageshow', interact);

	attach('blur', function(){
		ISBLUR = true;
		lefttime = Math.round(new Date().getTime() / 1000);
	})

	attach('focus', function(){
		if(ISBLUR === undefined){
			startsession()
		}
		if(ISBLUR === false) return;
		if(ISBLUR === true)
		{
			var delta = Math.round(new Date().getTime() / 1000) - lefttime;
			//the user has left for too long
			if(delta > SESSIONGAP)
			{
				stopsession(totaltime);
				startsession();
				return;
			}
			else
			{}
		}
		ISBLUR = false;
	});

	function stopsession(sessiontime)
	{
		ISBLUR = undefined;
		ajax('x/' + mt.actionid, {sessiontime: sessiontime});
	}

	function addIframeLink(){
		var ifm = doc.createElement('iframe');
		ifm.style.display="none";
		ifm.src = "//" + host + "/iframe.html?x=" + mt.appid + '-' + mt.actionid;
		if(doc.body === undefined) doc.head.appendChild(ifm);
		else doc.body.appendChild(ifm);
	}

	var startsession = mt.startsession = function ()
	{
		console.log('start session');
		//start a new pageview
		mt.track('pageview', {_link: null, _callback : true},0, function(){
			init();
			addIframeLink();
		});
	}

	function backgroundtimer()
	{
		console.log('cycle');
		if(ISBLUR === false)
		{
			totalidle+=T;
			totaltime+=T;
			if(totalidle > SESSIONGAP)
				stopsession(Math.max(totaltime, SESSIONGAP));
		}
		lastcycle = Math.round(new Date().getTime() / 1000);
		return setTimeout(backgroundtimer, T)
	}

	function ajax(url, data, callback) {
		var script = doc.createElement('script');
		// script.type = 'text/javascript'; comment this because we dont need to excute the script
		script.src = '//api.' + host + "/" + mt.appid + '/' + url + (data ? '?' + serialize(data) : '');
		script.style.display = 'none';
		script.onreadystatechange = script.onload = callback;//for IE
		doc.body === undefined ? doc.head.appendChild(script) : doc.body.appendChild(script);
	}

	function serialize(obj, prefix) {
		var str = [];
		for (var p in obj)/* if (obj.hasOwnProperty(p)) */{
			var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
			str.push(v instanceof Object ? serialize(v, k) : encodeFunction(k) + "=" + encodeFunction(v));
		}
		return str.join("&");
	}

	mt.info = function (data, callback, callback2, callback3) {
		if(typeof data == 'string') data = {userid: data};
		if(isready)
			ajax('info', data, callback || callback3)
		else{
			request_queue2.push(['info', data]);
			(callback || callback3)();
		}
	};

	mt.clear = function (callback, callback2, callback3, callback4) {
		if(isready)
			 ajax('clear', callback3 /*alway undefined, use callback3 for better minify*/, callback || callback4);
		else{
			request_queue2.push(['clear']);
			(callback || callback4)();
		}
	};

	mt.track = function (event, data, time, callback) {
		data._deltat = (new Date() - time) / 1000;
		data._typeid = event;
		if(isready) ajax('track', addVisitorPlatform(data), callback)
		else
		{
			request_queue2.push(['track', event, data, new Date()]);
			callback();
		}
	};

	function addVisitorPlatform(data) {
		data._ref = doc.referrer;
		data._scr = screen.width + "x" + screen.height;
		data._url = location.href;
		if(data._link === undefined) data._link = mt.actionid;
		return data;
	}

	// clean request queue
	function cleanRequest() {
		// clean queue number 2 when out of element in queue number 1
		if (i >= mt.rq.length) {
			isready = 1;
			return cleanRequest2();
		}
		var rq = mt.rq[i++];
		mt[rq[0]](rq[1], rq[2], rq[3], cleanRequest);
	}

	// clean request queue step 2
	function cleanRequest2() {
		if (j < request_queue2.length) // clean the state when done
		{
			var rq = request_queue2[j++];
			mt[rq[0]](rq[1], rq[2], rq[3], cleanRequest2);
		}
	}

	mt.excute = function(event){
		var data = JSON.parse(event.data);
		mt.actionid = data.actionid;
		if(data.lastactionid !== undefined)
		{
			var o1 = {
				actionid : data.actionid,
				lastactionid: data.lastactionid
			}
			addVisitorPlatform(o1);
			ajax('fix',o1);
		}
		else
		{
			var o2 = {actionid : data.actionid};
			addVisitorPlatform(o2);
			ajax('fix', o2);
		}
		cleanRequest();// excute delayed request in queue
	}
	init();
	backgroundtimer();
	addIframeLink();
	mt.onready();
})();<commit_msg>add limit non interact time<commit_after>(function () {

	var host = "meotrics.com";
	if(location.hostname == "client.meotrics.dev") host = "meotrics.dev";
	var encodeFunction = encodeURIComponent, i = 0, j = 0, isready, request_queue2 = [], doc = document;

	var T = 2;
	var SESSIONGAP = 1200;
	var STARTANDLEAVE;
	var ISBLUR, lastcycle,totaltime,totalidle;
	var lefttime;
	var canstartnewsession = false;
	function init()
	{
		totaltime = 0;
		totalidle = 0;
		STARTANDLEAVE = ISBLUR = lastcycle = lefttime = undefined;
	}

	function attach(event, fn)
	{
		if (window.addEventListener)
			window.addEventListener(event, fn, false);
		else if (window.attachEvent)
			window.attachEvent('on' + event, fn);
	}

	function interact(){
		ISBLUR = false;
		totalidle = 0;
		if(canstartnewsession) startsession();
		canstartnewsession = false;
	}

	attach("beforeunload", function (e) {
		var delta = Math.round(new Date().getTime() / 1000) - lastcycle;
		stopsession(totaltime+delta);
	});

	attach('keydown', interact);
	attach('mousemove', interact);
	attach('mousedown', interact);
	attach('scroll', interact);
	attach('resize', interact);
	attach('pagehide', interact);
	attach('pageshow', interact);

	attach('blur', function(){
		ISBLUR = true;
		lefttime = Math.round(new Date().getTime() / 1000);
	})

	attach('focus', function(){
		if(ISBLUR === undefined){
			startsession()
		}
		if(ISBLUR === false) return;
		if(ISBLUR === true)
		{
			var delta = Math.round(new Date().getTime() / 1000) - lefttime;
			//the user has left for too long
			if(delta > SESSIONGAP)
			{
				stopsession(totaltime);
				startsession();
				return;
			}
			else
			{}
		}
		ISBLUR = false;
	});

	function stopsession(sessiontime)
	{
		ISBLUR = undefined;
		ajax('x/' + mt.actionid, {sessiontime: sessiontime});
	}

	function addIframeLink(){
		var ifm = doc.createElement('iframe');
		ifm.style.display="none";
		ifm.src = "//" + host + "/iframe.html?x=" + mt.appid + '-' + mt.actionid;
		if(doc.body === undefined) doc.head.appendChild(ifm);
		else doc.body.appendChild(ifm);
	}

	var startsession = mt.startsession = function ()
	{
		//start a new pageview
		mt.track('pageview', {_link: null, _callback : true},0, function(){
			init();
			addIframeLink();
		});
	}

	function backgroundtimer()
	{
		if(ISBLUR === false)
		{
			totalidle+=T;
			totaltime+=T;
			if(totalidle > SESSIONGAP){
				stopsession(Math.max(totaltime, SESSIONGAP));
				canstartnewsession = true;
			}
		}
		lastcycle = Math.round(new Date().getTime() / 1000);
		return setTimeout(backgroundtimer, T*1000)
	}

	function ajax(url, data, callback) {
		var script = doc.createElement('script');
		// script.type = 'text/javascript'; comment this because we dont need to excute the script
		script.src = '//api.' + host + "/" + mt.appid + '/' + url + (data ? '?' + serialize(data) : '');
		script.style.display = 'none';
		script.onreadystatechange = script.onload = callback;//for IE
		doc.body === undefined ? doc.head.appendChild(script) : doc.body.appendChild(script);
	}

	function serialize(obj, prefix) {
		var str = [];
		for (var p in obj)/* if (obj.hasOwnProperty(p)) */{
			var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
			str.push(v instanceof Object ? serialize(v, k) : encodeFunction(k) + "=" + encodeFunction(v));
		}
		return str.join("&");
	}

	mt.info = function (data, callback, callback2, callback3) {
		if(typeof data == 'string') data = {userid: data};
		if(isready)
			ajax('info', data, callback || callback3)
		else{
			request_queue2.push(['info', data]);
			(callback || callback3)();
		}
	};

	mt.clear = function (callback, callback2, callback3, callback4) {
		if(isready)
			 ajax('clear', callback3 /*alway undefined, use callback3 for better minify*/, callback || callback4);
		else{
			request_queue2.push(['clear']);
			(callback || callback4)();
		}
	};

	mt.track = function (event, data, time, callback) {
		data._deltat = (new Date() - time) / 1000;
		data._typeid = event;
		if(isready) ajax('track', addVisitorPlatform(data), callback)
		else
		{
			request_queue2.push(['track', event, data, new Date()]);
			callback();
		}
	};

	function addVisitorPlatform(data) {
		data._ref = doc.referrer;
		data._scr = screen.width + "x" + screen.height;
		data._url = location.href;
		if(data._link === undefined) data._link = mt.actionid;
		return data;
	}

	// clean request queue
	function cleanRequest() {
		// clean queue number 2 when out of element in queue number 1
		if (i >= mt.rq.length) {
			isready = 1;
			return cleanRequest2();
		}
		var rq = mt.rq[i++];
		mt[rq[0]](rq[1], rq[2], rq[3], cleanRequest);
	}

	// clean request queue step 2
	function cleanRequest2() {
		if (j < request_queue2.length) // clean the state when done
		{
			var rq = request_queue2[j++];
			mt[rq[0]](rq[1], rq[2], rq[3], cleanRequest2);
		}
	}

	mt.excute = function(event){
		var data = JSON.parse(event.data);
		mt.actionid = data.actionid;
		if(data.lastactionid !== undefined)
		{
			var o1 = {
				actionid : data.actionid,
				lastactionid: data.lastactionid
			}
			addVisitorPlatform(o1);
			ajax('fix',o1);
		}
		else
		{
			var o2 = {actionid : data.actionid};
			addVisitorPlatform(o2);
			ajax('fix', o2);
		}
		cleanRequest();// excute delayed request in queue
	}
	init();
	backgroundtimer();
	addIframeLink();
	mt.onready();
})();<|endoftext|>


<commit_before>/**
 * a HUD container and child items
 */

game.HUD = game.HUD || {};

game.HUD.Container = me.Container.extend({

    init: function() {
        // call the constructor
        this._super(me.Container, 'init');

        // persistent across level change
        this.isPersistent = true;

        // make sure we use screen coordinates
        this.floating = true;

        // make sure our object is always draw first
        this.z = Infinity;

        // give a name
        this.name = "HUD";

        // add our child score object at the top left corner
        this.addChild(new game.HUD.ScoreItem(5, 5));
    }
});

/**
 * a basic HUD item to display score
 */
game.HUD.ScoreItem = me.Renderable.extend({
    /**
     * constructor
     */
    init: function(x, y) {

        // call the parent constructor
        // (size does not matter here)
        this._super(me.Renderable, 'init', [x, y, 10, 10]);

        // local copy of the global score
        this.score = -1;
    },

    /**
     * update function
     */
    update : function () {
        // we don't do anything fancy here, so just
        // return true if the score has been updated
        if (this.score !== game.data.score) {
            this.score = game.data.score;
            return true;
        }
        return false;
    },

    /**
     * draw the score
     */
    draw : function (context) {
        // draw it baby !
    }

});
<commit_msg>remove HUD's ScoreItem<commit_after>/**
 * a HUD container and child items
 */

game.HUD = game.HUD || {};

game.HUD.Container = me.Container.extend({

    init: function() {
        // call the constructor
        this._super(me.Container, 'init');

        // persistent across level change
        this.isPersistent = true;

        // make sure we use screen coordinates
        this.floating = true;

        // make sure our object is always draw first
        this.z = Infinity;

        // give a name
        this.name = "HUD";
    }
});
<|endoftext|>


<commit_before>'use strict';

function draw_logic(){
    for(var firework in fireworks){
        canvas_buffer.fillStyle = fireworks[firework]['color'];
        canvas_buffer.fillRect(
          fireworks[firework]['x'],
          fireworks[firework]['y'],
          fireworks[firework]['width'],
          fireworks[firework]['height']
        );
    }
}

function launch(firework){
    var firework = firework || {};
    firework['children'] = firework['children'] !== void 0
      ? firework['children']
      : 10;
    firework['color'] = firework['color'] || random_hex();
    firework['dx'] = firework['dx'] || Math.random() * 4 - 2;
    firework['dy'] = firework['dy'] || -(canvas_height / 200) - Math.random() * 2;
    firework['height'] = firework['height'] || 4;
    firework['timer'] = firework['timer'] || random_integer(200) + 100;
    firework['width'] = firework['width'] || 4;
    firework['x'] = firework['x'] || canvas_x;
    firework['y'] = firework['y'] || canvas_height;

    fireworks.push(firework);
}

function logic(){
    for(var firework in fireworks){
        fireworks[firework]['x'] += fireworks[firework]['dx'];
        fireworks[firework]['y'] += fireworks[firework]['dy'];

        fireworks[firework]['dy'] += .02;
        fireworks[firework]['dx'] *= .99;

        fireworks[firework]['timer'] -= 1;
        if(fireworks[firework]['timer'] <= 0){
            if(fireworks[firework]['children'] > 0){
                var loop_counter = fireworks[firework]['children'] - 1;
                do{
                    launch({
                      'children': 0,
                      'dx': Math.random() * 3 - 1.5,
                      'dy': Math.random() * 3 - 1.5,
                      'x': fireworks[firework]['x'],
                      'timer': random_integer(99) + 42,
                      'y': fireworks[firework]['y'],
                    });
                }while(loop_counter--);
            }

            fireworks.splice(
              firework,
              1
            );
        }
    }
}

var fireworks = [];

window.onload = function(e){
    canvas_init();
    input_init(
      {
        27: {
          'solo': true,
          'todo': function(){
              fireworks.length = 0;
          },
        },
        'all': {
          'todo': launch,
        },
      },
      {
        'mousedown': {
          'todo': launch,
        },
      }
    );
    launch();
};
<commit_msg>switched random.js to args<commit_after>'use strict';

function draw_logic(){
    for(var firework in fireworks){
        canvas_buffer.fillStyle = fireworks[firework]['color'];
        canvas_buffer.fillRect(
          fireworks[firework]['x'],
          fireworks[firework]['y'],
          fireworks[firework]['width'],
          fireworks[firework]['height']
        );
    }
}

function launch(firework){
    var firework = firework || {};
    firework['children'] = firework['children'] !== void 0
      ? firework['children']
      : 10;
    firework['color'] = firework['color'] || random_hex();
    firework['dx'] = firework['dx'] || Math.random() * 4 - 2;
    firework['dy'] = firework['dy'] || -(canvas_height / 200) - Math.random() * 2;
    firework['height'] = firework['height'] || 4;
    firework['timer'] = firework['timer'] || random_integer({
      'max': 200,
    }) + 100;
    firework['width'] = firework['width'] || 4;
    firework['x'] = firework['x'] || canvas_x;
    firework['y'] = firework['y'] || canvas_height;

    fireworks.push(firework);
}

function logic(){
    for(var firework in fireworks){
        fireworks[firework]['x'] += fireworks[firework]['dx'];
        fireworks[firework]['y'] += fireworks[firework]['dy'];

        fireworks[firework]['dy'] += .02;
        fireworks[firework]['dx'] *= .99;

        fireworks[firework]['timer'] -= 1;
        if(fireworks[firework]['timer'] <= 0){
            if(fireworks[firework]['children'] > 0){
                var loop_counter = fireworks[firework]['children'] - 1;
                do{
                    launch({
                      'children': 0,
                      'dx': Math.random() * 3 - 1.5,
                      'dy': Math.random() * 3 - 1.5,
                      'x': fireworks[firework]['x'],
                      'timer': random_integer({
                        'max': 99,
                      }) + 42,
                      'y': fireworks[firework]['y'],
                    });
                }while(loop_counter--);
            }

            fireworks.splice(
              firework,
              1
            );
        }
    }
}

var fireworks = [];

window.onload = function(e){
    canvas_init();
    input_init(
      {
        27: {
          'solo': true,
          'todo': function(){
              fireworks.length = 0;
          },
        },
        'all': {
          'todo': launch,
        },
      },
      {
        'mousedown': {
          'todo': launch,
        },
      }
    );
    launch();
};
<|endoftext|>