<commit_before>/*
 * mobile slider unit tests
 */

(function($){
	var onChangeCnt = 0;
	window.onChangeCounter = function() {
		onChangeCnt++;
	};

	module('jquery.mobile.slider.js', {
		setup: function() {
			// force the value to be an increment of 10 when we aren't testing the rounding
			$("#stepped").val( 20 );
		}
	});

	var keypressTest = function(opts){
		var slider = $(opts.selector),
		    val = window.parseFloat(slider.val()),
				handle = slider.siblings('.ui-slider').find('.ui-slider-handle');

		expect( opts.keyCodes.length );

		$.each(opts.keyCodes, function(i, elem){

			// stub the keycode value and trigger the keypress
			$.Event.prototype.keyCode = $.mobile.keyCode[elem];
			handle.trigger('keydown');

			val += opts.increment;
			same(val, window.parseFloat(slider.val(), 10), "new value is " + opts.increment + " different");
		});
	};

	test( "slider should move right with up, right, and page up keypress", function(){
		keypressTest({
			selector: '#range-slider-up',
			keyCodes: ['UP', 'RIGHT', 'PAGE_UP'],
			increment: 1
		});
	});

	test( "slider should move left with down, left, and page down keypress", function(){
		keypressTest({
			selector: '#range-slider-down',
			keyCodes: ['DOWN', 'LEFT', 'PAGE_DOWN'],
			increment: -1
		});
	});

	test( "slider should move to range minimum on end keypress", function(){
		var selector = "#range-slider-end",
				initialVal = window.parseFloat($(selector).val(), 10),
		    max = window.parseFloat($(selector).attr('max'), 10);

		keypressTest({
			selector: selector,
			keyCodes: ['END'],
			increment: max - initialVal
		});
	});

	test( "slider should move to range minimum on end keypress", function(){
		var selector = "#range-slider-home",
				initialVal = window.parseFloat($(selector).val(), 10);

		keypressTest({
			selector: selector,
			keyCodes: ['HOME'],
			increment: 0 - initialVal
		});
	});

	test( "slider should move positive by steps on keypress", function(){
		keypressTest({
			selector: "#stepped",
			keyCodes: ['RIGHT'],
			increment: 10
		});
	});

	test( "slider should move negative by steps on keypress", function(){
		keypressTest({
			selector: "#stepped",
			keyCodes: ['LEFT'],
			increment: -10
		});
	});

	test( "slider should validate input value on blur", function(){
		var slider = $("#range-slider-up");
		slider.focus();
		slider.val(200);
		same(slider.val(), "200");
		slider.blur();
		same(slider.val(), slider.attr('max'));
	});

	test( "slider should not validate input on keyup", function(){
		var slider = $("#range-slider-up");
		slider.focus();
		slider.val(200);
		same(slider.val(), "200");
		slider.keyup();
		same(slider.val(), "200");
	});

	test( "input type should degrade to number when slider is created", function(){
		same($("#range-slider-up").attr( "type" ), "number");
	});

	// generic switch test function
	var sliderSwitchTest = function(opts){
		var slider = $("#slider-switch"),
			  handle = slider.siblings('.ui-slider').find('a'),
		    switchValues = {
					'off' : 0,
					'on' : 1
				};

		// One for the select and one for the aria-valuenow
		expect( opts.keyCodes.length * 2 );

		$.each(opts.keyCodes, function(i, elem){
			// reset the values
			slider[0].selectedIndex = switchValues[opts.start];
			handle.attr({'aria-valuenow' : opts.start });

			// stub the keycode and trigger the event
			$.Event.prototype.keyCode = $.mobile.keyCode[elem];
			handle.trigger('keydown');

			same(handle.attr('aria-valuenow'), opts.finish, "handle value is " + opts.finish);
			same(slider[0].selectedIndex, switchValues[opts.finish], "select input has correct index");
		});
	};

	test( "switch should select on with up, right, page up and end", function(){
		sliderSwitchTest({
			start: 'off',
			finish: 'on',
			keyCodes: ['UP', 'RIGHT', 'PAGE_UP', 'END']
		});
	});

	test( "switch should select off with down, left, page down and home", function(){
		sliderSwitchTest({
			start: 'on',
			finish: 'off',
		  keyCodes: ['DOWN', 'LEFT', 'PAGE_DOWN', 'HOME']
		});
	});

	test( "onchange should not be called on create", function(){
		equals(onChangeCnt, 0, "onChange should not have been called");
	});

	test( "onchange should be called onchange", function(){
		onChangeCnt = 0;
		$( "#onchange" ).slider( "refresh", 50 );
		equals(onChangeCnt, 1, "onChange should have been called once");
	});

	test( "slider controls will create when inside a container that receives a 'create' event", function(){
		ok( !$("#enhancetest").appendTo(".ui-page-active").find(".ui-slider").length, "did not have enhancements applied" );
		ok( $("#enhancetest").trigger("create").find(".ui-slider").length, "enhancements applied" );
	});

	var createEvent = function( name, target, x, y ) {
		var event = $.Event( name );
		event.target = target;
		event.pageX = x;
		event.pageY = y;
		return event;
	};

	test( "toggle switch should fire one change event when clicked", function(){
		var control = $( "#slider-switch" ),
			widget = control.data( "slider" ),
			slider = widget.slider,
			handle = widget.handle,
			changeCount = 0,
			changeFunc = function( e ) {
				ok( control[0].selectedIndex !== currentValue, "change event should only be triggered if the value changes");
				++changeCount;
			},
			event = null,
			offset = handle.offset(),
			currentValue = control[0].selectedIndex;

		control.bind( "change", changeFunc );

		// The toggle switch actually updates on mousedown and mouseup events, so we go through
		// the motions of generating all the events that happen during a click to make sure that
		// during all of those events, the value only changes once.

		slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
		slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
		slider.trigger( createEvent( "click", handle[ 0 ], offset.left + 10, offset.top + 10 ) );

		control.unbind( "change", changeFunc );

		ok( control[0].selectedIndex !== currentValue, "value did change");
		same( changeCount, 1, "change event should be fired once during a click" );
	});

	var assertLeftCSS = function( obj, opts ) {
		var integerLeft, compare, css, threshold;

		css = obj.css('left');
		threshold = opts.pxThreshold || 0;

		if( css.indexOf( "px" ) > -1 ) {
			// parse the actual pixel value returned by the left css value
			// and the pixels passed in for comparison
			integerLeft = Math.round( parseFloat( css.replace("px", "") ) ),
			compare = parseInt( opts.pixels.replace( "px", "" ), 10 );

			// check that the pixel value provided is within a given threshold; default is 0px
			ok( compare >= integerLeft - threshold && compare <= integerLeft + threshold, opts.message );
		} else {
			equal( css, opts.percent, opts.message );
		}
	};

	asyncTest( "toggle switch handle should snap in the old position if dragged less than half of the slider width, in the new position if dragged more than half of the slider width", function() {
		var control = $( "#slider-switch" ),
			widget = control.data( "slider" ),
			slider = widget.slider,
			handle = widget.handle,
			width = handle.width(),
			offset = null;

		$.testHelper.sequence([
			function() {
				// initialize the switch
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle starts on the right side'
				});

				// simulate dragging less than a half
				offset = handle.offset();
				slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + width - 10, offset.top + 10 ) );
				slider.trigger( createEvent( "mousemove", handle[ 0 ], offset.left + width - 20, offset.top + 10 ) );
				slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left + width - 20, offset.top + 10 ) );
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle ends on the right side'
				});

				// initialize the switch
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle starts on the right side'
				});

				// simulate dragging more than a half
				offset = handle.offset();
				slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
				slider.trigger( createEvent( "mousemove", handle[ 0 ], offset.left - ( width / 2 ), offset.top + 10 ) );
				slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left - ( width / 2 ), offset.top + 10 ) );
			},

			function() {
				assertLeftCSS(handle, {
					percent: '0%',
					pixels: '0px',
					message: 'handle ends on the left side'
				});

				start();
			}
		], 500);
	});

	asyncTest( "toggle switch handle should not move if user is dragging and value is changed", function() {
		var control = $( "#slider-switch" ),
			widget = control.data( "slider" ),
			slider = widget.slider,
			handle = widget.handle,
			width = handle.width(),
			offset = null;

		$.testHelper.sequence([
			function() {
				// initialize the switch
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle starts on the right side'
				});

				// simulate dragging more than a half
				offset = handle.offset();
				slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
				slider.trigger( createEvent( "mousemove", handle[ 0 ], offset.left - ( width / 2 ), offset.top + 10 ) );
			},

			function() {
				var min, max;
				if( handle.css('left').indexOf("%") > -1 ){
					min = "0%";
					max = "100%";
				} else {
					min = "0px";
					max = handle.parent().css( 'width' );
				}

				notEqual(handle.css('left'), min, 'handle is not on the left side');
				notEqual(handle.css('left'), max, 'handle is not on the right side');

				// reset slider state so it is ready for other tests
				slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left - ( width / 2 ), offset.top + 10 ) );

				start();
			}
		], 500);
	});

	asyncTest( "toggle switch should refresh when disabled", function() {
		var control = $( "#slider-switch" ),
			handle = control.data( "slider" ).handle;

		$.testHelper.sequence([
			function() {
				// set the initial value
				control.val('off').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '0%',
					pixels: '0px',
					message: 'handle starts on the left side'
				});

				// disable and change value
				control.slider('disable');
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css( 'width' ),
					message: 'handle ends on the right side'
				});

				// reset slider state so it is ready for other tests
				control.slider('enable');

				start();
			}
		], 500);
	});
})(jQuery);<commit_msg>short term fix for exact middle calculation in slider test<commit_after>/*
 * mobile slider unit tests
 */

(function($){
	var onChangeCnt = 0;
	window.onChangeCounter = function() {
		onChangeCnt++;
	};

	module('jquery.mobile.slider.js', {
		setup: function() {
			// force the value to be an increment of 10 when we aren't testing the rounding
			$("#stepped").val( 20 );
		}
	});

	var keypressTest = function(opts){
		var slider = $(opts.selector),
		    val = window.parseFloat(slider.val()),
				handle = slider.siblings('.ui-slider').find('.ui-slider-handle');

		expect( opts.keyCodes.length );

		$.each(opts.keyCodes, function(i, elem){

			// stub the keycode value and trigger the keypress
			$.Event.prototype.keyCode = $.mobile.keyCode[elem];
			handle.trigger('keydown');

			val += opts.increment;
			same(val, window.parseFloat(slider.val(), 10), "new value is " + opts.increment + " different");
		});
	};

	test( "slider should move right with up, right, and page up keypress", function(){
		keypressTest({
			selector: '#range-slider-up',
			keyCodes: ['UP', 'RIGHT', 'PAGE_UP'],
			increment: 1
		});
	});

	test( "slider should move left with down, left, and page down keypress", function(){
		keypressTest({
			selector: '#range-slider-down',
			keyCodes: ['DOWN', 'LEFT', 'PAGE_DOWN'],
			increment: -1
		});
	});

	test( "slider should move to range minimum on end keypress", function(){
		var selector = "#range-slider-end",
				initialVal = window.parseFloat($(selector).val(), 10),
		    max = window.parseFloat($(selector).attr('max'), 10);

		keypressTest({
			selector: selector,
			keyCodes: ['END'],
			increment: max - initialVal
		});
	});

	test( "slider should move to range minimum on end keypress", function(){
		var selector = "#range-slider-home",
				initialVal = window.parseFloat($(selector).val(), 10);

		keypressTest({
			selector: selector,
			keyCodes: ['HOME'],
			increment: 0 - initialVal
		});
	});

	test( "slider should move positive by steps on keypress", function(){
		keypressTest({
			selector: "#stepped",
			keyCodes: ['RIGHT'],
			increment: 10
		});
	});

	test( "slider should move negative by steps on keypress", function(){
		keypressTest({
			selector: "#stepped",
			keyCodes: ['LEFT'],
			increment: -10
		});
	});

	test( "slider should validate input value on blur", function(){
		var slider = $("#range-slider-up");
		slider.focus();
		slider.val(200);
		same(slider.val(), "200");
		slider.blur();
		same(slider.val(), slider.attr('max'));
	});

	test( "slider should not validate input on keyup", function(){
		var slider = $("#range-slider-up");
		slider.focus();
		slider.val(200);
		same(slider.val(), "200");
		slider.keyup();
		same(slider.val(), "200");
	});

	test( "input type should degrade to number when slider is created", function(){
		same($("#range-slider-up").attr( "type" ), "number");
	});

	// generic switch test function
	var sliderSwitchTest = function(opts){
		var slider = $("#slider-switch"),
			  handle = slider.siblings('.ui-slider').find('a'),
		    switchValues = {
					'off' : 0,
					'on' : 1
				};

		// One for the select and one for the aria-valuenow
		expect( opts.keyCodes.length * 2 );

		$.each(opts.keyCodes, function(i, elem){
			// reset the values
			slider[0].selectedIndex = switchValues[opts.start];
			handle.attr({'aria-valuenow' : opts.start });

			// stub the keycode and trigger the event
			$.Event.prototype.keyCode = $.mobile.keyCode[elem];
			handle.trigger('keydown');

			same(handle.attr('aria-valuenow'), opts.finish, "handle value is " + opts.finish);
			same(slider[0].selectedIndex, switchValues[opts.finish], "select input has correct index");
		});
	};

	test( "switch should select on with up, right, page up and end", function(){
		sliderSwitchTest({
			start: 'off',
			finish: 'on',
			keyCodes: ['UP', 'RIGHT', 'PAGE_UP', 'END']
		});
	});

	test( "switch should select off with down, left, page down and home", function(){
		sliderSwitchTest({
			start: 'on',
			finish: 'off',
		  keyCodes: ['DOWN', 'LEFT', 'PAGE_DOWN', 'HOME']
		});
	});

	test( "onchange should not be called on create", function(){
		equals(onChangeCnt, 0, "onChange should not have been called");
	});

	test( "onchange should be called onchange", function(){
		onChangeCnt = 0;
		$( "#onchange" ).slider( "refresh", 50 );
		equals(onChangeCnt, 1, "onChange should have been called once");
	});

	test( "slider controls will create when inside a container that receives a 'create' event", function(){
		ok( !$("#enhancetest").appendTo(".ui-page-active").find(".ui-slider").length, "did not have enhancements applied" );
		ok( $("#enhancetest").trigger("create").find(".ui-slider").length, "enhancements applied" );
	});

	var createEvent = function( name, target, x, y ) {
		var event = $.Event( name );
		event.target = target;
		event.pageX = x;
		event.pageY = y;
		return event;
	};

	test( "toggle switch should fire one change event when clicked", function(){
		var control = $( "#slider-switch" ),
			widget = control.data( "slider" ),
			slider = widget.slider,
			handle = widget.handle,
			changeCount = 0,
			changeFunc = function( e ) {
				ok( control[0].selectedIndex !== currentValue, "change event should only be triggered if the value changes");
				++changeCount;
			},
			event = null,
			offset = handle.offset(),
			currentValue = control[0].selectedIndex;

		control.bind( "change", changeFunc );

		// The toggle switch actually updates on mousedown and mouseup events, so we go through
		// the motions of generating all the events that happen during a click to make sure that
		// during all of those events, the value only changes once.

		slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
		slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
		slider.trigger( createEvent( "click", handle[ 0 ], offset.left + 10, offset.top + 10 ) );

		control.unbind( "change", changeFunc );

		ok( control[0].selectedIndex !== currentValue, "value did change");
		same( changeCount, 1, "change event should be fired once during a click" );
	});

	var assertLeftCSS = function( obj, opts ) {
		var integerLeft, compare, css, threshold;

		css = obj.css('left');
		threshold = opts.pxThreshold || 0;

		if( css.indexOf( "px" ) > -1 ) {
			// parse the actual pixel value returned by the left css value
			// and the pixels passed in for comparison
			integerLeft = Math.round( parseFloat( css.replace("px", "") ) ),
			compare = parseInt( opts.pixels.replace( "px", "" ), 10 );

			// check that the pixel value provided is within a given threshold; default is 0px
			ok( compare >= integerLeft - threshold && compare <= integerLeft + threshold, opts.message );
		} else {
			equal( css, opts.percent, opts.message );
		}
	};

	asyncTest( "toggle switch handle should snap in the old position if dragged less than half of the slider width, in the new position if dragged more than half of the slider width", function() {
		var control = $( "#slider-switch" ),
			widget = control.data( "slider" ),
			slider = widget.slider,
			handle = widget.handle,
			width = handle.width(),
			offset = null;

		$.testHelper.sequence([
			function() {
				// initialize the switch
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle starts on the right side'
				});

				// simulate dragging less than a half
				offset = handle.offset();
				slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + width - 10, offset.top + 10 ) );
				slider.trigger( createEvent( "mousemove", handle[ 0 ], offset.left + width - 20, offset.top + 10 ) );
				slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left + width - 20, offset.top + 10 ) );
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle ends on the right side'
				});

				// initialize the switch
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle starts on the right side'
				});

				// simulate dragging more than a half
				offset = handle.offset();
				slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
				slider.trigger( createEvent( "mousemove", handle[ 0 ], offset.left - ( width / 2 + 10 ), offset.top + 10 ) );
				slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left - ( width / 2 + 10 ), offset.top + 10 ) );
			},

			function() {
				assertLeftCSS(handle, {
					percent: '0%',
					pixels: '0px',
					message: 'handle ends on the left side'
				});

				start();
			}
		], 500);
	});

	asyncTest( "toggle switch handle should not move if user is dragging and value is changed", function() {
		var control = $( "#slider-switch" ),
			widget = control.data( "slider" ),
			slider = widget.slider,
			handle = widget.handle,
			width = handle.width(),
			offset = null;

		$.testHelper.sequence([
			function() {
				// initialize the switch
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css('width'),
					message: 'handle starts on the right side'
				});

				// simulate dragging more than a half
				offset = handle.offset();
				slider.trigger( createEvent( "mousedown", handle[ 0 ], offset.left + 10, offset.top + 10 ) );
				slider.trigger( createEvent( "mousemove", handle[ 0 ], offset.left - ( width / 2 ), offset.top + 10 ) );
			},

			function() {
				var min, max;
				if( handle.css('left').indexOf("%") > -1 ){
					min = "0%";
					max = "100%";
				} else {
					min = "0px";
					max = handle.parent().css( 'width' );
				}

				notEqual(handle.css('left'), min, 'handle is not on the left side');
				notEqual(handle.css('left'), max, 'handle is not on the right side');

				// reset slider state so it is ready for other tests
				slider.trigger( createEvent( "mouseup", handle[ 0 ], offset.left - ( width / 2 ), offset.top + 10 ) );

				start();
			}
		], 500);
	});

	asyncTest( "toggle switch should refresh when disabled", function() {
		var control = $( "#slider-switch" ),
			handle = control.data( "slider" ).handle;

		$.testHelper.sequence([
			function() {
				// set the initial value
				control.val('off').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '0%',
					pixels: '0px',
					message: 'handle starts on the left side'
				});

				// disable and change value
				control.slider('disable');
				control.val('on').slider('refresh');
			},

			function() {
				assertLeftCSS(handle, {
					percent: '100%',
					pixels: handle.parent().css( 'width' ),
					message: 'handle ends on the right side'
				});

				// reset slider state so it is ready for other tests
				control.slider('enable');

				start();
			}
		], 500);
	});
})(jQuery);<|endoftext|>


<commit_before>'use strict';

(function() {

    /**
     * @ngdoc overview
     * @name ngStorage
     */

    angular.module('ngStorage', []).

    /**
     * @ngdoc object
     * @name ngStorage.$localStorage
     * @requires $rootScope
     * @requires $window
     */

    factory('$localStorage', _storageFactory('localStorage')).

    /**
     * @ngdoc object
     * @name ngStorage.$sessionStorage
     * @requires $rootScope
     * @requires $window
     */

    factory('$sessionStorage', _storageFactory('sessionStorage'));

    function _storageFactory(storageType) {
        return [
            '$rootScope',
            '$window',
            '$log',

            function(
                $rootScope,
                $window,
                $log
            ){
                // #9: Assign a placeholder object if Web Storage is unavailable to prevent breaking the entire AngularJS app
                var webStorage = $window[storageType] || ($log.warn('This browser does not support Web Storage!'), {}),
                    $storage = {
                        $default: function(items) {
                            for (var k in items) {
                                angular.isDefined($storage[k]) || ($storage[k] = items[k]);
                            }

                            return $storage;
                        },
                        $reset: function(items) {
                            for (var k in $storage) {
                                '$' === k[0] || delete $storage[k];
                            }

                            return $storage.$default(items);
                        }
                    },
                    _last$storage,
                    _debounce;

                for (var i = 0, k; i < webStorage.length; i++) {
                    // #8, #10: `webStorage.key(i)` may be an empty string (or throw an exception in IE9 if `webStorage` is empty)
                    (k = webStorage.key(i)) && 'ngStorage-' === k.slice(0, 10) && ($storage[k.slice(10)] = angular.fromJson(webStorage.getItem(k)));
                }

                _last$storage = angular.copy($storage);

                $rootScope.$watch(function() {
                    _debounce || (_debounce = setTimeout(function() {
                        _debounce = null;

                        if (!angular.equals($storage, _last$storage)) {
                            angular.forEach($storage, function(v, k) {
                                angular.isDefined(v) && '$' !== k[0] && webStorage.setItem('ngStorage-' + k, angular.toJson(v));

                                delete _last$storage[k];
                            });

                            for (var k in _last$storage) {
                                webStorage.removeItem('ngStorage-' + k);
                            }

                            _last$storage = angular.copy($storage);
                        }
                    }, 100));
                });

                // #6: Use `$window.addEventListener` instead of `angular.element` to avoid the jQuery-specific `event.originalEvent`
                'localStorage' === storageType && $window.addEventListener && $window.addEventListener('storage', function(event) {
                    if ('ngStorage-' === event.key.slice(0, 10)) {
                        event.newValue ? $storage[event.key.slice(10)] = angular.fromJson(event.newValue) : delete $storage[event.key.slice(10)];

                        _last$storage = angular.copy($storage);

                        $rootScope.$apply();
                    }
                });

                return $storage;
            }
        ];
    }

})();
<commit_msg>added $scan to manualy sync ngStorage.<commit_after>'use strict';

(function() {

    /**
     * @ngdoc overview
     * @name ngStorage
     */

    angular.module('ngStorage', []).

    /**
     * @ngdoc object
     * @name ngStorage.$localStorage
     * @requires $rootScope
     * @requires $window
     */

    factory('$localStorage', _storageFactory('localStorage')).

    /**
     * @ngdoc object
     * @name ngStorage.$sessionStorage
     * @requires $rootScope
     * @requires $window
     */

    factory('$sessionStorage', _storageFactory('sessionStorage'));

    function _storageFactory(storageType) {
        return [
            '$rootScope',
            '$window',
            '$log',

            function(
                $rootScope,
                $window,
                $log
            ){
                // #9: Assign a placeholder object if Web Storage is unavailable to prevent breaking the entire AngularJS app
                var webStorage = $window[storageType] || ($log.warn('This browser does not support Web Storage!'), {}),
                    $storage = {
                        $default: function(items) {
                            for (var k in items) {
                                angular.isDefined($storage[k]) || ($storage[k] = items[k]);
                            }

                            return $storage;
                        },
                        $reset: function(items) {
                            for (var k in $storage) {
                                '$' === k[0] || delete $storage[k];
                            }

                            return $storage.$default(items);
                        },
                        $scan: function () {
                            for (var i = 0, k; i < webStorage.length; i++) {
                                // #8, #10: `webStorage.key(i)` may be an empty string (or throw an exception in IE9 if `webStorage` is empty)
                                (k = webStorage.key(i)) && 'ngStorage-' === k.slice(0, 10) && ($storage[k.slice(10)] = angular.fromJson(webStorage.getItem(k)));
                            }
                        }
                    },
                    _last$storage,
                    _debounce;

                $storage.$scan();

                _last$storage = angular.copy($storage);

                $rootScope.$watch(function() {
                    _debounce || (_debounce = setTimeout(function() {
                        _debounce = null;

                        if (!angular.equals($storage, _last$storage)) {
                            angular.forEach($storage, function(v, k) {
                                angular.isDefined(v) && '$' !== k[0] && webStorage.setItem('ngStorage-' + k, angular.toJson(v));

                                delete _last$storage[k];
                            });

                            for (var k in _last$storage) {
                                webStorage.removeItem('ngStorage-' + k);
                            }

                            _last$storage = angular.copy($storage);
                        }
                    }, 100));
                });

                // #6: Use `$window.addEventListener` instead of `angular.element` to avoid the jQuery-specific `event.originalEvent`
                'localStorage' === storageType && $window.addEventListener && $window.addEventListener('storage', function(event) {
                    if ('ngStorage-' === event.key.slice(0, 10)) {
                        event.newValue ? $storage[event.key.slice(10)] = angular.fromJson(event.newValue) : delete $storage[event.key.slice(10)];

                        _last$storage = angular.copy($storage);

                        $rootScope.$apply();
                    }
                });

                return $storage;
            }
        ];
    }

})();
<|endoftext|>


<commit_before>if (!!$.prototype.justifiedGallery) {  // if justifiedGallery method is defined
  var options = {
    rowHeight: 140,
    margins: 4,
    lastRow: 'justify'
  };
  $('.article-gallery').justifiedGallery(options);
}

$(document).ready(function(){
  $("#menu-icon, #menu-icon-tablet").click(function(){
    if ( $('#menu').css('visibility') == 'hidden' ) {
      $('#menu').css('visibility','visible');
      $('#menu-icon, #menu-icon-tablet').addClass('active');

      var topDistance = $("#menu > #nav").offset().top;

      if ( $('#menu').css('visibility') != 'hidden' && topDistance < 50 ) {
        $("#menu > #nav").show();
      } else if ($('#menu').css('visibility') != 'hidden' && topDistance > 100) {
        $("#menu > #nav").hide();
      }
      return false;
    } else {
      $('#menu').css('visibility','hidden');
      $('#menu-icon, #menu-icon-tablet').removeClass('active');
      return false;
    }
  });

  /* Toggle between adding and removing the "responsive" class to topnav when the user clicks on the icon */
  $("#header > #nav > ul > .icon").click(function() {
    $("#header > #nav > ul").toggleClass("responsive");
  });

  if ( $( "#menu" ).length ) {
    $(window).on('scroll', function() {
      var topDistance = $("#menu > #nav").offset().top;

      if ( $('#menu').css('visibility') != 'hidden' && topDistance < 50 ) {
        $("#menu > #nav").show();
      } else if ($('#menu').css('visibility') != 'hidden' && topDistance > 100) {
        $("#menu > #nav").hide();
      }

      if ( ! $( "#menu-icon" ).is(":visible") && topDistance < 50 ) {
        $("#menu-icon-tablet").show();
        $("#top-icon-tablet").hide();
      } else if (! $( "#menu-icon" ).is(":visible") && topDistance > 100) {
        $("#menu-icon-tablet").hide();
        $("#top-icon-tablet").show();
      }
    });
  }

  if ( $( "#footer-post" ).length ) {
    var lastScrollTop = 0;
    $(window).on('scroll', function() {
      var topDistance = $(window).scrollTop();

    if (topDistance > lastScrollTop){
      // downscroll code
      $("#footer-post").hide();
    } else {
      // upscroll code
      $("#footer-post").show();
    }
    lastScrollTop = topDistance;

    $("#nav-footer").hide();
    $("#toc-footer").hide();
    $("#share-footer").hide();

    if ( topDistance < 50 ) {
      $("#actions-footer > ul > #top").hide();
      $("#actions-footer > ul > #menu").show();
    } else if ( topDistance > 100 ) {
      $("#actions-footer > ul > #menu").hide();
      $("#actions-footer > ul > #top").show();
    }
    });
  }
});
<commit_msg>Cleaned up javascript code.<commit_after>/**
 * Sets up Justified Gallery.
 */
if (!!$.prototype.justifiedGallery) {
  var options = {
    rowHeight: 140,
    margins: 4,
    lastRow: 'justify'
  };
  $('.article-gallery').justifiedGallery(options);
}

$(document).ready(function() {

  /**
   * Shows the responsive navigation menu on mobile.
   */
  $("#header > #nav > ul > .icon").click(function() {
    $("#header > #nav > ul").toggleClass("responsive");
  });

  /**
   * Controls the different versions of  the menu in blog post articles
   * for Desktop, tablet and mobile.
   */
  if ($(".post").length) {
    /**
     * Display the menu if the menu icon is clicked.
     */
    var menu = $("#menu");
    var menu_icon = $("#menu-icon, #menu-icon-tablet");
    menu_icon.click(function() {
      if (menu.css('visibility') === 'hidden') {
        menu.css("visibility", "visible");
        menu_icon.addClass('active');
      } else {
        menu.css("visibility", "hidden");
        menu_icon.removeClass('active');
      }
      return false;
    });

    /**
     * Add a scroll listener to the menu to hide/show the navigation links.
     */
    if (menu.length) {
      $(window).on('scroll', function() {
        var topDistance = $("#menu > #nav").offset().top;

        // hide only the navigation links on desktop
        if (menu.css('visibility') !== 'hidden' && topDistance < 50) {
          $("#menu > #nav").show();
        } else if (menu.css('visibility') !== 'hidden' && topDistance > 100) {
          $("#menu > #nav").hide();
        }

        // on tablet, hide the navigation icon as well and show a "scroll to top
        // icon" instead
        if ( ! $( "#menu-icon" ).is(":visible") && topDistance < 50 ) {
          $("#menu-icon-tablet").show();
          $("#top-icon-tablet").hide();
        } else if (! $( "#menu-icon" ).is(":visible") && topDistance > 100) {
          $("#menu-icon-tablet").hide();
          $("#top-icon-tablet").show();
        }
      });
    }

    /**
     * Show mobile navigation menu after scrolling upwards,
     * hide it again after scrolling downwards.
     */
    if ($( "#footer-post").length) {
      var lastScrollTop = 0;
      $(window).on('scroll', function() {
        var topDistance = $(window).scrollTop();

        if (topDistance > lastScrollTop){
          // downscroll -> show menu
          $("#footer-post").hide();
        } else {
          // upscroll -> hide menu
          $("#footer-post").show();
        }
        lastScrollTop = topDistance;

        // close all submenu's on scroll
        $("#nav-footer").hide();
        $("#toc-footer").hide();
        $("#share-footer").hide();

        // show a "navigation" icon when close to the top of the page,
        // otherwise show a "scroll to the top" icon
        if (topDistance < 50) {
          $("#actions-footer > ul > #top").hide();
          $("#actions-footer > ul > #menu").show();
        } else if (topDistance > 100) {
          $("#actions-footer > ul > #menu").hide();
          $("#actions-footer > ul > #top").show();
        }
      });
    }
  }
});
<|endoftext|>


<commit_before>module.exports = Build;

var async = require('async');
var child_process = require('child_process');
var fs = require('fs');
var path = require('path');
var concat = require('./concat.js');
var Uglify = require('./uglify.js');
var zlib = require('zlib');
var Log = require('./log.js');
var log = new Log();
var uglify = new Uglify();

var stdout;

String.prototype.endsWith = function(suffix) {
  return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

var deleteFolderRecursive = function(path) {
  var files = [];
  if (fs.existsSync(path)) {
    files = fs.readdirSync(path);
    files.forEach(function(file,index){
      var curPath = path + "/" + file;
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        deleteFolderRecursive(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
};

var walk = function(currentDirPath, callback) {
  fs.readdirSync(currentDirPath).forEach(function(name) {
    var filePath = path.join(currentDirPath, name);
    var stat = fs.statSync(filePath);
    if (stat.isFile()) {
      callback(filePath, stat);
    } else if (stat.isDirectory()) {
      walk(filePath, callback);
    }
  });
};

var javaVersionText = function() {
  var result = child_process.execSync('java -version 2>&1', {encoding: 'utf8'});
  var firstLine = result.split('\n')[0];
  var javaVersion = firstLine.match(/"(.*?)"/i)[1];
  return javaVersion.replace(/\./g, '').replace(/_/g, '');
}

function Build() {
  this.npmCoreFiles = [
    'src/npm/prepend-core.js',
    'build/asciidoctor-core.js'
  ];
}

Build.prototype.dist = function(callback) {
  if (process.env.DRY_RUN) {
    log.debug('dist');
    callback();
    return;
  }
  var build = this;
  var start = process.hrtime();

  // Step 1: clean
  build.clean();

  // Step 2: build
  build.buildRuby();

  // Step 3: concat
  build.concatJavaScripts();

  async.series([
    function(callback) {
      build.copyToDist(callback); // Step 4: Copy to dist
    },
    function(callback) {
      build.uglify(callback); // Step 5: Uglify (optional)
    },
    function(callback) {
      build.gzip(callback); // Step 6: Gzip
    }
  ], function() {
    log.success('Done in ' + process.hrtime(start)[0] + 's');
    callback();
  });
}

Build.prototype.clean = function() {
  log.title('clean');
  this.deleteBuildFolder(); // delete build folder
  this.deleteDistFolder(); // delete dist folder
}

Build.prototype.buildRuby = function() {
  log.title('build');
  this.execSync('bundle install');
  this.execSync('bundle exec rake dist');
}

Build.prototype.concatJavaScripts = function() {
  log.title('concat');
  this.concatCore();
  this.concatCoreMin();
  this.concatNpmExtensions();
  this.concatNpmDocbook();
  this.concatBowerCoreExtensions();
  this.concatBowerDocbook();
  this.concatBowerAll();
  this.concatBowerCore(); // must be the last because we're using 'build/asciidoctor-core.js' in other concat tasks
}

Build.prototype.release = function(releaseVersion) {
  var build = this;
  var start = process.hrtime();

  async.series([
    function(callback) { build.prepareRelease(releaseVersion, callback); },
    function(callback) { build.dist(callback); },
    function(callback) { build.commit(releaseVersion, callback); },
    function(callback) { build.publish(callback); },
    function(callback) { build.completeRelease(releaseVersion, callback); }
  ], function() {
    log.success('Done in ' + process.hrtime(start)[0] + 's');
  });
}

Build.prototype.prepareRelease = function(releaseVersion, callback) {
  log.title('Release version: ' + releaseVersion);

  if (process.env.DRY_RUN) {
    log.warn('Dry run! To perform the release, run the command again without DRY_RUN environment variable');
  }

  this.replaceFileSync('package.json', /"version": "(.*?)"/g, '"version": "' + releaseVersion + '"');
  this.replaceFileSync('bower.json', /"version": "(.*?)"/g, '"version": "' + releaseVersion + '"');
  callback();
}

Build.prototype.commit = function(releaseVersion, callback) {
  this.execSync('git add -A .');
  this.execSync('git commit -m "Prepare version ' + releaseVersion + '"');
  this.execSync('git tag v' + releaseVersion);
  callback();
}

Build.prototype.publish = function(callback) {
  this.execSync('npm publish');
  callback();
}

Build.prototype.completeRelease = function(releaseVersion, callback) {
  console.log('');
  log.info('To complete the release, you need to:');
  log.info("[ ] push changes upstream: 'git push origin master && git push origin " + releaseVersion + "'");
  log.info("[ ] publish a release page on GitHub: https://github.com/asciidoctor/asciidoctor.js/releases/new");
  log.info('[ ] create an issue here: https://github.com/webjars/asciidoctor.js to update Webjars');
  callback();
}

Build.prototype.concat = function(message, files, destination) {
  log.debug(message);
  concat(files, destination);
}

Build.prototype.concatCore = function() {
  this.concat('npm core', this.npmCoreFiles.concat(['src/npm/append-core.js']), 'build/npm/asciidoctor-core.js');
}

Build.prototype.concatCoreMin = function() {
  this.concat('npm core.min', this.npmCoreFiles.concat(['src/npm/append-core-min.js']), 'build/npm/asciidoctor-core-min.js');
}

Build.prototype.concatNpmExtensions = function() {
  var files = [
    'src/npm/prepend-extensions.js',
    'build/asciidoctor-extensions.js',
    'src/append-require-extensions.js',
    'src/npm/append-extensions.js'
  ];
  this.concat('npm extensions', files, 'build/npm/asciidoctor-extensions.js');
}

Build.prototype.concatNpmDocbook = function() {
  var files = [
    'src/npm/prepend-extensions.js',
    'build/asciidoctor-docbook45.js',
    'build/asciidoctor-docbook5.js',
    'src/append-require-docbook.js',
    'src/npm/append-extensions.js'
  ];
  this.concat('npm docbook', files, 'build/npm/asciidoctor-docbook.js');
}

Build.prototype.concatBowerCoreExtensions = function() {
  var files = [
    'build/asciidoctor-core.js',
    'build/asciidoctor-extensions.js',
    'src/append-require-core.js',
    'src/append-require-extensions.js'
  ];
  this.concat('Bower core + extensions', files, 'build/asciidoctor.js');
}

Build.prototype.concatBowerDocbook = function() {
  var files = [
    'build/asciidoctor-docbook45.js',
    'build/asciidoctor-docbook5.js',
    'src/append-require-docbook.js'
  ];
  this.concat('Bower docbook', files, 'build/asciidoctor-docbook.js');
}

Build.prototype.concatBowerAll = function() {
  var files = [
    'bower_components/opal/opal/current/opal.js',
    'build/asciidoctor-core.js',
    'build/asciidoctor-extensions.js',
    'src/append-require-core.js',
    'src/append-require-extensions.js'
  ];
  this.concat('Bower all', files, 'build/asciidoctor-all.js');
}

Build.prototype.concatBowerCore = function() {
  var files = [
    'build/asciidoctor-core.js',
    'src/append-require-core.js'
  ];
  this.concat('Bower core', files, 'build/asciidoctor-core.js');
}

Build.prototype.deleteBuildFolder = function() {
  log.debug('delete build directory');
  deleteFolderRecursive('build');
  fs.mkdirSync('build');
  fs.mkdirSync('build/npm');
}

Build.prototype.deleteDistFolder = function() {
  log.debug('delete dist directory');
  deleteFolderRecursive('dist');
  fs.mkdirSync('dist');
  fs.mkdirSync('dist/css');
  fs.mkdirSync('dist/npm');
}

Build.prototype.replaceFileSync = function(file, regexp, newSubString) {
  log.debug('update ' + file);
  if (!process.env.DRY_RUN) {
    var data = fs.readFileSync(file, 'utf8');
    var dataUpdated = data.replace(regexp, newSubString);
    fs.writeFileSync(file, dataUpdated, 'utf8');
  }
}

Build.prototype.execSync = function(command) {
  log.debug(command);
  if (!process.env.DRY_RUN) {
    stdout = child_process.execSync(command);
    process.stdout.write(stdout);
  }
}

Build.prototype.uglify = function(callback) {
  // Preconditions
  // - MINIFY environment variable is defined
  if (!process.env.MINIFY) {
    log.info('MINIFY environment variable is not defined, skipping "minify" task');
    callback();
    return;
  }
  // - Java7 or higher is available in PATH
  try {
    if (javaVersionText() < '170') {
      log.warn('Closure Compiler requires Java7 or higher, skipping "minify" task');
      callback();
      return;
    }
  } catch (e) {
    log.warn('\'java\' binary is not available in PATH, skipping "minify" task');
    callback();
    return;
  }
  log.title('uglify');
  var files = [
    {source: 'build/npm/asciidoctor-core-min.js', destination: 'dist/npm/asciidoctor-core.min.js' },
    {source: 'build/npm/asciidoctor-extensions.js', destination: 'dist/npm/asciidoctor-extensions.min.js' },
    {source: 'build/npm/asciidoctor-docbook.js', destination: 'dist/npm/asciidoctor-docbook.min.js' },
    {source: 'build/asciidoctor-core.js', destination: 'dist/asciidoctor-core.min.js' },
    {source: 'build/asciidoctor-extensions.js', destination: 'dist/asciidoctor-extensions.min.js' },
    {source: 'build/asciidoctor-docbook.js', destination: 'dist/asciidoctor-docbook.min.js' },
    {source: 'build/asciidoctor-all.js', destination: 'dist/asciidoctor-all.min.js' }
  ];

  var functions = [];

  var tasks = [];
  files.forEach(function(file) {
    var source = file.source;
    var destination = file.destination;
    log.transform('minify', source, destination);
    tasks.push(function(callback) { uglify.minify(source, destination, callback) });
  });
  async.parallelLimit(tasks, 4, callback);
}

Build.prototype.copyToDist = function(callback) {
  log.title('copy to dist/')
  fs.createReadStream('build/asciidoctor.css').pipe(fs.createWriteStream('dist/css/asciidoctor.css'));
  walk('build', function(filePath, stat) {
    if (filePath.endsWith(".js")
         && !filePath.endsWith("-min.js")
         && !filePath.endsWith(".min.js")
         && !filePath.endsWith('-docbook45.js')
         && !filePath.endsWith('-docbook5.js')) {
      var basename = path.basename(filePath);
      var paths = path.dirname(filePath).split(path.sep);
      // remove 'build' base directory
      paths.shift();
      // add 'dist' base directory
      paths.unshift('dist');
      paths.push(basename);
      var destination = paths.join(path.sep);
      log.transform('copy', filePath, destination);
      fs.createReadStream(filePath).pipe(fs.createWriteStream(destination));
    }
  });
  callback();
}

Build.prototype.gzip = function(callback) {
  log.title('gzip');
  walk('dist', function(filePath, stat) {
    var basename = path.basename(filePath);
    var dotIndex = basename.indexOf('.');
    var ext = basename.substr(dotIndex + 1);
    var basenameWithoutExt = basename.substr(0, dotIndex);
    if (ext === 'js') {
      var paths = path.dirname(filePath).split(path.sep);
      // remove 'build' base directory
      paths.shift();
      // add 'dist' base directory
      paths.unshift('dist');
      paths.push(basenameWithoutExt + '.gz.js');
      var source = filePath;
      var destination = paths.join(path.sep);
      var input = fs.createReadStream(filePath);
      var output = fs.createWriteStream(paths.join(path.sep));
      log.transform('gzip', source, destination);
      input.pipe(zlib.createGzip()).pipe(output);
    }
  });
  callback();
}
<commit_msg>callback is optional<commit_after>module.exports = Build;

var async = require('async');
var child_process = require('child_process');
var fs = require('fs');
var path = require('path');
var concat = require('./concat.js');
var Uglify = require('./uglify.js');
var zlib = require('zlib');
var Log = require('./log.js');
var log = new Log();
var uglify = new Uglify();

var stdout;

String.prototype.endsWith = function(suffix) {
  return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

var deleteFolderRecursive = function(path) {
  var files = [];
  if (fs.existsSync(path)) {
    files = fs.readdirSync(path);
    files.forEach(function(file,index){
      var curPath = path + "/" + file;
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        deleteFolderRecursive(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
};

var walk = function(currentDirPath, callback) {
  fs.readdirSync(currentDirPath).forEach(function(name) {
    var filePath = path.join(currentDirPath, name);
    var stat = fs.statSync(filePath);
    if (stat.isFile()) {
      callback(filePath, stat);
    } else if (stat.isDirectory()) {
      walk(filePath, callback);
    }
  });
};

var javaVersionText = function() {
  var result = child_process.execSync('java -version 2>&1', {encoding: 'utf8'});
  var firstLine = result.split('\n')[0];
  var javaVersion = firstLine.match(/"(.*?)"/i)[1];
  return javaVersion.replace(/\./g, '').replace(/_/g, '');
}

function Build() {
  this.npmCoreFiles = [
    'src/npm/prepend-core.js',
    'build/asciidoctor-core.js'
  ];
}

Build.prototype.dist = function(callback) {
  if (process.env.DRY_RUN) {
    log.debug('dist');
    callback();
    return;
  }
  var build = this;
  var start = process.hrtime();

  // Step 1: clean
  build.clean();

  // Step 2: build
  build.buildRuby();

  // Step 3: concat
  build.concatJavaScripts();

  async.series([
    function(callback) {
      build.copyToDist(callback); // Step 4: Copy to dist
    },
    function(callback) {
      build.uglify(callback); // Step 5: Uglify (optional)
    },
    function(callback) {
      build.gzip(callback); // Step 6: Gzip
    }
  ], function() {
    log.success('Done in ' + process.hrtime(start)[0] + 's');
    typeof callback === 'function' && callback();
  });
}

Build.prototype.clean = function() {
  log.title('clean');
  this.deleteBuildFolder(); // delete build folder
  this.deleteDistFolder(); // delete dist folder
}

Build.prototype.buildRuby = function() {
  log.title('build');
  this.execSync('bundle install');
  this.execSync('bundle exec rake dist');
}

Build.prototype.concatJavaScripts = function() {
  log.title('concat');
  this.concatCore();
  this.concatCoreMin();
  this.concatNpmExtensions();
  this.concatNpmDocbook();
  this.concatBowerCoreExtensions();
  this.concatBowerDocbook();
  this.concatBowerAll();
  this.concatBowerCore(); // must be the last because we're using 'build/asciidoctor-core.js' in other concat tasks
}

Build.prototype.release = function(releaseVersion) {
  var build = this;
  var start = process.hrtime();

  async.series([
    function(callback) { build.prepareRelease(releaseVersion, callback); },
    function(callback) { build.dist(callback); },
    function(callback) { build.commit(releaseVersion, callback); },
    function(callback) { build.publish(callback); },
    function(callback) { build.completeRelease(releaseVersion, callback); }
  ], function() {
    log.success('Done in ' + process.hrtime(start)[0] + 's');
  });
}

Build.prototype.prepareRelease = function(releaseVersion, callback) {
  log.title('Release version: ' + releaseVersion);

  if (process.env.DRY_RUN) {
    log.warn('Dry run! To perform the release, run the command again without DRY_RUN environment variable');
  }

  this.replaceFileSync('package.json', /"version": "(.*?)"/g, '"version": "' + releaseVersion + '"');
  this.replaceFileSync('bower.json', /"version": "(.*?)"/g, '"version": "' + releaseVersion + '"');
  callback();
}

Build.prototype.commit = function(releaseVersion, callback) {
  this.execSync('git add -A .');
  this.execSync('git commit -m "Prepare version ' + releaseVersion + '"');
  this.execSync('git tag v' + releaseVersion);
  callback();
}

Build.prototype.publish = function(callback) {
  this.execSync('npm publish');
  callback();
}

Build.prototype.completeRelease = function(releaseVersion, callback) {
  console.log('');
  log.info('To complete the release, you need to:');
  log.info("[ ] push changes upstream: 'git push origin master && git push origin " + releaseVersion + "'");
  log.info("[ ] publish a release page on GitHub: https://github.com/asciidoctor/asciidoctor.js/releases/new");
  log.info('[ ] create an issue here: https://github.com/webjars/asciidoctor.js to update Webjars');
  callback();
}

Build.prototype.concat = function(message, files, destination) {
  log.debug(message);
  concat(files, destination);
}

Build.prototype.concatCore = function() {
  this.concat('npm core', this.npmCoreFiles.concat(['src/npm/append-core.js']), 'build/npm/asciidoctor-core.js');
}

Build.prototype.concatCoreMin = function() {
  this.concat('npm core.min', this.npmCoreFiles.concat(['src/npm/append-core-min.js']), 'build/npm/asciidoctor-core-min.js');
}

Build.prototype.concatNpmExtensions = function() {
  var files = [
    'src/npm/prepend-extensions.js',
    'build/asciidoctor-extensions.js',
    'src/append-require-extensions.js',
    'src/npm/append-extensions.js'
  ];
  this.concat('npm extensions', files, 'build/npm/asciidoctor-extensions.js');
}

Build.prototype.concatNpmDocbook = function() {
  var files = [
    'src/npm/prepend-extensions.js',
    'build/asciidoctor-docbook45.js',
    'build/asciidoctor-docbook5.js',
    'src/append-require-docbook.js',
    'src/npm/append-extensions.js'
  ];
  this.concat('npm docbook', files, 'build/npm/asciidoctor-docbook.js');
}

Build.prototype.concatBowerCoreExtensions = function() {
  var files = [
    'build/asciidoctor-core.js',
    'build/asciidoctor-extensions.js',
    'src/append-require-core.js',
    'src/append-require-extensions.js'
  ];
  this.concat('Bower core + extensions', files, 'build/asciidoctor.js');
}

Build.prototype.concatBowerDocbook = function() {
  var files = [
    'build/asciidoctor-docbook45.js',
    'build/asciidoctor-docbook5.js',
    'src/append-require-docbook.js'
  ];
  this.concat('Bower docbook', files, 'build/asciidoctor-docbook.js');
}

Build.prototype.concatBowerAll = function() {
  var files = [
    'bower_components/opal/opal/current/opal.js',
    'build/asciidoctor-core.js',
    'build/asciidoctor-extensions.js',
    'src/append-require-core.js',
    'src/append-require-extensions.js'
  ];
  this.concat('Bower all', files, 'build/asciidoctor-all.js');
}

Build.prototype.concatBowerCore = function() {
  var files = [
    'build/asciidoctor-core.js',
    'src/append-require-core.js'
  ];
  this.concat('Bower core', files, 'build/asciidoctor-core.js');
}

Build.prototype.deleteBuildFolder = function() {
  log.debug('delete build directory');
  deleteFolderRecursive('build');
  fs.mkdirSync('build');
  fs.mkdirSync('build/npm');
}

Build.prototype.deleteDistFolder = function() {
  log.debug('delete dist directory');
  deleteFolderRecursive('dist');
  fs.mkdirSync('dist');
  fs.mkdirSync('dist/css');
  fs.mkdirSync('dist/npm');
}

Build.prototype.replaceFileSync = function(file, regexp, newSubString) {
  log.debug('update ' + file);
  if (!process.env.DRY_RUN) {
    var data = fs.readFileSync(file, 'utf8');
    var dataUpdated = data.replace(regexp, newSubString);
    fs.writeFileSync(file, dataUpdated, 'utf8');
  }
}

Build.prototype.execSync = function(command) {
  log.debug(command);
  if (!process.env.DRY_RUN) {
    stdout = child_process.execSync(command);
    process.stdout.write(stdout);
  }
}

Build.prototype.uglify = function(callback) {
  // Preconditions
  // - MINIFY environment variable is defined
  if (!process.env.MINIFY) {
    log.info('MINIFY environment variable is not defined, skipping "minify" task');
    callback();
    return;
  }
  // - Java7 or higher is available in PATH
  try {
    if (javaVersionText() < '170') {
      log.warn('Closure Compiler requires Java7 or higher, skipping "minify" task');
      callback();
      return;
    }
  } catch (e) {
    log.warn('\'java\' binary is not available in PATH, skipping "minify" task');
    callback();
    return;
  }
  log.title('uglify');
  var files = [
    {source: 'build/npm/asciidoctor-core-min.js', destination: 'dist/npm/asciidoctor-core.min.js' },
    {source: 'build/npm/asciidoctor-extensions.js', destination: 'dist/npm/asciidoctor-extensions.min.js' },
    {source: 'build/npm/asciidoctor-docbook.js', destination: 'dist/npm/asciidoctor-docbook.min.js' },
    {source: 'build/asciidoctor-core.js', destination: 'dist/asciidoctor-core.min.js' },
    {source: 'build/asciidoctor-extensions.js', destination: 'dist/asciidoctor-extensions.min.js' },
    {source: 'build/asciidoctor-docbook.js', destination: 'dist/asciidoctor-docbook.min.js' },
    {source: 'build/asciidoctor-all.js', destination: 'dist/asciidoctor-all.min.js' }
  ];

  var functions = [];

  var tasks = [];
  files.forEach(function(file) {
    var source = file.source;
    var destination = file.destination;
    log.transform('minify', source, destination);
    tasks.push(function(callback) { uglify.minify(source, destination, callback) });
  });
  async.parallelLimit(tasks, 4, callback);
}

Build.prototype.copyToDist = function(callback) {
  log.title('copy to dist/')
  fs.createReadStream('build/asciidoctor.css').pipe(fs.createWriteStream('dist/css/asciidoctor.css'));
  walk('build', function(filePath, stat) {
    if (filePath.endsWith(".js")
         && !filePath.endsWith("-min.js")
         && !filePath.endsWith(".min.js")
         && !filePath.endsWith('-docbook45.js')
         && !filePath.endsWith('-docbook5.js')) {
      var basename = path.basename(filePath);
      var paths = path.dirname(filePath).split(path.sep);
      // remove 'build' base directory
      paths.shift();
      // add 'dist' base directory
      paths.unshift('dist');
      paths.push(basename);
      var destination = paths.join(path.sep);
      log.transform('copy', filePath, destination);
      fs.createReadStream(filePath).pipe(fs.createWriteStream(destination));
    }
  });
  callback();
}

Build.prototype.gzip = function(callback) {
  log.title('gzip');
  walk('dist', function(filePath, stat) {
    var basename = path.basename(filePath);
    var dotIndex = basename.indexOf('.');
    var ext = basename.substr(dotIndex + 1);
    var basenameWithoutExt = basename.substr(0, dotIndex);
    if (ext === 'js') {
      var paths = path.dirname(filePath).split(path.sep);
      // remove 'build' base directory
      paths.shift();
      // add 'dist' base directory
      paths.unshift('dist');
      paths.push(basenameWithoutExt + '.gz.js');
      var source = filePath;
      var destination = paths.join(path.sep);
      var input = fs.createReadStream(filePath);
      var output = fs.createWriteStream(paths.join(path.sep));
      log.transform('gzip', source, destination);
      input.pipe(zlib.createGzip()).pipe(output);
    }
  });
  callback();
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Composites = require('users/gmiceli/ee-lct:impl/composites.js').Composites;
var Bands = require('users/gmiceli/ee-lct:impl/bands.js').Bands;

/**
 * Returns a new dataset instance for an arbitrary image collection.
 *
 * @constructor
 * @param {string} id The id of the collection in the Earth Engine data
 *     catalog.
 * @param {!ee.data.ImageVisualizationParameters} defaultVisParams The
 *     parameters to be used when adding the resulting collection to a layer for
 *     visualization.
 * @return {!Dataset}
 */
var Dataset = function(id, defaultVisParams) {
  this.collection_ = ee.ImageCollection(id);
  this.defaultVisParams_ = defaultVisParams;
};

/**
 * Filters the dataset by the specified date range.
 *
 * Returns the filtered dataset.
 *
 * @param {!Date|number|string} start The start date as a Date object, a
 *     string representation of a date, or milliseconds since epoch.
 * @param {!Date|number|string} end The end date as a Date object, a
 *     string representation of a date, or milliseconds since epoch.
 * @return {!Dataset}
 */
Dataset.prototype.filterDate = function(start, end) {
  // TODO(gino-m): Implement month and year ranges.
  // TODO(gino-m): Implement single day/month/year.
  // NOTE: We will probably want to either keep track of what we do to the
  // ImageCollection, or accumulate operations and run them at the end. Keeping
  // it simple for now until we have a better sense of what we need.
  this.collection_ = this.collection_.filterDate(start, end);
  return this;
};

/**
 * Filters the dataset by the specified geometry. Items in the collection with a
 * footprint that fails to intersect the bounds will be excluded when the
 * collection is evaluated.
 *
 * This is equivalent to ee.ImageCollection.filterBounds().
 *
 * Returns the filtered dataset.
 *
 * @param {!Feature|!Geometry} geometry The geometry to filter to.
 * @return {!Dataset}
 */
Dataset.prototype.filterBounds = function(geometry) {
  this.collection_ = this.collection_.filterBounds(geometry);
  return this;
};

/**
 * Returns the dataset's resulting image collection.
 *
 * @return {!ee.ImageCollection}
 */
Dataset.prototype.getImageCollection = function() {
  return this.collection_;
};

/**
 * Returns the default visualization params to be used when displaying this
 * dataset on a map.
 *
 * @return {!ee.data.ImageVisualizationParameters}
 */
Dataset.prototype.getDefaultVisParams = function() {
  return this.defaultVisParams_;
};

/**
 * Convert a collection into composite images based on fixed time intervals.
 * Adds a 'date' band to each input image that contains the date of the
 * observation and an 'observations' band to the composite that contains the
 * number of observations that went into each pixel.
 *
 * @param {string|!Date|!ee.Date} startDate The date of the first composite.
 * @param {number} count How many composites to make.
 * @param {number} interval How much to advance the start date of the next
 *        composite in units of intervalUnits.
 * @param {string} intervalUnits The units of interval. One of:
 *        'year', 'month' 'week', 'day', 'hour', 'minute', or 'second'.
 * @param {?ee.Reducer} reducer An optional reducer to be used to reduce
 *        each time period. Defaults to using a median reducer.
 * @return {!ee.ImageCollection}
 */
Dataset.prototype.createTemporalComposites =
    function(startDate, count, interval, intervalUnits, reducer) {
  this.collection_ =
      Composites.createTemporalComposites(
          this.collection_, startDate, count, interval, intervalUnits, reducer);
  return this;
};

/**
 * Computes a medioid composite by finding the median of one band
 * and returning the complete observation where that band is closest
 * to the median value.
 *
 * @param {string} band The name of the band which to
 *    select the median value.
 * @return {!ee.ImageCollection}
 */
Dataset.prototype.createMedioidComposite = function(band) {
  this.collection_ = ee.ImageCollection([
      Composites.createMedioidComposite(this.collection_, band)
  ]);
  return this;
};

/**
 * Computes the list of new band names to rename to common band names.
 * @param {!Array<string>} bandNames The input band names.
 * @return {!Array<string>} The modified band names in the same order as the
 *     input names.  Unknown bands are unmodified.
 *
 * @private
 */
Dataset.prototype.computeCommonBandNames_ = function(bandNames) {
  // Start with a lookup from oldname to newname using all the old names,
  // and augment it with the entries from this dataset's COMMON_BAND_NAMES.
  var commonNames = ee.Dictionary(bandNames.zip(bandNames).flatten());
  var lookup = commonNames.combine(this.COMMON_BAND_NAMES, true);
  return bandNames.map(function(name) {
    return lookup.get(name);
  });
};

/**
 * Add spectral indices to each image in the dataset.
 * @param {!string...} var_names The names of the spectral indexes to add.
 *     Must be string literals.
 * @return {!Dataset}
 */
Dataset.prototype.addBandIndices = function(var_names) {
  var indices = Array.prototype.slice.call(arguments);

  // Compute the transformaton to common band names.
  var bandNames = this.collection_.first().bandNames();
  var commonNames = this.computeCommonBandNames_(bandNames);

  var output = this.collection_.map(function(image) {
    // Rename the bands and compute the spectral indices.
    var renamed = image.select(bandNames, commonNames);
    var bands = Bands.getSpectralIndices(renamed, indices);
    return image.addBands(bands);
  });

  this.collection_ = output;
  return this;
};

/**
 * Adds a band (date) to each image in the dataset's collection,
 * containing the date of the image in milliseconds since the epoch.
 *
 * @return {!Dataset}
 */
Dataset.prototype.addDateBand = function() {
  this.collection_ = Bands.addDateBand(this.collection_);
  return this;
};

/**
 * Adds a band (doy) to each image in the dataset's collection,
 * containing the day of year of the image.
 *
 * @return {!Dataset}
 */
Dataset.prototype.addDayOfYearBand = function() {
  this.collection_ = Bands.addDayOfYearBand(this.collection_);
  return this;
};

/**
 * Adds a band (fYear) to each image in the dataset's collection,
 * containing the fractional year (year + doy/365) of the image.
 *
 * @return {!Dataset}
 */
Dataset.prototype.addFractionalYearBand = function() {
  this.collection_ = Bands.addFractionalYearBand(this.collection_);
  return this;
};

exports.Dataset = Dataset;
<commit_msg>Tweak comments<commit_after>/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Composites = require('users/gmiceli/ee-lct:impl/composites.js').Composites;
var Bands = require('users/gmiceli/ee-lct:impl/bands.js').Bands;

/**
 * Returns a new dataset instance for an arbitrary image collection.
 *
 * @constructor
 * @param {string} id The id of the collection in the Earth Engine data
 *     catalog.
 * @param {!ee.data.ImageVisualizationParameters} defaultVisParams The
 *     parameters to be used when adding the resulting collection to a layer for
 *     visualization.
 * @return {!Dataset}
 */
var Dataset = function(id, defaultVisParams) {
  this.collection_ = ee.ImageCollection(id);
  this.defaultVisParams_ = defaultVisParams;
};

/**
 * Filters the dataset by the specified date range.
 *
 * Returns the filtered dataset.
 *
 * @param {!Date|number|string} start The start date as a Date object, a
 *     string representation of a date, or milliseconds since epoch.
 * @param {!Date|number|string} end The end date as a Date object, a
 *     string representation of a date, or milliseconds since epoch.
 * @return {!Dataset}
 */
Dataset.prototype.filterDate = function(start, end) {
  // TODO(gino-m): Implement month and year ranges.
  // TODO(gino-m): Implement single day/month/year.
  this.collection_ = this.collection_.filterDate(start, end);
  return this;
};

/**
 * Filters the dataset by the specified geometry. Items in the collection with a
 * footprint that fails to intersect the bounds will be excluded when the
 * collection is evaluated.
 *
 * This is equivalent to ee.ImageCollection.filterBounds().
 *
 * Returns the filtered dataset.
 *
 * @param {!Feature|!Geometry} geometry The geometry to filter to.
 * @return {!Dataset}
 */
Dataset.prototype.filterBounds = function(geometry) {
  this.collection_ = this.collection_.filterBounds(geometry);
  return this;
};

/**
 * Returns the dataset's resulting image collection.
 *
 * @return {!ee.ImageCollection}
 */
Dataset.prototype.getImageCollection = function() {
  return this.collection_;
};

/**
 * Returns the default visualization params to be used when displaying this
 * dataset on a map.
 *
 * @return {!ee.data.ImageVisualizationParameters}
 */
Dataset.prototype.getDefaultVisParams = function() {
  return this.defaultVisParams_;
};

/**
 * Convert a collection into composite images based on fixed time intervals.
 * Adds a 'date' band to each input image that contains the date of the
 * observation and an 'observations' band to the composite that contains the
 * number of observations that went into each pixel.
 *
 * @param {string|!Date|!ee.Date} startDate The date of the first composite.
 * @param {number} count How many composites to make.
 * @param {number} interval How much to advance the start date of the next
 *        composite in units of intervalUnits.
 * @param {string} intervalUnits The units of interval. One of:
 *        'year', 'month' 'week', 'day', 'hour', 'minute', or 'second'.
 * @param {?ee.Reducer} reducer An optional reducer to be used to reduce
 *        each time period. Defaults to using a median reducer.
 * @return {!ee.ImageCollection}
 */
Dataset.prototype.createTemporalComposites =
    function(startDate, count, interval, intervalUnits, reducer) {
  this.collection_ =
      Composites.createTemporalComposites(
          this.collection_, startDate, count, interval, intervalUnits, reducer);
  return this;
};

/**
 * Computes a medioid composite by finding the median of one band
 * and returning the complete observation where that band is closest
 * to the median value.
 *
 * @param {string} band The name of the band which to
 *    select the median value.
 * @return {!ee.ImageCollection}
 */
Dataset.prototype.createMedioidComposite = function(band) {
  this.collection_ = ee.ImageCollection([
      Composites.createMedioidComposite(this.collection_, band)
  ]);
  return this;
};

/**
 * Computes the list of new band names to rename to common band names.
 * @param {!Array<string>} bandNames The input band names.
 * @return {!Array<string>} The modified band names in the same order as the
 *     input names.  Unknown bands are unmodified.
 *
 * @private
 */
Dataset.prototype.computeCommonBandNames_ = function(bandNames) {
  // Start with a lookup from oldname to newname using all the old names,
  // and augment it with the entries from this dataset's COMMON_BAND_NAMES.
  var commonNames = ee.Dictionary(bandNames.zip(bandNames).flatten());
  var lookup = commonNames.combine(this.COMMON_BAND_NAMES, true);
  return bandNames.map(function(name) {
    return lookup.get(name);
  });
};

/**
 * Add spectral indices to each image in the dataset.
 * @param {!string...} var_names The names of the spectral indexes to add.
 *     Must be string literals.
 * @return {!Dataset}
 */
Dataset.prototype.addBandIndices = function(var_names) {
  var indices = Array.prototype.slice.call(arguments);

  // Compute the transformation to common band names.
  var bandNames = this.collection_.first().bandNames();
  var commonNames = this.computeCommonBandNames_(bandNames);

  var output = this.collection_.map(function(image) {
    // Rename the bands and compute the spectral indices.
    var renamed = image.select(bandNames, commonNames);
    var bands = Bands.getSpectralIndices(renamed, indices);
    return image.addBands(bands);
  });

  this.collection_ = output;
  return this;
};

/**
 * Adds a band (date) to each image in the dataset's collection,
 * containing the date of the image in milliseconds since the epoch.
 *
 * @return {!Dataset}
 */
Dataset.prototype.addDateBand = function() {
  this.collection_ = Bands.addDateBand(this.collection_);
  return this;
};

/**
 * Adds a band (doy) to each image in the dataset's collection,
 * containing the day of year of the image.
 *
 * @return {!Dataset}
 */
Dataset.prototype.addDayOfYearBand = function() {
  this.collection_ = Bands.addDayOfYearBand(this.collection_);
  return this;
};

/**
 * Adds a band (fYear) to each image in the dataset's collection,
 * containing the fractional year (year + doy/365) of the image.
 *
 * @return {!Dataset}
 */
Dataset.prototype.addFractionalYearBand = function() {
  this.collection_ = Bands.addFractionalYearBand(this.collection_);
  return this;
};

exports.Dataset = Dataset;
<|endoftext|>


<commit_before>import * as ConfigConstants from '../constants/config'
import {getConfig, getCurrentStatus} from './config'
import {autoLogin} from './login'
import engine from '../engine'
import {NotifyPopup} from '../native/notifications'

// This requires things across actions, so to avoid a circular dependency we'll pull this out
// into it's own file
export function startup () {
  return function (dispatch) {
    dispatch({type: ConfigConstants.startupLoading})

    engine.listenOnConnect('getCurrentStatus', () => {
      return (
        Promise.all([dispatch(getCurrentStatus()), dispatch(getConfig())])
          .then(() => {
            dispatch({type: ConfigConstants.startupLoaded})
            dispatch(autoLogin())
          })
          .catch(error => {
            console.error('Error starting up:', error)
            dispatch({type: ConfigConstants.startupLoaded, payload: error, error: true})
            NotifyPopup('Startup Failed', {body: 'Run `keybase log send` to tell us why!'})
          })
      )
    })
  }
}

<commit_msg>Remove notification that startup failed and send log<commit_after>import * as ConfigConstants from '../constants/config'
import {getConfig, getCurrentStatus} from './config'
import {autoLogin} from './login'
import engine from '../engine'
import {NotifyPopup} from '../native/notifications'

// This requires things across actions, so to avoid a circular dependency we'll pull this out
// into it's own file
export function startup () {
  return function (dispatch) {
    dispatch({type: ConfigConstants.startupLoading})

    engine.listenOnConnect('getCurrentStatus', () => {
      return (
        Promise.all([dispatch(getCurrentStatus()), dispatch(getConfig())])
          .then(() => {
            dispatch({type: ConfigConstants.startupLoaded})
            dispatch(autoLogin())
          })
          .catch(error => {
            console.error('Error starting up:', error)
            dispatch({type: ConfigConstants.startupLoaded, payload: error, error: true})
          })
      )
    })
  }
}

<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
//                                    UTILS
//-----------------------------------------------------------------------------

var helpMessage = [
  "Zoom-in (x-axis)   : Ctrl + / 4",
  "Zoom-out (x-axis)  : Ctrl - / 3",
  "Reset zoom (x-axis): Ctrl 0 / 0",
  "Undo zoom (x-axis) : u / U",
  "Zoom-in (y-axis)   : Ctrl-Alt + / 2",
  "Zoom-out (y-axis)  : Ctrl-Alt - / 1",
  "Reset zoom (y-axis): Ctrl-Alt 0 / `",
  "Range Zoom-in      : drag-select",
  "Measure duration   : Alt + drag-select",
  "Search             : s / S",
  "Search History     : h / H",
  "Previous Search    : p / P",
  "Next Search        : n / N",
  "Clear Search       : c / C",
  "Toggle Search      : t / T",
];

var Command = {
  none : 0,
  help : 1,
  zox : 2,
  zix : 3,
  zrx : 4,
  zux : 5,
  zoy : 6,
  ziy : 7,
  zry : 8,
  search : 9,
  clear_search : 10,
  toggle_search : 11,
  search_history : 12,
  previous_search : 13,
  next_search : 14
};

// commands without a modifier key pressed
var noModifierCommands = {
  '0': Command.zrx,
  '1': Command.zoy,
  '2': Command.ziy,
  '3': Command.zox,
  '4': Command.zix,
  'c': Command.clear_search,
  'h': Command.search_history,
  'n': Command.next_search,
  'p': Command.previous_search,
  's': Command.search,
  't': Command.toggle_search,
  'u': Command.zux,
  '/': Command.help
};

var modifierCommands = {
  '+': Command.zix,
  '-': Command.zox,
  '0': Command.zrx
}

var multipleModifierCommands = {
  '+': Command.ziy,
  '-': Command.zoy,
  '0': Command.zry
}

var keys = {
  13  : 'enter',
  27  : 'esc',
  48  : '0',
  49  : '1',
  50  : '2',
  51  : '3',
  52  : '4',
  61  : '+', // Firefox
  67  : 'c',
  72  : 'h',
  78  : 'n',
  80  : 'p',
  83  : 's',
  84  : 't',
  85  : 'u',
  173 : '-', // Firefox
  187 : '+',
  189 : '-',
  191 : '/',
  192 : '`'
};

/**
 * Function: convertToTime
 *
 * Description:
 *    Takes a value and converts it to time. The input 'x' can either be
 *    a single position on the timeline, or it can be a width.
 */
function convertToTime(state, x) {
  return x / state.zoom / state.scale;
}

/**
 * Function: convertToPos
 *
 * Description:
 *    Takes a time and converts it to a position in the window.
 *    The 'time' parameter MUST BE IN us
 */
function convertToPos(state, time) {
  return time * state.zoom * state.scale;
}

/**
 * Function: getTimeString
 *
 * Description:
 *    This function takes a time (in us) as well as a 'width'
 *    field. The 'width' field determines over what interval
 *    the time is being considered.
 *
 *    If the width is too large, the time will be converted
 *    to either ms or sec.
 *
 *    The function will return a string representation of the
 *    (possibly) scaled time at the end of the method
 */
function getTimeString(time, timeWidth) {
  var unit = "us";
  var scaledTime = Math.floor(time);
  if (timeWidth >= 100000) {
    var scaledTime = Math.floor(time / 1000);
    unit = "ms";
  } else if (timeWidth >= 100000000) {
    var scaledTime = Math.floor(time / 1000000);
    unit = "s";
  }
  return scaledTime + " " + unit;
}

// timeField should be 'end' for the left hand side and
// 'start' for the right hand side
function binarySearch(data, level, time, useStart) {
  var low = 0;
  var high = data[level].length;
  while (true) {
    // ugh is there a way to do integer division in javascrtipt?
    var mid = Math.floor((high - low) / 2) + low;

    // In this case, we haven't found it. This is as close
    // as we were able to get.
    if (low == high || low == mid) {
      return low;
    } else if (high == mid) {
      return high;
    }
    var midTime;
    if (useStart) {
      midTime = data[level][mid].start;
    } else {
      midTime = data[level][mid].end;
    }

    if (midTime > time) {
      // need to look below
      high = mid;
    } else if (midTime < time) {
      // need to look above
      low = mid;
    } else {
      // Exact Match
      return mid;
    }
  }
}

function filterAndMergeBlocks(state) {
  var windowStart = $("#timeline").scrollLeft();
  var windowEnd = windowStart + $("#timeline").width();
  state.dataToDraw = Array();
  var startTime = convertToTime(state, windowStart);
  var endTime = convertToTime(state, windowEnd);
  var min_feature_time = convertToTime(state, constants.min_feature_width);
  var min_gap_time = convertToTime(state, constants.min_gap_width);
  for (var proc_num in state.processors) {
    var proc = state.processors[proc_num];
    if (proc.enabled) {
      var items = state.processorData[proc.processor];
      for (var level in items) {
        // gap merging below assumes intervals are sorted - do that first
        //items[level].sort(function(a,b) { return a.start - b.start; });

        // We will use binary search to limit the following section
        var startIndex = binarySearch(items, level, startTime, false);
        var endIndex = binarySearch(items, level, endTime, true);
        for (var i = startIndex; i <= endIndex; ++i) {
          var d = items[level][i];
          var start = d.start;
          var end = d.end;
          // is this block too narrow?
          if ((end - start) < min_feature_time) {
            // see how many more after this are also too narrow and too close to us
            var count = 1;
            // don't do this if we're the subject of the current search and don't merge with
            // something that is
            if (!state.searchEnabled || searchRegex[currentPos].exec(d.title) == null) {
              while (((i + count) < items[level].length) &&
                     ((items[level][i + count].start - end) < min_gap_time) &&
                     ((items[level][i + count].end - items[level][i + count].start) < min_feature_time) &&
                     (!state.searchEnabled || searchRegex[currentPos].exec(items[level][i + count].title) == null)) {
                end = items[level][i + count].end;
                count++;
              }
            }
            // are we still too narrow?  if so, bloat, but make sure we don't overlap something later
            if ((end - start) < min_feature_time) {
              end = start + min_feature_time;
              if (((i + count) < items[level].length) && (items[level][i + count].start < end))
                end = items[level][i + count].start;
            }
            if (count > 1) {
              state.dataToDraw.push({
                id: d.id,
                proc: proc_num,
                level: d.level + proc.base,
                start: d.start,
                end: end,
                color: "#808080",
                title: count + " merged tasks"
              });
              i += (count - 1);
            } else {
              state.dataToDraw.push({
                id: d.id,
                proc: proc_num,
                level: d.level + proc.base,
                start: d.start,
                end: d.end,
                color: d.color,
                initiation: d.initiation,
                title: d.title + " (expanded for visibility)"
              });
            }
          } else {
            state.dataToDraw.push({
              id: d.id,
              proc: proc_num,
              level: d.level + proc.base,
              start: d.start,
              end: d.end,
              color: d.color,
              initiation: d.initiation,
              title: d.title
            });
          }
        }
      }
    }
  }
}

<commit_msg>legion_prof: fixed opacity bug<commit_after>//-----------------------------------------------------------------------------
//                                    UTILS
//-----------------------------------------------------------------------------

var helpMessage = [
  "Zoom-in (x-axis)   : Ctrl + / 4",
  "Zoom-out (x-axis)  : Ctrl - / 3",
  "Reset zoom (x-axis): Ctrl 0 / 0",
  "Undo zoom (x-axis) : u / U",
  "Zoom-in (y-axis)   : Ctrl-Alt + / 2",
  "Zoom-out (y-axis)  : Ctrl-Alt - / 1",
  "Reset zoom (y-axis): Ctrl-Alt 0 / `",
  "Range Zoom-in      : drag-select",
  "Measure duration   : Alt + drag-select",
  "Search             : s / S",
  "Search History     : h / H",
  "Previous Search    : p / P",
  "Next Search        : n / N",
  "Clear Search       : c / C",
  "Toggle Search      : t / T",
];

var Command = {
  none : 0,
  help : 1,
  zox : 2,
  zix : 3,
  zrx : 4,
  zux : 5,
  zoy : 6,
  ziy : 7,
  zry : 8,
  search : 9,
  clear_search : 10,
  toggle_search : 11,
  search_history : 12,
  previous_search : 13,
  next_search : 14
};

// commands without a modifier key pressed
var noModifierCommands = {
  '0': Command.zrx,
  '1': Command.zoy,
  '2': Command.ziy,
  '3': Command.zox,
  '4': Command.zix,
  'c': Command.clear_search,
  'h': Command.search_history,
  'n': Command.next_search,
  'p': Command.previous_search,
  's': Command.search,
  't': Command.toggle_search,
  'u': Command.zux,
  '/': Command.help
};

var modifierCommands = {
  '+': Command.zix,
  '-': Command.zox,
  '0': Command.zrx
}

var multipleModifierCommands = {
  '+': Command.ziy,
  '-': Command.zoy,
  '0': Command.zry
}

var keys = {
  13  : 'enter',
  27  : 'esc',
  48  : '0',
  49  : '1',
  50  : '2',
  51  : '3',
  52  : '4',
  61  : '+', // Firefox
  67  : 'c',
  72  : 'h',
  78  : 'n',
  80  : 'p',
  83  : 's',
  84  : 't',
  85  : 'u',
  173 : '-', // Firefox
  187 : '+',
  189 : '-',
  191 : '/',
  192 : '`'
};

/**
 * Function: convertToTime
 *
 * Description:
 *    Takes a value and converts it to time. The input 'x' can either be
 *    a single position on the timeline, or it can be a width.
 */
function convertToTime(state, x) {
  return x / state.zoom / state.scale;
}

/**
 * Function: convertToPos
 *
 * Description:
 *    Takes a time and converts it to a position in the window.
 *    The 'time' parameter MUST BE IN us
 */
function convertToPos(state, time) {
  return time * state.zoom * state.scale;
}

/**
 * Function: getTimeString
 *
 * Description:
 *    This function takes a time (in us) as well as a 'width'
 *    field. The 'width' field determines over what interval
 *    the time is being considered.
 *
 *    If the width is too large, the time will be converted
 *    to either ms or sec.
 *
 *    The function will return a string representation of the
 *    (possibly) scaled time at the end of the method
 */
function getTimeString(time, timeWidth) {
  var unit = "us";
  var scaledTime = Math.floor(time);
  if (timeWidth >= 100000) {
    var scaledTime = Math.floor(time / 1000);
    unit = "ms";
  } else if (timeWidth >= 100000000) {
    var scaledTime = Math.floor(time / 1000000);
    unit = "s";
  }
  return scaledTime + " " + unit;
}

// timeField should be 'end' for the left hand side and
// 'start' for the right hand side
function binarySearch(data, level, time, useStart) {
  var low = 0;
  var high = data[level].length;
  while (true) {
    // ugh is there a way to do integer division in javascrtipt?
    var mid = Math.floor((high - low) / 2) + low;

    // In this case, we haven't found it. This is as close
    // as we were able to get.
    if (low == high || low == mid) {
      return low;
    } else if (high == mid) {
      return high;
    }
    var midTime;
    if (useStart) {
      midTime = data[level][mid].start;
    } else {
      midTime = data[level][mid].end;
    }

    if (midTime > time) {
      // need to look below
      high = mid;
    } else if (midTime < time) {
      // need to look above
      low = mid;
    } else {
      // Exact Match
      return mid;
    }
  }
}

function filterAndMergeBlocks(state) {
  var windowStart = $("#timeline").scrollLeft();
  var windowEnd = windowStart + $("#timeline").width();
  state.dataToDraw = Array();
  var startTime = convertToTime(state, windowStart);
  var endTime = convertToTime(state, windowEnd);
  var min_feature_time = convertToTime(state, constants.min_feature_width);
  var min_gap_time = convertToTime(state, constants.min_gap_width);
  for (var proc_num in state.processors) {
    var proc = state.processors[proc_num];
    if (proc.enabled) {
      var items = state.processorData[proc.processor];
      for (var level in items) {
        // gap merging below assumes intervals are sorted - do that first
        //items[level].sort(function(a,b) { return a.start - b.start; });

        // We will use binary search to limit the following section
        var startIndex = binarySearch(items, level, startTime, false);
        var endIndex = binarySearch(items, level, endTime, true);
        for (var i = startIndex; i <= endIndex; ++i) {
          var d = items[level][i];
          var start = d.start;
          var end = d.end;
          // is this block too narrow?
          if ((end - start) < min_feature_time) {
            // see how many more after this are also too narrow and too close to us
            var count = 1;
            // don't do this if we're the subject of the current search and don't merge with
            // something that is
            if (!state.searchEnabled || searchRegex[currentPos].exec(d.title) == null) {
              while (((i + count) < items[level].length) &&
                     ((items[level][i + count].start - end) < min_gap_time) &&
                     ((items[level][i + count].end - items[level][i + count].start) < min_feature_time) &&
                     (!state.searchEnabled || searchRegex[currentPos].exec(items[level][i + count].title) == null)) {
                end = items[level][i + count].end;
                count++;
              }
            }
            // are we still too narrow?  if so, bloat, but make sure we don't overlap something later
            if ((end - start) < min_feature_time) {
              end = start + min_feature_time;
              if (((i + count) < items[level].length) && (items[level][i + count].start < end))
                end = items[level][i + count].start;
            }
            if (count > 1) {
              state.dataToDraw.push({
                id: d.id,
                proc: proc_num,
                level: d.level + proc.base,
                start: d.start,
                end: end,
                color: "#808080",
                opacity: d.opacity,
                title: count + " merged tasks"
              });
              i += (count - 1);
            } else {
              state.dataToDraw.push({
                id: d.id,
                proc: proc_num,
                level: d.level + proc.base,
                start: d.start,
                end: d.end,
                color: d.color,
                opacity: d.opacity,
                initiation: d.initiation,
                title: d.title + " (expanded for visibility)"
              });
            }
          } else {
            state.dataToDraw.push({
              id: d.id,
              proc: proc_num,
              level: d.level + proc.base,
              start: d.start,
              end: d.end,
              opacity: d.opacity,
              color: d.color,
              initiation: d.initiation,
              title: d.title
            });
          }
        }
      }
    }
  }
}

<|endoftext|>


<commit_before>import React from 'react';
import cx from 'classnames';

const DATABASE_SVG = (
  <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 50 50">
    <path d="M24.985,0C37.556,0,46,4.576,46,8.849c0,4.274-8.444,8.85-21.015,8.85c-12.572,0-21.017-4.576-21.017-8.85 C3.968,4.576,12.413,0,24.985,0z M46,39.151C46,43.424,37.556,48,24.985,48c-12.572,0-21.017-4.576-21.017-8.849v-5.195 c3.676,3.753,11.597,6.302,21.017,6.302c9.418,0,17.34-2.549,21.015-6.302V39.151z M46,29.196c0,4.272-8.444,8.849-21.015,8.849 c-12.572,0-21.017-4.576-21.017-8.849v-5.286c3.676,3.752,11.597,6.301,21.017,6.301c9.418,0,17.34-2.549,21.015-6.301V29.196z M46,19.15C46,23.424,37.556,28,24.985,28c-12.572,0-21.017-4.576-21.017-8.85v-5.541c3.676,3.753,11.597,6.301,21.017,6.301 c9.418,0,17.34-2.547,21.015-6.301V19.15z"></path>
  </svg>
);

const Database = (props) => {
  return (

{DATABASE_SVG} {!props.database || props.database === 'none' ? 'Database' : props.database}

          <input type="radio" name="databaseRadios" value="none" onChange={props.handleChange} checked={props.database === 'none'} /> None

          <input type="radio" name="databaseRadios" value="mongodb" onChange={props.handleChange} checked={props.database === 'mongodb'} /> MongoDB

          <input type="radio" name="databaseRadios" value="mysql" onChange={props.handleChange} checked={props.database === 'mysql'} /> MySQL

          <input type="radio" name="databaseRadios" value="postgresql" onChange={props.handleChange} checked={props.database === 'postgresql'} /> PostgreSQL

          <input type="radio" name="databaseRadios" value="rethinkdb" onChange={props.handleChange} checked={props.database === 'rethinkdb'} /> RethinkDB

               Do I need a database?

                Select None if you are building an API server or a single-page application.

               Database Comparison

                Select None if you are building an API server or a single-page application.

  );
};

export default Database;
<commit_msg>Database section refactoring<commit_after>import React from 'react';
import cx from 'classnames';

const DATABASE_SVG = (
  <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 50 50">
    <path d="M24.985,0C37.556,0,46,4.576,46,8.849c0,4.274-8.444,8.85-21.015,8.85c-12.572,0-21.017-4.576-21.017-8.85 C3.968,4.576,12.413,0,24.985,0z M46,39.151C46,43.424,37.556,48,24.985,48c-12.572,0-21.017-4.576-21.017-8.849v-5.195 c3.676,3.753,11.597,6.302,21.017,6.302c9.418,0,17.34-2.549,21.015-6.302V39.151z M46,29.196c0,4.272-8.444,8.849-21.015,8.849 c-12.572,0-21.017-4.576-21.017-8.849v-5.286c3.676,3.752,11.597,6.301,21.017,6.301c9.418,0,17.34-2.549,21.015-6.301V29.196z M46,19.15C46,23.424,37.556,28,24.985,28c-12.572,0-21.017-4.576-21.017-8.85v-5.541c3.676,3.753,11.597,6.301,21.017,6.301 c9.418,0,17.34-2.547,21.015-6.301V19.15z"></path>
  </svg>
);

const Database = (props) => {
  return (

{DATABASE_SVG} {!props.database || props.database === 'none' ? 'Database' : props.database}

            <input type="radio" name="databaseRadios" value="none" onChange={props.handleChange} checked={props.database === 'none'} />
            None

            <input type="radio" name="databaseRadios" value="mongodb" onChange={props.handleChange} checked={props.database === 'mongodb'} />
            MongoDB

            <input type="radio" name="databaseRadios" value="mysql" onChange={props.handleChange} checked={props.database === 'mysql'} />
            MySQL

            <input type="radio" name="databaseRadios" value="postgresql" onChange={props.handleChange} checked={props.database === 'postgresql'} />
            PostgreSQL

            <input type="radio" name="databaseRadios" value="rethinkdb" onChange={props.handleChange} checked={props.database === 'rethinkdb'} />
            RethinkDB

  );
};

export default Database;
<|endoftext|>


<commit_before>
var fse = require('fs-extra');
var pathUtil = require('path');

var originalCwd = process.cwd();
var workingDir = pathUtil.resolve('../tmp');

module.exports.workingDir = workingDir;

module.exports.beforeEach = function () {
    if (fse.existsSync(workingDir)) {
        fse.removeSync(workingDir);
    }
    fse.mkdirSync(workingDir);
    process.chdir(workingDir);
};

module.exports.afterEach = function () {
    process.chdir(originalCwd);
};<commit_msg>os temp folder used for tests<commit_after>
var fse = require('fs-extra');
var pathUtil = require('path');
var os = require('os');

var originalCwd = process.cwd();
var workingDir = pathUtil.join(os.tmpdir(), 'fs-jetpack');

module.exports.workingDir = workingDir;

module.exports.beforeEach = function () {
    if (fse.existsSync(workingDir)) {
        fse.removeSync(workingDir);
    }
    fse.mkdirSync(workingDir);
    process.chdir(workingDir);
};

module.exports.afterEach = function () {
    process.chdir(originalCwd);
};<|endoftext|>