<commit_before>(function () {
	"use strict";

	$(document).ready(function () {
		templates.setGlobal('ignorePluginEnabled', true);
	});

	$(window).on('action:topic.loaded', function (event, data) {
		console.log(data);
		addTopicHandlers();
	});

	$(window).on('action:ajaxify.contentLoaded', function (event, data) {
		/* Estamos en el perfil */
		console.log(data);
		if ($('.account-username-box').length) {
			addProfileHandlers();
		}
	});

	function addTopicHandlers() {
		$('.posts').on('click', 'a.ignore, a.unignore', function () {

			//Ejecutamos la accion de des/ignorar
			var post = $(this).parents('.post-row');
			toggleIgnoreUser({
				id: post.data('uid'),
				name: post.data('username'),
				ignored: post.is('.ignored')
			}, toggleIgnorePosts);

			//Cerramos el dropdown
			_clearMenus();

			return false;
		});
	}

	function addProfileHandlers() {
		$('.account').on('click', 'a.ignore, a.unignore', function () {

			//Ejecutamos la accion de des/ignorar
			var user = $(this).parents('.account');
			toggleIgnoreUser({
				id: user.data('uid'),
				name: user.data('username'),
				ignored: user.is('.ignored')
			}, toggleIgnoreProfile);

			return false;
		});
	}

	/**
	 * Ignora o des-ignora al usuario seleccionado
	 */
	function toggleIgnoreUser(user, callback) {
		socket.emit(user.ignored ? 'modules.unignoreUser' : 'modules.ignoreUser', {
			ignoreduid: user.id
		}, function (err, res) {

			if (err) {
				return;
			}

			user.ignored = !user.ignored;

			//Mostramos un aviso al usuario
			if (user.ignored) {
				app.alert({
					message: 'A partir de ahora dejarás de ver todos los posts de ' + user.name + '',
					type: 'danger',
					timeout: 5000
				});
			} else {
				app.alert({
					message: 'A partir de ahora volverás a ver todos los posts de ' + user.name + '',
					type: 'success',
					timeout: 5000
				});
			}

			callback(user);
		});
	}

	/**
	 * Marca como ignorados todos los posts de un usuario
	 */
	function toggleIgnorePosts(user) {
		$('.post-row[data-uid=' + user.id + ']').each(function (i, post) {
			post = $(post);

			if (user.ignored) {

				//Nos guardamos el contenido original
				var content = post.find('.post-content');
				var originalContent = content.html();

				//Ocultamos el post
				post.addClass('ignored');
				content.html('Este post está oculto porque ' + user.name + ' está en tu lista de ignorados.');

				//Añadimos el contenido original la lado del ocultado para poder recuperarlo luego
				post.find('.original-content').html(originalContent);

				//				//Botones de ignorar-designorar
				//				post.find('a.ignore').hide();
				//				post.find('a.unignore').show();
			} else {
				//Mostramos de nuevo el post
				post.removeClass('ignored');

				//Devolvemos el contenido original
				post.find('.post-content').html(post.find('.original-content').html());

				//				//Botones de ignorar-designorar
				//				post.find('a.ignore').show();
				//				post.find('a.unignore').hide();
			}
		});
	}

	/**
	 * Marca como ignorado el perfil de un usuario
	 */
	function toggleIgnoreProfile(user) {
		if (user.ignored) {
			$('.account').addClass('ignored');
		} else {
			$('.account').removeClass('ignored');
		}
	}

}());<commit_msg>console log disabled<commit_after>(function () {
	"use strict";

	$(document).ready(function () {
		templates.setGlobal('ignorePluginEnabled', true);
	});

	$(window).on('action:topic.loaded', function (event, data) {
		//console.log(data);
		addTopicHandlers();
	});

	$(window).on('action:ajaxify.contentLoaded', function (event, data) {
		/* Estamos en el perfil */
		//console.log(data);
		if ($('.account-username-box').length) {
			addProfileHandlers();
		}
	});

	function addTopicHandlers() {
		$('.posts').on('click', 'a.ignore, a.unignore', function () {

			//Ejecutamos la accion de des/ignorar
			var post = $(this).parents('.post-row');
			toggleIgnoreUser({
				id: post.data('uid'),
				name: post.data('username'),
				ignored: post.is('.ignored')
			}, toggleIgnorePosts);

			//Cerramos el dropdown
			_clearMenus();

			return false;
		});
	}

	function addProfileHandlers() {
		$('.account').on('click', 'a.ignore, a.unignore', function () {

			//Ejecutamos la accion de des/ignorar
			var user = $(this).parents('.account');
			toggleIgnoreUser({
				id: user.data('uid'),
				name: user.data('username'),
				ignored: user.is('.ignored')
			}, toggleIgnoreProfile);

			return false;
		});
	}

	/**
	 * Ignora o des-ignora al usuario seleccionado
	 */
	function toggleIgnoreUser(user, callback) {
		socket.emit(user.ignored ? 'modules.unignoreUser' : 'modules.ignoreUser', {
			ignoreduid: user.id
		}, function (err, res) {

			if (err) {
				return;
			}

			user.ignored = !user.ignored;

			//Mostramos un aviso al usuario
			if (user.ignored) {
				app.alert({
					message: 'A partir de ahora dejarás de ver todos los posts de ' + user.name + '',
					type: 'danger',
					timeout: 5000
				});
			} else {
				app.alert({
					message: 'A partir de ahora volverás a ver todos los posts de ' + user.name + '',
					type: 'success',
					timeout: 5000
				});
			}

			callback(user);
		});
	}

	/**
	 * Marca como ignorados todos los posts de un usuario
	 */
	function toggleIgnorePosts(user) {
		$('.post-row[data-uid=' + user.id + ']').each(function (i, post) {
			post = $(post);

			if (user.ignored) {

				//Nos guardamos el contenido original
				var content = post.find('.post-content');
				var originalContent = content.html();

				//Ocultamos el post
				post.addClass('ignored');
				content.html('Este post está oculto porque ' + user.name + ' está en tu lista de ignorados.');

				//Añadimos el contenido original la lado del ocultado para poder recuperarlo luego
				post.find('.original-content').html(originalContent);

				//				//Botones de ignorar-designorar
				//				post.find('a.ignore').hide();
				//				post.find('a.unignore').show();
			} else {
				//Mostramos de nuevo el post
				post.removeClass('ignored');

				//Devolvemos el contenido original
				post.find('.post-content').html(post.find('.original-content').html());

				//				//Botones de ignorar-designorar
				//				post.find('a.ignore').show();
				//				post.find('a.unignore').hide();
			}
		});
	}

	/**
	 * Marca como ignorado el perfil de un usuario
	 */
	function toggleIgnoreProfile(user) {
		if (user.ignored) {
			$('.account').addClass('ignored');
		} else {
			$('.account').removeClass('ignored');
		}
	}

}());<|endoftext|>


<commit_before>var keystone = require('keystone'),
	_ = require('underscore');

// Load models to allow fetching of slideshow data
var Slideshow = keystone.list('Slideshow'),
	SlideshowItems = keystone.list('Slideshow Item'),
	FeaturedItems = keystone.list('Featured Item');

exports = module.exports = function(req, res) {
	'use strict';

	var view = new keystone.View(req, res),
		locals = res.locals;

	Slideshow.model.find()
		.where('title', 'Main Page Slideshow')
		.exec()
		.then(function (slideshow) {

			var slideshowId = slideshow[0].get('_id');

			SlideshowItems.model.find()
				.where('parent', slideshowId)
				.exec()
				.then(function (slides) {
					locals.slides = _.sortBy(slides, function(slide) { return +slide.order; });

				}).then(function() {
					FeaturedItems.model.find()
						.exec()
						.then(function(featuredItems) {

							locals.featuredItems = featuredItems;

							view.render('main');
						});
				});
		});
};<commit_msg>Update main page route with failsafe to send the user to the login page if the Slideshow model doesn't exist.<commit_after>var keystone = require('keystone'),
	_ = require('underscore');

// Load models to allow fetching of slideshow data
var Slideshow = keystone.list('Slideshow'),
	SlideshowItems = keystone.list('Slideshow Item'),
	FeaturedItems = keystone.list('Featured Item');

exports = module.exports = function(req, res) {
	'use strict';

	var view = new keystone.View(req, res),
		locals = res.locals;

	Slideshow.model.find()
		.where('title', 'Main Page Slideshow')
		.exec()
		.then(function (slideshow) {
			if(!slideshow) {
				console.log('unable to load the slideshow');
				res.redirect('/preferences');
			}

			var slideshowId = slideshow[0].get('_id');

			SlideshowItems.model.find()
				.where('parent', slideshowId)
				.exec()
				.then(function (slides) {
					locals.slides = _.sortBy(slides, function(slide) { return +slide.order; });

				}).then(function() {
					FeaturedItems.model.find()
						.exec()
						.then(function(featuredItems) {

							locals.featuredItems = featuredItems;

							view.render('main');
						});
				});
		});
};<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2016, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

import i18next from './language';

const t = i18next.t.bind(i18next);

export const URL_UPLOADER_CHROME_STORE = 'http://chrome.google.com/webstore/detail/tidepool-uploader/cabklgajffclbljkhmjphejemhpbghfb';
export const URL_TIDEPOOL_MOBILE_APP_STORE = 'https://itunes.apple.com/us/app/tidepool-mobile/id1026395200?mt=8';
export const URL_TERMS_OF_USE = 'https://tidepool.org/terms-of-use';
export const URL_PRIVACY_POLICY = 'https://tidepool.org/privacy-policy';
export const URL_BIG_DATA_DONATION_INFO = 'https://tidepool.org/announcing-the-tidepool-big-data-donation-project';
export const URL_DEXCOM_CONNECT_INFO = 'http://support.tidepool.org/article/73-connecting-dexcom-account-to-tidepool';
export const URL_UPLOADER_DOWNLOAD_PAGE = 'https://tidepool.org/products/tidepool-uploader/'

export const TIDEPOOL_DATA_DONATION_ACCOUNT_EMAIL = 'bigdata@tidepool.org';

export const DATA_DONATION_NONPROFITS = () => [
  { value: 'ADCES', label: t('ADCES Foundation') },
  { value: 'BT1', label: t('Beyond Type 1') },
  { value: 'CWD', label: t('Children with Diabetes') },
  { value: 'CDN', label: t('College Diabetes Network') },
  { value: 'DYF', label: t('Diabetes Youth Families (DYF)') },
  { value: 'DIABETESSISTERS', label: t('DiabetesSisters') },
  { value: 'DIATRIBE', label: t('The diaTribe Foundation') },
  { value: 'JDRF', label: t('JDRF') },
  { value: 'NSF', label: t('Nightscout Foundation') },
  { value: 'T1DX', label: t('T1D Exchange') },
];

export const DIABETES_TYPES = () => [
  { value: 'type1', label: t('Type 1') },
  { value: 'type2', label: t('Type 2') },
  { value: 'gestational', label: t('Gestational') },
  { value: 'prediabetes', label: t('Pre-diabetes') },
  { value: 'lada', label: t('LADA (Type 1.5)') },
  { value: 'other', label: t('Other') },
];

export const BG_DATA_TYPES = [
  'cbg',
  'smbg',
];

export const DIABETES_DATA_TYPES = [
  ...BG_DATA_TYPES,
  'basal',
  'bolus',
  'wizard',
  'food',
];

export const MGDL_UNITS = t('mg/dL');
export const MMOLL_UNITS = t('mmol/L');
export const MGDL_PER_MMOLL = 18.01559;
<commit_msg>[WEB-821] Add constants for common MS_IN_[Time] durations<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2016, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

import i18next from './language';

const t = i18next.t.bind(i18next);

export const URL_UPLOADER_CHROME_STORE = 'http://chrome.google.com/webstore/detail/tidepool-uploader/cabklgajffclbljkhmjphejemhpbghfb';
export const URL_TIDEPOOL_MOBILE_APP_STORE = 'https://itunes.apple.com/us/app/tidepool-mobile/id1026395200?mt=8';
export const URL_TERMS_OF_USE = 'https://tidepool.org/terms-of-use';
export const URL_PRIVACY_POLICY = 'https://tidepool.org/privacy-policy';
export const URL_BIG_DATA_DONATION_INFO = 'https://tidepool.org/announcing-the-tidepool-big-data-donation-project';
export const URL_DEXCOM_CONNECT_INFO = 'http://support.tidepool.org/article/73-connecting-dexcom-account-to-tidepool';
export const URL_UPLOADER_DOWNLOAD_PAGE = 'https://tidepool.org/products/tidepool-uploader/'

export const TIDEPOOL_DATA_DONATION_ACCOUNT_EMAIL = 'bigdata@tidepool.org';

export const DATA_DONATION_NONPROFITS = () => [
  { value: 'ADCES', label: t('ADCES Foundation') },
  { value: 'BT1', label: t('Beyond Type 1') },
  { value: 'CWD', label: t('Children with Diabetes') },
  { value: 'CDN', label: t('College Diabetes Network') },
  { value: 'DYF', label: t('Diabetes Youth Families (DYF)') },
  { value: 'DIABETESSISTERS', label: t('DiabetesSisters') },
  { value: 'DIATRIBE', label: t('The diaTribe Foundation') },
  { value: 'JDRF', label: t('JDRF') },
  { value: 'NSF', label: t('Nightscout Foundation') },
  { value: 'T1DX', label: t('T1D Exchange') },
];

export const DIABETES_TYPES = () => [
  { value: 'type1', label: t('Type 1') },
  { value: 'type2', label: t('Type 2') },
  { value: 'gestational', label: t('Gestational') },
  { value: 'prediabetes', label: t('Pre-diabetes') },
  { value: 'lada', label: t('LADA (Type 1.5)') },
  { value: 'other', label: t('Other') },
];

export const BG_DATA_TYPES = [
  'cbg',
  'smbg',
];

export const DIABETES_DATA_TYPES = [
  ...BG_DATA_TYPES,
  'basal',
  'bolus',
  'wizard',
  'food',
];

export const MGDL_UNITS = t('mg/dL');
export const MMOLL_UNITS = t('mmol/L');
export const MGDL_PER_MMOLL = 18.01559;

export const MS_IN_DAY = 864e5;
export const MS_IN_HOUR = 864e5 / 24;
export const MS_IN_MIN = MS_IN_HOUR / 60;
<|endoftext|>


<commit_before>/**
 * 引用的入口模块
**/
define([
    'exports'
], function(exports){
    exports.init = function(){

    };
});
<commit_msg>Init repo path structure and editor<commit_after>/**
 * 应用的入口模块
**/
define([
    'exports'
], function(exports){
    exports.init = function(){

    };
});
<|endoftext|>


<commit_before>// Add file path shim for Jupyter 3/4
var IGV_PATH = location.origin + Jupyter.contents.base_url + "nbextensions/igv/";

define([
    "base/js/namespace",
    "jquery",
    IGV_PATH + "igvjs/igv-1.0.1.min.js"], function(Jupyter) {

    /**
     * Determines if the CSS file has been added to the head yet
     * @returns {boolean}
     */
    function is_css_loaded() {
        return $("link[href='" + IGV_PATH + "/igvjs/igv-1.0.1.css']").length > 0;
    }

    function load_css() {
        $("head").append('<link rel="stylesheet" type="text/css" href="' + IGV_PATH + '/igvjs/igv-1.0.1.css">');
    }

    /**
     * Load the IGV.js nbextension
     */
    function load_ipython_extension() {
        // Attach the CSS file, if necessary
        if (!is_css_loaded()) load_css();
    }

    return {
        load_ipython_extension: load_ipython_extension
    };

});<commit_msg>Fix double / bug<commit_after>// Add file path shim for Jupyter 3/4
var IGV_PATH = location.origin + Jupyter.contents.base_url + "nbextensions/igv/";

define([
    "base/js/namespace",
    "jquery",
    IGV_PATH + "igvjs/igv-1.0.1.min.js"], function(Jupyter) {

    /**
     * Determines if the CSS file has been added to the head yet
     * @returns {boolean}
     */
    function is_css_loaded() {
        return $("link[href='" + IGV_PATH + "igvjs/igv-1.0.1.css']").length > 0;
    }

    function load_css() {
        $("head").append('<link rel="stylesheet" type="text/css" href="' + IGV_PATH + 'igvjs/igv-1.0.1.css">');
    }

    /**
     * Load the IGV.js nbextension
     */
    function load_ipython_extension() {
        // Attach the CSS file, if necessary
        if (!is_css_loaded()) load_css();
    }

    return {
        load_ipython_extension: load_ipython_extension
    };

});<|endoftext|>


<commit_before>
function hideCard(id) {
  return {
    type: 'HIDE_CARD'
    id: id
  }
}

module.exports = {
  hideCard
};
<commit_msg>add missing comma<commit_after>
function hideCard(id) {
  return {
    type: 'HIDE_CARD',
    id: id
  }
}

module.exports = {
  hideCard
};
<|endoftext|>


<commit_before>import * as actionTypes from './actionTypes'
import { get as g } from 'lodash'

export const connected = () => ({
  type: g(actionTypes, 'FIREBASE_CONNECTED')
})

export const disconnected = () => ({
  type: g(actionTypes, 'FIREBASE_DISCONNECTED')
})

export const isDataBeingFetched = () => ({
  type: g(actionTypes, 'IS_DATA_BEING_FETCHED')
})

export const fetchDataSuccess = response => ({
  type: g(actionTypes, 'FETCH_DATA_SUCCESS'),
  payload: response
})

export const fetchDataFailure = (error) => ({
  type: g(actionTypes, 'FETCH_DATA_FAILURE'),
  payload: { error }
})

export const addRecipeRequest = () => {
  return {
    type: g(actionTypes, 'ADD_RECIPE_REQUEST')
  }
}

export const addRecipeSuccess = () => {
  console.log('SUC')
  return {
    type: g(actionTypes, 'ADD_RECIPE_SUCCESS')
  }
}

export const addRecipeFailure = (error) => ({
  type: g(actionTypes, 'ADD_RECIPE_FAILURE'),
  payload: { error }
})

export const deleteRecipeRequest = (recipeId, ingredientsIds) => ({
  type: g(actionTypes, 'DELETE_RECIPE_REQUEST'),
  ingredientsIds,
  recipeId
})
<commit_msg>fix error messages<commit_after>import * as actionTypes from './actionTypes'
import { get as g } from 'lodash'

export const connected = () => ({
  type: g(actionTypes, 'FIREBASE_CONNECTED')
})

export const disconnected = () => ({
  type: g(actionTypes, 'FIREBASE_DISCONNECTED')
})

export const isDataBeingFetched = () => ({
  type: g(actionTypes, 'IS_DATA_BEING_FETCHED')
})

export const fetchDataSuccess = response => ({
  type: g(actionTypes, 'FETCH_DATA_SUCCESS'),
  payload: response
})

export const fetchDataFailure = error => ({
  type: g(actionTypes, 'FETCH_DATA_FAILURE'),
  payload: { error: g(error, 'message') }
})

export const addRecipeRequest = () => {
  return {
    type: g(actionTypes, 'ADD_RECIPE_REQUEST')
  }
}

export const addRecipeSuccess = () => ({
  type: g(actionTypes, 'ADD_RECIPE_SUCCESS')
})

export const addRecipeFailure = error => ({
  type: g(actionTypes, 'ADD_RECIPE_FAILURE'),
  payload: { error: g(error, 'message') }
})

export const deleteRecipeRequest = (recipeId, ingredientsIds) => ({
  type: g(actionTypes, 'DELETE_RECIPE_REQUEST'),
  ingredientsIds,
  recipeId
})
<|endoftext|>


<commit_before>'use strict';
angular.module('ngAudio', [])
  .constant('ngAudioDomUid', (function () {
    var domUid = '';
    for (var i=0; i<8; i++)
    {
      domUid = domUid + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
    }
    return domUid;//unique id persisting through module life
  })())
.directive('ngAudio', ['$compile', '$q', 'ngAudio', function($compile, $q, ngAudio) {
    return {
        restrict: 'AEC',
        scope: {
            volume: '=',
            start: '=',
            currentTime: '=',
            loop: '=',
            clickPlay: '=',
            disablePreload:'='
            //ngAudio:'='
        },
        controller: ['$scope', '$attrs', '$element', '$timeout', function($scope, $attrs, $element, $timeout) {

            /* Loads the sound from destination */
            var audio;
            function initSound(){
                audio = ngAudio.load($attrs.ngAudio, $scope);
                /* Add audio to local scope for modification with nested inputs */
                $scope.$audio = audio;

                /* Remove watching features for improved performance */
                audio.unbind();
            }

            if (!$scope.disablePreload){
                initSound();
            }

            $element.on('click', function() {
                if ($scope.clickPlay === false) {
                    return;
                }

                if ($scope.disablePreload){
                    initSound();
                }

                /* iOS workaround: Call the play method directly in listener function */
                audio.audio.play();

                /* Set volume to $scope volume if it exists, or default to audio's current value */
                audio.volume = $scope.volume || audio.volume;
                audio.loop = $scope.loop;
                audio.currentTime = $scope.start || 0;

                /* Fixes a bug with Firefox (???) */
                $timeout(function() {
                    audio.play();
                }, 5);
            });

            $element.on('$destroy', function() {
                audio.destroy();
            });
        }]
    };
}])

.directive('ngAudioHover', ['$compile', '$q', 'ngAudio', function($compile, $q, ngAudio) {
    return {
        restrict: 'AEC',
        controller: ['$scope', '$attrs', '$element', '$timeout', function($scope, $attrs, $element, $timeout) {

            var audio = ngAudio.load($attrs.ngAudioHover, $scope);

            $element.on('mouseover rollover hover', function() {

                /* iOS workaround: Call the play method directly in listener function */
                audio.audio.play();

                audio.volume = $attrs.volumeHover || audio.volume;
                audio.loop = $attrs.loop;
                audio.currentTime = $attrs.startHover || 0;

            });

            $element.on('$destroy', function() {
                audio.destroy();
            });
        }]
    };
}])

.service('localAudioFindingService', ['$q', function($q) {

    this.find = function(id) {
        var deferred = $q.defer();
        var $sound = document.getElementById(id);
        if ($sound) {
            deferred.resolve($sound);
        } else {
            deferred.reject(id);
        }

        return deferred.promise;
    };
}])

.service('remoteAudioFindingService', ['$q', 'ngAudioDomUid', function($q, ngAudioDomUid) {

    this.find = function(url) {
        var deferred = $q.defer();
        var $sound = document.getElementById(ngAudioDomUid);
        if (!$sound)
        {
          var audioTag = document.createElement('audio');
          audioTag.style.display = 'none';
          audioTag.id = ngAudioDomUid;
          audioTag.src = url;
          document.body.appendChild(audioTag);
          $sound = document.getElementById(ngAudioDomUid);
          $sound.load();
        }
        else
        {
          $sound.pause();
          $sound.src = url;
          $sound.load();
        }

        if ($sound) {
          deferred.resolve($sound);
        } else {
          deferred.reject(id);
        }

        return deferred.promise;

    };
}])

.service('cleverAudioFindingService', ['$q', 'localAudioFindingService', 'remoteAudioFindingService', function($q, localAudioFindingService, remoteAudioFindingService) {
    this.find = function(id) {
        var deferred = $q.defer();

        id = id.replace('|', '/');

        localAudioFindingService.find(id)
            .then(deferred.resolve, function() {
                return remoteAudioFindingService.find(id);
            })
            .then(deferred.resolve, deferred.reject);

        return deferred.promise;
    };
}])

.value('ngAudioGlobals', {
    muting: false,
    performance: 25,
    unlock: true,
    volume:1
})

.factory('NgAudioObject', ['cleverAudioFindingService', '$rootScope', '$interval', '$timeout', 'ngAudioGlobals', function(cleverAudioFindingService, $rootScope, $interval, $timeout, ngAudioGlobals) {
    return function(id, scope) {

        function twiddle(){
            try{
              audio.play();
              audio.pause();
            }catch(e){}
            window.removeEventListener("click",twiddle);
        }

        var $audioWatch,
            $intervalWatch,
            $willPlay = false,
            $willPause = false,
            $willRestart = false,
            $willChangePlaybackRate = false,
            $newPlaybackRate = false,
            $volumeToSet,
            $looping,
            $isMuting = false,
            $observeProperties = true,
            $destroyed = false,
            $scope = scope || $rootScope,
            audio,
            audioObject = this;

        this.id = id;
        this.safeId = id.replace('/', '|');
        this.loop = 0;

        this.unbind = function() {
            $observeProperties = false;
        };

        this.play = function() {
            $willPlay = true;
            return this;
        };

        var completeListeners = [];
        this.complete = function(callback){
            completeListeners.push(callback);
        };

        var toFinishListeners = [];
        this.toFinish = function(secs, callback){
            toFinishListeners.push({'secs': secs, 'callback': callback});
        };

        this.pause = function() {
            $willPause = true;
        };

        this.restart = function() {
            $willRestart = true;
        };

        this.stop = function() {
            this.restart();
        };

        this.setVolume = function(volume) {
            $volumeToSet = volume;
        };

        this.setPlaybackRate = function(rate) {
            $newPlaybackRate = rate;
            $willChangePlaybackRate = true;
        };

        this.setMuting = function(muting) {
            $isMuting = muting;
        };

        this.setProgress = function(progress) {
            if (audio && audio.duration && isFinite(progress)) {
                audio.currentTime = audio.duration * progress;
            }
        };

        this.setCurrentTime = function(currentTime) {
            if (audio && audio.duration) {
                audio.currentTime = currentTime;
            }
        };

        this.destroy = $destroy;

        $scope.$on('$destroy', function() {
            $destroy();
        });

        function $destroy() {
            if (!$destroyed) {
                if (interval) {
                    $interval.cancel(interval);
                }
                if ($intervalWatch) {
                    $intervalWatch();
                }
                if ($audioWatch) {
                    $audioWatch();
                }
                $destroyed = true;
            }
        }

        this.destroyed = function() {
          return $destroyed;
        };

        function $setWatch() {
            if ($destroyed) {
                return;
            }
            $audioWatch = $scope.$watch(function() {
                return {
                    volume: audioObject.volume,
                    currentTime: audioObject.currentTime,
                    progress: audioObject.progress,
                    muting: audioObject.muting,
                    loop: audioObject.loop,
                    playbackRate: audioObject.playbackRate,
                    globalVolume: ngAudioGlobals.volume
                };
            }, function(newValue, oldValue) {
                //console.log("ngaudio watch callback for: " + audioObject.id);
                if (newValue.currentTime !== oldValue.currentTime) {
                    audioObject.setCurrentTime(newValue.currentTime);
                }

                if (newValue.progress !== oldValue.progress) {
                    audioObject.setProgress(newValue.progress);
                }
                if (newValue.volume !== oldValue.volume) {
                    audioObject.setVolume(newValue.volume);
                }

                if (newValue.playbackRate !== oldValue.playbackRate) {
                    audioObject.setPlaybackRate(newValue.playbackRate);
                }

                if (newValue.globalVolume !== oldValue.globalVolume) {
                    if (newValue.globalVolume === 0) {
                        audioObject.setMuting(true);
                    } else {
                        audioObject.setMuting(false);
                        audioObject.setVolume(newValue.globalVolume);
                    }
                }

                $looping = newValue.loop;

                if (newValue.muting !== oldValue.muting) {
                    audioObject.setMuting(newValue.muting);
                }
            }, true);
        }

        cleverAudioFindingService.find(id)
            .then(function(nativeAudio) {
                audio = nativeAudio;
                if (ngAudioGlobals.unlock) {

                    window.addEventListener("click", twiddle);

                    audio.addEventListener('playing', function() {
                        window.removeEventListener("click",twiddle);
                    });

                }

                audio.addEventListener('canplay', function() {
                    audioObject.canPlay = true;
                });

            }, function(error) {
                audioObject.error = true;
                console.warn(error);
            });

        var interval = $interval(checkWatchers, ngAudioGlobals.performance);
        $intervalWatch = $scope.$watch(function(){
            return ngAudioGlobals.performance;
        },function(){
            $interval.cancel(interval);
            interval = $interval(checkWatchers, ngAudioGlobals.performance);
        });

        function checkWatchers() {
            if ($audioWatch) {
                $audioWatch();
            }
            if (audio) {

                if ($isMuting || ngAudioGlobals.muting) {
                    audio.volume = 0;
                } else {
                    audio.volume = audioObject.volume !== undefined ? audioObject.volume : 1;
                }

                if ($willPlay) {
                    audio.play();
                    $willPlay = false;
                }

                if ($willRestart) {
                    audio.pause();
                    audio.currentTime = 0;
                    $willRestart = false;
                }

                if ($willPause) {
                    audio.pause();
                    $willPause = false;
                }

                if ($willChangePlaybackRate) {
                    audio.playbackRate = $newPlaybackRate;
                    $willChangePlaybackRate = false;
                }

                if ($volumeToSet) {
                    audio.volume = $volumeToSet;
                    $volumeToSet = undefined;
                }

                if ($observeProperties) {
                    audioObject.currentTime = audio.currentTime;
                    audioObject.duration = audio.duration;
                    audioObject.remaining = audio.duration - audio.currentTime;
					audioObject.progress = 0; //We set initial value to 0
                    audioObject.paused = audio.paused;
                    audioObject.src = audio.src;

					//After we check if progress is bigger than 0, and we set
                    var tempProgress = (audio.currentTime / audio.duration);
                    if(tempProgress  > 0 ){
                      audioObject.progress = tempProgress;
                    }

                    if (audioObject.currentTime >= audioObject.duration) {
                        completeListeners.forEach(function(listener){
                            listener(audioObject);
                        })
                    }

                    toFinishListeners.forEach(function(listener) {
                        if ((audioObject.duration - audioObject.currentTime) <= listener.secs) {
                            listener.callback(audioObject);
                            toFinishListeners.shift();
                        }
                    });

                    if ($looping && audioObject.currentTime >= audioObject.duration) {
                        if ($looping !== true) {
                            $looping--;
                            audioObject.loop--;
                            // if (!$looping) return;
                        }
                        audioObject.setCurrentTime(0);
                        audioObject.play();

                    }
                }

                if (!$isMuting && !ngAudioGlobals.muting) {
                    audioObject.volume = audio.volume;
                }

                audioObject.audio = audio;
            }

            $setWatch();
        }
    };
}])
.service('ngAudio', ['NgAudioObject', 'ngAudioGlobals', function(NgAudioObject, ngAudioGlobals) {
    this.play = function(id, scope) {

        var audio = new NgAudioObject(id, scope);
        audio.play();
        return audio;
    };

    this.load = function(id, scope) {
        return new NgAudioObject(id, scope);
    };

    this.mute = function() {
        ngAudioGlobals.muting = true;
    };

    this.unmute = function() {
        ngAudioGlobals.muting = false;
    };

    this.toggleMute = function() {
        ngAudioGlobals.muting = !ngAudioGlobals.muting;
    };

    this.setUnlock = function(unlock) {
      ngAudioGlobals.unlock = unlock;
    };

    this.setGlobalVolume = function(globalVolume) {
      ngAudioGlobals.volume = globalVolume;
    };
}])
.filter("trackTime", function(){
    /* Conveniently takes a number and returns the track time */

    return function(input){

        var totalSec = Math.floor(input | 0);

        var output = "";
        var hours = 0;
        var minutes = 0;
        var seconds = 0;

        if (totalSec > 3599) {

            hours = Math.floor(totalSec / 3600);
            minutes = Math.floor((totalSec - (hours * 3600)) / 60);
            seconds = (totalSec - ((minutes * 60) + (hours * 3600)));

            if (hours.toString().length == 1) {
                hours = "0" + (Math.floor(totalSec / 3600)).toString();
            }

            if (minutes.toString().length == 1) {
                minutes = "0" + (Math.floor((totalSec - (hours * 3600)) / 60)).toString();
            }

            if (seconds.toString().length == 1) {
                seconds = "0" + (totalSec - ((minutes * 60) + (hours * 3600))).toString();
            }

            output = hours + ":" + minutes + ":" + seconds;

        } else if (totalSec > 59) {

            minutes = Math.floor(totalSec / 60);
            seconds = totalSec - (minutes * 60);

            if (minutes.toString().length == 1) {
                 minutes = "0" + (Math.floor(totalSec / 60)).toString();
            }

            if (seconds.toString().length == 1) {
                 seconds = "0" + (totalSec - (minutes * 60)).toString();
            }

            output = minutes + ":" + seconds;

        } else {

            seconds = totalSec;

            if (seconds.toString().length == 1) {
                seconds = "0" + (totalSec).toString();
            }

            output = totalSec + "s";

        }

        if (typeof Number.isNaN === "function" && Number.isNaN(output)){
            debugger;
        }

        return output;
    }
});
<commit_msg>Fixes Error Handling<commit_after>'use strict';
angular.module('ngAudio', [])
  .constant('ngAudioDomUid', (function () {
    var domUid = '';
    for (var i=0; i<8; i++)
    {
      domUid = domUid + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
    }
    return domUid;//unique id persisting through module life
  })())
.directive('ngAudio', ['$compile', '$q', 'ngAudio', function($compile, $q, ngAudio) {
    return {
        restrict: 'AEC',
        scope: {
            volume: '=',
            start: '=',
            currentTime: '=',
            loop: '=',
            clickPlay: '=',
            disablePreload:'='
            //ngAudio:'='
        },
        controller: ['$scope', '$attrs', '$element', '$timeout', function($scope, $attrs, $element, $timeout) {

            /* Loads the sound from destination */
            var audio;
            function initSound(){
                audio = ngAudio.load($attrs.ngAudio, $scope);
                /* Add audio to local scope for modification with nested inputs */
                $scope.$audio = audio;

                /* Remove watching features for improved performance */
                audio.unbind();
            }

            if (!$scope.disablePreload){
                initSound();
            }

            $element.on('click', function() {
                if ($scope.clickPlay === false) {
                    return;
                }

                if ($scope.disablePreload){
                    initSound();
                }

                /* iOS workaround: Call the play method directly in listener function */
                audio.audio.play();

                /* Set volume to $scope volume if it exists, or default to audio's current value */
                audio.volume = $scope.volume || audio.volume;
                audio.loop = $scope.loop;
                audio.currentTime = $scope.start || 0;

                /* Fixes a bug with Firefox (???) */
                $timeout(function() {
                    audio.play();
                }, 5);
            });

            $element.on('$destroy', function() {
                audio.destroy();
            });
        }]
    };
}])

.directive('ngAudioHover', ['$compile', '$q', 'ngAudio', function($compile, $q, ngAudio) {
    return {
        restrict: 'AEC',
        controller: ['$scope', '$attrs', '$element', '$timeout', function($scope, $attrs, $element, $timeout) {

            var audio = ngAudio.load($attrs.ngAudioHover, $scope);

            $element.on('mouseover rollover hover', function() {

                /* iOS workaround: Call the play method directly in listener function */
                audio.audio.play();

                audio.volume = $attrs.volumeHover || audio.volume;
                audio.loop = $attrs.loop;
                audio.currentTime = $attrs.startHover || 0;

            });

            $element.on('$destroy', function() {
                audio.destroy();
            });
        }]
    };
}])

.service('localAudioFindingService', ['$q', function($q) {

    this.find = function(id) {
        var deferred = $q.defer();
        var $sound = document.getElementById(id);
        if ($sound) {
            deferred.resolve($sound);
        } else {
            deferred.reject(id);
        }

        return deferred.promise;
    };
}])

.service('remoteAudioFindingService', ['$q', 'ngAudioDomUid', function($q, ngAudioDomUid) {

    this.find = function(url) {
        var deferred = $q.defer();
        var $sound = document.getElementById(ngAudioDomUid);
        if (!$sound)
        {
          var audioTag = document.createElement('audio');
          audioTag.style.display = 'none';
          audioTag.id = ngAudioDomUid;
          audioTag.src = url;
          document.body.appendChild(audioTag);
          $sound = document.getElementById(ngAudioDomUid);
          $sound.load();
        }
        else
        {
          $sound.pause();
          $sound.src = url;
          $sound.load();
        }

        if ($sound) {
          deferred.resolve($sound);
        } else {
          deferred.reject(id);
        }

        return deferred.promise;

    };
}])

.service('cleverAudioFindingService', ['$q', 'localAudioFindingService', 'remoteAudioFindingService', function($q, localAudioFindingService, remoteAudioFindingService) {
    this.find = function(id) {
        var deferred = $q.defer();

        id = id.replace('|', '/');

        localAudioFindingService.find(id)
            .then(deferred.resolve, function() {
                return remoteAudioFindingService.find(id);
            })
            .then(deferred.resolve, deferred.reject);

        return deferred.promise;
    };
}])

.value('ngAudioGlobals', {
    muting: false,
    performance: 25,
    unlock: true,
    volume:1
})

.factory('NgAudioObject', ['cleverAudioFindingService', '$rootScope', '$interval', '$timeout', 'ngAudioGlobals', function(cleverAudioFindingService, $rootScope, $interval, $timeout, ngAudioGlobals) {
    return function(id, scope) {

        function twiddle(){
            try{
              audio.play();
              audio.pause();
            }catch(e){}
            window.removeEventListener("click",twiddle);
        }

        var $audioWatch,
            $intervalWatch,
            $willPlay = false,
            $willPause = false,
            $willRestart = false,
            $willChangePlaybackRate = false,
            $newPlaybackRate = false,
            $volumeToSet,
            $looping,
            $isMuting = false,
            $observeProperties = true,
            $destroyed = false,
            $scope = scope || $rootScope,
            audio,
            audioObject = this;

        this.id = id;
        this.safeId = id.replace('/', '|');
        this.loop = 0;

        this.unbind = function() {
            $observeProperties = false;
        };

        this.play = function() {
            $willPlay = true;
            return this;
        };

        var completeListeners = [];
        this.complete = function(callback){
            completeListeners.push(callback);
        };

        var toFinishListeners = [];
        this.toFinish = function(secs, callback){
            toFinishListeners.push({'secs': secs, 'callback': callback});
        };

        this.pause = function() {
            $willPause = true;
        };

        this.restart = function() {
            $willRestart = true;
        };

        this.stop = function() {
            this.restart();
        };

        this.setVolume = function(volume) {
            $volumeToSet = volume;
        };

        this.setPlaybackRate = function(rate) {
            $newPlaybackRate = rate;
            $willChangePlaybackRate = true;
        };

        this.setMuting = function(muting) {
            $isMuting = muting;
        };

        this.setProgress = function(progress) {
            if (audio && audio.duration && isFinite(progress)) {
                audio.currentTime = audio.duration * progress;
            }
        };

        this.setCurrentTime = function(currentTime) {
            if (audio && audio.duration) {
                audio.currentTime = currentTime;
            }
        };

        this.destroy = $destroy;

        $scope.$on('$destroy', function() {
            $destroy();
        });

        function $destroy() {
            if (!$destroyed) {
                if (interval) {
                    $interval.cancel(interval);
                }
                if ($intervalWatch) {
                    $intervalWatch();
                }
                if ($audioWatch) {
                    $audioWatch();
                }
                $destroyed = true;
            }
        }

        this.destroyed = function() {
          return $destroyed;
        };

        function $setWatch() {
            if ($destroyed) {
                return;
            }
            $audioWatch = $scope.$watch(function() {
                return {
                    volume: audioObject.volume,
                    currentTime: audioObject.currentTime,
                    progress: audioObject.progress,
                    muting: audioObject.muting,
                    loop: audioObject.loop,
                    playbackRate: audioObject.playbackRate,
                    globalVolume: ngAudioGlobals.volume
                };
            }, function(newValue, oldValue) {
                //console.log("ngaudio watch callback for: " + audioObject.id);
                if (newValue.currentTime !== oldValue.currentTime) {
                    audioObject.setCurrentTime(newValue.currentTime);
                }

                if (newValue.progress !== oldValue.progress) {
                    audioObject.setProgress(newValue.progress);
                }
                if (newValue.volume !== oldValue.volume) {
                    audioObject.setVolume(newValue.volume);
                }

                if (newValue.playbackRate !== oldValue.playbackRate) {
                    audioObject.setPlaybackRate(newValue.playbackRate);
                }

                if (newValue.globalVolume !== oldValue.globalVolume) {
                    if (newValue.globalVolume === 0) {
                        audioObject.setMuting(true);
                    } else {
                        audioObject.setMuting(false);
                        audioObject.setVolume(newValue.globalVolume);
                    }
                }

                $looping = newValue.loop;

                if (newValue.muting !== oldValue.muting) {
                    audioObject.setMuting(newValue.muting);
                }
            }, true);
        }

        function audioLoadError() {
            audioObject.error = true;
        }

        cleverAudioFindingService.find(id)
            .then(function(nativeAudio) {
                audio = nativeAudio;
                if (ngAudioGlobals.unlock) {

                    window.addEventListener("click", twiddle);

                    audio.addEventListener('playing', function() {
                        window.removeEventListener("click",twiddle);
                    });

                }

                audio.addEventListener('error', audioLoadError);

                audio.addEventListener('canplay', function() {
                    audioObject.canPlay = true;
                });

            }, audioLoadError);

        var interval = $interval(checkWatchers, ngAudioGlobals.performance);
        $intervalWatch = $scope.$watch(function(){
            return ngAudioGlobals.performance;
        },function(){
            $interval.cancel(interval);
            interval = $interval(checkWatchers, ngAudioGlobals.performance);
        });

        function checkWatchers() {
            if ($audioWatch) {
                $audioWatch();
            }
            if (audio) {

                if ($isMuting || ngAudioGlobals.muting) {
                    audio.volume = 0;
                } else {
                    audio.volume = audioObject.volume !== undefined ? audioObject.volume : 1;
                }

                if ($willPlay) {
                    audio.play();
                    $willPlay = false;
                }

                if ($willRestart) {
                    audio.pause();
                    audio.currentTime = 0;
                    $willRestart = false;
                }

                if ($willPause) {
                    audio.pause();
                    $willPause = false;
                }

                if ($willChangePlaybackRate) {
                    audio.playbackRate = $newPlaybackRate;
                    $willChangePlaybackRate = false;
                }

                if ($volumeToSet) {
                    audio.volume = $volumeToSet;
                    $volumeToSet = undefined;
                }

                if ($observeProperties) {
                    audioObject.currentTime = audio.currentTime;
                    audioObject.duration = audio.duration;
                    audioObject.remaining = audio.duration - audio.currentTime;
					audioObject.progress = 0; //We set initial value to 0
                    audioObject.paused = audio.paused;
                    audioObject.src = audio.src;

					//After we check if progress is bigger than 0, and we set
                    var tempProgress = (audio.currentTime / audio.duration);
                    if(tempProgress  > 0 ){
                      audioObject.progress = tempProgress;
                    }

                    if (audioObject.currentTime >= audioObject.duration) {
                        completeListeners.forEach(function(listener){
                            listener(audioObject);
                        })
                    }

                    toFinishListeners.forEach(function(listener) {
                        if ((audioObject.duration - audioObject.currentTime) <= listener.secs) {
                            listener.callback(audioObject);
                            toFinishListeners.shift();
                        }
                    });

                    if ($looping && audioObject.currentTime >= audioObject.duration) {
                        if ($looping !== true) {
                            $looping--;
                            audioObject.loop--;
                            // if (!$looping) return;
                        }
                        audioObject.setCurrentTime(0);
                        audioObject.play();

                    }
                }

                if (!$isMuting && !ngAudioGlobals.muting) {
                    audioObject.volume = audio.volume;
                }

                audioObject.audio = audio;
            }

            $setWatch();
        }
    };
}])
.service('ngAudio', ['NgAudioObject', 'ngAudioGlobals', function(NgAudioObject, ngAudioGlobals) {
    this.play = function(id, scope) {

        var audio = new NgAudioObject(id, scope);
        audio.play();
        return audio;
    };

    this.load = function(id, scope) {
        return new NgAudioObject(id, scope);
    };

    this.mute = function() {
        ngAudioGlobals.muting = true;
    };

    this.unmute = function() {
        ngAudioGlobals.muting = false;
    };

    this.toggleMute = function() {
        ngAudioGlobals.muting = !ngAudioGlobals.muting;
    };

    this.setUnlock = function(unlock) {
      ngAudioGlobals.unlock = unlock;
    };

    this.setGlobalVolume = function(globalVolume) {
      ngAudioGlobals.volume = globalVolume;
    };
}])
.filter("trackTime", function(){
    /* Conveniently takes a number and returns the track time */

    return function(input){

        var totalSec = Math.floor(input | 0);

        var output = "";
        var hours = 0;
        var minutes = 0;
        var seconds = 0;

        if (totalSec > 3599) {

            hours = Math.floor(totalSec / 3600);
            minutes = Math.floor((totalSec - (hours * 3600)) / 60);
            seconds = (totalSec - ((minutes * 60) + (hours * 3600)));

            if (hours.toString().length == 1) {
                hours = "0" + (Math.floor(totalSec / 3600)).toString();
            }

            if (minutes.toString().length == 1) {
                minutes = "0" + (Math.floor((totalSec - (hours * 3600)) / 60)).toString();
            }

            if (seconds.toString().length == 1) {
                seconds = "0" + (totalSec - ((minutes * 60) + (hours * 3600))).toString();
            }

            output = hours + ":" + minutes + ":" + seconds;

        } else if (totalSec > 59) {

            minutes = Math.floor(totalSec / 60);
            seconds = totalSec - (minutes * 60);

            if (minutes.toString().length == 1) {
                 minutes = "0" + (Math.floor(totalSec / 60)).toString();
            }

            if (seconds.toString().length == 1) {
                 seconds = "0" + (totalSec - (minutes * 60)).toString();
            }

            output = minutes + ":" + seconds;

        } else {

            seconds = totalSec;

            if (seconds.toString().length == 1) {
                seconds = "0" + (totalSec).toString();
            }

            output = totalSec + "s";

        }

        if (typeof Number.isNaN === "function" && Number.isNaN(output)){
            debugger;
        }

        return output;
    }
});
<|endoftext|>


<commit_before><commit_msg>remove unused import<commit_after><|endoftext|>


<commit_before>/**
 * Functions to build/cache match object
 * */
const constants = require('dotaconstants');
const { promisify } = require('util');
const config = require('../config');
const queries = require('./queries');
const compute = require('../util/compute');
const utility = require('../util/utility');
const cassandra = require('../store/cassandra');
const redis = require('../store/redis');
const db = require('../store/db');

const { computeMatchData } = compute;
const { deserialize, buildReplayUrl, isContributor } = utility;
const getRedisAsync = promisify(redis.get).bind(redis);

async function getMatchData(matchId) {
  const result = await cassandra.execute('SELECT * FROM matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 1,
    autoPage: true,
  });
  const deserializedResult = result.rows.map(m => deserialize(m));
  return Promise.resolve(deserializedResult[0]);
}

async function getPlayerMatchData(matchId) {
  const result = await cassandra.execute('SELECT * FROM player_matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 24,
    autoPage: true,
  });
  const deserializedResult = result.rows.map(m => deserialize(m));
  return Promise.all(deserializedResult.map(r => db.raw(`
        SELECT personaname, name, last_login
        FROM players
        LEFT JOIN notable_players
        ON players.account_id = notable_players.account_id
        WHERE players.account_id = ?
      `, [r.account_id])
    .then(names => ({ ...r, ...names.rows[0] }))));
}

async function extendPlayerData(player, match) {
  const p = {
    ...player,
    radiant_win: match.radiant_win,
    start_time: match.start_time,
    duration: match.duration,
    cluster: match.cluster,
    lobby_type: match.lobby_type,
    game_mode: match.game_mode,
    is_contributor: isContributor(player.account_id),
  };
  computeMatchData(p);
  const row = await db.first().from('rank_tier').where({ account_id: p.account_id || null });
  p.rank_tier = row ? row.rating : null;
  return Promise.resolve(p);
}

async function prodataInfo(matchId) {
  const result = await db.first(['radiant_team_id', 'dire_team_id', 'leagueid'])
    .from('matches')
    .where({
      match_id: matchId,
    });
  if (!result) {
    return Promise.resolve({});
  }
  const leaguePromise = db.first().from('leagues').where({
    leagueid: result.leagueid,
  });
  const radiantTeamPromise = db.first().from('teams').where({
    team_id: result.radiant_team_id,
  });
  const direTeamPromise = db.first().from('teams').where({
    team_id: result.dire_team_id,
  });
  const [league, radiantTeam, direTeam] = await Promise.all([leaguePromise, radiantTeamPromise, direTeamPromise]);
  return Promise.resolve({
    league,
    radiant_team: radiantTeam,
    dire_team: direTeam,
  });
}

async function getMatch(matchId) {
  if (!matchId || Number.isNaN(Number(matchId)) || Number(matchId) <= 0) {
    return Promise.resolve();
  }
  const match = await getMatchData(matchId);
  if (!match) {
    return Promise.resolve();
  }
  let playersMatchData = [];
  try {
    playersMatchData = await getPlayerMatchData(matchId);
  } catch (e) {
    console.error(e);
    if (e.message.startsWith('Server failure during read query')) {
      // Delete and request new
      await cassandra.execute('DELETE FROM player_matches where match_id = ?', [Number(matchId)], { prepare: true });
      const match = {
        match_id: Number(matchId),
      };
      await new Promise((resolve, reject) => {
      utility.getData(utility.generateJob('api_details', match).url, (err, body) => {
        if (err) {
          console.error(err);
          return reject();
        }
        // match details response
        const match = body.result;
        return queries.insertMatch(match, {
          type: 'api',
          attempts: 1,
          priority: 1,
          forceParse: false,
        }, () => {
          // Count for logging
          utility.redisCount(redis, 'cassandra_repair');
          resolve();
        });
      });
    });
    playersMatchData = await getPlayerMatchData(matchId);
    } else {
      throw e;
    }
  }
  const playersPromise = Promise.all(playersMatchData.map(p => extendPlayerData(p, match)));
  const gcdataPromise = db.first().from('match_gcdata').where({
    match_id: matchId,
  });
  const cosmeticsPromise = Promise.all(Object.keys(match.cosmetics || {}).map(itemId => db.first().from('cosmetics').where({
    item_id: itemId,
  })));
  const prodataPromise = prodataInfo(matchId);

  const [players, gcdata, prodata, cosmetics] = await Promise.all([playersPromise, gcdataPromise, prodataPromise, cosmeticsPromise]);

  let matchResult = {
    ...match,
    ...gcdata,
    ...prodata,
    players,
  };

  if (cosmetics) {
    const playersWithCosmetics = matchResult.players.map((p) => {
      const hero = constants.heroes[p.hero_id] || {};
      const playerCosmetics = cosmetics.filter(Boolean).filter(c => match.cosmetics[c.item_id] === p.player_slot
        && (!c.used_by_heroes || c.used_by_heroes === hero.name));
      return {
        ...p,
        cosmetics: playerCosmetics,
      };
    });
    matchResult = {
      ...matchResult,
      players: playersWithCosmetics,
    };
  }
  computeMatchData(matchResult);
  if (matchResult.replay_salt) {
    matchResult.replay_url = buildReplayUrl(matchResult.match_id, matchResult.cluster, matchResult.replay_salt);
  }
  const matchWithBenchmarks = await queries.getMatchBenchmarksPromisified(matchResult);
  return Promise.resolve(matchWithBenchmarks);
}

async function buildMatch(matchId) {
  const key = `match:${matchId}`;
  const reply = await getRedisAsync(key);
  if (reply) {
    return Promise.resolve(JSON.parse(reply));
  }
  const match = await getMatch(matchId);
  if (!match) {
    return Promise.resolve();
  }
  if (match.version && config.ENABLE_MATCH_CACHE) {
    await redis.setex(key, config.MATCH_CACHE_SECONDS, JSON.stringify(match));
  }
  return Promise.resolve(match);
}

module.exports = buildMatch;
<commit_msg>throw exception on no players found<commit_after>/**
 * Functions to build/cache match object
 * */
const constants = require('dotaconstants');
const { promisify } = require('util');
const config = require('../config');
const queries = require('./queries');
const compute = require('../util/compute');
const utility = require('../util/utility');
const cassandra = require('../store/cassandra');
const redis = require('../store/redis');
const db = require('../store/db');

const { computeMatchData } = compute;
const { deserialize, buildReplayUrl, isContributor } = utility;
const getRedisAsync = promisify(redis.get).bind(redis);

async function getMatchData(matchId) {
  const result = await cassandra.execute('SELECT * FROM matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 1,
    autoPage: true,
  });
  const deserializedResult = result.rows.map(m => deserialize(m));
  return Promise.resolve(deserializedResult[0]);
}

async function getPlayerMatchData(matchId) {
  const result = await cassandra.execute('SELECT * FROM player_matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 24,
    autoPage: true,
  });
  const deserializedResult = result.rows.map(m => deserialize(m));
  return Promise.all(deserializedResult.map(r => db.raw(`
        SELECT personaname, name, last_login
        FROM players
        LEFT JOIN notable_players
        ON players.account_id = notable_players.account_id
        WHERE players.account_id = ?
      `, [r.account_id])
    .then(names => ({ ...r, ...names.rows[0] }))));
}

async function extendPlayerData(player, match) {
  const p = {
    ...player,
    radiant_win: match.radiant_win,
    start_time: match.start_time,
    duration: match.duration,
    cluster: match.cluster,
    lobby_type: match.lobby_type,
    game_mode: match.game_mode,
    is_contributor: isContributor(player.account_id),
  };
  computeMatchData(p);
  const row = await db.first().from('rank_tier').where({ account_id: p.account_id || null });
  p.rank_tier = row ? row.rating : null;
  return Promise.resolve(p);
}

async function prodataInfo(matchId) {
  const result = await db.first(['radiant_team_id', 'dire_team_id', 'leagueid'])
    .from('matches')
    .where({
      match_id: matchId,
    });
  if (!result) {
    return Promise.resolve({});
  }
  const leaguePromise = db.first().from('leagues').where({
    leagueid: result.leagueid,
  });
  const radiantTeamPromise = db.first().from('teams').where({
    team_id: result.radiant_team_id,
  });
  const direTeamPromise = db.first().from('teams').where({
    team_id: result.dire_team_id,
  });
  const [league, radiantTeam, direTeam] = await Promise.all([leaguePromise, radiantTeamPromise, direTeamPromise]);
  return Promise.resolve({
    league,
    radiant_team: radiantTeam,
    dire_team: direTeam,
  });
}

async function getMatch(matchId) {
  if (!matchId || Number.isNaN(Number(matchId)) || Number(matchId) <= 0) {
    return Promise.resolve();
  }
  const match = await getMatchData(matchId);
  if (!match) {
    return Promise.resolve();
  }
  let playersMatchData = [];
  try {
    playersMatchData = await getPlayerMatchData(matchId);
    if (playersMatchData.length === 0) {
      throw new Error('no players found for match %s');
    }
  } catch (e) {
    console.error(e);
    if (e.message.startsWith('Server failure during read query') || e.message.startsWith('no players found')) {
      // Delete and request new
      await cassandra.execute('DELETE FROM player_matches where match_id = ?', [Number(matchId)], { prepare: true });
      const match = {
        match_id: Number(matchId),
      };
      await new Promise((resolve, reject) => {
      utility.getData(utility.generateJob('api_details', match).url, (err, body) => {
        if (err) {
          console.error(err);
          return reject();
        }
        // match details response
        const match = body.result;
        return queries.insertMatch(match, {
          type: 'api',
          attempts: 1,
          priority: 1,
          forceParse: false,
        }, () => {
          // Count for logging
          utility.redisCount(redis, 'cassandra_repair');
          resolve();
        });
      });
    });
    playersMatchData = await getPlayerMatchData(matchId);
    } else {
      throw e;
    }
  }
  const playersPromise = Promise.all(playersMatchData.map(p => extendPlayerData(p, match)));
  const gcdataPromise = db.first().from('match_gcdata').where({
    match_id: matchId,
  });
  const cosmeticsPromise = Promise.all(Object.keys(match.cosmetics || {}).map(itemId => db.first().from('cosmetics').where({
    item_id: itemId,
  })));
  const prodataPromise = prodataInfo(matchId);

  const [players, gcdata, prodata, cosmetics] = await Promise.all([playersPromise, gcdataPromise, prodataPromise, cosmeticsPromise]);

  let matchResult = {
    ...match,
    ...gcdata,
    ...prodata,
    players,
  };

  if (cosmetics) {
    const playersWithCosmetics = matchResult.players.map((p) => {
      const hero = constants.heroes[p.hero_id] || {};
      const playerCosmetics = cosmetics.filter(Boolean).filter(c => match.cosmetics[c.item_id] === p.player_slot
        && (!c.used_by_heroes || c.used_by_heroes === hero.name));
      return {
        ...p,
        cosmetics: playerCosmetics,
      };
    });
    matchResult = {
      ...matchResult,
      players: playersWithCosmetics,
    };
  }
  computeMatchData(matchResult);
  if (matchResult.replay_salt) {
    matchResult.replay_url = buildReplayUrl(matchResult.match_id, matchResult.cluster, matchResult.replay_salt);
  }
  const matchWithBenchmarks = await queries.getMatchBenchmarksPromisified(matchResult);
  return Promise.resolve(matchWithBenchmarks);
}

async function buildMatch(matchId) {
  const key = `match:${matchId}`;
  const reply = await getRedisAsync(key);
  if (reply) {
    return Promise.resolve(JSON.parse(reply));
  }
  const match = await getMatch(matchId);
  if (!match) {
    return Promise.resolve();
  }
  if (match.version && config.ENABLE_MATCH_CACHE) {
    await redis.setex(key, config.MATCH_CACHE_SECONDS, JSON.stringify(match));
  }
  return Promise.resolve(match);
}

module.exports = buildMatch;
<|endoftext|>


<commit_before><commit_msg>dadd opcode.<commit_after><|endoftext|>


<commit_before>/*
 * Toady
 * Copyright 2013 Tom Frost
 */

var objUtil = require('../util/Object'),
	modLoad = require('../modmanager/ModLoader'),
	pkgjson = require('../../package.json'),
	name = pkgjson.name,
	version = pkgjson.version,
	author = pkgjson.author,
	url = pkgjson.homepage;

const PERM_CHARS = ['O', 'S', 'P', '~', '&', '@', '%', '+', '', '0'];

function padStr(str, len) {
	while (str.length < len)
		str += ' ';
	return str;
}

function strSort(a, b) {
	if (a > b) return 1;
	if (a == b) return 0;
	return -1;
}

/**
 * Help provides all user commands necessary to display mod and command
 * metadata in a digestible format.
 *
 * @param {Object} config A Toady config object
 * @param {Object} client An IRC client object
 * @param {Object} modMan The Toady ModManager object
 * @returns {Object} A Toady mod
 */
module.exports = function(config, client, modMan) {

	/**
	 * Gets an object mapping of all Mod IDs to an additional object mapping
	 * of command IDs to command objects.  This result set will be limited to
	 * commands requiring permissions equal to or less than maxPerm, and
	 * mods which contain commands after that filter is applied.
	 *
	 * @param {String} maxPerm The maximum permission char for which to
	 *      return commands
	 * @returns {Object} An object mapping mod IDs to objects mapping command
	 *      IDs to commands, where each command's required permission is equal
	 *      to or less than maxPerm
	 */
	function getModCommands(maxPerm) {
		var mods = modMan.getMods(),
			pMod = modMan.getMod('users'),
			modCommands = {};
		if (!maxPerm && maxPerm != '')
			maxPerm = null;
		mods.forEach(function(mod) {
			objUtil.forEach(mod.commands || {}, function(cmdId, cmd) {
				var hasPerm = cmd.hasOwnProperty('minPermission');
				if (!cmd.hidden && (!hasPerm || (maxPerm !== null && hasPerm &&
						pMod.permEqualOrGreater(maxPerm, cmd.minPermission)))) {
					if (!modCommands[mod.id])
						modCommands[mod.id] = {};
					modCommands[mod.id][cmdId] = cmd;
				}
			});
		});
		return modCommands;
	}

	/**
	 * Gets an object mapping of permission characters to another mapping of
	 * command IDs to command objects, grouping together all the commands
	 * that fall into that permission level for a given mod.  Only commands
	 * with required permissions equal to or less than maxPerm will be
	 * included.  Commands which do not have a required permission will
	 * be grouped under the "0" key.  Commands which only require a user's
	 * presence in a channel will be grouped under the "" key.
	 *
	 * @param {Object} mod A mod object whose commands should be sorted by
	 *      permission
	 * @param {String} maxPerm The permission char by which to limit the
	 *      returned commands
	 * @returns {Object} An object mapping of permission chars to an object
	 *      mapping command IDs to command objects
	 */
	function getCommandsByPerm(mod, maxPerm) {
		var pMod = modMan.getMod('users'),
			cmds = {};
		if (mod.commands) {
			objUtil.forEach(mod.commands, function(cmdId, cmd) {
				var perm = cmd.minPermission == undefined ? '0' :
						cmd.minPermission;
				if (!cmd.hidden && (perm == '0' ||
						pMod.permEqualOrGreater(maxPerm, perm))) {
					if (!cmds[perm])
						cmds[perm] = {};
					cmds[perm][cmdId] = cmd;
				}
			});
		}
		return cmds;
	}

	/**
	 * Sends an array of messages to the given target as irc NOTICEs one at
	 * a time, optionally replacing placeholders with actual values.
	 * Placeholders within the string should be put in curly braces.  For
	 * example:
	 *
	 *      "My name is {nick}"
	 *
	 * The 'replace' object then maps the text inside the braces to what
	 * should be inserted in their place.  For example:
	 *
	 *      {
	 *          nick: "Toady"
	 *      }
	 *
	 * @param {String} target The channel or nick to which the notices should
	 *      be sent
	 * @param {Array} messages An array of strings to be sent to the target
	 *      sequentially
	 * @param {Object} replace An object mapping placeholder text to the
	 *      strings that the braces and placeholders should be replaced with
	 */
	function sendHelp(target, messages, replace) {
		messages.forEach(function(msg) {
			if (replace) {
				objUtil.forEach(replace, function(str, repl) {
					msg = msg.replace('{' + str + '}', repl);
				});
			}
			client.notice(target, msg);
		});
	}

	/**
	 * Offers help for a specific command ID.
	 *
	 * @param {String} nick The nick to which the help notices should be sent
	 * @param {String} cmdId The ID of the command for which the help page
	 *      should be sent
	 */
	function showCommand(nick, cmdId) {
		var pMod = modMan.getMod('users'),
			cmd = modMan.getCommand(cmdId),
			fantasyChar = modMan.getMod('commandrunner').getFantasyChar();
		if (cmd) {
			var messages = [
				'***** {nick} Help *****',
				'COMMAND: {cmd}'
			];
			if (cmd.minPermission) {
				messages.push('REQUIRED PERMISSION: [' + cmd.minPermission +
					']' + pMod.getPermName(cmd.minPermission));
			}
			messages = messages.concat([
				'Provided by {mod} v{version} ({modId})',
				' '
			]);
			messages.push(cmd.desc);
			messages = messages.concat(cmd.help);
			messages.push('***** End of Help *****');
			sendHelp(nick, messages, {
				nick: client.nick,
				"!": fantasyChar,
				cmd: cmdId,
				mod: cmd.mod.name,
				modId: cmd.mod.id,
				version: cmd.mod.version
			});
		}
		else
			client.notice(nick, 'Command ' + cmdId + ' does not exist.');
	}

	/**
	 * Sends the main help page in irc NOTICEs to a given nick.
	 *
	 * @param {String} nick The user to receive the help page
	 * @param {String} maxPerm The highest permission for which to send
	 *      commands.  If this is set to the user's highest permission, they
	 *      will only see commands they have the ability to execute on at
	 *      least one channel
	 */
	function showMain(nick, maxPerm) {
		var fantasyChar = modMan.getMod('commandrunner').getFantasyChar(),
			modCmds = getModCommands(maxPerm),
			modIds = Object.keys(modCmds).sort(strSort);
		var messages = [
			'***** {nick} Help *****',
			name + ' v' + version + ' written by ' + author,
			'Get yourself a Toady: ' + url,
			' ',
			'To execute any command, you can send it like this:',
			'/msg {nick} COMMAND [other options here]',
			'Or say it in a channel I\'m in:',
			'{!}COMMAND [other options here]',
			'Type /msg {nick} help COMMAND for help on a specific command.',
			' ',
			'Modules with available commands:'
		];
		modIds.forEach(function(modId) {
			var mod = modMan.getMod(modId),
				cmds = modCmds[modId];
			messages.push(mod.name + ' v' + mod.version);
			objUtil.forEach(cmds, function(cmdId, cmd) {
				messages.push('  ' + padStr(cmdId, 15) + ' ' + cmd.desc);
			});
			messages.push(' ');
		});
		messages.push('***** End of Help *****');
		sendHelp(nick, messages, {
			nick: client.nick,
			"!": fantasyChar
		});
	}

	/**
	 * Shows the help page for a given mod, limiting the command listing to
	 * only commands requiring permissions equal to or less than maxPerm.
	 *
	 * @param {String} nick The user to whom the help page should be sent
	 * @param {String} modId The ID of the mod for which to display help
	 * @param {String} maxPerm The highest permission char for which to limit
	 *      the resulting command set
	 */
	function showMod(nick, modId, maxPerm) {
		var pMod = modMan.getMod('users'),
			mod = modMan.getMod(modId);
		if (mod) {
			var permCmds = getCommandsByPerm(mod, maxPerm),
				messages = [
				'***** {nick} Help *****',
				mod.name + ' v' + mod.version + ' (' + modId + ')',
				'Author: ' + mod.author
			];
			if (mod.url)
				messages.push('Website: ' + mod.url);
			messages.push(mod.desc);
			for (var i = 0; i < PERM_CHARS.length; i++) {
				var cmds = permCmds[PERM_CHARS[i]];
				if (cmds) {
					var permStr;
					switch (PERM_CHARS[i]) {
						case '': permStr = 'User'; break;
						case '0': permStr = 'Global'; break;
						default: permStr = '[' + PERM_CHARS[i] + ']' +
							pMod.getPermName(PERM_CHARS[i]);
					}
					messages.push(' ');
					messages.push(permStr + ':');
					objUtil.forEach(cmds, function(cmdId, cmd) {
						messages.push('  ' + padStr(cmdId, 15) + ' ' +
							cmd.desc);
					});
				}
			}
			messages.push('***** End of Help *****');
			sendHelp(nick, messages, {
				nick: client.nick
			});
		}
		else
			client.notice(nick, "Mod '" + modId + "' doesn't exist.");
	}

	/**
	 * Displays a list of all mods, loaded and not.
	 *
	 * @param nick
	 */
	function showModList(nick) {
		var modIds = modMan.getLoadedModIds().sort(strSort),
			messages = [
				'***** ' + client.nick + ' Help *****',
				'For more information on any loaded mod, type:',
				'/msg ' + client.nick + ' viewmod MODULE',
				' ',
				'Loaded mods:'
			];
		modIds.forEach(function(modId) {
			var mod = modMan.getMod(modId);
			messages.push('  ' + padStr(modId, 15) + ' ' + mod.desc);
		});
		modLoad.getUserModIds(function(err, ids) {
			if (!err && ids.length) {
				var availIds = [];
				ids.forEach(function(id) {
					if (!modMan.isLoaded(id))
						availIds.push(id);
				});
				availIds = availIds.sort(strSort);
				messages.push(' ');
				messages.push('Available to be loaded:');
				messages.push(availIds.join(', '));
			}
			messages.push('***** End of Help *****');
			sendHelp(nick, messages);
		});
	}

	return {
		name: 'Help',
		desc: "Provides help for bot commands",
		version: '0.1.0',
		author: 'Tom Frost',
		commands: {
			help: {
				handler: function(from, to, target, args) {
					if (args[1])
						showCommand(from, args[1]);
					else {
						var pMod = modMan.getMod('users');
						pMod.getHighestPermission(from, function(err, perm) {
							showMain(from, perm);
						});
					}
				},
				desc: "Shows the help page for a specific command, or lists \
commands",
				help: [
					"Format: {cmd} [command]",
					"Examples:",
					"  /msg {nick} {cmd}",
					"  {!}{cmd} say"
				],
				pattern: /^(\S+)?$/
			},
			listmods: {
				handler: function(from, to, target, args) {
					showModList(from);
				},
				desc: "Displays a list of all loaded and unloaded mods",
				help: [
					"Format: {cmd}",
					"Example:",
					"  /msg {nick} {cmd}"
				]
			},
			viewmod: {
				handler: function(from, to, target, args) {
					var pMod = modMan.getMod('users');
					pMod.getHighestPermission(from, function(err, perm) {
						showMod(from, args[1], perm);
					});
				},
				desc: "Shows the information associated with a given mod",
				help: [
					"Format: {cmd} [modId]",
					"Examples:",
					"  /msg {nick} {cmd} remote",
					"  {!}{cmd} help"
				],
				pattern: /^(\S+)$/
			}
		},
		sendHelp: sendHelp
	};
};<commit_msg>Help: Display config items in viewmod output<commit_after>/*
 * Toady
 * Copyright 2013 Tom Frost
 */

var objUtil = require('../util/Object'),
	modLoad = require('../modmanager/ModLoader'),
	pkgjson = require('../../package.json'),
	name = pkgjson.name,
	version = pkgjson.version,
	author = pkgjson.author,
	url = pkgjson.homepage;

const PERM_CHARS = ['O', 'S', 'P', '~', '&', '@', '%', '+', '', '0'];

function padStr(str, len) {
	while (str.length < len)
		str += ' ';
	return str;
}

function strSort(a, b) {
	if (a > b) return 1;
	if (a == b) return 0;
	return -1;
}

/**
 * Help provides all user commands necessary to display mod and command
 * metadata in a digestible format.
 *
 * @param {Object} config A Toady config object
 * @param {Object} client An IRC client object
 * @param {Object} modMan The Toady ModManager object
 * @returns {Object} A Toady mod
 */
module.exports = function(config, client, modMan) {

	/**
	 * Gets an object mapping of all Mod IDs to an additional object mapping
	 * of command IDs to command objects.  This result set will be limited to
	 * commands requiring permissions equal to or less than maxPerm, and
	 * mods which contain commands after that filter is applied.
	 *
	 * @param {String} maxPerm The maximum permission char for which to
	 *      return commands
	 * @returns {Object} An object mapping mod IDs to objects mapping command
	 *      IDs to commands, where each command's required permission is equal
	 *      to or less than maxPerm
	 */
	function getModCommands(maxPerm) {
		var mods = modMan.getMods(),
			pMod = modMan.getMod('users'),
			modCommands = {};
		if (!maxPerm && maxPerm != '')
			maxPerm = null;
		mods.forEach(function(mod) {
			objUtil.forEach(mod.commands || {}, function(cmdId, cmd) {
				var hasPerm = cmd.hasOwnProperty('minPermission');
				if (!cmd.hidden && (!hasPerm || (maxPerm !== null && hasPerm &&
						pMod.permEqualOrGreater(maxPerm, cmd.minPermission)))) {
					if (!modCommands[mod.id])
						modCommands[mod.id] = {};
					modCommands[mod.id][cmdId] = cmd;
				}
			});
		});
		return modCommands;
	}

	/**
	 * Gets an object mapping of permission characters to another mapping of
	 * command IDs to command objects, grouping together all the commands
	 * that fall into that permission level for a given mod.  Only commands
	 * with required permissions equal to or less than maxPerm will be
	 * included.  Commands which do not have a required permission will
	 * be grouped under the "0" key.  Commands which only require a user's
	 * presence in a channel will be grouped under the "" key.
	 *
	 * @param {Object} mod A mod object whose commands should be sorted by
	 *      permission
	 * @param {String} maxPerm The permission char by which to limit the
	 *      returned commands
	 * @returns {Object} An object mapping of permission chars to an object
	 *      mapping command IDs to command objects
	 */
	function getCommandsByPerm(mod, maxPerm) {
		var pMod = modMan.getMod('users'),
			cmds = {};
		if (mod.commands) {
			objUtil.forEach(mod.commands, function(cmdId, cmd) {
				var perm = cmd.minPermission == undefined ? '0' :
						cmd.minPermission;
				if (!cmd.hidden && (perm == '0' ||
						pMod.permEqualOrGreater(maxPerm, perm))) {
					if (!cmds[perm])
						cmds[perm] = {};
					cmds[perm][cmdId] = cmd;
				}
			});
		}
		return cmds;
	}

	/**
	 * Sends an array of messages to the given target as irc NOTICEs one at
	 * a time, optionally replacing placeholders with actual values.
	 * Placeholders within the string should be put in curly braces.  For
	 * example:
	 *
	 *      "My name is {nick}"
	 *
	 * The 'replace' object then maps the text inside the braces to what
	 * should be inserted in their place.  For example:
	 *
	 *      {
	 *          nick: "Toady"
	 *      }
	 *
	 * @param {String} target The channel or nick to which the notices should
	 *      be sent
	 * @param {Array} messages An array of strings to be sent to the target
	 *      sequentially
	 * @param {Object} replace An object mapping placeholder text to the
	 *      strings that the braces and placeholders should be replaced with
	 */
	function sendHelp(target, messages, replace) {
		messages.forEach(function(msg) {
			if (replace) {
				objUtil.forEach(replace, function(str, repl) {
					msg = msg.replace('{' + str + '}', repl);
				});
			}
			client.notice(target, msg);
		});
	}

	/**
	 * Offers help for a specific command ID.
	 *
	 * @param {String} nick The nick to which the help notices should be sent
	 * @param {String} cmdId The ID of the command for which the help page
	 *      should be sent
	 */
	function showCommand(nick, cmdId) {
		var pMod = modMan.getMod('users'),
			cmd = modMan.getCommand(cmdId),
			fantasyChar = modMan.getMod('commandrunner').getFantasyChar();
		if (cmd) {
			var messages = [
				'***** {nick} Help *****',
				'COMMAND: {cmd}'
			];
			if (cmd.minPermission) {
				messages.push('REQUIRED PERMISSION: [' + cmd.minPermission +
					']' + pMod.getPermName(cmd.minPermission));
			}
			messages = messages.concat([
				'Provided by {mod} v{version} ({modId})',
				' '
			]);
			messages.push(cmd.desc);
			messages = messages.concat(cmd.help);
			messages.push('***** End of Help *****');
			sendHelp(nick, messages, {
				nick: client.nick,
				"!": fantasyChar,
				cmd: cmdId,
				mod: cmd.mod.name,
				modId: cmd.mod.id,
				version: cmd.mod.version
			});
		}
		else
			client.notice(nick, 'Command ' + cmdId + ' does not exist.');
	}

	/**
	 * Sends the main help page in irc NOTICEs to a given nick.
	 *
	 * @param {String} nick The user to receive the help page
	 * @param {String} maxPerm The highest permission for which to send
	 *      commands.  If this is set to the user's highest permission, they
	 *      will only see commands they have the ability to execute on at
	 *      least one channel
	 */
	function showMain(nick, maxPerm) {
		var fantasyChar = modMan.getMod('commandrunner').getFantasyChar(),
			modCmds = getModCommands(maxPerm),
			modIds = Object.keys(modCmds).sort(strSort);
		var messages = [
			'***** {nick} Help *****',
			name + ' v' + version + ' written by ' + author,
			'Get yourself a Toady: ' + url,
			' ',
			'To execute any command, you can send it like this:',
			'/msg {nick} COMMAND [other options here]',
			'Or say it in a channel I\'m in:',
			'{!}COMMAND [other options here]',
			'Type /msg {nick} help COMMAND for help on a specific command.',
			' ',
			'Modules with available commands:'
		];
		modIds.forEach(function(modId) {
			var mod = modMan.getMod(modId),
				cmds = modCmds[modId];
			messages.push(mod.name + ' v' + mod.version);
			objUtil.forEach(cmds, function(cmdId, cmd) {
				messages.push('  ' + padStr(cmdId, 15) + ' ' + cmd.desc);
			});
			messages.push(' ');
		});
		messages.push('***** End of Help *****');
		sendHelp(nick, messages, {
			nick: client.nick,
			"!": fantasyChar
		});
	}

	/**
	 * Shows the help page for a given mod, limiting the command listing to
	 * only commands requiring permissions equal to or less than maxPerm.
	 * If maxPerm is S or O, the config options for the mod will be also be
	 * shown (if applicable).
	 *
	 * @param {String} nick The user to whom the help page should be sent
	 * @param {String} modId The ID of the mod for which to display help
	 * @param {String} maxPerm The highest permission char for which to limit
	 *      the resulting command set
	 */
	function showMod(nick, modId, maxPerm) {
		var pMod = modMan.getMod('users'),
			mod = modMan.getMod(modId);
		if (mod) {
			var permCmds = getCommandsByPerm(mod, maxPerm),
				messages = [
				'***** {nick} Help *****',
				mod.name + ' v' + mod.version + ' (' + modId + ')',
				'Author: ' + mod.author
			];
			if (mod.url)
				messages.push('Website: ' + mod.url);
			messages.push(mod.desc);
			for (var i = 0; i < PERM_CHARS.length; i++) {
				var cmds = permCmds[PERM_CHARS[i]];
				if (cmds) {
					var permStr;
					switch (PERM_CHARS[i]) {
						case '': permStr = 'User'; break;
						case '0': permStr = 'Global'; break;
						default: permStr = '[' + PERM_CHARS[i] + ']' +
							pMod.getPermName(PERM_CHARS[i]);
					}
					messages.push(' ');
					messages.push(permStr + ':');
					objUtil.forEach(cmds, function(cmdId, cmd) {
						messages.push('  ' + padStr(cmdId, 15) + ' ' +
							cmd.desc);
					});
				}
			}
			if (mod.configItems && pMod.permEqualOrGreater(maxPerm, 'S')) {
				messages.push(' ');
				messages.push('Config Items (To set: !viewmod config):');
				objUtil.forEach(mod.configItems, function(key, def) {
					var val;
					switch (def.type) {
						case 'boolean':
							val = mod.config[key] ? 'true' : 'false';
							break;
						case 'number':
							val = mod.config[key] || 0;
							break;
						default:
							val = mod.config[key] || '';
					}
					messages.push('  ' + padStr(key, 15) + ' ' +
						(def.desc || '') + ' (' + val + ')');
				});
			}
			messages.push('***** End of Help *****');
			sendHelp(nick, messages, {
				nick: client.nick
			});
		}
		else
			client.notice(nick, "Mod '" + modId + "' doesn't exist.");
	}

	/**
	 * Displays a list of all mods, loaded and not.
	 *
	 * @param nick
	 */
	function showModList(nick) {
		var modIds = modMan.getLoadedModIds().sort(strSort),
			messages = [
				'***** ' + client.nick + ' Help *****',
				'For more information on any loaded mod, type:',
				'/msg ' + client.nick + ' viewmod MODULE',
				' ',
				'Loaded mods:'
			];
		modIds.forEach(function(modId) {
			var mod = modMan.getMod(modId);
			messages.push('  ' + padStr(modId, 15) + ' ' + mod.desc);
		});
		modLoad.getUserModIds(function(err, ids) {
			if (!err && ids.length) {
				var availIds = [];
				ids.forEach(function(id) {
					if (!modMan.isLoaded(id))
						availIds.push(id);
				});
				availIds = availIds.sort(strSort);
				messages.push(' ');
				messages.push('Available to be loaded:');
				messages.push(availIds.join(', '));
			}
			messages.push('***** End of Help *****');
			sendHelp(nick, messages);
		});
	}

	return {
		name: 'Help',
		desc: "Provides help for bot commands",
		version: '0.1.0',
		author: 'Tom Frost',
		commands: {
			help: {
				handler: function(from, to, target, args) {
					if (args[1])
						showCommand(from, args[1]);
					else {
						var pMod = modMan.getMod('users');
						pMod.getHighestPermission(from, function(err, perm) {
							showMain(from, perm);
						});
					}
				},
				desc: "Shows the help page for a specific command, or lists \
commands",
				help: [
					"Format: {cmd} [command]",
					"Examples:",
					"  /msg {nick} {cmd}",
					"  {!}{cmd} say"
				],
				pattern: /^(\S+)?$/
			},
			listmods: {
				handler: function(from, to, target, args) {
					showModList(from);
				},
				desc: "Displays a list of all loaded and unloaded mods",
				help: [
					"Format: {cmd}",
					"Example:",
					"  /msg {nick} {cmd}"
				]
			},
			viewmod: {
				handler: function(from, to, target, args) {
					var pMod = modMan.getMod('users');
					pMod.getHighestPermission(from, function(err, perm) {
						showMod(from, args[1], perm);
					});
				},
				desc: "Shows the information associated with a given mod",
				help: [
					"Format: {cmd} [modId]",
					"Examples:",
					"  /msg {nick} {cmd} remote",
					"  {!}{cmd} help"
				],
				pattern: /^(\S+)$/
			}
		},
		sendHelp: sendHelp
	};
};<|endoftext|>


<commit_before>var APIURL = 'https://1dhhcnzmxi.execute-api.us-east-1.amazonaws.com/v1';
var HEADERS = {'Accept': 'application/json', 'Content-Type': 'application/json'};
var USER_URL = 'https://s3.amazonaws.com/constellational-store';
var POST_URL = 'https://d2nxl7qthm5fu1.cloudfront.net';

var SettingStore = require('../stores/SettingStore');
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var React = require('react-native');

var {
    AsyncStorage,
} = React;

var CHANGE_EVENT = 'change';

var _posts = null;
var _postURLs = null;
var _requests = null;

function retryFailedRequests() {
  var promiseArr = _requests.map((req) => {
    if (req.stat === 'succeeded') return req;
    else return fetch(req.url, req.params).then(res => res.json()).then((newPost) => {
      if (req.temporaryPostURL) replaceTemporaryPost(req.temporaryPostURL, newPost);
      req.stat = 'succeeded';
      return req;
    }).catch(() => {
      req.stat = 'failed';
      return req;
    });
  });
  Promise.all(promiseArr).then((res) => {
    _requests = res;
  });
}

function loadRequests() {
  return AsyncStorage.getItem('requests').then((str) => {
    if (!str) _requests = [];
    else _requests = JSON.parse(str);
  });
}

function saveRequests() {
  return AsyncStorage.setItem('requests', JSON.stringify(_requests));
}

function addRequest(url, params, temporaryPostURL) {
  var req = {url: url, params: params, temporaryPostURL: temporaryPostURL};
  if (!_requests) loadRequests().then(() => _requests.push(req)).then(saveRequests).then(retryFailedRequests);
  else {
    _requests.push(req);
    saveRequests().then(retryFailedRequests);
  }
}

function loadAsyncStore() {
  return AsyncStorage.getItem('posts').then((str) => {
    if (!str) _posts = {};
    else _posts = JSON.parse(str);
    return AsyncStorage.getItem('postURLs');
  }).then((str) => {
    if (!str) _postURLs = [];
    else _postURLs = JSON.parse(str);
    PostStore.emitChange();
  }).then(() => {
    return AsyncStorage.getItem('requests');
  }).then((str) => {
    if (!str) _requests = [];
    else _requests = JSON.parse(str);
  });
}

function replaceTemporaryPost(temporaryPostURL, newPost) {
  delete _posts[temporaryPostURL];
  var i = _postURLs.indexOf(temporaryPostURL);
  _postURLs.splice(i, 1);
  _postURLs.unshift(newPost.url);
  _posts[newPost.url] = newPost;
  PostStore.emitChange();
  return updateAsyncStore();
}

function createPost(post) {
  post.created = new Date().toISOString();
  post.updated = post.created;
  if (!post.id) post.id = post.created;
  post.key = post.created;
  post.url = post.key;
  _postURLs.unshift(post.url);
  _posts[post.url] = post;
  PostStore.emitChange();

  var username = SettingStore.getUsername();
  var url = APIURL + '/' + username;
  post.token = SettingStore.getToken();
  var params = {method: 'POST', body: JSON.stringify(post), headers: HEADERS};

  addRequest(url, params, post.url);
}

function editPost(post) {
  var i = _postURLs.indexOf(post.url);
  _postURLs.splice(i, 1);
  _postURLs.unshift(post.url);
  _posts[post.url] = post;
  PostStore.emitChange();

  var username = SettingStore.getUsername();
  var key = post.key;
  if (!key) key = post.created + post.id;
  var url = APIURL + '/' + username + '/' + key;
  post.token = SettingStore.getToken();
  var params = {method: 'PUT', body: JSON.stringify(post), headers: HEADERS};

  addRequest(url, params, post.url);
}

function deletePost(post) {
  var i = _postURLs.indexOf(post.url);
  _postURLs.splice(i, 1);
  delete _posts[post.url];
  PostStore.emitChange();

  var username = SettingStore.getUsername();
  var token = SettingStore.getToken();
  var body = JSON.stringify({token: token});
  var key = post.key;
  if (!key) key = post.created + post.id;
  var url = APIURL + '/' + username + '/' + key;
  var params = {method: 'DELETE', body: body, headers: HEADERS};

  addRequest(url, params);
}

function fetchUser(username) {
  return fetch(USER_URL + '/' + username).then(res => res.json());
}

function fetchPost(username, url) {
  return fetch(POST_URL + '/' + username + '/' + url).then(res => res.json()).then((post) => {
    post.url = url;
    return post;
  });
}

function fetchFromServer() {
  var username = SettingStore.getUsername();
  return fetchUser(username).then((user) => {
    _postURLs = user.posts;
    var promiseArr = user.posts.map(url => fetchPost(username, url));
    return Promise.all(promiseArr);
  }).then((posts) => {
    posts.map((post) => {
      _posts[post.url] = post;
    });
    PostStore.emitChange();
  });
}

function updateAsyncStore() {
  return AsyncStorage.setItem('posts', JSON.stringify(_posts)).then(() => {
    if (_postURLs) return AsyncStorage.setItem('postURLs', JSON.stringify(_postURLs));
  }).catch(err => {
    console.log("couldn't store post: " + err);
  });
}

var PostStore = assign({}, EventEmitter.prototype, {
  getAll: function() {
    if (!_postURLs) {
      loadAsyncStore().then(fetchFromServer).then(updateAsyncStore).then(retryFailedRequests);
      return [];
    } else {
      _postURLs = _postURLs.filter(url => !!url);
      return _postURLs.map(url => _posts[url]);
    }
  },

  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },

  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
  }
});

AppDispatcher.register(function(action) {
  switch(action.actionType) {
    case 'create-post':
      createPost(action.post);
      break;

    case 'edit-post':
      editPost(action.post);
      break;

    case 'delete-post':
      deletePost(action.post);
      break;

  }
});

module.exports = PostStore;
<commit_msg>support reading other users' posts<commit_after>var APIURL = 'https://1dhhcnzmxi.execute-api.us-east-1.amazonaws.com/v1';
var HEADERS = {'Accept': 'application/json', 'Content-Type': 'application/json'};
var USER_URL = 'https://s3.amazonaws.com/constellational-store';
var POST_URL = 'https://d2nxl7qthm5fu1.cloudfront.net';

var SettingStore = require('../stores/SettingStore');
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var React = require('react-native');

var {
    AsyncStorage,
} = React;

var CHANGE_EVENT = 'change';

var _posts = null;
var _users = null;
var _requests = null;

function retryFailedRequests() {
  var promiseArr = _requests.map((req) => {
    if (req.stat === 'succeeded') return req;
    else return fetch(req.url, req.params).then(res => res.json()).then((newPost) => {
      if (req.temporaryPostURL) replaceTemporaryPost(req.temporaryPostURL, newPost);
      req.stat = 'succeeded';
      return req;
    }).catch(() => {
      req.stat = 'failed';
      return req;
    });
  });
  Promise.all(promiseArr).then((res) => {
    _requests = res;
  });
}

function loadRequests() {
  return AsyncStorage.getItem('requests').then((str) => {
    if (!str) _requests = [];
    else _requests = JSON.parse(str);
  });
}

function saveRequests() {
  return AsyncStorage.setItem('requests', JSON.stringify(_requests));
}

function addRequest(url, params, temporaryPostURL) {
  var req = {url: url, params: params, temporaryPostURL: temporaryPostURL};
  if (!_requests) loadRequests().then(() => _requests.push(req)).then(saveRequests).then(retryFailedRequests);
  else {
    _requests.push(req);
    saveRequests().then(retryFailedRequests);
  }
}

function loadAsyncStore() {
  return AsyncStorage.getItem('posts').then((str) => {
    if (!str) _posts = {};
    else _posts = JSON.parse(str);
    return AsyncStorage.getItem('users');
  }).then((str) => {
    if (!str) _users = {}
    else _users = JSON.parse(str);
    PostStore.emitChange();
  }).then(() => {
    return AsyncStorage.getItem('requests');
  }).then((str) => {
    if (!str) _requests = [];
    else _requests = JSON.parse(str);
  });
}

function replaceTemporaryPost(temporaryPostURL, newPost) {
  var username = SettingStore.getUsername();
  delete _posts[username][temporaryPostURL];
  var i = _users[username].posts.indexOf(temporaryPostURL);
  _users[username].posts.splice(i, 1);
  _users[username].posts.unshift(newPost.url);
  _posts[username][newPost.url] = newPost;
  PostStore.emitChange();
  return updateAsyncStore();
}

function createPost(post) {
  var username = SettingStore.getUsername();
  post.created = new Date().toISOString();
  post.updated = post.created;
  if (!post.id) post.id = post.created;
  post.key = post.created;
  post.url = post.key;
  _users[username].posts.unshift(post.url);
  _posts[username][post.url] = post;
  PostStore.emitChange();

  var url = APIURL + '/' + username;
  post.token = SettingStore.getToken();
  var params = {method: 'POST', body: JSON.stringify(post), headers: HEADERS};

  addRequest(url, params, post.url);
}

function editPost(post) {
  var username = SettingStore.getUsername();
  var i = _users[username].posts.indexOf(post.url);
  _users[username].posts.splice(i, 1);
  _users[username].posts.unshift(post.url);
  _posts[username][post.url] = post;
  PostStore.emitChange();

  var key = post.key;
  if (!key) key = post.created + post.id;
  var url = APIURL + '/' + username + '/' + key;
  post.token = SettingStore.getToken();
  var params = {method: 'PUT', body: JSON.stringify(post), headers: HEADERS};

  addRequest(url, params, post.url);
}

function deletePost(post) {
  var username = SettingStore.getUsername();
  var i = _users[username].posts.indexOf(post.url);
  _users[username].posts.splice(i, 1);
  delete _posts[username][post.url];
  PostStore.emitChange();

  var token = SettingStore.getToken();
  var body = JSON.stringify({token: token});
  var key = post.key;
  if (!key) key = post.created + post.id;
  var url = APIURL + '/' + username + '/' + key;
  var params = {method: 'DELETE', body: body, headers: HEADERS};

  addRequest(url, params);
}

function fetchUser(username) {
  return fetch(USER_URL + '/' + username).then(res => res.json());
}

function fetchPost(username, url) {
  return fetch(POST_URL + '/' + username + '/' + url).then(res => res.json()).then((post) => {
    post.url = url;
    return post;
  });
}

function fetchFromServer(username) {
  if (!username) username = SettingStore.getUsername();
  return fetchUser(username).then((user) => {
    _users[username] = user;
    var promiseArr = user.posts.map(url => fetchPost(username, url));
    return Promise.all(promiseArr);
  }).then((posts) => {
    posts.map((post) => {
      _posts[username][post.url] = post;
    });
    PostStore.emitChange();
  });
}

function updateAsyncStore() {
  return AsyncStorage.setItem('posts', JSON.stringify(_posts)).then(() => {
    if (_users) return AsyncStorage.setItem('users', JSON.stringify(_users));
  }).catch(err => {
    console.log("couldn't update async store: " + err);
  });
}

var PostStore = assign({}, EventEmitter.prototype, {
  getAll: function(username) {
    if (!username) username = SettingStore.getUsername();
    if (!_users) {
      loadAsyncStore().then(fetchFromServer).then(updateAsyncStore).then(retryFailedRequests);
      return [];
    } else if (!_users[username]) {
      fetchFromServer(username).then(updateAsyncStore);
      return [];
    } else {
      _users[username].posts = _users[username].posts.filter(url => !!url);
      return _users[username].posts.map(url => _posts[username][url]);
    }
  },

  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },

  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
  }
});

AppDispatcher.register(function(action) {
  switch(action.actionType) {
    case 'create-post':
      createPost(action.post);
      break;

    case 'edit-post':
      editPost(action.post);
      break;

    case 'delete-post':
      deletePost(action.post);
      break;

  }
});

module.exports = PostStore;
<|endoftext|>


<commit_before>export default [
  {
    name: "Bengals",
    abbreviation: "CIN",
    logo: "",
    locationIdentifier: "city",
    stadium: {
      city: "Cincinnati",
      state: "Ohio",
      name: "",
      location: {
        lat: 39.095442,
        lng: -84.516039
      },
      roofType: "open"
    }
  }
];
<commit_msg>changed abbreviation -> abbr<commit_after>export default [
  {
    name: "Bengals",
    abbr: "CIN",
    logo: "",
    locationIdentifier: "city",
    stadium: {
      city: "Cincinnati",
      state: "Ohio",
      name: "",
      location: {
        lat: 39.095442,
        lng: -84.516039
      },
      roofType: "open"
    }
  }
];
<|endoftext|>


<commit_before><commit_msg>Remove unused createDebounce<commit_after><|endoftext|>