<commit_before>
const RG = require('./rg');

RG.Animation = {};

/* Very simple "animation" object handed to the Screen object. slowDown can be
 * used to repeat the frame for addFrame() multiple times.
 *  Each frame should be an object such as
 *  {
 *    '1,1': {char: '-', className: 'css-class'},
 *    '2,2': {char: '-', className: 'css-class'}
 *  }
 * Screen object will always render specified chars to the given locations
 * over normal map cells.
 * */
RG.Animation.Animation = function() {

    this.levelID = -1;
    this.numFrames = 0;
    this.currFrame = 0;

    // "Slows" down the animation by this factor
    this.slowDown = 2;

    this.frames = [];

    this.setLevel = function(level) {
        this.levelID = level.getID();
    };

    this.addFrame = function(frame) {
        for (let i = 0; i < this.slowDown; i++) {
            ++this.numFrames;
            this.frames.push(frame);
        }
    };

    /* Advances animation to the next frame, and returns the frame */
    this.nextFrame = function() {
        const frame = this.frames[this.currFrame++];
        return frame;
    };

    this.hasFrames = function() {
        return this.currFrame < this.frames.length;
    };

};

/* Combines the frames of two animations together. */
RG.Animation.Animation.prototype.combine = function(animation) {
    let frameIndex = 0;
    while (animation.hasFrames()) {
        const frame = animation.nextFrame();
        if (frameIndex < this.frames.length) {
            const frameKeys = Object.keys(frame);
            for (let i = 0; i < frameKeys.length; i++) {
                const xy = frameKeys[i];
                this.frames[frameIndex][xy] = frame[xy];
            }
        }
        else {
            this.frames.push(frame);
        }
        ++frameIndex;
    }
};

/* Returns true if any frame in the animation contains at least one coordinates
 * from the given list. */
RG.Animation.Animation.prototype.hasCoord = function(coordMap) {
    const nFrames = this.frames.length;
    for (let n = 0; n < nFrames; n++) {
        const frame = this.frames[n];
        for (const key in frame) {
            if (coordMap[key]) {
                return true;
            }
        }
    }
    return false;
};

module.exports = RG.Animation;
<commit_msg>Moved remaining funcs to prototype.<commit_after>
const RG = require('./rg');

RG.Animation = {};

/* Very simple "animation" object handed to the Screen object. slowDown can be
 * used to repeat the frame for addFrame() multiple times.
 *  Each frame should be an object such as
 *  {
 *    '1,1': {char: '-', className: 'css-class'},
 *    '2,2': {char: '-', className: 'css-class'}
 *  }
 * Screen object will always render specified chars to the given locations
 * over normal map cells.
 * */
RG.Animation.Animation = function() {
    this.levelID = -1;
    this.numFrames = 0;
    this.currFrame = 0;

    // "Slows" down the animation by this factor
    this.slowDown = 2;

    this.frames = [];
};

RG.Animation.Animation.prototype.setLevel = function(level) {
    this.levelID = level.getID();
};

RG.Animation.Animation.prototype.addFrame = function(frame) {
    for (let i = 0; i < this.slowDown; i++) {
        ++this.numFrames;
        this.frames.push(frame);
    }
};

/* Advances animation to the next frame, and returns the frame */
RG.Animation.Animation.prototype.nextFrame = function() {
    const frame = this.frames[this.currFrame++];
    return frame;
};

RG.Animation.Animation.prototype.hasFrames = function() {
    return this.currFrame < this.frames.length;
};

/* Combines the frames of two animations together. */
RG.Animation.Animation.prototype.combine = function(animation) {
    let frameIndex = 0;
    while (animation.hasFrames()) {
        const frame = animation.nextFrame();
        if (frameIndex < this.frames.length) {
            const frameKeys = Object.keys(frame);
            for (let i = 0; i < frameKeys.length; i++) {
                const xy = frameKeys[i];
                this.frames[frameIndex][xy] = frame[xy];
            }
        }
        else {
            this.frames.push(frame);
        }
        ++frameIndex;
    }
};

/* Returns true if any frame in the animation contains at least one coordinates
 * from the given list. */
RG.Animation.Animation.prototype.hasCoord = function(coordMap) {
    const nFrames = this.frames.length;
    for (let n = 0; n < nFrames; n++) {
        const frame = this.frames[n];
        for (const key in frame) {
            if (coordMap[key]) {
                return true;
            }
        }
    }
    return false;
};

module.exports = RG.Animation;
<|endoftext|>


<commit_before>'use strict';
const l10nFile = __dirname + '/../l10n/commands/inventory.yml';
const l10n = require('../src/l10n')(l10nFile);
const _    = require('../src/helpers');
const util = require('util');

exports.command = (rooms, items, players, npcs, Commands) => {
  return (args, player) => {
    const inventory   = player.getInventory();
    const equipped    = player.getEquipped();
    const equipment   = new Map();

    const longestSlot = Object.keys(equipped)
      .reduce((longest, key) => longest > key.length ? longest : key.length, 0);

    let longest = 0;

    for (let slot in equipped) {
      const item     = items.get(equipped[slot]);
      const name     = item.getShortDesc();
      const weight   = item.getWeight();
      const contents = item.isContainer() ? item.getInventory() : false;
      const capacity = item.isContainer() ?
        { max: item.getAttribute('maxSizeCapacity'), current: item.getSizeOfContents() } :
        null;
      equipment.set(slot, { name, weight, contents, capacity });

      longest = name.length > longest ?
        name.length :
        longest;
    }

    if (!equipment.size) {
      return player.warn(`You're stark naked, with nothing to your name...`);
    }

    player.say(
      `<bold>Your inventory:</bold>
      <green>Encumbrance: ${player.getCarriedWeight()}/${player.getMaxCarryWeight()} aums</green>
      `);

    const displayListItem = (name, nestingLevel) => player.say(`<cyan>${_.leftPad(nestingLevel)} - ${name}</cyan>`);

    for (let [slot, details] of equipment) {
      const { name, weight, contents, capacity } = details;
      const weightPadding = _.leftPad(longest - name.length);
      const namePadding   = _.leftPad(longestSlot - slot.length);
      player.say(`<magenta><${slot}></magenta>${namePadding} <bold>${name}</bold> ${weightPadding} | <cyan>weight: ${weight} gravets</cyan> ${printCap(capacity)}`);
      if (contents) {
        displayContainerContents(contents, 0, true);
      }
    }

    function displayContainerContents(contents, nestingLevel) {
      contents.forEach(item => item.isContainer() ?
        displayNestedContainer(item, nestingLevel) :
        displayListItem(item.getShortDesc(), nestingLevel));
    }

    function displayNestedContainer(item, nestingLevel) {
      displayListItem(item.getShortDesc(), nestingLevel);
      displayContainerContents(item.getInventory(), nestingLevel + 1);
    }

    function printCap(capacity) {
      if (!capacity) { return ''; }
      const { current, max } = capacity;
      return ` <green>${current}/${max} aums</green>`;
    }

  };
};
<commit_msg>Check for empty equipment right away. Extract container capacity formatting into a function.<commit_after>'use strict';
const l10nFile = __dirname + '/../l10n/commands/inventory.yml';
const l10n = require('../src/l10n')(l10nFile);
const _    = require('../src/helpers');
const util = require('util');

exports.command = (rooms, items, players, npcs, Commands) => {
  return (args, player) => {
    const inventory   = player.getInventory();
    const equipped    = player.getEquipped();

    if (!Object.keys(equipped).length) {
      return player.warn(`You're stark naked, with nothing to your name...`);
    }

    const equipment   = new Map();
    const longestSlot = Object.keys(equipped)
      .reduce((longest, key) => longest > key.length ? longest : key.length, 0);

    let longest = 0;

    for (let slot in equipped) {
      const item     = items.get(equipped[slot]);
      const name     = item.getShortDesc();
      const weight   = item.getWeight();
      const contents = item.isContainer() ? item.getInventory() : false;
      const capacity = item.isContainer() ?
        getContainerCapacity(item) :
        null;
      equipment.set(slot, { name, weight, contents, capacity });

      longest = name.length > longest ?
        name.length :
        longest;
    }

    player.say(
      `<bold>Your inventory:</bold>
      <green>Encumbrance: ${player.getCarriedWeight()}/${player.getMaxCarryWeight()} aums</green>
      `);

    const displayListItem = (name, nestingLevel) => player.say(`<cyan>${_.leftPad(nestingLevel)} - ${name}</cyan>`);

    for (let [slot, details] of equipment) {
      const { name, weight, contents, capacity } = details;
      const weightPadding = _.leftPad(longest - name.length);
      const namePadding   = _.leftPad(longestSlot - slot.length);
      player.say(`<magenta><${slot}></magenta>${namePadding} <bold>${name}</bold> ${weightPadding} | <cyan>weight: ${weight} gravets</cyan> ${printCap(capacity)}`);
      if (contents) {
        displayContainerContents(contents, 0, true);
      }
    }

    function displayContainerContents(contents, nestingLevel) {
      contents.forEach(item => item.isContainer() ?
        displayNestedContainer(item, nestingLevel) :
        displayListItem(item.getShortDesc(), nestingLevel));
    }

    function displayNestedContainer(item, nestingLevel) {
      displayListItem(item.getShortDesc(), nestingLevel);
      displayContainerContents(item.getInventory(), nestingLevel + 1);
    }

    function getContainerCapacity(item) {
      return {
        max:     item.getAttribute('maxSizeCapacity'),
        current: item.getSizeOfContents()
      };
    }

    function printCap(capacity) {
      if (!capacity) { return ''; }
      const { current, max } = capacity;
      return ` <green>${current}/${max} aums</green>`;
    }

  };
};
<|endoftext|>


<commit_before>var container;
var wrapper;
var page = 1;
var pageSize = 12;
var total = 9007199254740992; //max int
var isFetchingResults = false;

var stepsToMove;

var observations = [];
var previousEntryHolders = new Array();
var currentEntryHolders = new Array();
var futureEntryHolders = new Array();
var imageIndex;

var navigationDisabled = true;

var timerId = null;

jQuery(document).ready(function() {
	$ = jQuery;
	container = $('.new_observations_container');
	initializeImages();
	initializeCache();
	initializeHover();
	initializeTimer();
});

/**
 * Adds the object references to the different arrays and variables.
 */
function initializeImages() {
	previousEntryHolders[0] =  {
			content: $('#previousEntry01'),
			observationIndex : 0
	};
	previousEntryHolders[1] =  {
			content: $('#previousEntry02'),
			observationIndex : 0
	};
	previousEntryHolders[2] =  {
			content: $('#previousEntry03'),
			observationIndex : 0
	};
	previousEntryHolders[3] =  {
			content: $('#previousEntry04'),
			observationIndex : 0
	};
	currentEntryHolders[0] = {
			content: $('#currentEntry01'),
			observationIndex : 0
	};
	currentEntryHolders[1] = {
			content: $('#currentEntry02'),
			observationIndex : 0
	};
	currentEntryHolders[2] = {
			content: $('#currentEntry03'),
			observationIndex : 0
	};
	currentEntryHolders[3] = {
			content: $('#currentEntry04'),
			observationIndex : 0
	};
	futureEntryHolders[0] = {
			content: $('#futureEntry01'),
			observationIndex : 0
	};
	futureEntryHolders[1] = {
			content: $('#futureEntry02'),
			observationIndex : 0
	};
	futureEntryHolders[2] = {
			content: $('#futureEntry03'),
			observationIndex : 0
	};
	futureEntryHolders[3] = {
			content: $('#futureEntry04'),
			observationIndex : 0
	};
}

function initializeHover() {
	container.hover(function() {
		stopTimer();
	}, function() {
		initializeTimer();
	});
}

function initializeTimer() {
	if(timerId) stopTimer(timerId);
	timerId = setInterval(function() {moveImages(4); }, 8000);
}

function stopTimer() {
	if(timerId)
		clearInterval(timerId);
}

function cacheAllData(result) {

	// cache general information
	total = result.total;
	var tmpDiv = null;
	// cache observation information
	var j = 0;
	for(var i = (result.page-1) * pageSize; j < result.content.length; i++) {
		//we need to save the height of the new content.. add it to dom, wait for loading all images, get display height and remove it again.
		tmpDiv = $('
' + result.content[j++] + '
');
		container.append(tmpDiv.hide());
	}
	container.waitForImages(function() {
		k = 0;
		for(var i = (result.page-1) * pageSize; k < result.content.length; i++) {
			tmpDiv = $('.tmpDiv' + i);
			observations[i] = {
					content: result.content[k++],
					height: tmpDiv.height()
			};
			tmpDiv.remove();
		}
	});
}

function initializeCache() {
	showLoading(true);
	isFetchingResults = true;
	$.ajax({
		type: "POST",
		url: Drupal.settings.basePath + "observation/block/newobservations",
		success: function(result){
			showLoading(false,function() {
				cacheAllData(result);
				imageIndex = 0;
				loadImagesFromCache();
				container.waitForImages(function() {
					navigationDisabled = false;
					page++;
					isFetchingResults = false;
				});
			});
		},
		error: function(result) {
			isFetchingResults = false;
			showLoading(false);
		},
		data: {
			page: page
		}
	});

}
function fetchPage(steps) {
	if(isFetchingResults || (page-1) * pageSize >= parseInt(total)) return false; //no more observations to fetch
	showLoading(true);
	isFetchingResults = true;
	$.ajax({
		type: "POST",
		url: Drupal.settings.basePath + "observation/block/newobservations",
		success: function(result){
				cacheAllData(result);
				loadImagesFromCache();
				container.waitForImages(function() {
					showLoading(false,function() {
						navigationDisabled = false;
						page++;
						moveImages(steps);
						isFetchingResults = false;
					});
				});
		},
		error: function(result) {
			isFetchingResults = false;
			showLoading(false);
		},
		data: {
			page: page
		}
	});
	return true;
}

/**
 * Move the image index using the given number of steps (e.g. -4 moves four images back, 3 moves three images forward).
 * If the boolan replaceMainImage is set to true, the main image will be replaced with the destination image.
 *
 * @param steps number of steps to move
 * @param replaceMainImage if the main image should be replaced or not
 */
function moveImages(steps) {
	if (navigationDisabled) {
		return;
	}

	//if imageIndex + step + 4 future images  is greater then pagesize, and more images are available on server, fetch next page first to load the images
	tmpsteps = imageIndex + steps + 4;
	if(tmpsteps >= (page-1)*pageSize && (page-1)*pageSize < parseInt(total)) {
		navigationDisabled = true;
		fetchPage(steps);
		return;
	}
	stepsToMove = steps;

	navigationDisabled = true;

	animateCurrentImages();
}

/**
 * Loads the images from the cache using the imageIndex variable as index.
 * changeOpacityOfCurrentImages is used to if the opacity of images should be changed by showLoading()
 */
function loadImagesFromCache(changeOpacityOfCurrentImages) {
	var numberToCount;
	if(observations.length < currentEntryHolders.length) {
		numberToCount = observations.length - 1;
	} else {
		numberToCount = currentEntryHolders.length;
	}

	for (var i = 0; i < numberToCount; i ++) {
		// load previous thumbnail and fullsize images into cache
		var cleanIndex = checkIndex(imageIndex - numberToCount + i);
		previousEntryHolders[i].content.html(observations[cleanIndex].content);
		previousEntryHolders[i].observationIndex = cleanIndex;

		// load next thumbnail and fullsize images into cache
		cleanIndex = checkIndex(imageIndex + i);
		//display image (restarting at the beginning, if no more images can be fetched from the server
		currentEntryHolders[i].content.html(observations[cleanIndex].content);
		currentEntryHolders[i].observationIndex = cleanIndex;

		// load future thumbnail and fullsize images into cache
		cleanIndex = checkIndex(imageIndex + numberToCount + i);
		futureEntryHolders[i].content.html(observations[cleanIndex].content);
		futureEntryHolders[i].observationIndex = cleanIndex;

		previousEntryHolders[i].content.css({ height: 0, opacity: 0 });
		previousEntryHolders[i].content.hide();

		if (i < futureEntryHolders.length) {
			futureEntryHolders[i].content.css({ height: 0, opacity: 0 });
			futureEntryHolders[i].content.hide();
		}

		if(changeOpacityOfCurrentImages)
			currentEntryHolders[i].content.css({ height: observations[currentEntryHolders[i].observationIndex].height, opacity: 0.5 });
		else currentEntryHolders[i].content.css({ height: observations[currentEntryHolders[i].observationIndex].height, opacity: 1 });

		currentEntryHolders[i].content.show();
	}

	// hide next/previous button if there are not enough images to switch
	if (observations.length <= currentEntryHolders.length) {
		$('.imageSliderNavigation').hide();
		for (var i = observations.length - 1; i < currentEntryHolders.length; i ++) {
			currentEntryHolders[i].content.hide();
		}
	} else {
		$('.imageSliderNavigation').show();
		for (var i = observations.length - 1; i < currentEntryHolders.length; i ++) {
			currentEntryHolders[i].content.show();
		}
	}
	initLightBox();
}

/**
 * Animates the next images.
 *
 * @param replaceMainImage if the main image should be replaced or not
 */
function animateCurrentImages() {

	// set the new image index to reload the images
	imageIndex = checkIndex(stepsToMove + imageIndex);

	//check if the next images are positive or negative. if positive the future images will be loaded, if negative the previousEntryHolders will be loaded
	var positive = stepsToMove >= 0;
	for (var i = 0; i < Math.abs(stepsToMove); i ++) {
		if (positive) {
			if (i < futureEntryHolders.length) {
				futureEntryHolders[i].content.show();
				futureEntryHolders[i].content.animate({ height: observations[futureEntryHolders[i].observationIndex].height, opacity: 1 }, 1500, function() {
					navigationDisabled = false;
				});
			}
			if (i < currentEntryHolders.length) {
				if(i >= Math.abs(stepsToMove) - 1){
					currentEntryHolders[i].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						loadImagesFromCache();
						navigationDisabled = false;
					});
				} else {
					currentEntryHolders[i].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						navigationDisabled = false;
					});
				}
			}
		} else {
			if (i < previousEntryHolders.length) {
				var cleanIndex = currentEntryHolders.length - i - 1;
				if (cleanIndex < 0) {
					cleanIndex = 0;
				}
				previousEntryHolders[cleanIndex].content.show();
				previousEntryHolders[cleanIndex].content.animate({ height: observations[previousEntryHolders[cleanIndex].observationIndex].height, opacity: 1 }, 1500, function() {
					navigationDisabled = false;
				});
			}
			if (i < currentEntryHolders.length) {
				if(i >= Math.abs(stepsToMove) - 1){
					currentEntryHolders[currentEntryHolders.length - i - 1].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						loadImagesFromCache();
						navigationDisabled = false;
					});
				} else {
					currentEntryHolders[currentEntryHolders.length - i - 1].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						navigationDisabled = false;
					});
				}
			}
		}
	}
}

/**
 * Checks if the index is below zero or above the array length and returns a valid index (regarding the image loop)
 *
 * @param index the index to check if it's valid
 */
function checkIndex(index) {
	if (index < 0) {
		return observations.length + index;
	} else if (index >= observations.length) {
		return index % observations.length;
	} else {
		return index;
	}
}

/**
 * Initializes the light box.
 */
function initLightBox() {
	var galleryLightboxSettings = {
		captionSelector : ".block_newest_observation_img_caption",
		captionAttr : false,
		captionHTML : true,
	};

	$('a.lightbox').lightBox(galleryLightboxSettings);
}

function showLoading(display, completeCallback) {
	if(display) {
		$('#showLoadingImage').css({ top: - container.height()/2});
		$('#showLoadingImage').show();
		if(completeCallback)
			container.fadeTo("slow", 0.5, completeCallback);
		else
			container.fadeTo("slow", 0.5);
	} else {
		 $('#showLoadingImage').hide();
		 if(completeCallback)
			 container.fadeTo("slow", 1, completeCallback);
		 else
			 container.fadeTo("slow", 1);
	}
}<commit_msg>smoother transition<commit_after>var container;
var wrapper;
var page = 1;
var pageSize = 12;
var total = 9007199254740992; //max int
var isFetchingResults = false;

var stepsToMove;

var observations = [];
var previousEntryHolders = new Array();
var currentEntryHolders = new Array();
var futureEntryHolders = new Array();
var imageIndex;

var navigationDisabled = true;

var timerId = null;

jQuery(document).ready(function() {
	$ = jQuery;
	container = $('.new_observations_container');
	initializeImages();
	initializeCache();
	initializeHover();
	initializeTimer();
});

/**
 * Adds the object references to the different arrays and variables.
 */
function initializeImages() {
	previousEntryHolders[0] =  {
			content: $('#previousEntry01'),
			observationIndex : 0
	};
	previousEntryHolders[1] =  {
			content: $('#previousEntry02'),
			observationIndex : 0
	};
	previousEntryHolders[2] =  {
			content: $('#previousEntry03'),
			observationIndex : 0
	};
	previousEntryHolders[3] =  {
			content: $('#previousEntry04'),
			observationIndex : 0
	};
	currentEntryHolders[0] = {
			content: $('#currentEntry01'),
			observationIndex : 0
	};
	currentEntryHolders[1] = {
			content: $('#currentEntry02'),
			observationIndex : 0
	};
	currentEntryHolders[2] = {
			content: $('#currentEntry03'),
			observationIndex : 0
	};
	currentEntryHolders[3] = {
			content: $('#currentEntry04'),
			observationIndex : 0
	};
	futureEntryHolders[0] = {
			content: $('#futureEntry01'),
			observationIndex : 0
	};
	futureEntryHolders[1] = {
			content: $('#futureEntry02'),
			observationIndex : 0
	};
	futureEntryHolders[2] = {
			content: $('#futureEntry03'),
			observationIndex : 0
	};
	futureEntryHolders[3] = {
			content: $('#futureEntry04'),
			observationIndex : 0
	};
}

function initializeHover() {
	container.hover(function() {
		stopTimer();
	}, function() {
		initializeTimer();
	});
}

function initializeTimer() {
	if(timerId) stopTimer(timerId);
	timerId = setInterval(function() {moveImages(4); }, 8000);
}

function stopTimer() {
	if(timerId)
		clearInterval(timerId);
}

function cacheAllData(result) {

	// cache general information
	total = result.total;
	var tmpDiv = null;
	// cache observation information
	var j = 0;
	for(var i = (result.page-1) * pageSize; j < result.content.length; i++) {
		//we need to save the height of the new content.. add it to dom, wait for loading all images, get display height and remove it again.
		tmpDiv = $('
' + result.content[j++] + '
').hide();
		container.append(tmpDiv.hide());
	}
	container.waitForImages(function() {
		k = 0;
		for(var i = (result.page-1) * pageSize; k < result.content.length; i++) {
			tmpDiv = $('.tmpDiv' + i);
			observations[i] = {
					content: result.content[k++],
					height: tmpDiv.height()
			};
			tmpDiv.remove();
		}
	});
}

function initializeCache() {
	showLoading(true);
	isFetchingResults = true;
	$.ajax({
		type: "POST",
		url: Drupal.settings.basePath + "observation/block/newobservations",
		success: function(result){
			showLoading(false,function() {
				cacheAllData(result);
				imageIndex = 0;
				loadImagesFromCache();
				container.waitForImages(function() {
					navigationDisabled = false;
					page++;
					isFetchingResults = false;
				});
			});
		},
		error: function(result) {
			isFetchingResults = false;
			showLoading(false);
		},
		data: {
			page: page
		}
	});

}
function fetchPage(steps) {
	if(isFetchingResults || (page-1) * pageSize >= parseInt(total)) return false; //no more observations to fetch
	showLoading(true);
	isFetchingResults = true;
	$.ajax({
		type: "POST",
		url: Drupal.settings.basePath + "observation/block/newobservations",
		success: function(result){
				cacheAllData(result);
				loadImagesFromCache();
				container.waitForImages(function() {
					showLoading(false,function() {
						navigationDisabled = false;
						page++;
						moveImages(steps);
						isFetchingResults = false;
					});
				});
		},
		error: function(result) {
			isFetchingResults = false;
			showLoading(false);
		},
		data: {
			page: page
		}
	});
	return true;
}

/**
 * Move the image index using the given number of steps (e.g. -4 moves four images back, 3 moves three images forward).
 * If the boolan replaceMainImage is set to true, the main image will be replaced with the destination image.
 *
 * @param steps number of steps to move
 * @param replaceMainImage if the main image should be replaced or not
 */
function moveImages(steps) {
	if (navigationDisabled) {
		return;
	}

	//if imageIndex + step + 4 future images  is greater then pagesize, and more images are available on server, fetch next page first to load the images
	tmpsteps = imageIndex + steps + 4;
	if(tmpsteps >= (page-1)*pageSize && (page-1)*pageSize < parseInt(total)) {
		navigationDisabled = true;
		fetchPage(steps);
		return;
	}
	stepsToMove = steps;

	navigationDisabled = true;

	animateCurrentImages();
}

/**
 * Loads the images from the cache using the imageIndex variable as index.
 * changeOpacityOfCurrentImages is used to if the opacity of images should be changed by showLoading()
 */
function loadImagesFromCache(changeOpacityOfCurrentImages) {
	var numberToCount;
	if(observations.length < currentEntryHolders.length) {
		numberToCount = observations.length - 1;
	} else {
		numberToCount = currentEntryHolders.length;
	}

	for (var i = 0; i < numberToCount; i ++) {
		// load previous thumbnail and fullsize images into cache
		var cleanIndex = checkIndex(imageIndex - numberToCount + i);
		previousEntryHolders[i].content.html(observations[cleanIndex].content);
		previousEntryHolders[i].observationIndex = cleanIndex;

		// load next thumbnail and fullsize images into cache
		cleanIndex = checkIndex(imageIndex + i);
		//display image (restarting at the beginning, if no more images can be fetched from the server
		currentEntryHolders[i].content.html(observations[cleanIndex].content);
		currentEntryHolders[i].observationIndex = cleanIndex;

		// load future thumbnail and fullsize images into cache
		cleanIndex = checkIndex(imageIndex + numberToCount + i);
		futureEntryHolders[i].content.html(observations[cleanIndex].content);
		futureEntryHolders[i].observationIndex = cleanIndex;

		previousEntryHolders[i].content.css({ height: 0, opacity: 0 });
		previousEntryHolders[i].content.hide();

		if (i < futureEntryHolders.length) {
			futureEntryHolders[i].content.css({ height: 0, opacity: 0 });
			futureEntryHolders[i].content.hide();
		}

		if(changeOpacityOfCurrentImages)
			currentEntryHolders[i].content.css({ height: observations[currentEntryHolders[i].observationIndex].height, opacity: 0.5 });
		else currentEntryHolders[i].content.css({ height: observations[currentEntryHolders[i].observationIndex].height, opacity: 1 });

		currentEntryHolders[i].content.show();
	}

	// hide next/previous button if there are not enough images to switch
	if (observations.length <= currentEntryHolders.length) {
		$('.imageSliderNavigation').hide();
		for (var i = observations.length - 1; i < currentEntryHolders.length; i ++) {
			currentEntryHolders[i].content.hide();
		}
	} else {
		$('.imageSliderNavigation').show();
		for (var i = observations.length - 1; i < currentEntryHolders.length; i ++) {
			currentEntryHolders[i].content.show();
		}
	}
	initLightBox();
}

/**
 * Animates the next images.
 *
 * @param replaceMainImage if the main image should be replaced or not
 */
function animateCurrentImages() {

	// set the new image index to reload the images
	imageIndex = checkIndex(stepsToMove + imageIndex);

	//check if the next images are positive or negative. if positive the future images will be loaded, if negative the previousEntryHolders will be loaded
	var positive = stepsToMove >= 0;
	for (var i = 0; i < Math.abs(stepsToMove); i ++) {
		if (positive) {
			if (i < futureEntryHolders.length) {
				futureEntryHolders[i].content.show();
				futureEntryHolders[i].content.animate({ height: observations[futureEntryHolders[i].observationIndex].height, opacity: 1 }, 1500, function() {
					navigationDisabled = false;
				});
			}
			if (i < currentEntryHolders.length) {
				if(i >= Math.abs(stepsToMove) - 1){
					currentEntryHolders[i].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						loadImagesFromCache();
						navigationDisabled = false;
					});
				} else {
					currentEntryHolders[i].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						navigationDisabled = false;
					});
				}
			}
		} else {
			if (i < previousEntryHolders.length) {
				var cleanIndex = currentEntryHolders.length - i - 1;
				if (cleanIndex < 0) {
					cleanIndex = 0;
				}
				previousEntryHolders[cleanIndex].content.show();
				previousEntryHolders[cleanIndex].content.animate({ height: observations[previousEntryHolders[cleanIndex].observationIndex].height, opacity: 1 }, 1500, function() {
					navigationDisabled = false;
				});
			}
			if (i < currentEntryHolders.length) {
				if(i >= Math.abs(stepsToMove) - 1){
					currentEntryHolders[currentEntryHolders.length - i - 1].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						loadImagesFromCache();
						navigationDisabled = false;
					});
				} else {
					currentEntryHolders[currentEntryHolders.length - i - 1].content.animate({ height: 0, opacity: 0 }, 1500, function() {
						navigationDisabled = false;
					});
				}
			}
		}
	}
}

/**
 * Checks if the index is below zero or above the array length and returns a valid index (regarding the image loop)
 *
 * @param index the index to check if it's valid
 */
function checkIndex(index) {
	if (index < 0) {
		return observations.length + index;
	} else if (index >= observations.length) {
		return index % observations.length;
	} else {
		return index;
	}
}

/**
 * Initializes the light box.
 */
function initLightBox() {
	var galleryLightboxSettings = {
		captionSelector : ".block_newest_observation_img_caption",
		captionAttr : false,
		captionHTML : true,
	};

	$('a.lightbox').lightBox(galleryLightboxSettings);
}

function showLoading(display, completeCallback) {
	if(display) {
		$('#showLoadingImage').css({ top: - container.height()/2});
		$('#showLoadingImage').show();
		if(completeCallback)
			container.fadeTo("slow", 0.5, completeCallback);
		else
			container.fadeTo("slow", 0.5);
	} else {
		 $('#showLoadingImage').hide();
		 if(completeCallback)
			 container.fadeTo("slow", 1, completeCallback);
		 else
			 container.fadeTo("slow", 1);
	}
}<|endoftext|>


<commit_before>app.controller('controlsController', ['$scope', '$http', function($scope, $http) {
  $scope.types = ['line', 'spline', 'step', 'area', 'area-spline', 'area-step'];
  $scope.type = 'area-spline';

  $scope.$watch(function(scope){
    return scope.type;
  }, function(newValue){
    for (var i in $scope.data.types) {
      $scope.data.types[i] = newValue;
    }
    refreshChartData();
  });

  $scope.data = {
    x: 'x',
    columns: [
      ['x']
    ],
    types: {}
  };

  var dates,
      nuclear,
      solar,
      wind,
      windSolar,
      btuTotal,
      mwTotal,
      events = {
        nuclear: [],
        solar: [],
        wind: []
      };

  $http.get('json/productionData.json').success(function(data){
    console.log(data);
    dates = ['x'].concat(_.pluck(data, 'year'));
    nuclear = ['Nuclear'].concat(_.pluck(data, 'nuclear'));
    solar = ['Solar'].concat(_.pluck(data, 'solar'));
    wind = ['Wind'].concat(_.pluck(data, 'wind'));
    windSolar = ['Wind & Solar'].concat(_.pluck(data, 'wind solar'));
    btuTotal = ['Trillion BTU Total'].concat(_.pluck(data, 'trillionBtuTotal'));
    mwTotal = ['MegaWatt Total'].concat(_.pluck(data, 'MWTotal'));

    applyEventsToChartData();  });

  function addEvent(powerType, btuDelta, date){
    var e = {
      btuDelta: btuDelta,
      date: date
    };
    events[powerType].push(e);
    applyEventsToChartData();
  }

  function applyEventsToChartData(){
    $scope.data.columns = [];
    $scope.data.columns[0] = dates;

    var _nuclear = nuclear.concat([]),
        _solar = solar.concat([]),
        _wind = wind.concat([]);

    _.each(events.nuclear, function(e){ applyEventToDataSet(_nuclear, e); });
    _.each(events.solar, function(e){ applyEventToDataSet(_solar, e); });
    _.each(events.wind, function(e){ applyEventToDataSet(_wind, e); });

    addDataSet('Nuclear', _nuclear);
    addDataSet('Solar', _solar);
    addDataSet('Wind', _wind);
    //addDataSet('Wind & Solar', windSolar);
    //addDataSet('Total', btuTotal);
    //addDataSet('MegaWatt Total', mwTotal);
  }

  function applyEventToDataSet(dataSet, e){
    for (var i = 0; i < dataSet.length; i++){
      if (dates[i] >= e.date){
        dataSet[i] = dataSet[i] + e.btuDelta;
      }
    }
  }

  var customers = ['detailed-service-client1', 'detailed-service-client2', 'detailed-service-client3', 'detailed-service-client4'];
  // init w/ the detailed 4 customer data
//  for (var i in customers){
//    loadRawData(customers[i]);
//  }

  function loadRawData(source){
    $http.get('/api/collections/raw?take=100&query=' + JSON.stringify({ Source: source })).success(function(data){
      addDetailedClientDataSet(source, data);
    });
  }

  function addDetailedClientDataSet(name, dataSet){
    var kwh_c = [],
        kwh_g = [],
        dates = [];
    for (var i in dataSet){
      kwh_c.push(dataSet[i].kwh_c);
      kwh_g.push(dataSet[i].kwh_g);
      var date = new Date(Date.parse(dataSet[i].dt));
      dates.push(date);
    }
    dates.unshift('x');
    $scope.data.columns[0] = dates;

    var name_kwh_c = name + '_kwh_c',
        name_kwh_g = name + '_kwh_g';
    kwh_c.unshift(name_kwh_c);
    kwh_g.unshift(name_kwh_g);

    addDataSet(name_kwh_c, kwh_c);
    addDataSet(name_kwh_g, kwh_g);
  }

  function addDataSet(name, dataSet){
    $scope.data.columns.push(dataSet);
    $scope.data.types[name] = $scope.type;
    refreshChartData();
  }

  $scope.changeType = function(dataName, type){
    $scope.data.types[dataName] = type;
    refreshChartData();
  };

  function refreshChartData(){
    if ($scope.chart){
      $scope.chart.load($scope.data);
    }
  }

  function btuToMw(btu){
    return btu * 0.3;
  }
}]);<commit_msg>added function to delete event. added funciton to create dummy event.<commit_after>app.controller('controlsController', ['$scope', '$http', function($scope, $http) {
  $scope.types = ['line', 'spline', 'step', 'area', 'area-spline', 'area-step'];
  $scope.type = 'area-spline';

  $scope.$watch(function(scope){
    return scope.type;
  }, function(newValue){
    for (var i in $scope.data.types) {
      $scope.data.types[i] = newValue;
    }
    refreshChartData();
  });

  $scope.data = {
    x: 'x',
    columns: [
      ['x']
    ],
    types: {}
  };

  var dates,
      nuclear,
      solar,
      wind,
      windSolar,
      btuTotal,
      mwTotal;

  $scope.events = {
    nuclear: [],
    solar: [],
    wind: []
  };

  $http.get('json/productionData.json').success(function(data){
    console.log(data);
    dates = ['x'].concat(_.pluck(data, 'year'));
    nuclear = ['Nuclear'].concat(_.pluck(data, 'nuclear'));
    solar = ['Solar'].concat(_.pluck(data, 'solar'));
    wind = ['Wind'].concat(_.pluck(data, 'wind'));
    windSolar = ['Wind & Solar'].concat(_.pluck(data, 'wind solar'));
    btuTotal = ['Trillion BTU Total'].concat(_.pluck(data, 'trillionBtuTotal'));
    mwTotal = ['MegaWatt Total'].concat(_.pluck(data, 'MWTotal'));

    applyEventsToChartData();
  });

  function addEvent(powerType, btuDelta, date){
    var e = {
      btuDelta: btuDelta,
      date: date
    };
    events[powerType].push(e);
    applyEventsToChartData();
  }

  function applyEventsToChartData(){
    $scope.data.columns = [];
    $scope.data.columns[0] = dates;

    var _nuclear = nuclear.concat([]),
        _solar = solar.concat([]),
        _wind = wind.concat([]);

    _.each($scope.events.nuclear, function(e){ applyEventToDataSet(_nuclear, e); });
    _.each($scope.events.solar, function(e){ applyEventToDataSet(_solar, e); });
    _.each($scope.events.wind, function(e){ applyEventToDataSet(_wind, e); });

    addDataSet('Nuclear', _nuclear);
    addDataSet('Solar', _solar);
    addDataSet('Wind', _wind);
    //addDataSet('Wind & Solar', windSolar);
    //addDataSet('Total', btuTotal);
    //addDataSet('MegaWatt Total', mwTotal);
  }

  function applyEventToDataSet(dataSet, e){
    for (var i = 0; i < dataSet.length; i++){
      if (dates[i] >= e.date){
        dataSet[i] = dataSet[i] + e.btuDelta;
      }
    }
  }

  $scope.removeEvent = function(e){
    for (var i in events){
      var index = events[i].indexOf(e);
      if (index > -1){
        delete events[i][index];
      }
    }
  };

  $scope.addDummyEvent = function(){
    addEvent('solar', 10, 2030);
  };

  var customers = ['detailed-service-client1', 'detailed-service-client2', 'detailed-service-client3', 'detailed-service-client4'];
  // init w/ the detailed 4 customer data
//  for (var i in customers){
//    loadRawData(customers[i]);
//  }

  function loadRawData(source){
    $http.get('/api/collections/raw?take=100&query=' + JSON.stringify({ Source: source })).success(function(data){
      addDetailedClientDataSet(source, data);
    });
  }

  function addDetailedClientDataSet(name, dataSet){
    var kwh_c = [],
        kwh_g = [],
        dates = [];
    for (var i in dataSet){
      kwh_c.push(dataSet[i].kwh_c);
      kwh_g.push(dataSet[i].kwh_g);
      var date = new Date(Date.parse(dataSet[i].dt));
      dates.push(date);
    }
    dates.unshift('x');
    $scope.data.columns[0] = dates;

    var name_kwh_c = name + '_kwh_c',
        name_kwh_g = name + '_kwh_g';
    kwh_c.unshift(name_kwh_c);
    kwh_g.unshift(name_kwh_g);

    addDataSet(name_kwh_c, kwh_c);
    addDataSet(name_kwh_g, kwh_g);
  }

  function addDataSet(name, dataSet){
    $scope.data.columns.push(dataSet);
    $scope.data.types[name] = $scope.type;
    refreshChartData();
  }

  $scope.changeType = function(dataName, type){
    $scope.data.types[dataName] = type;
    refreshChartData();
  };

  function refreshChartData(){
    if ($scope.chart){
      $scope.chart.load($scope.data);
    }
  }

  function btuToMw(btu){
    return btu * 0.3;
  }
}]);<|endoftext|>


<commit_before>const { exec } = require('child_process');
const { isMac } = require('../../utils/misc');
const searchConfig = require('../searchConfig.js');

function checkDiskSpace(path, resolve, reject) {
    if (!path) {
        reject(new Error("Please provide path"));
        return;
    }

    if (isMac) {
        exec("df -k '" + path.replace(/'/g,"'\\''") + "'", (error, stdout, stderr) => {
            if (error) {
                if (stderr.indexOf("No such file or directory") !== -1) {
                    return reject(new Error("No such file or directory : " + error))
                }
                return reject(new Error("Error : " + error));
            }

            let data = stdout.trim().split("\n");

            let disk_info_str = data[data.length - 1].replace( /[\s\n\r]+/g,' ');
            let freeSpace = disk_info_str.split(' ');
            let space = freeSpace[3] * 1024;
            return resolve(space >= searchConfig.MINIMUM_DISK_SPACE);
        });
    } else {
        exec(`fsutil volume diskfree ${path}`, (error, stdout) => {
            if (error) {
                if (stdout.indexOf("Error:  The system cannot find the path specified.") !== -1) {
                    return reject(new Error("No such file or directory : " + error));
                }
                if (stdout.indexOf("The FSUTIL utility requires that you have administrative privileges.") !== -1) {
                    // this is temporary until we use the custom exe file.
                    return true;
                }
                return reject(new Error("Error : " + error));
            }
            if (stdout.indexOf("The FSUTIL utility requires that you have administrative privileges.") !== -1) {
                // this is temporary until we use the custom exe file.
                return true;
            }
            let data = stdout.trim().split("\n");

            let disk_info_str = data[data.length - 1].split(':');
            return resolve(disk_info_str[1] >= searchConfig.MINIMUM_DISK_SPACE);
        });
    }
}

module.exports = {
    checkDiskSpace: checkDiskSpace
};<commit_msg>SEARCH-605<commit_after>const { exec } = require('child_process');
const { isMac } = require('../../utils/misc');
const searchConfig = require('../searchConfig.js');

function checkDiskSpace(path, resolve, reject) {
    if (!path) {
        reject(new Error("Please provide path"));
        return;
    }

    if (isMac) {
        exec("df -k '" + path.replace(/'/g,"'\\''") + "'", (error, stdout, stderr) => {
            if (error) {
                if (stderr.indexOf("No such file or directory") !== -1) {
                    return reject(new Error("No such file or directory : " + error))
                }
                return reject(new Error("Error : " + error));
            }

            let data = stdout.trim().split("\n");

            let disk_info_str = data[data.length - 1].replace( /[\s\n\r]+/g,' ');
            let freeSpace = disk_info_str.split(' ');
            let space = freeSpace[3] * 1024;
            return resolve(space >= searchConfig.MINIMUM_DISK_SPACE);
        });
    } else {
        exec(`fsutil volume diskfree ${path}`, (error, stdout) => {
            if (error) {
                if (stdout.indexOf("Error:  The system cannot find the path specified.") !== -1) {
                    return reject(new Error("No such file or directory : " + error));
                }
                if (stdout.indexOf("The FSUTIL utility requires that you have administrative privileges.") !== -1) {
                    // this is temporary until we use the custom exe file.
                    return resolve(true);
                }
                return reject(new Error("Error : " + error));
            }
            if (stdout.indexOf("The FSUTIL utility requires that you have administrative privileges.") !== -1) {
                // this is temporary until we use the custom exe file.
                return resolve(true);
            }
            let data = stdout.trim().split("\n");

            let disk_info_str = data[data.length - 1].split(':');
            return resolve(disk_info_str[1] >= searchConfig.MINIMUM_DISK_SPACE);
        });
    }
}

module.exports = {
    checkDiskSpace: checkDiskSpace
};<|endoftext|>


<commit_before>DEBUG = true;
GU = 10;

CENTER = {
  x: 8,
  y: 4.5
};

MOUSE = {x: 0, y: 0, left: false, right: false};

missedGFXFrames = 0;

/* smoothstep interpolates between a and b, at time t from 0 to 1 */
function smoothstep(a, b, t) {
  var v = t * t * (3 - 2 * t);
  return b * v + a * (1 - v);
}

function clamp(low, x, high) {
  return Math.max(low, Math.min(x, high));
}

function loadImage(path) {
  var img = new Image();
  loaded++;
  img.onload = function() {
    loaded--;
  };
  img.src = path;
  return img;
}

window.requestAnimFrame = (function() {
  return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 0);
    };
})();

function loop() {
  if (loaded > 0) {
    canvas.width = canvas.width;
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillText("Loading " + loaded, 8 * GU, 4.5 * GU);
    requestAnimFrame(loop);
    return;
  }
  t = +new Date();
  dt += (t - old_time);
  old_time = t;
  while (dt > 20) {
    sm.update();
    dt -= 20;
  }
  /* clearing canvas */
  canvas.width = canvas.width;
  sm.render(ctx);

  requestAnimFrame(loop);
}

function bootstrap() {

  loaded = 1;

  /* global on purpose */
  canvas = document.createElement("canvas");
  ctx = canvas.getContext("2d");
  canvas.style.zIndex = 999;
  game_data = readData();

  sm = new StateManager();

  AudioButton.prototype.sprite_on = loadImage("res/audio_on.png");
  AudioButton.prototype.sprite_off = loadImage("res/audio_off.png");

  dt = 0;
  t = 0;
  time = +new Date();
  old_time = time;
  KEYS = [];
  for (var i = 0; i < 256; i++) {
    KEYS[i] = false;
  }

  document.addEventListener("keydown", function(e) {
    KEYS[e.keyCode] = true;
  });

  document.addEventListener("keyup", function(e) {
    KEYS[e.keyCode] = false;
  });

  // prevent context menu from appearing on right click
  document.addEventListener('contextmenu', function(e) {
    if (e.button === 2) {
      e.preventDefault();
      return false;
    }
  }, false);

  document.addEventListener("mousedown", function(e) {
    if (e.button === 0) {
      MOUSE.left = true;
    } else if (e.button === 2) {
      MOUSE.right = true;
    }
  });

  document.addEventListener("mouseup", function(e) {
    if (e.button === 0) {
      MOUSE.left = false;
    } else if (e.button === 2) {
      MOUSE.right = false;
    }
  });

  /* add game states here */

  sm.addState("game", new GameState());
  sm.addState("menu", new MenuState());

  document.body.appendChild(canvas);

  resize({});

  /* start the game */

  sm.changeState("game");

  loaded--;
  requestAnimFrame(loop);
}

function resize(e) {
  if (window.innerWidth / window.innerHeight > 16 / 9) {
    GU = (window.innerHeight / 9);
  } else {
    GU = (window.innerWidth / 16);
  }
  if (typeof canvas !== "undefined") {
    canvas.width = 16 * GU;
    canvas.height = 9 * GU;
    canvas.style.margin = (($(window).height() - 9 * GU) / 2) + "px 0 0 " + (($(window).width() - 16 * GU) / 2) + "px";
    var wrapper = document.getElementById('wrapper');
    wrapper.style.margin = canvas.style.margin;
    wrapper.style.width = 16 * GU + 'px';
    wrapper.style.height = 9 * GU + 'px';
    wrapper.style.fontSize = 0.15 * GU + 'px';
    wrapper.style.zIndex = 99999999;
  }
}

function saveData(data) {
  json_data = JSON.stringify(data);
  setCookie("game_data", json_data, 10 ^ 5);
}

function readData() {
  json_data = getCookie("game_data");
  if (typeof json_data !== "undefined") {
    return JSON.parse(json_data);
  } else {
    /* default game_data object */
    return {progress: [0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]};
  }
}

function setCookie(c_name, value, exdays) {
  var exdate = new Date();
  exdate.setDate(exdate.getDate() + exdays);
  var c_value = encodeURIComponent(value) + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString());
  document.cookie = c_name + "=" + c_value;
}

function getCookie(c_name) {
  var i, x, y, ARRcookies = document.cookie.split(";");
  for (i = 0; i < ARRcookies.length; i++) {
    x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
    y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
    x = x.replace(/^\s+|\s+$/g, "");
    if (x == c_name) {
      return decodeURIComponent(y);
    }
  }
}

function relMouseCoords(e) {
  if (e.type !== "touchstart") {
    e.preventDefault();
  }
  if (typeof this.canvas === "undefined") {
    return {x: 0, y: 0};
  }
  var currentElement = this.canvas;
  var totalOffsetX = 0;
  var totalOffsetY = 0;
  var canvasX = 0;
  var canvasY = 0;

  do {
    totalOffsetX += currentElement.offsetLeft;
    totalOffsetY += currentElement.offsetTop;
  }
  while (currentElement = currentElement.offsetParent);

  canvasX = (e.pageX || (e.touches && e.touches[0] && e.touches[0].pageX) || (this.cached_coords.x + totalOffsetX)) - totalOffsetX;
  canvasY = (e.pageY || (e.touches && e.touches[0] && e.touches[0].pageY) || (this.cached_coords.y + totalOffsetY)) - totalOffsetY;

  return {x: canvasX / GU, y: canvasY / GU}
}

if (window.navigator.msPointerEnabled) {
  document.addEventListener("MSPointerDown", handleEvent);
  document.addEventListener("MSPointerMove", function(e) {
    e.preventDefault();
    e.stopPropagation();
    handleEvent(e);
    return false;
  });
} else {
  document.addEventListener('touchstart', handleEvent);
  document.addEventListener('click', handleEvent);
  document.addEventListener("mousemove", handleEvent);
  document.addEventListener('touchmove', function(e) {
    e.preventDefault();
    e.stopPropagation();
    handleEvent(e);
    return false;
  });
}

function handleEvent(e) {
  e.preventDefault();
  var position = relMouseCoords(e);
  MOUSE.x = position.x;
  MOUSE.y = position.y;
  var eventType = (e.type === "mousemove" || e.type === "touchmove" || e.type === "pointermove" ? "hover" : "click");
  var clickables = [];
  if (typeof sm === "undefined") {
    return;
  } else if (typeof sm.activeState.gameMenuWindow !== "undefined" && sm.activeState.gameMenuWindow.visible) {
    clickables = sm.activeState.gameMenuWindow.buttons;
  } else {
    clickables = sm.activeState.elements;
  }
  var coordX, coordY, sizeX, sizeY;
  var hoverOverClickable = false;
  for (var i = 0; i < clickables.length; i++) {
    coordX = clickables[i][1].x;
    coordY = clickables[i][1].y;
    sizeX = clickables[i][1].w;
    sizeY = clickables[i][1].h;
    if (MOUSE.x >= coordX && MOUSE.x <= coordX + sizeX && MOUSE.y >= coordY && MOUSE.y <= coordY + sizeY) {
      if (eventType === "click") {
        clickables[i][0](clickables[i].slice(2));
      } else if (eventType === "hover") {
        hoverOverClickable = true;
      }
      break;
    }
  }
  clickables && clickables[i] && clickables[i][1].hover && clickables[i][1].hover();
  $("body").css('cursor', hoverOverClickable ? "pointer" : "auto");
}

window.addEventListener('resize', resize);

/* global mixin for position/size-objects that do AABB collision with another posititon/size-object */
function contains(obj) {
  return obj.position.x < this.position.x + this.size.w &&
    obj.position.x + obj.size.w > this.position.x &&
    obj.position.y < this.position.y + this.size.h &&
    obj.position.y + obj.size.h > this.position.y;
}

// Array Remove - By John Resig (MIT Licensed)
Array.remove = function(array, from, to) {
  var rest = array.slice((to || from) + 1 || array.length);
  array.length = from < 0 ? array.length + from : from;
  return array.push.apply(array, rest);
}

function highResolution() {
  var pixelRatio = 1;
  if (window.devicePixelRatio) {
    pixelRatio = window.devicePixelRatio;
  }
  return pixelRatio * $(window).width() > 1440 && pixelRatio * $(window).height() > 810;
}
<commit_msg>Set ms per frame to 15<commit_after>DEBUG = true;
GU = 10;

CENTER = {
  x: 8,
  y: 4.5
};

MOUSE = {x: 0, y: 0, left: false, right: false};

missedGFXFrames = 0;

/* smoothstep interpolates between a and b, at time t from 0 to 1 */
function smoothstep(a, b, t) {
  var v = t * t * (3 - 2 * t);
  return b * v + a * (1 - v);
}

function clamp(low, x, high) {
  return Math.max(low, Math.min(x, high));
}

function loadImage(path) {
  var img = new Image();
  loaded++;
  img.onload = function() {
    loaded--;
  };
  img.src = path;
  return img;
}

window.requestAnimFrame = (function() {
  return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 0);
    };
})();

var MS_PER_FRAME = 15;
function loop() {
  if (loaded > 0) {
    canvas.width = canvas.width;
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillText("Loading " + loaded, 8 * GU, 4.5 * GU);
    requestAnimFrame(loop);
    return;
  }
  t = +new Date();
  dt += (t - old_time);
  old_time = t;
  while (dt > MS_PER_FRAME) {
    sm.update();
    dt -= MS_PER_FRAME;
  }
  /* clearing canvas */
  canvas.width = canvas.width;
  sm.render(ctx);

  requestAnimFrame(loop);
}

function bootstrap() {

  loaded = 1;

  /* global on purpose */
  canvas = document.createElement("canvas");
  ctx = canvas.getContext("2d");
  canvas.style.zIndex = 999;
  game_data = readData();

  sm = new StateManager();

  AudioButton.prototype.sprite_on = loadImage("res/audio_on.png");
  AudioButton.prototype.sprite_off = loadImage("res/audio_off.png");

  dt = 0;
  t = 0;
  time = +new Date();
  old_time = time;
  KEYS = [];
  for (var i = 0; i < 256; i++) {
    KEYS[i] = false;
  }

  document.addEventListener("keydown", function(e) {
    KEYS[e.keyCode] = true;
  });

  document.addEventListener("keyup", function(e) {
    KEYS[e.keyCode] = false;
  });

  // prevent context menu from appearing on right click
  document.addEventListener('contextmenu', function(e) {
    if (e.button === 2) {
      e.preventDefault();
      return false;
    }
  }, false);

  document.addEventListener("mousedown", function(e) {
    if (e.button === 0) {
      MOUSE.left = true;
    } else if (e.button === 2) {
      MOUSE.right = true;
    }
  });

  document.addEventListener("mouseup", function(e) {
    if (e.button === 0) {
      MOUSE.left = false;
    } else if (e.button === 2) {
      MOUSE.right = false;
    }
  });

  /* add game states here */

  sm.addState("game", new GameState());
  sm.addState("menu", new MenuState());

  document.body.appendChild(canvas);

  resize({});

  /* start the game */

  sm.changeState("game");

  loaded--;
  requestAnimFrame(loop);
}

function resize(e) {
  if (window.innerWidth / window.innerHeight > 16 / 9) {
    GU = (window.innerHeight / 9);
  } else {
    GU = (window.innerWidth / 16);
  }
  if (typeof canvas !== "undefined") {
    canvas.width = 16 * GU;
    canvas.height = 9 * GU;
    canvas.style.margin = (($(window).height() - 9 * GU) / 2) + "px 0 0 " + (($(window).width() - 16 * GU) / 2) + "px";
    var wrapper = document.getElementById('wrapper');
    wrapper.style.margin = canvas.style.margin;
    wrapper.style.width = 16 * GU + 'px';
    wrapper.style.height = 9 * GU + 'px';
    wrapper.style.fontSize = 0.15 * GU + 'px';
    wrapper.style.zIndex = 99999999;
  }
}

function saveData(data) {
  json_data = JSON.stringify(data);
  setCookie("game_data", json_data, 10 ^ 5);
}

function readData() {
  json_data = getCookie("game_data");
  if (typeof json_data !== "undefined") {
    return JSON.parse(json_data);
  } else {
    /* default game_data object */
    return {progress: [0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]};
  }
}

function setCookie(c_name, value, exdays) {
  var exdate = new Date();
  exdate.setDate(exdate.getDate() + exdays);
  var c_value = encodeURIComponent(value) + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString());
  document.cookie = c_name + "=" + c_value;
}

function getCookie(c_name) {
  var i, x, y, ARRcookies = document.cookie.split(";");
  for (i = 0; i < ARRcookies.length; i++) {
    x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
    y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
    x = x.replace(/^\s+|\s+$/g, "");
    if (x == c_name) {
      return decodeURIComponent(y);
    }
  }
}

function relMouseCoords(e) {
  if (e.type !== "touchstart") {
    e.preventDefault();
  }
  if (typeof this.canvas === "undefined") {
    return {x: 0, y: 0};
  }
  var currentElement = this.canvas;
  var totalOffsetX = 0;
  var totalOffsetY = 0;
  var canvasX = 0;
  var canvasY = 0;

  do {
    totalOffsetX += currentElement.offsetLeft;
    totalOffsetY += currentElement.offsetTop;
  }
  while (currentElement = currentElement.offsetParent);

  canvasX = (e.pageX || (e.touches && e.touches[0] && e.touches[0].pageX) || (this.cached_coords.x + totalOffsetX)) - totalOffsetX;
  canvasY = (e.pageY || (e.touches && e.touches[0] && e.touches[0].pageY) || (this.cached_coords.y + totalOffsetY)) - totalOffsetY;

  return {x: canvasX / GU, y: canvasY / GU}
}

if (window.navigator.msPointerEnabled) {
  document.addEventListener("MSPointerDown", handleEvent);
  document.addEventListener("MSPointerMove", function(e) {
    e.preventDefault();
    e.stopPropagation();
    handleEvent(e);
    return false;
  });
} else {
  document.addEventListener('touchstart', handleEvent);
  document.addEventListener('click', handleEvent);
  document.addEventListener("mousemove", handleEvent);
  document.addEventListener('touchmove', function(e) {
    e.preventDefault();
    e.stopPropagation();
    handleEvent(e);
    return false;
  });
}

function handleEvent(e) {
  e.preventDefault();
  var position = relMouseCoords(e);
  MOUSE.x = position.x;
  MOUSE.y = position.y;
  var eventType = (e.type === "mousemove" || e.type === "touchmove" || e.type === "pointermove" ? "hover" : "click");
  var clickables = [];
  if (typeof sm === "undefined") {
    return;
  } else if (typeof sm.activeState.gameMenuWindow !== "undefined" && sm.activeState.gameMenuWindow.visible) {
    clickables = sm.activeState.gameMenuWindow.buttons;
  } else {
    clickables = sm.activeState.elements;
  }
  var coordX, coordY, sizeX, sizeY;
  var hoverOverClickable = false;
  for (var i = 0; i < clickables.length; i++) {
    coordX = clickables[i][1].x;
    coordY = clickables[i][1].y;
    sizeX = clickables[i][1].w;
    sizeY = clickables[i][1].h;
    if (MOUSE.x >= coordX && MOUSE.x <= coordX + sizeX && MOUSE.y >= coordY && MOUSE.y <= coordY + sizeY) {
      if (eventType === "click") {
        clickables[i][0](clickables[i].slice(2));
      } else if (eventType === "hover") {
        hoverOverClickable = true;
      }
      break;
    }
  }
  clickables && clickables[i] && clickables[i][1].hover && clickables[i][1].hover();
  $("body").css('cursor', hoverOverClickable ? "pointer" : "auto");
}

window.addEventListener('resize', resize);

/* global mixin for position/size-objects that do AABB collision with another posititon/size-object */
function contains(obj) {
  return obj.position.x < this.position.x + this.size.w &&
    obj.position.x + obj.size.w > this.position.x &&
    obj.position.y < this.position.y + this.size.h &&
    obj.position.y + obj.size.h > this.position.y;
}

// Array Remove - By John Resig (MIT Licensed)
Array.remove = function(array, from, to) {
  var rest = array.slice((to || from) + 1 || array.length);
  array.length = from < 0 ? array.length + from : from;
  return array.push.apply(array, rest);
}

function highResolution() {
  var pixelRatio = 1;
  if (window.devicePixelRatio) {
    pixelRatio = window.devicePixelRatio;
  }
  return pixelRatio * $(window).width() > 1440 && pixelRatio * $(window).height() > 810;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief test the server-side database interface
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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
///
///     http://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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var jsunity = require("jsunity");
var internal = require("internal");
var arangodb = require("org/arangodb");
var ERRORS = arangodb.errors;

// -----------------------------------------------------------------------------
// --SECTION--                                                  database methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: dropping databases while holding references
////////////////////////////////////////////////////////////////////////////////

function DatabaseSuite () {
  return {

    setUp : function () {
      internal.db._useDatabase("_system");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test references helt on dropped database collections
////////////////////////////////////////////////////////////////////////////////

    testDropDatabaseCollectionReferences : function () {
      assertEqual("_system", internal.db._name());

      try {
        internal.db._dropDatabase("UnitTestsDatabase0");
      }
      catch (err) {
      }

      assertTrue(internal.db._createDatabase("UnitTestsDatabase0"));

      internal.db._useDatabase("UnitTestsDatabase0");
      assertEqual("UnitTestsDatabase0", internal.db._name());

      // insert 1000 docs and hold a reference on the data
      var c = internal.db._create("test");
      for (var i = 0; i < 1000; ++i) {
        c.save({ "_key": "test" + i, "value" : i });
      }
      assertEqual(1000, c.count());

      internal.db._useDatabase("_system");
      assertEqual(1000, c.count());

      // drop the database
      internal.db._dropDatabase("UnitTestsDatabase0");
      // should be dropped
      internal.db._listDatabases().forEach(function (d) {
        if (d === "UnitTestsDatabase0") {
          fail();
        }
      });

      // collection should still be there
      assertEqual(1000, c.count());
      assertEqual("test", c.name());

      internal.wait(5);
      // still...
      assertEqual(1000, c.count());

      c = null;
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test references helt on documents of dropped databases
////////////////////////////////////////////////////////////////////////////////

    testDropDatabaseDocumentReferences : function () {
      assertEqual("_system", internal.db._name());

      try {
        internal.db._dropDatabase("UnitTestsDatabase0");
      }
      catch (err) {
      }

      assertTrue(internal.db._createDatabase("UnitTestsDatabase0"));

      internal.db._useDatabase("UnitTestsDatabase0");
      assertEqual("UnitTestsDatabase0", internal.db._name());

      // insert docs and hold a reference on the data
      var c = internal.db._create("test");
      for (var i = 0; i < 10; ++i) {
        c.save({ "_key": "test" + i, "value" : i });
      }

      var d0 = c.document("test0");
      var d4 = c.document("test4");
      var d9 = c.document("test9");

      c = null;

      internal.db._useDatabase("_system");

      // drop the database
      internal.db._dropDatabase("UnitTestsDatabase0");
      // should be dropped
      internal.db._listDatabases().forEach(function (d) {
        if (d === "UnitTestsDatabase0") {
          fail();
        }
      });

      assertEqual(0, d0.value);
      assertEqual(4, d4.value);
      assertEqual(9, d9.value);

      internal.wait(5);

      assertEqual(0, d0.value);
      assertEqual(4, d4.value);
      assertEqual(9, d9.value);

      d0 = null;
      d4 = null;

      internal.wait(3);
      assertEqual(9, d9.value);

      d9 = null;
    }

  };
}

// -----------------------------------------------------------------------------
// --SECTION--                                                              main
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////

jsunity.run(DatabaseSuite);

return jsunity.done();

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

<commit_msg>added database-directory test<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief test the server-side database interface
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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
///
///     http://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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var jsunity = require("jsunity");
var internal = require("internal");
var arangodb = require("org/arangodb");
var ERRORS = arangodb.errors;

// -----------------------------------------------------------------------------
// --SECTION--                                                  database methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: dropping databases while holding references
////////////////////////////////////////////////////////////////////////////////

function DatabaseSuite () {
  return {

    setUp : function () {
      internal.db._useDatabase("_system");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test references helt on dropped database collections
////////////////////////////////////////////////////////////////////////////////

    testDropDatabaseCollectionReferences : function () {
      assertEqual("_system", internal.db._name());

      try {
        internal.db._dropDatabase("UnitTestsDatabase0");
      }
      catch (err) {
      }

      assertTrue(internal.db._createDatabase("UnitTestsDatabase0"));

      internal.db._useDatabase("UnitTestsDatabase0");
      assertEqual("UnitTestsDatabase0", internal.db._name());

      // insert 1000 docs and hold a reference on the data
      var c = internal.db._create("test");
      for (var i = 0; i < 1000; ++i) {
        c.save({ "_key": "test" + i, "value" : i });
      }
      assertEqual(1000, c.count());

      internal.db._useDatabase("_system");
      assertEqual(1000, c.count());

      // drop the database
      internal.db._dropDatabase("UnitTestsDatabase0");
      // should be dropped
      internal.db._listDatabases().forEach(function (d) {
        if (d === "UnitTestsDatabase0") {
          fail();
        }
      });

      // collection should still be there
      assertEqual(1000, c.count());
      assertEqual("test", c.name());

      internal.wait(5);
      // still...
      assertEqual(1000, c.count());

      c = null;
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test references helt on documents of dropped databases
////////////////////////////////////////////////////////////////////////////////

    testDropDatabaseDocumentReferences : function () {
      assertEqual("_system", internal.db._name());

      try {
        internal.db._dropDatabase("UnitTestsDatabase0");
      }
      catch (err) {
      }

      assertTrue(internal.db._createDatabase("UnitTestsDatabase0"));

      internal.db._useDatabase("UnitTestsDatabase0");
      assertEqual("UnitTestsDatabase0", internal.db._name());

      // insert docs and hold a reference on the data
      var c = internal.db._create("test");
      for (var i = 0; i < 10; ++i) {
        c.save({ "_key": "test" + i, "value" : i });
      }

      var d0 = c.document("test0");
      var d4 = c.document("test4");
      var d9 = c.document("test9");

      c = null;

      internal.db._useDatabase("_system");

      // drop the database
      internal.db._dropDatabase("UnitTestsDatabase0");
      // should be dropped
      internal.db._listDatabases().forEach(function (d) {
        if (d === "UnitTestsDatabase0") {
          fail();
        }
      });

      assertEqual(0, d0.value);
      assertEqual(4, d4.value);
      assertEqual(9, d9.value);

      internal.wait(5);

      assertEqual(0, d0.value);
      assertEqual(4, d4.value);
      assertEqual(9, d9.value);

      d0 = null;
      d4 = null;

      internal.wait(3);
      assertEqual(9, d9.value);

      d9 = null;
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test removal of database directory
////////////////////////////////////////////////////////////////////////////////

    testDropDatabaseDirectory : function () {
      assertEqual("_system", internal.db._name());

      try {
        internal.db._dropDatabase("UnitTestsDatabase0");
      }
      catch (err) {
      }

      assertTrue(internal.db._createDatabase("UnitTestsDatabase0"));
      assertTrue(internal.db._useDatabase("UnitTestsDatabase0"));

      var fs = require("fs");

      // get path
      var path = internal.db._path();
      assertTrue(fs.exists(path));
      var files = fs.listTree(path);

      // assert some files
      assertTrue(files.length > 10);

      assertTrue(internal.db._useDatabase("_system"));

      // drop db, and check path again
      assertTrue(internal.db._dropDatabase("UnitTestsDatabase0"));

      var tries = 0;
      while (tries++ < 15) {
        if (fs.exists(path)) {
          internal.wait(1);
          continue;
        }
      }

      assertFalse(fs.exists(path));
    }

  };
}

// -----------------------------------------------------------------------------
// --SECTION--                                                              main
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////

jsunity.run(DatabaseSuite);

return jsunity.done();

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

<|endoftext|>


<commit_before>import {
  isPlainObject,
  supportsPassive
} from 'uni-shared'

import {
  hasLifecycleHook
} from 'uni-helpers/index'

import {
  NAVBAR_HEIGHT,
  TABBAR_HEIGHT
} from 'uni-helpers/constants'

import {
  disableScroll,
  createScrollListener
} from 'uni-core/view/bridge/subscribe/scroll'

const passiveOptions = supportsPassive ? {
  passive: false
} : false

function updateCssVar (vm) {
  if (uni.canIUse('css.var')) {
    const pageVm = vm.$parent.$parent
    const navigationBarType = pageVm.navigationBar.type
    const windowTopValue = navigationBarType === 'default' || navigationBarType === 'float' ? NAVBAR_HEIGHT : 0
    const windowBottomValue = getApp().$children[0].showTabBar ? TABBAR_HEIGHT : 0
    const envMethod = uni.canIUse('css.env') ? 'env' : (uni.canIUse('css.constant') ? 'constant' : '')
    const windowTop = windowTopValue && envMethod ? `calc(${windowTopValue}px + ${envMethod}(safe-area-inset-top))` : `${windowTopValue}0px`
    const windowBottom = windowBottomValue && envMethod ? `calc(${windowBottomValue}px + ${envMethod}(safe-area-inset-bottom))` : `${windowBottomValue}px`
    const style = document.documentElement.style
    style.setProperty('--window-top', windowTop)
    style.setProperty('--window-bottom', windowBottom)
    console.debug(`${vm.$page.route}[${vm.$page.id}]：--window-top=${windowTop}`)
    console.debug(`${vm.$page.route}[${vm.$page.id}]：--window-bottom=${windowBottom}`)
  }
}

export default function initSubscribe (subscribe) {
  let scrollListener = false
  let disableScrollListener = false

  subscribe('onPageLoad', vm => { // 用户 onLoad 之前 update
    updateCssVar(vm)
  })

  subscribe('onPageShow', vm => {
    const pageVm = vm.$parent.$parent

    if (vm._isMounted) { // 非首次 show 才 update（首次 show 的时候在 onPageLoad 中触发了）
      updateCssVar(vm)
    }

    if (disableScrollListener) {
      document.removeEventListener('touchmove', disableScrollListener, passiveOptions)
    }

    if (pageVm.disableScroll) {
      disableScrollListener = disableScroll
      document.addEventListener('touchmove', disableScrollListener, passiveOptions)
    }

    const enablePageScroll = hasLifecycleHook(vm.$options, 'onPageScroll')
    const enablePageReachBottom = hasLifecycleHook(vm.$options, 'onReachBottom')
    const onReachBottomDistance = pageVm.onReachBottomDistance

    const enableTransparentTitleNView = (isPlainObject(pageVm.titleNView) && pageVm.titleNView.type ===
      'transparent') || (isPlainObject(pageVm.navigationBar) && pageVm.navigationBar.type === 'transparent')

    if (scrollListener) {
      document.removeEventListener('scroll', scrollListener)
    }

    if (enableTransparentTitleNView || enablePageScroll || enablePageReachBottom) { // 初始化 scroll 监听
      scrollListener = createScrollListener(vm.$page.id, {
        enablePageScroll,
        enablePageReachBottom,
        onReachBottomDistance,
        enableTransparentTitleNView
      })
      requestAnimationFrame(function () { // 避免监听太早，直接触发了 scroll
        document.addEventListener('scroll', scrollListener)
      })
    }
  })
}
<commit_msg>fix: windowTop 在低版本浏览器下值不正确的Bug askId: 89952<commit_after>import {
  isPlainObject,
  supportsPassive
} from 'uni-shared'

import {
  hasLifecycleHook
} from 'uni-helpers/index'

import {
  NAVBAR_HEIGHT,
  TABBAR_HEIGHT
} from 'uni-helpers/constants'

import {
  disableScroll,
  createScrollListener
} from 'uni-core/view/bridge/subscribe/scroll'

const passiveOptions = supportsPassive ? {
  passive: false
} : false

function updateCssVar (vm) {
  if (uni.canIUse('css.var')) {
    const pageVm = vm.$parent.$parent
    const navigationBarType = pageVm.navigationBar.type
    const windowTopValue = navigationBarType === 'default' || navigationBarType === 'float' ? NAVBAR_HEIGHT : 0
    const windowBottomValue = getApp().$children[0].showTabBar ? TABBAR_HEIGHT : 0
    const envMethod = uni.canIUse('css.env') ? 'env' : (uni.canIUse('css.constant') ? 'constant' : '')
    const windowTop = windowTopValue && envMethod ? `calc(${windowTopValue}px + ${envMethod}(safe-area-inset-top))` : `${windowTopValue}px`
    const windowBottom = windowBottomValue && envMethod ? `calc(${windowBottomValue}px + ${envMethod}(safe-area-inset-bottom))` : `${windowBottomValue}px`
    const style = document.documentElement.style
    style.setProperty('--window-top', windowTop)
    style.setProperty('--window-bottom', windowBottom)
    console.debug(`${vm.$page.route}[${vm.$page.id}]：--window-top=${windowTop}`)
    console.debug(`${vm.$page.route}[${vm.$page.id}]：--window-bottom=${windowBottom}`)
  }
}

export default function initSubscribe (subscribe) {
  let scrollListener = false
  let disableScrollListener = false

  subscribe('onPageLoad', vm => { // 用户 onLoad 之前 update
    updateCssVar(vm)
  })

  subscribe('onPageShow', vm => {
    const pageVm = vm.$parent.$parent

    if (vm._isMounted) { // 非首次 show 才 update（首次 show 的时候在 onPageLoad 中触发了）
      updateCssVar(vm)
    }

    if (disableScrollListener) {
      document.removeEventListener('touchmove', disableScrollListener, passiveOptions)
    }

    if (pageVm.disableScroll) {
      disableScrollListener = disableScroll
      document.addEventListener('touchmove', disableScrollListener, passiveOptions)
    }

    const enablePageScroll = hasLifecycleHook(vm.$options, 'onPageScroll')
    const enablePageReachBottom = hasLifecycleHook(vm.$options, 'onReachBottom')
    const onReachBottomDistance = pageVm.onReachBottomDistance

    const enableTransparentTitleNView = (isPlainObject(pageVm.titleNView) && pageVm.titleNView.type ===
      'transparent') || (isPlainObject(pageVm.navigationBar) && pageVm.navigationBar.type === 'transparent')

    if (scrollListener) {
      document.removeEventListener('scroll', scrollListener)
    }

    if (enableTransparentTitleNView || enablePageScroll || enablePageReachBottom) { // 初始化 scroll 监听
      scrollListener = createScrollListener(vm.$page.id, {
        enablePageScroll,
        enablePageReachBottom,
        onReachBottomDistance,
        enableTransparentTitleNView
      })
      requestAnimationFrame(function () { // 避免监听太早，直接触发了 scroll
        document.addEventListener('scroll', scrollListener)
      })
    }
  })
}
<|endoftext|>


<commit_before>var reload = require('require-reload'),
	formatTime = reload('../../utils/utils.js').formatTime,
	version = reload('../../package.json').version,
	Nf = new Intl.NumberFormat('en-US');

module.exports = {
	desc: "Displays statistics about the bot.",
	hidden: true,
	guildOnly: true,
	cooldown: 10,
	requiredPermission: 'manageGuild',
	task(bot, msg) {
		let totalCommandUsage = commandsProcessed + cleverbotTimesUsed;
		bot.createMessage(msg.channel.id, `\`\`\`md
[Mirai Statistics]:
[Uptime](${formatTime(bot.uptime)})
[Memory Usage](${Math.round(process.memoryUsage().rss / 1024 / 1000)}MB)
[Version](MiraiBot ${version})
[Shards](${bot.shards.size})

# Avalible to:
[Guilds](${Nf.format(bot.guilds.size)})
[Channels](${Nf.format(Object.keys(bot.channelGuildMap).length)})
[Private Channels](${Nf.format(bot.privateChannels.size)})
[Users](${Nf.format(bot.users.size)})
[Average Users/Guild](${Nf.format((bot.users.size / bot.guilds.size).toFixed(2))})

# Command Usage:
[Total | Commands | Cleverbot](${Nf.format(totalCommandUsage)} | ${Nf.format(commandsProcessed)} | ${Nf.format(cleverbotTimesUsed)})
[Average](${(totalCommandUsage / (bot.uptime / (1000 * 60))).toFixed(2)}/min)\`\`\``);
	}
};
<commit_msg>Fixed Typo in stats (#20)<commit_after>var reload = require('require-reload'),
	formatTime = reload('../../utils/utils.js').formatTime,
	version = reload('../../package.json').version,
	Nf = new Intl.NumberFormat('en-US');

module.exports = {
	desc: "Displays statistics about the bot.",
	hidden: true,
	guildOnly: true,
	cooldown: 10,
	requiredPermission: 'manageGuild',
	task(bot, msg) {
		let totalCommandUsage = commandsProcessed + cleverbotTimesUsed;
		bot.createMessage(msg.channel.id, `\`\`\`md
[Mirai Statistics]:
[Uptime](${formatTime(bot.uptime)})
[Memory Usage](${Math.round(process.memoryUsage().rss / 1024 / 1000)}MB)
[Version](MiraiBot ${version})
[Shards](${bot.shards.size})

# Available to:
[Guilds](${Nf.format(bot.guilds.size)})
[Channels](${Nf.format(Object.keys(bot.channelGuildMap).length)})
[Private Channels](${Nf.format(bot.privateChannels.size)})
[Users](${Nf.format(bot.users.size)})
[Average Users/Guild](${Nf.format((bot.users.size / bot.guilds.size).toFixed(2))})

# Command Usage:
[Total | Commands | Cleverbot](${Nf.format(totalCommandUsage)} | ${Nf.format(commandsProcessed)} | ${Nf.format(cleverbotTimesUsed)})
[Average](${(totalCommandUsage / (bot.uptime / (1000 * 60))).toFixed(2)}/min)\`\`\``);
	}
};
<|endoftext|>


<commit_before>// Auto Generated on 2022-04-09T13:26:57.734Z
 module.exports = [
  {
    "event": {
      "title": "Coding Comp!",
      "description": "Hey everyone, Blast Furnace in April- fire up for another opportunity to show off your skills!\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\nWhat you need to know about this event:\n\n1. Laid back, no pressure and collaboration is encouraged\n2. Anyone can participate! (It doesn't matter what country you're in!)\n3. Use CodinGame to run the comps\n4. Each challenge is no longer than 10min (often faster)\n5. You can program in your choice of 24 different languages\n6. Have a practice on CodinGame beforehand if you want to get a feel\n\nHow it works:\nWe use CodinGame (https://www.codingame.com/start) to run code clashes. These are time restricted (10-15min) programming problems that you can solve using 1 of 27 different programming languages including Bash, JavaScript, Python3, C, C++ Dart, Swift, Ruby and many more...\n\nSee here for full list https://www.codingame.com/playgrounds/40701/help-center/languages-versions\n\nThere are 3 types of problems we solve:\n\n* **Fastest:** You win if you come up with the correct solution in the fastest amount of time\n* **Shortest:** The person who uses the least amount of characters to solve the problem wins\n* **Reverse:** you get given the inputs and outputs and must write the code to produce the given outputs based on the given inputs.\n\nYou get points for attempting each challenge and rewarded for coming in 1st, 2nd, or 3rd. We will complete around 6 - 8 challenges over the duration of the event and the final winner is the person with the most points at the end.\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\nJoin us online for a few laughs and some healthy competition!",
      "dateTime": "2022-04-14T18:30+10:00",
      "eventUrl": "https://www.meetup.com/Blast-Furnace/events/284893515",
      "going": 4,
      "maxTickets": 40,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/501791387/676x380.webp",
      "venue": {
        "name": "The Melt",
        "lat": -32.96363,
        "lng": 151.65958,
        "address": "1/323 Hillsborough Road",
        "city": "Warners Bay"
      }
    },
    "group": {
      "name": "Blast Furnace",
      "urlname": "Blast-Furnace",
      "groupPhoto": {
        "id": "483748559",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483748559",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "data.APR <- Provisional; Predicting extreme wind events",
      "description": "CALL FOR SPEAKERS:\n\nDo you have an interesting data story to tell?\n\nWould you like to give this month's presentation?\n\nFollow the link below to our Google form to express your interest and we'll contact you soon!\n\nhttps://forms.gle/y57b2seehSgvtGgn7\n\n##-------------------------------------------------------------------##\n\nVENUE:\n\nNEW LOCATION!\n\nThe university's brand new Q building in Honeysuckle!\n\nhttps://goo.gl/maps/35LwcLhKV1nvoFAh7\n\nIMPORTANT this is NOT the NewSpace building where we met last year.\n\nWe will meet in the Level 2 Seminar Space. You'll need to enter through the main doors on Worth Place and will be directed to the elevators to join the meetup.\n\nPARKING: The closest parking is Wright Lane Carpark.\nhttps://goo.gl/maps/rj6Yg8EkpjYzUmbi7\n\nAfter 5pm it is free and is a 400m - 5 minute walk.\n\n##-------------------------------------------------------------------##\n\nTIME: 5.30pm - 7.30pm\n\nFOOD: 🍕 + 🥤\n- Wood fired pizza, sponsored by Newy Tech People\n- Please advise dietary requirements in RSVP\n- Soft drinks\n\nSCHEDULE:\n- 5:30pm: Networking + Food + Drinks\n(Don't stress if you are held up in traffic)\n- 6:15pm: Presentation\n- 7:15pm: Packing up + Bonus questions\n- 7:30pm: Close",
      "dateTime": "2022-04-21T17:30+10:00",
      "eventUrl": "https://www.meetup.com/Hunter-Data-Analytics/events/283702240",
      "going": 10,
      "maxTickets": 40,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/501789003/676x380.webp",
      "venue": {
        "name": "Q Building, The University of Newcastle",
        "lat": -32.926277,
        "lng": 151.7683,
        "address": "16B Honeysuckle Dr",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Hunter Data Analytics",
      "urlname": "Hunter-Data-Analytics",
      "groupPhoto": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "May Meeting",
      "description": "We are sorting out details",
      "dateTime": "2022-05-04T18:00+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-Coders-Group/events/285145356",
      "going": 1,
      "maxTickets": 0,
      "duration": "PT3H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/469014591/676x380.webp",
      "venue": null
    },
    "group": {
      "name": "Newcastle Coders Group",
      "urlname": "Newcastle-Coders-Group",
      "groupPhoto": {
        "id": "469014591",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "469014591",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "Industrial IoT as a tipping point - Hear from Telstra's IIoT Domain Lead",
      "description": "IoT Pioneers in May, hear from Telstra's Domain Lead for Industrial IoT Mark Atkinson as he walks us through industrial IoT as a tipping point.\n\nWith the explosion of connected devices, the value proposition is no longer about connecting and monitoring. Industrial IoT now moves to a world of analysis, building insights for timely actionable outcomes.\n\nAs an experienced innovator with a proven record of bringing new technology outcomes to market, Mark helps businesses span the gap between ‘need’ and technology. Mark is also an active participant at the IoT Alliance Australia (IOTAA) - a founding member, current Lead of the Energy/Mining Work Stream and a member of the awards judging panel. Within Telstra Mark focuses on Industrial IoT - the capability to monitor behaviour at scale, provide analysis and draw insights for quick action.\n\nJoin us on May 5th from 6:30 pm - 8:30 pm at The Stag & Hunter Hotel. Feel free to grab a drink at the bar and come on up; dinner will be provided.\n\nPlease make sure to RSVP\n\n#meetup #networking #engineering #startup #IoT",
      "dateTime": "2022-05-05T18:30+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-IoT-Pioneers/events/285071516",
      "going": 3,
      "maxTickets": 0,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/503178697/676x380.webp",
      "venue": {
        "name": "The Stag and Hunter hotel ",
        "lat": -32.897346,
        "lng": 151.73651,
        "address": "cnr hanbury and maitland rd  mayfield",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Newcastle IoT Pioneers",
      "urlname": "Newcastle-IoT-Pioneers",
      "groupPhoto": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  }
]<commit_msg>Get latest set of Meetup events<commit_after>// Auto Generated on 2022-04-10T13:27:11.999Z
 module.exports = [
  {
    "event": {
      "title": "Coding Comp!",
      "description": "Hey everyone, Blast Furnace in April- fire up for another opportunity to show off your skills!\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\nWhat you need to know about this event:\n\n1. Laid back, no pressure and collaboration is encouraged\n2. Anyone can participate! (It doesn't matter what country you're in!)\n3. Use CodinGame to run the comps\n4. Each challenge is no longer than 10min (often faster)\n5. You can program in your choice of 24 different languages\n6. Have a practice on CodinGame beforehand if you want to get a feel\n\nHow it works:\nWe use CodinGame (https://www.codingame.com/start) to run code clashes. These are time restricted (10-15min) programming problems that you can solve using 1 of 27 different programming languages including Bash, JavaScript, Python3, C, C++ Dart, Swift, Ruby and many more...\n\nSee here for full list https://www.codingame.com/playgrounds/40701/help-center/languages-versions\n\nThere are 3 types of problems we solve:\n\n* **Fastest:** You win if you come up with the correct solution in the fastest amount of time\n* **Shortest:** The person who uses the least amount of characters to solve the problem wins\n* **Reverse:** you get given the inputs and outputs and must write the code to produce the given outputs based on the given inputs.\n\nYou get points for attempting each challenge and rewarded for coming in 1st, 2nd, or 3rd. We will complete around 6 - 8 challenges over the duration of the event and the final winner is the person with the most points at the end.\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\nJoin us online for a few laughs and some healthy competition!",
      "dateTime": "2022-04-14T18:30+10:00",
      "eventUrl": "https://www.meetup.com/Blast-Furnace/events/284893515",
      "going": 4,
      "maxTickets": 40,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/501791387/676x380.webp",
      "venue": {
        "name": "The Melt",
        "lat": -32.96363,
        "lng": 151.65958,
        "address": "1/323 Hillsborough Road",
        "city": "Warners Bay"
      }
    },
    "group": {
      "name": "Blast Furnace",
      "urlname": "Blast-Furnace",
      "groupPhoto": {
        "id": "483748559",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483748559",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "data.APR <- Provisional; Predicting extreme wind events",
      "description": "CALL FOR SPEAKERS:\n\nDo you have an interesting data story to tell?\n\nWould you like to give this month's presentation?\n\nFollow the link below to our Google form to express your interest and we'll contact you soon!\n\nhttps://forms.gle/y57b2seehSgvtGgn7\n\n##-------------------------------------------------------------------##\n\nVENUE:\n\nNEW LOCATION!\n\nThe university's brand new Q building in Honeysuckle!\n\nhttps://goo.gl/maps/35LwcLhKV1nvoFAh7\n\nIMPORTANT this is NOT the NewSpace building where we met last year.\n\nWe will meet in the Level 2 Seminar Space. You'll need to enter through the main doors on Worth Place and will be directed to the elevators to join the meetup.\n\nPARKING: The closest parking is Wright Lane Carpark.\nhttps://goo.gl/maps/rj6Yg8EkpjYzUmbi7\n\nAfter 5pm it is free and is a 400m - 5 minute walk.\n\n##-------------------------------------------------------------------##\n\nTIME: 5.30pm - 7.30pm\n\nFOOD: 🍕 + 🥤\n- Wood fired pizza, sponsored by Newy Tech People\n- Please advise dietary requirements in RSVP\n- Soft drinks\n\nSCHEDULE:\n- 5:30pm: Networking + Food + Drinks\n(Don't stress if you are held up in traffic)\n- 6:15pm: Presentation\n- 7:15pm: Packing up + Bonus questions\n- 7:30pm: Close",
      "dateTime": "2022-04-21T17:30+10:00",
      "eventUrl": "https://www.meetup.com/Hunter-Data-Analytics/events/283702240",
      "going": 10,
      "maxTickets": 40,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/501789003/676x380.webp",
      "venue": {
        "name": "Q Building, The University of Newcastle",
        "lat": -32.926277,
        "lng": 151.7683,
        "address": "16B Honeysuckle Dr",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Hunter Data Analytics",
      "urlname": "Hunter-Data-Analytics",
      "groupPhoto": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "May Meeting",
      "description": "We are sorting out details",
      "dateTime": "2022-05-04T18:00+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-Coders-Group/events/285145356",
      "going": 1,
      "maxTickets": 0,
      "duration": "PT3H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/469014591/676x380.webp",
      "venue": null
    },
    "group": {
      "name": "Newcastle Coders Group",
      "urlname": "Newcastle-Coders-Group",
      "groupPhoto": {
        "id": "469014591",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "469014591",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "Industrial IoT as a tipping point - Hear from Telstra's IIoT Domain Lead",
      "description": "IoT Pioneers in May, hear from Telstra's Domain Lead for Industrial IoT Mark Atkinson as he walks us through industrial IoT as a tipping point.\n\nWith the explosion of connected devices, the value proposition is no longer about connecting and monitoring. Industrial IoT now moves to a world of analysis, building insights for timely actionable outcomes.\n\nAs an experienced innovator with a proven record of bringing new technology outcomes to market, Mark helps businesses span the gap between ‘need’ and technology. Mark is also an active participant at the IoT Alliance Australia (IOTAA) - a founding member, current Lead of the Energy/Mining Work Stream and a member of the awards judging panel. Within Telstra Mark focuses on Industrial IoT - the capability to monitor behaviour at scale, provide analysis and draw insights for quick action.\n\nJoin us on May 5th from 6:30 pm - 8:30 pm at The Stag & Hunter Hotel. Feel free to grab a drink at the bar and come on up; dinner will be provided.\n\nPlease make sure to RSVP\n\n#meetup #networking #engineering #startup #IoT",
      "dateTime": "2022-05-05T18:30+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-IoT-Pioneers/events/285071516",
      "going": 3,
      "maxTickets": 0,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/503178697/676x380.webp",
      "venue": {
        "name": "The Stag and Hunter hotel ",
        "lat": -32.897346,
        "lng": 151.73651,
        "address": "cnr hanbury and maitland rd  mayfield",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Newcastle IoT Pioneers",
      "urlname": "Newcastle-IoT-Pioneers",
      "groupPhoto": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  }
]<|endoftext|>